1d62bc4baSyz147064 /*
2d62bc4baSyz147064 * CDDL HEADER START
3d62bc4baSyz147064 *
4d62bc4baSyz147064 * The contents of this file are subject to the terms of the
5d62bc4baSyz147064 * Common Development and Distribution License (the "License").
6d62bc4baSyz147064 * You may not use this file except in compliance with the License.
7d62bc4baSyz147064 *
8d62bc4baSyz147064 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d62bc4baSyz147064 * or http://www.opensolaris.org/os/licensing.
10d62bc4baSyz147064 * See the License for the specific language governing permissions
11d62bc4baSyz147064 * and limitations under the License.
12d62bc4baSyz147064 *
13d62bc4baSyz147064 * When distributing Covered Code, include this CDDL HEADER in each
14d62bc4baSyz147064 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d62bc4baSyz147064 * If applicable, add the following below this CDDL HEADER, with the
16d62bc4baSyz147064 * fields enclosed by brackets "[]" replaced with your own identifying
17d62bc4baSyz147064 * information: Portions Copyright [yyyy] [name of copyright owner]
18d62bc4baSyz147064 *
19d62bc4baSyz147064 * CDDL HEADER END
20d62bc4baSyz147064 */
21d62bc4baSyz147064 /*
22d62bc4baSyz147064 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23d62bc4baSyz147064 * Use is subject to license terms.
24*9b664393SGarrett D'Amore *
25*9b664393SGarrett D'Amore * Copyright 2022 Garrett D'Amore
26d62bc4baSyz147064 */
27d62bc4baSyz147064
28d62bc4baSyz147064 #include <sys/types.h>
29d62bc4baSyz147064 #include <sys/mac.h>
30d62bc4baSyz147064 #include <sys/softmac_impl.h>
31d62bc4baSyz147064
32d62bc4baSyz147064 typedef struct softmac_capab_ops {
33d62bc4baSyz147064 int (*sc_hcksum_ack)(void *, t_uscalar_t);
34d62bc4baSyz147064 int (*sc_zcopy_ack)(void *, t_uscalar_t);
35d62bc4baSyz147064 } softmac_capab_ops_t;
36d62bc4baSyz147064
37d62bc4baSyz147064 static int dl_capab(ldi_handle_t, mblk_t **);
38d62bc4baSyz147064 static int softmac_fill_hcksum_ack(void *, t_uscalar_t);
39d62bc4baSyz147064 static int softmac_fill_zcopy_ack(void *, t_uscalar_t);
40d62bc4baSyz147064 static int softmac_adv_hcksum_ack(void *, t_uscalar_t);
41d62bc4baSyz147064 static int softmac_adv_zcopy_ack(void *, t_uscalar_t);
42d62bc4baSyz147064 static int softmac_enable_hcksum_ack(void *, t_uscalar_t);
43d62bc4baSyz147064 static int softmac_capab_send(softmac_lower_t *, boolean_t);
44d62bc4baSyz147064 static int i_capab_ack(mblk_t *, queue_t *, softmac_capab_ops_t *, void *);
45d62bc4baSyz147064 static int i_capab_id_ack(mblk_t *, dl_capability_sub_t *, queue_t *,
46d62bc4baSyz147064 softmac_capab_ops_t *, void *);
47d62bc4baSyz147064 static int i_capab_sub_ack(mblk_t *, dl_capability_sub_t *, queue_t *,
48d62bc4baSyz147064 softmac_capab_ops_t *, void *);
49d62bc4baSyz147064 static int i_capab_hcksum_ack(dl_capab_hcksum_t *, queue_t *,
50d62bc4baSyz147064 softmac_capab_ops_t *, void *);
51d62bc4baSyz147064 static int i_capab_zcopy_ack(dl_capab_zerocopy_t *, queue_t *,
52d62bc4baSyz147064 softmac_capab_ops_t *, void *);
53d62bc4baSyz147064 static int i_capab_hcksum_verify(dl_capab_hcksum_t *, queue_t *);
54d62bc4baSyz147064 static int i_capab_zcopy_verify(dl_capab_zerocopy_t *, queue_t *);
55d62bc4baSyz147064
56d62bc4baSyz147064 static softmac_capab_ops_t softmac_fill_capab_ops =
57d62bc4baSyz147064 {
58d62bc4baSyz147064 softmac_fill_hcksum_ack,
59d62bc4baSyz147064 softmac_fill_zcopy_ack,
60d62bc4baSyz147064 };
61d62bc4baSyz147064
62d62bc4baSyz147064 static softmac_capab_ops_t softmac_adv_capab_ops =
63d62bc4baSyz147064 {
64d62bc4baSyz147064 softmac_adv_hcksum_ack,
65d62bc4baSyz147064 softmac_adv_zcopy_ack,
66d62bc4baSyz147064 };
67d62bc4baSyz147064
68d62bc4baSyz147064 static softmac_capab_ops_t softmac_enable_capab_ops =
69d62bc4baSyz147064 {
70d62bc4baSyz147064 softmac_enable_hcksum_ack,
71d62bc4baSyz147064 NULL,
72d62bc4baSyz147064 };
73d62bc4baSyz147064
74d62bc4baSyz147064 int
softmac_fill_capab(ldi_handle_t lh,softmac_t * softmac)75d62bc4baSyz147064 softmac_fill_capab(ldi_handle_t lh, softmac_t *softmac)
76d62bc4baSyz147064 {
77d62bc4baSyz147064 mblk_t *mp = NULL;
78d62bc4baSyz147064 union DL_primitives *prim;
79d62bc4baSyz147064 int err = 0;
80d62bc4baSyz147064
81d62bc4baSyz147064 if ((err = dl_capab(lh, &mp)) != 0)
82d62bc4baSyz147064 goto exit;
83d62bc4baSyz147064
84d62bc4baSyz147064 prim = (union DL_primitives *)mp->b_rptr;
85d62bc4baSyz147064 if (prim->dl_primitive == DL_ERROR_ACK) {
86d62bc4baSyz147064 err = -1;
87d62bc4baSyz147064 goto exit;
88d62bc4baSyz147064 }
89d62bc4baSyz147064
90d62bc4baSyz147064 err = i_capab_ack(mp, NULL, &softmac_fill_capab_ops, softmac);
91d62bc4baSyz147064
92d62bc4baSyz147064 exit:
93d62bc4baSyz147064 freemsg(mp);
94d62bc4baSyz147064 return (err);
95d62bc4baSyz147064 }
96d62bc4baSyz147064
97d62bc4baSyz147064 static int
dl_capab(ldi_handle_t lh,mblk_t ** mpp)98d62bc4baSyz147064 dl_capab(ldi_handle_t lh, mblk_t **mpp)
99d62bc4baSyz147064 {
100d62bc4baSyz147064 dl_capability_req_t *capb;
101d62bc4baSyz147064 union DL_primitives *dl_prim;
102d62bc4baSyz147064 mblk_t *mp;
103d62bc4baSyz147064 int err;
104d62bc4baSyz147064
105d62bc4baSyz147064 if ((mp = allocb(sizeof (dl_capability_req_t), BPRI_MED)) == NULL)
106d62bc4baSyz147064 return (ENOMEM);
107d62bc4baSyz147064 mp->b_datap->db_type = M_PROTO;
108d62bc4baSyz147064
109d62bc4baSyz147064 capb = (dl_capability_req_t *)mp->b_wptr;
110d62bc4baSyz147064 mp->b_wptr += sizeof (dl_capability_req_t);
111d62bc4baSyz147064 bzero(mp->b_rptr, sizeof (dl_capability_req_t));
112d62bc4baSyz147064 capb->dl_primitive = DL_CAPABILITY_REQ;
113d62bc4baSyz147064
114d62bc4baSyz147064 (void) ldi_putmsg(lh, mp);
115d62bc4baSyz147064 if ((err = ldi_getmsg(lh, &mp, (timestruc_t *)NULL)) != 0)
116d62bc4baSyz147064 return (err);
117d62bc4baSyz147064
118d62bc4baSyz147064 dl_prim = (union DL_primitives *)mp->b_rptr;
119d62bc4baSyz147064 switch (dl_prim->dl_primitive) {
120d62bc4baSyz147064 case DL_CAPABILITY_ACK:
121d62bc4baSyz147064 if (MBLKL(mp) < DL_CAPABILITY_ACK_SIZE) {
122d62bc4baSyz147064 printf("dl_capability: DL_CAPABILITY_ACK "
123d62bc4baSyz147064 "protocol err\n");
124d62bc4baSyz147064 break;
125d62bc4baSyz147064 }
126d62bc4baSyz147064 *mpp = mp;
127d62bc4baSyz147064 return (0);
128d62bc4baSyz147064
129d62bc4baSyz147064 case DL_ERROR_ACK:
130d62bc4baSyz147064 if (MBLKL(mp) < DL_ERROR_ACK_SIZE) {
131d62bc4baSyz147064 printf("dl_capability: DL_ERROR_ACK protocol err\n");
132d62bc4baSyz147064 break;
133d62bc4baSyz147064 }
134d62bc4baSyz147064 if (((dl_error_ack_t *)dl_prim)->dl_error_primitive !=
135d62bc4baSyz147064 DL_CAPABILITY_REQ) {
136d62bc4baSyz147064 printf("dl_capability: DL_ERROR_ACK rtnd prim %u\n",
137d62bc4baSyz147064 ((dl_error_ack_t *)dl_prim)->dl_error_primitive);
138d62bc4baSyz147064 break;
139d62bc4baSyz147064 }
140d62bc4baSyz147064
141d62bc4baSyz147064 *mpp = mp;
142d62bc4baSyz147064 return (0);
143d62bc4baSyz147064
144d62bc4baSyz147064 default:
145d62bc4baSyz147064 printf("dl_capability: bad ACK header %u\n",
146d62bc4baSyz147064 dl_prim->dl_primitive);
147d62bc4baSyz147064 break;
148d62bc4baSyz147064 }
149d62bc4baSyz147064
150d62bc4baSyz147064 freemsg(mp);
151d62bc4baSyz147064 return (-1);
152d62bc4baSyz147064 }
153d62bc4baSyz147064
154d62bc4baSyz147064 static int
softmac_fill_hcksum_ack(void * arg,t_uscalar_t flags)155d62bc4baSyz147064 softmac_fill_hcksum_ack(void *arg, t_uscalar_t flags)
156d62bc4baSyz147064 {
157d62bc4baSyz147064 softmac_t *softmac = (softmac_t *)arg;
158d62bc4baSyz147064
159d62bc4baSyz147064 /*
160d62bc4baSyz147064 * There are two types of acks we process here:
161d62bc4baSyz147064 * 1. acks in reply to a (first form) generic capability req
162d62bc4baSyz147064 * (no ENABLE flag set)
163d62bc4baSyz147064 * 2. acks in reply to a ENABLE capability req.
164d62bc4baSyz147064 * (ENABLE flag set)
165d62bc4baSyz147064 * Only the first type should be expected here.
166d62bc4baSyz147064 */
167d62bc4baSyz147064
168d62bc4baSyz147064 if (flags & HCKSUM_ENABLE) {
169d62bc4baSyz147064 cmn_err(CE_WARN, "softmac_fill_hcksum_ack: unexpected "
170d62bc4baSyz147064 "HCKSUM_ENABLE flag in hardware checksum capability");
171d62bc4baSyz147064 } else if (flags & (HCKSUM_INET_PARTIAL | HCKSUM_INET_FULL_V4 |
172d62bc4baSyz147064 HCKSUM_INET_FULL_V6 | HCKSUM_IPHDRCKSUM)) {
173d62bc4baSyz147064 softmac->smac_capab_flags |= MAC_CAPAB_HCKSUM;
174d62bc4baSyz147064 softmac->smac_hcksum_txflags = flags;
175d62bc4baSyz147064 }
176d62bc4baSyz147064 return (0);
177d62bc4baSyz147064 }
178d62bc4baSyz147064
179d62bc4baSyz147064 static int
softmac_fill_zcopy_ack(void * arg,t_uscalar_t flags)180d62bc4baSyz147064 softmac_fill_zcopy_ack(void *arg, t_uscalar_t flags)
181d62bc4baSyz147064 {
182d62bc4baSyz147064 softmac_t *softmac = (softmac_t *)arg;
183d62bc4baSyz147064
184d62bc4baSyz147064 ASSERT(flags == DL_CAPAB_VMSAFE_MEM);
185d62bc4baSyz147064 softmac->smac_capab_flags &= (~MAC_CAPAB_NO_ZCOPY);
186d62bc4baSyz147064 return (0);
187d62bc4baSyz147064 }
188d62bc4baSyz147064
189d62bc4baSyz147064 int
softmac_capab_enable(softmac_lower_t * slp)190d62bc4baSyz147064 softmac_capab_enable(softmac_lower_t *slp)
191d62bc4baSyz147064 {
192d62bc4baSyz147064 softmac_t *softmac = slp->sl_softmac;
193d62bc4baSyz147064 int err;
194d62bc4baSyz147064
195d62bc4baSyz147064 if (softmac->smac_no_capability_req)
196d62bc4baSyz147064 return (0);
197d62bc4baSyz147064
198d62bc4baSyz147064 /*
199d62bc4baSyz147064 * Send DL_CAPABILITY_REQ to get capability advertisement.
200d62bc4baSyz147064 */
201d62bc4baSyz147064 if ((err = softmac_capab_send(slp, B_FALSE)) != 0)
202d62bc4baSyz147064 return (err);
203d62bc4baSyz147064
204d62bc4baSyz147064 /*
205d62bc4baSyz147064 * Send DL_CAPABILITY_REQ to enable specific capabilities.
206d62bc4baSyz147064 */
207d62bc4baSyz147064 if ((err = softmac_capab_send(slp, B_TRUE)) != 0)
208d62bc4baSyz147064 return (err);
209d62bc4baSyz147064
210d62bc4baSyz147064 return (0);
211d62bc4baSyz147064 }
212d62bc4baSyz147064
213d62bc4baSyz147064 static int
softmac_capab_send(softmac_lower_t * slp,boolean_t enable)214d62bc4baSyz147064 softmac_capab_send(softmac_lower_t *slp, boolean_t enable)
215d62bc4baSyz147064 {
216d62bc4baSyz147064 softmac_t *softmac;
217d62bc4baSyz147064 dl_capability_req_t *capb;
218d62bc4baSyz147064 dl_capability_sub_t *subcapb;
219d62bc4baSyz147064 mblk_t *reqmp, *ackmp;
220d62bc4baSyz147064 int err;
221d62bc4baSyz147064 size_t size = 0;
222d62bc4baSyz147064
223d62bc4baSyz147064 softmac = slp->sl_softmac;
224d62bc4baSyz147064
225d62bc4baSyz147064 if (enable) {
226d62bc4baSyz147064 /* No need to enable DL_CAPAB_ZEROCOPY */
227d62bc4baSyz147064 if (softmac->smac_capab_flags & MAC_CAPAB_HCKSUM)
228d62bc4baSyz147064 size += sizeof (dl_capability_sub_t) +
229d62bc4baSyz147064 sizeof (dl_capab_hcksum_t);
230d62bc4baSyz147064
231d62bc4baSyz147064 if (size == 0)
232d62bc4baSyz147064 return (0);
233d62bc4baSyz147064 }
234d62bc4baSyz147064
235d62bc4baSyz147064 /*
236d62bc4baSyz147064 * Create DL_CAPABILITY_REQ message and send it down
237d62bc4baSyz147064 */
238d62bc4baSyz147064 reqmp = allocb(sizeof (dl_capability_req_t) + size, BPRI_MED);
239d62bc4baSyz147064 if (reqmp == NULL)
240d62bc4baSyz147064 return (ENOMEM);
241d62bc4baSyz147064
242d62bc4baSyz147064 bzero(reqmp->b_rptr, sizeof (dl_capability_req_t) + size);
243d62bc4baSyz147064
244d62bc4baSyz147064 DB_TYPE(reqmp) = M_PROTO;
245d62bc4baSyz147064 reqmp->b_wptr = reqmp->b_rptr + sizeof (dl_capability_req_t) + size;
246d62bc4baSyz147064
247d62bc4baSyz147064 capb = (dl_capability_req_t *)reqmp->b_rptr;
248d62bc4baSyz147064 capb->dl_primitive = DL_CAPABILITY_REQ;
249d62bc4baSyz147064
250d62bc4baSyz147064 if (!enable)
251d62bc4baSyz147064 goto output;
252d62bc4baSyz147064
253d62bc4baSyz147064 capb->dl_sub_offset = sizeof (dl_capability_req_t);
254d62bc4baSyz147064
255d62bc4baSyz147064 if (softmac->smac_capab_flags & MAC_CAPAB_HCKSUM) {
256d62bc4baSyz147064 dl_capab_hcksum_t *hck_subcapp;
257d62bc4baSyz147064
258d62bc4baSyz147064 size = sizeof (dl_capability_sub_t) +
259d62bc4baSyz147064 sizeof (dl_capab_hcksum_t);
260d62bc4baSyz147064 capb->dl_sub_length += size;
261d62bc4baSyz147064
262d62bc4baSyz147064 subcapb = (dl_capability_sub_t *)(capb + 1);
263d62bc4baSyz147064 subcapb->dl_cap = DL_CAPAB_HCKSUM;
264d62bc4baSyz147064 subcapb->dl_length = sizeof (dl_capab_hcksum_t);
265d62bc4baSyz147064 hck_subcapp = (dl_capab_hcksum_t *)(subcapb + 1);
266d62bc4baSyz147064 hck_subcapp->hcksum_version = HCKSUM_VERSION_1;
267d62bc4baSyz147064 hck_subcapp->hcksum_txflags =
268d62bc4baSyz147064 softmac->smac_hcksum_txflags | HCKSUM_ENABLE;
269d62bc4baSyz147064 }
270d62bc4baSyz147064
271d62bc4baSyz147064 output:
272d62bc4baSyz147064 err = softmac_proto_tx(slp, reqmp, &ackmp);
273d62bc4baSyz147064 if (err == 0) {
274d62bc4baSyz147064 if (enable) {
275d62bc4baSyz147064 err = i_capab_ack(ackmp, NULL,
276d62bc4baSyz147064 &softmac_enable_capab_ops, softmac);
277d62bc4baSyz147064 } else {
278d62bc4baSyz147064 err = i_capab_ack(ackmp, NULL,
279d62bc4baSyz147064 &softmac_adv_capab_ops, softmac);
280d62bc4baSyz147064 }
281d62bc4baSyz147064 }
282d62bc4baSyz147064 freemsg(ackmp);
283d62bc4baSyz147064
284d62bc4baSyz147064 return (err);
285d62bc4baSyz147064 }
286d62bc4baSyz147064
287d62bc4baSyz147064 static int
softmac_adv_hcksum_ack(void * arg,t_uscalar_t flags)288d62bc4baSyz147064 softmac_adv_hcksum_ack(void *arg, t_uscalar_t flags)
289d62bc4baSyz147064 {
290d62bc4baSyz147064 softmac_t *softmac = (softmac_t *)arg;
291d62bc4baSyz147064
292d62bc4baSyz147064 /*
293d62bc4baSyz147064 * There are two types of acks we process here:
294d62bc4baSyz147064 * 1. acks in reply to a (first form) generic capability req
295d62bc4baSyz147064 * (no ENABLE flag set)
296d62bc4baSyz147064 * 2. acks in reply to a ENABLE capability req.
297d62bc4baSyz147064 * (ENABLE flag set)
298d62bc4baSyz147064 * Only the first type should be expected here.
299d62bc4baSyz147064 */
300d62bc4baSyz147064
301d62bc4baSyz147064 if (flags & HCKSUM_ENABLE) {
302d62bc4baSyz147064 cmn_err(CE_WARN, "softmac_adv_hcksum_ack: unexpected "
303d62bc4baSyz147064 "HCKSUM_ENABLE flag in hardware checksum capability");
304d62bc4baSyz147064 return (-1);
305d62bc4baSyz147064 } else if (flags & (HCKSUM_INET_PARTIAL | HCKSUM_INET_FULL_V4 |
306d62bc4baSyz147064 HCKSUM_INET_FULL_V6 | HCKSUM_IPHDRCKSUM)) {
307d62bc4baSyz147064 /*
308d62bc4baSyz147064 * The acknowledgement should be the same as we got when
309d62bc4baSyz147064 * the softmac is created.
310d62bc4baSyz147064 */
311d62bc4baSyz147064 if (!(softmac->smac_capab_flags & MAC_CAPAB_HCKSUM)) {
312d62bc4baSyz147064 ASSERT(B_FALSE);
313d62bc4baSyz147064 return (-1);
314d62bc4baSyz147064 }
315d62bc4baSyz147064 if (softmac->smac_hcksum_txflags != flags) {
316d62bc4baSyz147064 ASSERT(B_FALSE);
317d62bc4baSyz147064 return (-1);
318d62bc4baSyz147064 }
319d62bc4baSyz147064 }
320d62bc4baSyz147064
321d62bc4baSyz147064 return (0);
322d62bc4baSyz147064 }
323d62bc4baSyz147064
324d62bc4baSyz147064 static int
softmac_adv_zcopy_ack(void * arg,t_uscalar_t flags)325d62bc4baSyz147064 softmac_adv_zcopy_ack(void *arg, t_uscalar_t flags)
326d62bc4baSyz147064 {
327d62bc4baSyz147064 softmac_t *softmac = (softmac_t *)arg;
328d62bc4baSyz147064
329d62bc4baSyz147064 /*
330d62bc4baSyz147064 * The acknowledgement should be the same as we got when
331d62bc4baSyz147064 * the softmac is created.
332d62bc4baSyz147064 */
333d62bc4baSyz147064 ASSERT(flags == DL_CAPAB_VMSAFE_MEM);
334d62bc4baSyz147064 if (softmac->smac_capab_flags & MAC_CAPAB_NO_ZCOPY) {
335d62bc4baSyz147064 ASSERT(B_FALSE);
336d62bc4baSyz147064 return (-1);
337d62bc4baSyz147064 }
338d62bc4baSyz147064
339d62bc4baSyz147064 return (0);
340d62bc4baSyz147064 }
341d62bc4baSyz147064
342d62bc4baSyz147064 static int
softmac_enable_hcksum_ack(void * arg,t_uscalar_t flags)343d62bc4baSyz147064 softmac_enable_hcksum_ack(void *arg, t_uscalar_t flags)
344d62bc4baSyz147064 {
345d62bc4baSyz147064 softmac_t *softmac = (softmac_t *)arg;
346d62bc4baSyz147064
347d62bc4baSyz147064 /*
348d62bc4baSyz147064 * There are two types of acks we process here:
349d62bc4baSyz147064 * 1. acks in reply to a (first form) generic capability req
350d62bc4baSyz147064 * (no ENABLE flag set)
351d62bc4baSyz147064 * 2. acks in reply to a ENABLE capability req.
352d62bc4baSyz147064 * (ENABLE flag set)
353d62bc4baSyz147064 * Only the second type should be expected here.
354d62bc4baSyz147064 */
355d62bc4baSyz147064
356d62bc4baSyz147064 if (flags & HCKSUM_ENABLE) {
357d62bc4baSyz147064 if ((flags & ~HCKSUM_ENABLE) != softmac->smac_hcksum_txflags) {
358d62bc4baSyz147064 cmn_err(CE_WARN, "softmac_enable_hcksum_ack: unexpected"
359d62bc4baSyz147064 " hardware capability flag value 0x%x", flags);
360d62bc4baSyz147064 return (-1);
361d62bc4baSyz147064 }
362d62bc4baSyz147064 } else {
363d62bc4baSyz147064 cmn_err(CE_WARN, "softmac_enable_hcksum_ack: "
364d62bc4baSyz147064 "hardware checksum flag HCKSUM_ENABLE is not set");
365d62bc4baSyz147064 return (-1);
366d62bc4baSyz147064 }
367d62bc4baSyz147064
368d62bc4baSyz147064 return (0);
369d62bc4baSyz147064 }
370d62bc4baSyz147064
371d62bc4baSyz147064 static int
i_capab_ack(mblk_t * mp,queue_t * q,softmac_capab_ops_t * op,void * arg)372d62bc4baSyz147064 i_capab_ack(mblk_t *mp, queue_t *q, softmac_capab_ops_t *op, void *arg)
373d62bc4baSyz147064 {
374d62bc4baSyz147064 union DL_primitives *prim;
375d62bc4baSyz147064 dl_capability_ack_t *cap;
376d62bc4baSyz147064 dl_capability_sub_t *sub, *end;
377d62bc4baSyz147064 int err = 0;
378d62bc4baSyz147064
379d62bc4baSyz147064 prim = (union DL_primitives *)mp->b_rptr;
380d62bc4baSyz147064 ASSERT(prim->dl_primitive == DL_CAPABILITY_ACK);
381d62bc4baSyz147064
382d62bc4baSyz147064 cap = (dl_capability_ack_t *)prim;
383d62bc4baSyz147064 if (cap->dl_sub_length == 0)
384d62bc4baSyz147064 goto exit;
385d62bc4baSyz147064
386d62bc4baSyz147064 /* Is dl_sub_length correct? */
387d62bc4baSyz147064 if ((sizeof (*cap) + cap->dl_sub_length) > MBLKL(mp)) {
388d62bc4baSyz147064 err = EINVAL;
389d62bc4baSyz147064 goto exit;
390d62bc4baSyz147064 }
391d62bc4baSyz147064
392d62bc4baSyz147064 sub = (dl_capability_sub_t *)((caddr_t)cap + cap->dl_sub_offset);
393d62bc4baSyz147064 end = (dl_capability_sub_t *)((caddr_t)cap + cap->dl_sub_length
394d62bc4baSyz147064 - sizeof (*sub));
395d62bc4baSyz147064 for (; (sub <= end) && (err == 0); ) {
396d62bc4baSyz147064 switch (sub->dl_cap) {
397d62bc4baSyz147064 case DL_CAPAB_ID_WRAPPER:
398d62bc4baSyz147064 err = i_capab_id_ack(mp, sub, q, op, arg);
399d62bc4baSyz147064 break;
400d62bc4baSyz147064 default:
401d62bc4baSyz147064 err = i_capab_sub_ack(mp, sub, q, op, arg);
402d62bc4baSyz147064 break;
403d62bc4baSyz147064 }
404d62bc4baSyz147064 sub = (dl_capability_sub_t *)((caddr_t)sub + sizeof (*sub)
405d62bc4baSyz147064 + sub->dl_length);
406d62bc4baSyz147064 }
407d62bc4baSyz147064
408d62bc4baSyz147064 exit:
409d62bc4baSyz147064 return (err);
410d62bc4baSyz147064 }
411d62bc4baSyz147064
412d62bc4baSyz147064 static int
i_capab_id_ack(mblk_t * mp,dl_capability_sub_t * outers,queue_t * q,softmac_capab_ops_t * op,void * arg)413d62bc4baSyz147064 i_capab_id_ack(mblk_t *mp, dl_capability_sub_t *outers,
414d62bc4baSyz147064 queue_t *q, softmac_capab_ops_t *op, void *arg)
415d62bc4baSyz147064 {
416d62bc4baSyz147064 dl_capab_id_t *capab_id;
417d62bc4baSyz147064 dl_capability_sub_t *inners;
418d62bc4baSyz147064 caddr_t capend;
419d62bc4baSyz147064 int err = EINVAL;
420d62bc4baSyz147064
421d62bc4baSyz147064 ASSERT(outers->dl_cap == DL_CAPAB_ID_WRAPPER);
422d62bc4baSyz147064
423d62bc4baSyz147064 capend = (caddr_t)(outers + 1) + outers->dl_length;
424d62bc4baSyz147064 if (capend > (caddr_t)mp->b_wptr) {
425d62bc4baSyz147064 cmn_err(CE_WARN, "i_capab_id_ack: malformed "
426d62bc4baSyz147064 "sub-capability too long");
427d62bc4baSyz147064 return (err);
428d62bc4baSyz147064 }
429d62bc4baSyz147064
430d62bc4baSyz147064 capab_id = (dl_capab_id_t *)(outers + 1);
431d62bc4baSyz147064
432d62bc4baSyz147064 if (outers->dl_length < sizeof (*capab_id) ||
433d62bc4baSyz147064 (inners = &capab_id->id_subcap,
434d62bc4baSyz147064 inners->dl_length > (outers->dl_length - sizeof (*inners)))) {
435d62bc4baSyz147064 cmn_err(CE_WARN, "i_capab_id_ack: malformed "
436d62bc4baSyz147064 "encapsulated capab type %d too long",
437d62bc4baSyz147064 inners->dl_cap);
438d62bc4baSyz147064 return (err);
439d62bc4baSyz147064 }
440d62bc4baSyz147064
441d62bc4baSyz147064 if ((q != NULL) && (!dlcapabcheckqid(&capab_id->id_mid, q))) {
442d62bc4baSyz147064 cmn_err(CE_WARN, "i_capab_id_ack: pass-thru module(s) "
443d62bc4baSyz147064 "detected, discarding capab type %d", inners->dl_cap);
444d62bc4baSyz147064 return (err);
445d62bc4baSyz147064 }
446d62bc4baSyz147064
447d62bc4baSyz147064 /* Process the encapsulated sub-capability */
448d62bc4baSyz147064 return (i_capab_sub_ack(mp, inners, q, op, arg));
449d62bc4baSyz147064 }
450d62bc4baSyz147064
451d62bc4baSyz147064 static int
i_capab_sub_ack(mblk_t * mp,dl_capability_sub_t * sub,queue_t * q,softmac_capab_ops_t * op,void * arg)452d62bc4baSyz147064 i_capab_sub_ack(mblk_t *mp, dl_capability_sub_t *sub, queue_t *q,
453d62bc4baSyz147064 softmac_capab_ops_t *op, void *arg)
454d62bc4baSyz147064 {
455d62bc4baSyz147064 caddr_t capend;
456d62bc4baSyz147064 dl_capab_hcksum_t *hcksum;
457d62bc4baSyz147064 dl_capab_zerocopy_t *zcopy;
458d62bc4baSyz147064 int err = 0;
459d62bc4baSyz147064
460d62bc4baSyz147064 capend = (caddr_t)(sub + 1) + sub->dl_length;
461d62bc4baSyz147064 if (capend > (caddr_t)mp->b_wptr) {
462d62bc4baSyz147064 cmn_err(CE_WARN, "i_capab_sub_ack: "
463d62bc4baSyz147064 "malformed sub-capability too long");
464d62bc4baSyz147064 return (EINVAL);
465d62bc4baSyz147064 }
466d62bc4baSyz147064
467d62bc4baSyz147064 switch (sub->dl_cap) {
468d62bc4baSyz147064 case DL_CAPAB_HCKSUM:
469d62bc4baSyz147064 hcksum = (dl_capab_hcksum_t *)(sub + 1);
470d62bc4baSyz147064 err = i_capab_hcksum_ack(hcksum, q, op, arg);
471d62bc4baSyz147064 break;
472d62bc4baSyz147064
473d62bc4baSyz147064 case DL_CAPAB_ZEROCOPY:
474d62bc4baSyz147064 zcopy = (dl_capab_zerocopy_t *)(sub + 1);
475d62bc4baSyz147064 err = i_capab_zcopy_ack(zcopy, q, op, arg);
476d62bc4baSyz147064 break;
477d62bc4baSyz147064
478d62bc4baSyz147064 default:
479d62bc4baSyz147064 cmn_err(CE_WARN, "i_capab_sub_ack: unknown capab type %d",
480d62bc4baSyz147064 sub->dl_cap);
481d62bc4baSyz147064 err = EINVAL;
482d62bc4baSyz147064 }
483d62bc4baSyz147064
484d62bc4baSyz147064 return (err);
485d62bc4baSyz147064 }
486d62bc4baSyz147064
487d62bc4baSyz147064 static int
i_capab_hcksum_ack(dl_capab_hcksum_t * hcksum,queue_t * q,softmac_capab_ops_t * op,void * arg)488d62bc4baSyz147064 i_capab_hcksum_ack(dl_capab_hcksum_t *hcksum, queue_t *q,
489d62bc4baSyz147064 softmac_capab_ops_t *op, void *arg)
490d62bc4baSyz147064 {
491d62bc4baSyz147064 t_uscalar_t flags;
492d62bc4baSyz147064 int err = 0;
493d62bc4baSyz147064
494d62bc4baSyz147064 if ((err = i_capab_hcksum_verify(hcksum, q)) != 0)
495d62bc4baSyz147064 return (err);
496d62bc4baSyz147064
497d62bc4baSyz147064 flags = hcksum->hcksum_txflags;
498d62bc4baSyz147064
499d62bc4baSyz147064 if (!(flags & (HCKSUM_INET_PARTIAL | HCKSUM_INET_FULL_V4 |
500d62bc4baSyz147064 HCKSUM_INET_FULL_V6 | HCKSUM_IPHDRCKSUM | HCKSUM_ENABLE))) {
501d62bc4baSyz147064 cmn_err(CE_WARN, "i_capab_hcksum_ack: invalid "
502d62bc4baSyz147064 "hardware checksum capability flags 0x%x", flags);
503d62bc4baSyz147064 return (EINVAL);
504d62bc4baSyz147064 }
505d62bc4baSyz147064
506d62bc4baSyz147064 if (op->sc_hcksum_ack)
507d62bc4baSyz147064 return (op->sc_hcksum_ack(arg, flags));
508d62bc4baSyz147064 else {
509d62bc4baSyz147064 cmn_err(CE_WARN, "i_capab_hcksum_ack: unexpected hardware "
510d62bc4baSyz147064 "checksum acknowledgement");
511d62bc4baSyz147064 return (EINVAL);
512d62bc4baSyz147064 }
513d62bc4baSyz147064 }
514d62bc4baSyz147064
515d62bc4baSyz147064 static int
i_capab_zcopy_ack(dl_capab_zerocopy_t * zcopy,queue_t * q,softmac_capab_ops_t * op,void * arg)516d62bc4baSyz147064 i_capab_zcopy_ack(dl_capab_zerocopy_t *zcopy, queue_t *q,
517d62bc4baSyz147064 softmac_capab_ops_t *op, void *arg)
518d62bc4baSyz147064 {
519d62bc4baSyz147064 t_uscalar_t flags;
520d62bc4baSyz147064 int err = 0;
521d62bc4baSyz147064
522d62bc4baSyz147064 if ((err = i_capab_zcopy_verify(zcopy, q)) != 0)
523d62bc4baSyz147064 return (err);
524d62bc4baSyz147064
525d62bc4baSyz147064 flags = zcopy->zerocopy_flags;
526d62bc4baSyz147064 if (!(flags & DL_CAPAB_VMSAFE_MEM)) {
527d62bc4baSyz147064 cmn_err(CE_WARN, "i_capab_zcopy_ack: invalid zcopy capability "
528d62bc4baSyz147064 "flags 0x%x", flags);
529d62bc4baSyz147064 return (EINVAL);
530d62bc4baSyz147064 }
531d62bc4baSyz147064 if (op->sc_zcopy_ack)
532d62bc4baSyz147064 return (op->sc_zcopy_ack(arg, flags));
533d62bc4baSyz147064 else {
534d62bc4baSyz147064 cmn_err(CE_WARN, "i_capab_zcopy_ack: unexpected zcopy "
535d62bc4baSyz147064 "acknowledgement");
536d62bc4baSyz147064 return (EINVAL);
537d62bc4baSyz147064 }
538d62bc4baSyz147064 }
539d62bc4baSyz147064
540d62bc4baSyz147064 static int
i_capab_hcksum_verify(dl_capab_hcksum_t * hcksum,queue_t * q)541d62bc4baSyz147064 i_capab_hcksum_verify(dl_capab_hcksum_t *hcksum, queue_t *q)
542d62bc4baSyz147064 {
543d62bc4baSyz147064 if (hcksum->hcksum_version != HCKSUM_VERSION_1) {
544d62bc4baSyz147064 cmn_err(CE_WARN, "i_capab_hcksum_verify: "
545d62bc4baSyz147064 "unsupported hardware checksum capability (version %d, "
546d62bc4baSyz147064 "expected %d)", hcksum->hcksum_version, HCKSUM_VERSION_1);
547d62bc4baSyz147064 return (-1);
548d62bc4baSyz147064 }
549d62bc4baSyz147064
550d62bc4baSyz147064 if ((q != NULL) && !dlcapabcheckqid(&hcksum->hcksum_mid, q)) {
551d62bc4baSyz147064 cmn_err(CE_WARN, "i_capab_hcksum_verify: unexpected pass-thru "
552d62bc4baSyz147064 "module detected; hardware checksum capability discarded");
553d62bc4baSyz147064 return (-1);
554d62bc4baSyz147064 }
555d62bc4baSyz147064 return (0);
556d62bc4baSyz147064 }
557d62bc4baSyz147064
558d62bc4baSyz147064 static int
i_capab_zcopy_verify(dl_capab_zerocopy_t * zcopy,queue_t * q)559d62bc4baSyz147064 i_capab_zcopy_verify(dl_capab_zerocopy_t *zcopy, queue_t *q)
560d62bc4baSyz147064 {
561d62bc4baSyz147064 if (zcopy->zerocopy_version != ZEROCOPY_VERSION_1) {
562d62bc4baSyz147064 cmn_err(CE_WARN, "i_capab_zcopy_verify: unsupported zcopy "
563d62bc4baSyz147064 "capability (version %d, expected %d)",
564d62bc4baSyz147064 zcopy->zerocopy_version, ZEROCOPY_VERSION_1);
565d62bc4baSyz147064 return (-1);
566d62bc4baSyz147064 }
567d62bc4baSyz147064
568d62bc4baSyz147064 if ((q != NULL) && !dlcapabcheckqid(&zcopy->zerocopy_mid, q)) {
569d62bc4baSyz147064 cmn_err(CE_WARN, "i_capab_zcopy_verify: unexpected pass-thru "
570d62bc4baSyz147064 "module detected; zcopy checksum capability discarded");
571d62bc4baSyz147064 return (-1);
572d62bc4baSyz147064 }
573d62bc4baSyz147064 return (0);
574d62bc4baSyz147064 }
575