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
softmac_fill_capab(ldi_handle_t lh,softmac_t * softmac)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
dl_capab(ldi_handle_t lh,mblk_t ** mpp)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
softmac_fill_hcksum_ack(void * arg,t_uscalar_t flags)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
softmac_fill_zcopy_ack(void * arg,t_uscalar_t flags)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
softmac_fill_mdt_ack(void * arg,dl_capab_mdt_t * mdt)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
softmac_capab_enable(softmac_lower_t * slp)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
softmac_capab_send(softmac_lower_t * slp,boolean_t enable)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
softmac_adv_hcksum_ack(void * arg,t_uscalar_t flags)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
softmac_adv_zcopy_ack(void * arg,t_uscalar_t flags)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
softmac_adv_mdt_ack(void * arg,dl_capab_mdt_t * mdt)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
softmac_enable_hcksum_ack(void * arg,t_uscalar_t flags)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
softmac_enable_mdt_ack(void * arg,dl_capab_mdt_t * mdt)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
i_capab_ack(mblk_t * mp,queue_t * q,softmac_capab_ops_t * op,void * arg)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
i_capab_id_ack(mblk_t * mp,dl_capability_sub_t * outers,queue_t * q,softmac_capab_ops_t * op,void * arg)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
i_capab_sub_ack(mblk_t * mp,dl_capability_sub_t * sub,queue_t * q,softmac_capab_ops_t * op,void * arg)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
i_capab_hcksum_ack(dl_capab_hcksum_t * hcksum,queue_t * q,softmac_capab_ops_t * op,void * arg)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
i_capab_zcopy_ack(dl_capab_zerocopy_t * zcopy,queue_t * q,softmac_capab_ops_t * op,void * arg)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
i_capab_mdt_ack(dl_capab_mdt_t * mdt,queue_t * q,softmac_capab_ops_t * op,void * arg)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
i_capab_hcksum_verify(dl_capab_hcksum_t * hcksum,queue_t * q)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
i_capab_zcopy_verify(dl_capab_zerocopy_t * zcopy,queue_t * q)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
i_capab_mdt_verify(dl_capab_mdt_t * mdt,queue_t * q)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