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