1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <sys/mac.h> 30 #include <sys/softmac_impl.h> 31 32 typedef struct softmac_capab_ops { 33 int (*sc_hcksum_ack)(void *, t_uscalar_t); 34 int (*sc_zcopy_ack)(void *, t_uscalar_t); 35 int (*sc_mdt_ack)(void *, dl_capab_mdt_t *); 36 } softmac_capab_ops_t; 37 38 static int dl_capab(ldi_handle_t, mblk_t **); 39 static int softmac_fill_hcksum_ack(void *, t_uscalar_t); 40 static int softmac_fill_zcopy_ack(void *, t_uscalar_t); 41 static int softmac_fill_mdt_ack(void *, dl_capab_mdt_t *); 42 static int softmac_adv_hcksum_ack(void *, t_uscalar_t); 43 static int softmac_adv_zcopy_ack(void *, t_uscalar_t); 44 static int softmac_adv_mdt_ack(void *, dl_capab_mdt_t *); 45 static int softmac_enable_hcksum_ack(void *, t_uscalar_t); 46 static int softmac_enable_mdt_ack(void *, dl_capab_mdt_t *); 47 static int softmac_capab_send(softmac_lower_t *, boolean_t); 48 static int i_capab_ack(mblk_t *, queue_t *, softmac_capab_ops_t *, void *); 49 static int i_capab_id_ack(mblk_t *, dl_capability_sub_t *, queue_t *, 50 softmac_capab_ops_t *, void *); 51 static int i_capab_sub_ack(mblk_t *, dl_capability_sub_t *, queue_t *, 52 softmac_capab_ops_t *, void *); 53 static int i_capab_hcksum_ack(dl_capab_hcksum_t *, queue_t *, 54 softmac_capab_ops_t *, void *); 55 static int i_capab_zcopy_ack(dl_capab_zerocopy_t *, queue_t *, 56 softmac_capab_ops_t *, void *); 57 static int i_capab_mdt_ack(dl_capab_mdt_t *, queue_t *, 58 softmac_capab_ops_t *, void *); 59 static int i_capab_hcksum_verify(dl_capab_hcksum_t *, queue_t *); 60 static int i_capab_zcopy_verify(dl_capab_zerocopy_t *, queue_t *); 61 static int i_capab_mdt_verify(dl_capab_mdt_t *, queue_t *); 62 63 static softmac_capab_ops_t softmac_fill_capab_ops = 64 { 65 softmac_fill_hcksum_ack, 66 softmac_fill_zcopy_ack, 67 softmac_fill_mdt_ack, 68 }; 69 70 static softmac_capab_ops_t softmac_adv_capab_ops = 71 { 72 softmac_adv_hcksum_ack, 73 softmac_adv_zcopy_ack, 74 softmac_adv_mdt_ack 75 }; 76 77 static softmac_capab_ops_t softmac_enable_capab_ops = 78 { 79 softmac_enable_hcksum_ack, 80 NULL, 81 softmac_enable_mdt_ack 82 }; 83 84 int 85 softmac_fill_capab(ldi_handle_t lh, softmac_t *softmac) 86 { 87 mblk_t *mp = NULL; 88 union DL_primitives *prim; 89 int err = 0; 90 91 if ((err = dl_capab(lh, &mp)) != 0) 92 goto exit; 93 94 prim = (union DL_primitives *)mp->b_rptr; 95 if (prim->dl_primitive == DL_ERROR_ACK) { 96 err = -1; 97 goto exit; 98 } 99 100 err = i_capab_ack(mp, NULL, &softmac_fill_capab_ops, softmac); 101 102 exit: 103 freemsg(mp); 104 return (err); 105 } 106 107 static int 108 dl_capab(ldi_handle_t lh, mblk_t **mpp) 109 { 110 dl_capability_req_t *capb; 111 union DL_primitives *dl_prim; 112 mblk_t *mp; 113 int err; 114 115 if ((mp = allocb(sizeof (dl_capability_req_t), BPRI_MED)) == NULL) 116 return (ENOMEM); 117 mp->b_datap->db_type = M_PROTO; 118 119 capb = (dl_capability_req_t *)mp->b_wptr; 120 mp->b_wptr += sizeof (dl_capability_req_t); 121 bzero(mp->b_rptr, sizeof (dl_capability_req_t)); 122 capb->dl_primitive = DL_CAPABILITY_REQ; 123 124 (void) ldi_putmsg(lh, mp); 125 if ((err = ldi_getmsg(lh, &mp, (timestruc_t *)NULL)) != 0) 126 return (err); 127 128 dl_prim = (union DL_primitives *)mp->b_rptr; 129 switch (dl_prim->dl_primitive) { 130 case DL_CAPABILITY_ACK: 131 if (MBLKL(mp) < DL_CAPABILITY_ACK_SIZE) { 132 printf("dl_capability: DL_CAPABILITY_ACK " 133 "protocol err\n"); 134 break; 135 } 136 *mpp = mp; 137 return (0); 138 139 case DL_ERROR_ACK: 140 if (MBLKL(mp) < DL_ERROR_ACK_SIZE) { 141 printf("dl_capability: DL_ERROR_ACK protocol err\n"); 142 break; 143 } 144 if (((dl_error_ack_t *)dl_prim)->dl_error_primitive != 145 DL_CAPABILITY_REQ) { 146 printf("dl_capability: DL_ERROR_ACK rtnd prim %u\n", 147 ((dl_error_ack_t *)dl_prim)->dl_error_primitive); 148 break; 149 } 150 151 *mpp = mp; 152 return (0); 153 154 default: 155 printf("dl_capability: bad ACK header %u\n", 156 dl_prim->dl_primitive); 157 break; 158 } 159 160 freemsg(mp); 161 return (-1); 162 } 163 164 static int 165 softmac_fill_hcksum_ack(void *arg, t_uscalar_t flags) 166 { 167 softmac_t *softmac = (softmac_t *)arg; 168 169 /* 170 * There are two types of acks we process here: 171 * 1. acks in reply to a (first form) generic capability req 172 * (no ENABLE flag set) 173 * 2. acks in reply to a ENABLE capability req. 174 * (ENABLE flag set) 175 * Only the first type should be expected here. 176 */ 177 178 if (flags & HCKSUM_ENABLE) { 179 cmn_err(CE_WARN, "softmac_fill_hcksum_ack: unexpected " 180 "HCKSUM_ENABLE flag in hardware checksum capability"); 181 } else if (flags & (HCKSUM_INET_PARTIAL | HCKSUM_INET_FULL_V4 | 182 HCKSUM_INET_FULL_V6 | HCKSUM_IPHDRCKSUM)) { 183 softmac->smac_capab_flags |= MAC_CAPAB_HCKSUM; 184 softmac->smac_hcksum_txflags = flags; 185 } 186 return (0); 187 } 188 189 static int 190 softmac_fill_zcopy_ack(void *arg, t_uscalar_t flags) 191 { 192 softmac_t *softmac = (softmac_t *)arg; 193 194 ASSERT(flags == DL_CAPAB_VMSAFE_MEM); 195 softmac->smac_capab_flags &= (~MAC_CAPAB_NO_ZCOPY); 196 return (0); 197 } 198 199 static int 200 softmac_fill_mdt_ack(void *arg, dl_capab_mdt_t *mdt) 201 { 202 softmac_t *softmac = (softmac_t *)arg; 203 204 /* 205 * There are two types of acks we process here: 206 * 1. acks in reply to a (first form) generic capability req 207 * (ENABLE flag might be set by some drivers) 208 * 2. acks in reply to a ENABLE capability req. 209 * (ENABLE flag set) 210 */ 211 212 ASSERT(mdt->mdt_version == MDT_VERSION_2); 213 softmac->smac_mdt = B_TRUE; 214 softmac->smac_mdt_capab.mdt_hdr_head = mdt->mdt_hdr_head; 215 softmac->smac_mdt_capab.mdt_hdr_tail = mdt->mdt_hdr_tail; 216 softmac->smac_mdt_capab.mdt_max_pld = mdt->mdt_max_pld; 217 softmac->smac_mdt_capab.mdt_span_limit = mdt->mdt_span_limit; 218 return (0); 219 } 220 221 int 222 softmac_capab_enable(softmac_lower_t *slp) 223 { 224 softmac_t *softmac = slp->sl_softmac; 225 int err; 226 227 if (softmac->smac_no_capability_req) 228 return (0); 229 230 /* 231 * Send DL_CAPABILITY_REQ to get capability advertisement. 232 */ 233 if ((err = softmac_capab_send(slp, B_FALSE)) != 0) 234 return (err); 235 236 /* 237 * Send DL_CAPABILITY_REQ to enable specific capabilities. 238 */ 239 if ((err = softmac_capab_send(slp, B_TRUE)) != 0) 240 return (err); 241 242 return (0); 243 } 244 245 static int 246 softmac_capab_send(softmac_lower_t *slp, boolean_t enable) 247 { 248 softmac_t *softmac; 249 dl_capability_req_t *capb; 250 dl_capability_sub_t *subcapb; 251 mblk_t *reqmp, *ackmp; 252 int err; 253 size_t size = 0; 254 255 softmac = slp->sl_softmac; 256 257 if (enable) { 258 /* No need to enable DL_CAPAB_ZEROCOPY */ 259 if (softmac->smac_capab_flags & MAC_CAPAB_HCKSUM) 260 size += sizeof (dl_capability_sub_t) + 261 sizeof (dl_capab_hcksum_t); 262 263 if (softmac->smac_mdt) { 264 if (!(softmac->smac_mdt_capab.mdt_flags & 265 DL_CAPAB_MDT_ENABLE)) { 266 /* 267 * The MDT capability was not enabled for the 268 * first time, enable it now. 269 */ 270 size += sizeof (dl_capability_sub_t) + 271 sizeof (dl_capab_mdt_t); 272 } 273 } 274 275 if (size == 0) 276 return (0); 277 } 278 279 /* 280 * Create DL_CAPABILITY_REQ message and send it down 281 */ 282 reqmp = allocb(sizeof (dl_capability_req_t) + size, BPRI_MED); 283 if (reqmp == NULL) 284 return (ENOMEM); 285 286 bzero(reqmp->b_rptr, sizeof (dl_capability_req_t) + size); 287 288 DB_TYPE(reqmp) = M_PROTO; 289 reqmp->b_wptr = reqmp->b_rptr + sizeof (dl_capability_req_t) + size; 290 291 capb = (dl_capability_req_t *)reqmp->b_rptr; 292 capb->dl_primitive = DL_CAPABILITY_REQ; 293 294 if (!enable) 295 goto output; 296 297 capb->dl_sub_offset = sizeof (dl_capability_req_t); 298 299 if (softmac->smac_capab_flags & MAC_CAPAB_HCKSUM) { 300 dl_capab_hcksum_t *hck_subcapp; 301 302 size = sizeof (dl_capability_sub_t) + 303 sizeof (dl_capab_hcksum_t); 304 capb->dl_sub_length += size; 305 306 subcapb = (dl_capability_sub_t *)(capb + 1); 307 subcapb->dl_cap = DL_CAPAB_HCKSUM; 308 subcapb->dl_length = sizeof (dl_capab_hcksum_t); 309 hck_subcapp = (dl_capab_hcksum_t *)(subcapb + 1); 310 hck_subcapp->hcksum_version = HCKSUM_VERSION_1; 311 hck_subcapp->hcksum_txflags = 312 softmac->smac_hcksum_txflags | HCKSUM_ENABLE; 313 } 314 315 if (softmac->smac_mdt) { 316 if (!(softmac->smac_mdt_capab.mdt_flags & 317 DL_CAPAB_MDT_ENABLE)) { 318 dl_capab_mdt_t *mdt_subcapp; 319 320 size = sizeof (dl_capability_sub_t) + 321 sizeof (dl_capab_mdt_t); 322 capb->dl_sub_length += size; 323 324 subcapb = (dl_capability_sub_t *) 325 ((uint8_t *)(subcapb + 1) + subcapb->dl_length); 326 327 subcapb->dl_cap = DL_CAPAB_MDT; 328 subcapb->dl_length = sizeof (dl_capab_mdt_t); 329 mdt_subcapp = (dl_capab_mdt_t *)(subcapb + 1); 330 mdt_subcapp->mdt_version = MDT_VERSION_2; 331 mdt_subcapp->mdt_flags = 332 (softmac->smac_mdt_capab.mdt_flags | 333 DL_CAPAB_MDT_ENABLE); 334 mdt_subcapp->mdt_hdr_head = 335 softmac->smac_mdt_capab.mdt_hdr_head; 336 mdt_subcapp->mdt_hdr_tail = 337 softmac->smac_mdt_capab.mdt_hdr_tail; 338 mdt_subcapp->mdt_max_pld = 339 softmac->smac_mdt_capab.mdt_max_pld; 340 mdt_subcapp->mdt_span_limit = 341 softmac->smac_mdt_capab.mdt_span_limit; 342 } 343 } 344 345 output: 346 err = softmac_proto_tx(slp, reqmp, &ackmp); 347 if (err == 0) { 348 if (enable) { 349 err = i_capab_ack(ackmp, NULL, 350 &softmac_enable_capab_ops, softmac); 351 } else { 352 err = i_capab_ack(ackmp, NULL, 353 &softmac_adv_capab_ops, softmac); 354 } 355 } 356 freemsg(ackmp); 357 358 return (err); 359 } 360 361 static int 362 softmac_adv_hcksum_ack(void *arg, t_uscalar_t flags) 363 { 364 softmac_t *softmac = (softmac_t *)arg; 365 366 /* 367 * There are two types of acks we process here: 368 * 1. acks in reply to a (first form) generic capability req 369 * (no ENABLE flag set) 370 * 2. acks in reply to a ENABLE capability req. 371 * (ENABLE flag set) 372 * Only the first type should be expected here. 373 */ 374 375 if (flags & HCKSUM_ENABLE) { 376 cmn_err(CE_WARN, "softmac_adv_hcksum_ack: unexpected " 377 "HCKSUM_ENABLE flag in hardware checksum capability"); 378 return (-1); 379 } else if (flags & (HCKSUM_INET_PARTIAL | HCKSUM_INET_FULL_V4 | 380 HCKSUM_INET_FULL_V6 | HCKSUM_IPHDRCKSUM)) { 381 /* 382 * The acknowledgement should be the same as we got when 383 * the softmac is created. 384 */ 385 if (!(softmac->smac_capab_flags & MAC_CAPAB_HCKSUM)) { 386 ASSERT(B_FALSE); 387 return (-1); 388 } 389 if (softmac->smac_hcksum_txflags != flags) { 390 ASSERT(B_FALSE); 391 return (-1); 392 } 393 } 394 395 return (0); 396 } 397 398 static int 399 softmac_adv_zcopy_ack(void *arg, t_uscalar_t flags) 400 { 401 softmac_t *softmac = (softmac_t *)arg; 402 403 /* 404 * The acknowledgement should be the same as we got when 405 * the softmac is created. 406 */ 407 ASSERT(flags == DL_CAPAB_VMSAFE_MEM); 408 if (softmac->smac_capab_flags & MAC_CAPAB_NO_ZCOPY) { 409 ASSERT(B_FALSE); 410 return (-1); 411 } 412 413 return (0); 414 } 415 416 static int 417 softmac_adv_mdt_ack(void *arg, dl_capab_mdt_t *mdt) 418 { 419 softmac_t *softmac = (softmac_t *)arg; 420 421 /* 422 * The acknowledgement should be the same as we got when 423 * the softmac is created. 424 */ 425 if (!softmac->smac_mdt) { 426 ASSERT(B_FALSE); 427 return (-1); 428 } 429 430 if ((softmac->smac_mdt_capab.mdt_hdr_head != mdt->mdt_hdr_head) || 431 (softmac->smac_mdt_capab.mdt_hdr_tail != mdt->mdt_hdr_tail) || 432 (softmac->smac_mdt_capab.mdt_max_pld != mdt->mdt_max_pld) || 433 (softmac->smac_mdt_capab.mdt_span_limit != mdt->mdt_span_limit)) { 434 ASSERT(B_FALSE); 435 return (-1); 436 } 437 /* 438 * We need the mdt_flags field to know whether an additional 439 * DL_CAPAB_MDT_ENABLE is necessary. 440 */ 441 softmac->smac_mdt_capab.mdt_flags = mdt->mdt_flags; 442 return (0); 443 } 444 445 static int 446 softmac_enable_hcksum_ack(void *arg, t_uscalar_t flags) 447 { 448 softmac_t *softmac = (softmac_t *)arg; 449 450 /* 451 * There are two types of acks we process here: 452 * 1. acks in reply to a (first form) generic capability req 453 * (no ENABLE flag set) 454 * 2. acks in reply to a ENABLE capability req. 455 * (ENABLE flag set) 456 * Only the second type should be expected here. 457 */ 458 459 if (flags & HCKSUM_ENABLE) { 460 if ((flags & ~HCKSUM_ENABLE) != softmac->smac_hcksum_txflags) { 461 cmn_err(CE_WARN, "softmac_enable_hcksum_ack: unexpected" 462 " hardware capability flag value 0x%x", flags); 463 return (-1); 464 } 465 } else { 466 cmn_err(CE_WARN, "softmac_enable_hcksum_ack: " 467 "hardware checksum flag HCKSUM_ENABLE is not set"); 468 return (-1); 469 } 470 471 return (0); 472 } 473 474 static int 475 softmac_enable_mdt_ack(void *arg, dl_capab_mdt_t *mdt) 476 { 477 softmac_t *softmac = (softmac_t *)arg; 478 479 /* 480 * There are two types of acks we process here: 481 * 1. acks in reply to a (first form) generic capability req 482 * (no ENABLE flag set) 483 * 2. acks in reply to a ENABLE capability req. 484 * (ENABLE flag set) 485 * Only the second type should be expected here. 486 */ 487 488 if (mdt->mdt_flags & DL_CAPAB_MDT_ENABLE) { 489 if ((softmac->smac_mdt_capab.mdt_hdr_head != 490 mdt->mdt_hdr_head) || 491 (softmac->smac_mdt_capab.mdt_hdr_tail != 492 mdt->mdt_hdr_tail) || 493 (softmac->smac_mdt_capab.mdt_max_pld != 494 mdt->mdt_max_pld) || 495 (softmac->smac_mdt_capab.mdt_span_limit != 496 mdt->mdt_span_limit)) { 497 cmn_err(CE_WARN, "softmac_enable_mdt_ack: " 498 "unexpected MDT capability value"); 499 return (-1); 500 } 501 softmac->smac_mdt_capab.mdt_flags = mdt->mdt_flags; 502 } else { 503 cmn_err(CE_WARN, "softmac_enable_mdt_ack: " 504 "MDT flag DL_CAPAB_MDT_ENABLE is not set"); 505 return (-1); 506 } 507 508 return (0); 509 } 510 511 static int 512 i_capab_ack(mblk_t *mp, queue_t *q, softmac_capab_ops_t *op, void *arg) 513 { 514 union DL_primitives *prim; 515 dl_capability_ack_t *cap; 516 dl_capability_sub_t *sub, *end; 517 int err = 0; 518 519 prim = (union DL_primitives *)mp->b_rptr; 520 ASSERT(prim->dl_primitive == DL_CAPABILITY_ACK); 521 522 cap = (dl_capability_ack_t *)prim; 523 if (cap->dl_sub_length == 0) 524 goto exit; 525 526 /* Is dl_sub_length correct? */ 527 if ((sizeof (*cap) + cap->dl_sub_length) > MBLKL(mp)) { 528 err = EINVAL; 529 goto exit; 530 } 531 532 sub = (dl_capability_sub_t *)((caddr_t)cap + cap->dl_sub_offset); 533 end = (dl_capability_sub_t *)((caddr_t)cap + cap->dl_sub_length 534 - sizeof (*sub)); 535 for (; (sub <= end) && (err == 0); ) { 536 switch (sub->dl_cap) { 537 case DL_CAPAB_ID_WRAPPER: 538 err = i_capab_id_ack(mp, sub, q, op, arg); 539 break; 540 default: 541 err = i_capab_sub_ack(mp, sub, q, op, arg); 542 break; 543 } 544 sub = (dl_capability_sub_t *)((caddr_t)sub + sizeof (*sub) 545 + sub->dl_length); 546 } 547 548 exit: 549 return (err); 550 } 551 552 static int 553 i_capab_id_ack(mblk_t *mp, dl_capability_sub_t *outers, 554 queue_t *q, softmac_capab_ops_t *op, void *arg) 555 { 556 dl_capab_id_t *capab_id; 557 dl_capability_sub_t *inners; 558 caddr_t capend; 559 int err = EINVAL; 560 561 ASSERT(outers->dl_cap == DL_CAPAB_ID_WRAPPER); 562 563 capend = (caddr_t)(outers + 1) + outers->dl_length; 564 if (capend > (caddr_t)mp->b_wptr) { 565 cmn_err(CE_WARN, "i_capab_id_ack: malformed " 566 "sub-capability too long"); 567 return (err); 568 } 569 570 capab_id = (dl_capab_id_t *)(outers + 1); 571 572 if (outers->dl_length < sizeof (*capab_id) || 573 (inners = &capab_id->id_subcap, 574 inners->dl_length > (outers->dl_length - sizeof (*inners)))) { 575 cmn_err(CE_WARN, "i_capab_id_ack: malformed " 576 "encapsulated capab type %d too long", 577 inners->dl_cap); 578 return (err); 579 } 580 581 if ((q != NULL) && (!dlcapabcheckqid(&capab_id->id_mid, q))) { 582 cmn_err(CE_WARN, "i_capab_id_ack: pass-thru module(s) " 583 "detected, discarding capab type %d", inners->dl_cap); 584 return (err); 585 } 586 587 /* Process the encapsulated sub-capability */ 588 return (i_capab_sub_ack(mp, inners, q, op, arg)); 589 } 590 591 static int 592 i_capab_sub_ack(mblk_t *mp, dl_capability_sub_t *sub, queue_t *q, 593 softmac_capab_ops_t *op, void *arg) 594 { 595 caddr_t capend; 596 dl_capab_hcksum_t *hcksum; 597 dl_capab_zerocopy_t *zcopy; 598 dl_capab_mdt_t *mdt; 599 int err = 0; 600 601 capend = (caddr_t)(sub + 1) + sub->dl_length; 602 if (capend > (caddr_t)mp->b_wptr) { 603 cmn_err(CE_WARN, "i_capab_sub_ack: " 604 "malformed sub-capability too long"); 605 return (EINVAL); 606 } 607 608 switch (sub->dl_cap) { 609 case DL_CAPAB_HCKSUM: 610 hcksum = (dl_capab_hcksum_t *)(sub + 1); 611 err = i_capab_hcksum_ack(hcksum, q, op, arg); 612 break; 613 614 case DL_CAPAB_ZEROCOPY: 615 zcopy = (dl_capab_zerocopy_t *)(sub + 1); 616 err = i_capab_zcopy_ack(zcopy, q, op, arg); 617 break; 618 619 case DL_CAPAB_MDT: 620 mdt = (dl_capab_mdt_t *)(sub + 1); 621 err = i_capab_mdt_ack(mdt, q, op, arg); 622 break; 623 624 default: 625 cmn_err(CE_WARN, "i_capab_sub_ack: unknown capab type %d", 626 sub->dl_cap); 627 err = EINVAL; 628 } 629 630 return (err); 631 } 632 633 static int 634 i_capab_hcksum_ack(dl_capab_hcksum_t *hcksum, queue_t *q, 635 softmac_capab_ops_t *op, void *arg) 636 { 637 t_uscalar_t flags; 638 int err = 0; 639 640 if ((err = i_capab_hcksum_verify(hcksum, q)) != 0) 641 return (err); 642 643 flags = hcksum->hcksum_txflags; 644 645 if (!(flags & (HCKSUM_INET_PARTIAL | HCKSUM_INET_FULL_V4 | 646 HCKSUM_INET_FULL_V6 | HCKSUM_IPHDRCKSUM | HCKSUM_ENABLE))) { 647 cmn_err(CE_WARN, "i_capab_hcksum_ack: invalid " 648 "hardware checksum capability flags 0x%x", flags); 649 return (EINVAL); 650 } 651 652 if (op->sc_hcksum_ack) 653 return (op->sc_hcksum_ack(arg, flags)); 654 else { 655 cmn_err(CE_WARN, "i_capab_hcksum_ack: unexpected hardware " 656 "checksum acknowledgement"); 657 return (EINVAL); 658 } 659 } 660 661 static int 662 i_capab_zcopy_ack(dl_capab_zerocopy_t *zcopy, queue_t *q, 663 softmac_capab_ops_t *op, void *arg) 664 { 665 t_uscalar_t flags; 666 int err = 0; 667 668 if ((err = i_capab_zcopy_verify(zcopy, q)) != 0) 669 return (err); 670 671 flags = zcopy->zerocopy_flags; 672 if (!(flags & DL_CAPAB_VMSAFE_MEM)) { 673 cmn_err(CE_WARN, "i_capab_zcopy_ack: invalid zcopy capability " 674 "flags 0x%x", flags); 675 return (EINVAL); 676 } 677 if (op->sc_zcopy_ack) 678 return (op->sc_zcopy_ack(arg, flags)); 679 else { 680 cmn_err(CE_WARN, "i_capab_zcopy_ack: unexpected zcopy " 681 "acknowledgement"); 682 return (EINVAL); 683 } 684 } 685 686 static int 687 i_capab_mdt_ack(dl_capab_mdt_t *mdt, queue_t *q, 688 softmac_capab_ops_t *op, void *arg) 689 { 690 int err; 691 692 if ((err = i_capab_mdt_verify(mdt, q)) != 0) 693 return (err); 694 695 if (op->sc_mdt_ack) 696 return (op->sc_mdt_ack(arg, mdt)); 697 else { 698 cmn_err(CE_WARN, "i_capab_mdt_ack: unexpected MDT " 699 "acknowledgement"); 700 return (EINVAL); 701 } 702 } 703 704 static int 705 i_capab_hcksum_verify(dl_capab_hcksum_t *hcksum, queue_t *q) 706 { 707 if (hcksum->hcksum_version != HCKSUM_VERSION_1) { 708 cmn_err(CE_WARN, "i_capab_hcksum_verify: " 709 "unsupported hardware checksum capability (version %d, " 710 "expected %d)", hcksum->hcksum_version, HCKSUM_VERSION_1); 711 return (-1); 712 } 713 714 if ((q != NULL) && !dlcapabcheckqid(&hcksum->hcksum_mid, q)) { 715 cmn_err(CE_WARN, "i_capab_hcksum_verify: unexpected pass-thru " 716 "module detected; hardware checksum capability discarded"); 717 return (-1); 718 } 719 return (0); 720 } 721 722 static int 723 i_capab_zcopy_verify(dl_capab_zerocopy_t *zcopy, queue_t *q) 724 { 725 if (zcopy->zerocopy_version != ZEROCOPY_VERSION_1) { 726 cmn_err(CE_WARN, "i_capab_zcopy_verify: unsupported zcopy " 727 "capability (version %d, expected %d)", 728 zcopy->zerocopy_version, ZEROCOPY_VERSION_1); 729 return (-1); 730 } 731 732 if ((q != NULL) && !dlcapabcheckqid(&zcopy->zerocopy_mid, q)) { 733 cmn_err(CE_WARN, "i_capab_zcopy_verify: unexpected pass-thru " 734 "module detected; zcopy checksum capability discarded"); 735 return (-1); 736 } 737 return (0); 738 } 739 740 static int 741 i_capab_mdt_verify(dl_capab_mdt_t *mdt, queue_t *q) 742 { 743 if (mdt->mdt_version != MDT_VERSION_2) { 744 cmn_err(CE_WARN, "i_capab_mdt_verify: unsupported MDT " 745 "capability (version %d, expected %d)", 746 mdt->mdt_version, MDT_VERSION_2); 747 return (-1); 748 } 749 750 if ((q != NULL) && !dlcapabcheckqid(&mdt->mdt_mid, q)) { 751 cmn_err(CE_WARN, "i_capab_mdt_verify: unexpected pass-thru " 752 "module detected; MDT capability discarded"); 753 return (-1); 754 } 755 return (0); 756 } 757