17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
56b6515e2Sericheng * Common Development and Distribution License (the "License").
66b6515e2Sericheng * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
229056fcebSCathy Zhou * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23cabb4db9SDan McDonald * Copyright 2012, Nexenta Systems, Inc. All rights reserved.
2415c07adcSJohn Levon * Copyright (c) 2018, Joyent, Inc.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate * Data-Link Driver
297c478bd9Sstevel@tonic-gate */
307c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
317c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
32da14cebeSEric Cheng #include <sys/strsun.h>
337c478bd9Sstevel@tonic-gate #include <sys/vlan.h>
347c478bd9Sstevel@tonic-gate #include <sys/dld_impl.h>
35da14cebeSEric Cheng #include <sys/mac_client.h>
36da14cebeSEric Cheng #include <sys/mac_client_impl.h>
37da14cebeSEric Cheng #include <sys/mac_client_priv.h>
387c478bd9Sstevel@tonic-gate
39da14cebeSEric Cheng typedef void proto_reqfunc_t(dld_str_t *, mblk_t *);
407c478bd9Sstevel@tonic-gate
417c478bd9Sstevel@tonic-gate static proto_reqfunc_t proto_info_req, proto_attach_req, proto_detach_req,
427c478bd9Sstevel@tonic-gate proto_bind_req, proto_unbind_req, proto_promiscon_req, proto_promiscoff_req,
437c478bd9Sstevel@tonic-gate proto_enabmulti_req, proto_disabmulti_req, proto_physaddr_req,
447c478bd9Sstevel@tonic-gate proto_setphysaddr_req, proto_udqos_req, proto_req, proto_capability_req,
45d62bc4baSyz proto_notify_req, proto_passive_req;
467c478bd9Sstevel@tonic-gate
47da14cebeSEric Cheng static void proto_capability_advertise(dld_str_t *, mblk_t *);
48da14cebeSEric Cheng static int dld_capab_poll_disable(dld_str_t *, dld_capab_poll_t *);
498d4cf8d8S static boolean_t check_mod_above(queue_t *, const char *);
504b46d1efSkrgopi
517c478bd9Sstevel@tonic-gate #define DL_ACK_PENDING(state) \
527c478bd9Sstevel@tonic-gate ((state) == DL_ATTACH_PENDING || \
537c478bd9Sstevel@tonic-gate (state) == DL_DETACH_PENDING || \
547c478bd9Sstevel@tonic-gate (state) == DL_BIND_PENDING || \
557c478bd9Sstevel@tonic-gate (state) == DL_UNBIND_PENDING)
567c478bd9Sstevel@tonic-gate
577c478bd9Sstevel@tonic-gate /*
58210db224Sericheng * Process a DLPI protocol message.
59210db224Sericheng * The primitives DL_BIND_REQ, DL_ENABMULTI_REQ, DL_PROMISCON_REQ,
60210db224Sericheng * DL_SET_PHYS_ADDR_REQ put the data link below our dld_str_t into an
61210db224Sericheng * 'active' state. The primitive DL_PASSIVE_REQ marks our dld_str_t
62210db224Sericheng * as 'passive' and forbids it from being subsequently made 'active'
63210db224Sericheng * by the above primitives.
647c478bd9Sstevel@tonic-gate */
657c478bd9Sstevel@tonic-gate void
dld_proto(dld_str_t * dsp,mblk_t * mp)66da14cebeSEric Cheng dld_proto(dld_str_t *dsp, mblk_t *mp)
677c478bd9Sstevel@tonic-gate {
687c478bd9Sstevel@tonic-gate t_uscalar_t prim;
697c478bd9Sstevel@tonic-gate
70da14cebeSEric Cheng if (MBLKL(mp) < sizeof (t_uscalar_t)) {
71da14cebeSEric Cheng freemsg(mp);
72da14cebeSEric Cheng return;
73da14cebeSEric Cheng }
74da14cebeSEric Cheng prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive;
757c478bd9Sstevel@tonic-gate
76210db224Sericheng switch (prim) {
77210db224Sericheng case DL_INFO_REQ:
78da14cebeSEric Cheng proto_info_req(dsp, mp);
79210db224Sericheng break;
80210db224Sericheng case DL_BIND_REQ:
81da14cebeSEric Cheng proto_bind_req(dsp, mp);
82210db224Sericheng break;
83210db224Sericheng case DL_UNBIND_REQ:
84da14cebeSEric Cheng proto_unbind_req(dsp, mp);
85da14cebeSEric Cheng break;
86da14cebeSEric Cheng case DL_UNITDATA_REQ:
87da14cebeSEric Cheng proto_unitdata_req(dsp, mp);
88210db224Sericheng break;
89210db224Sericheng case DL_UDQOS_REQ:
90da14cebeSEric Cheng proto_udqos_req(dsp, mp);
91210db224Sericheng break;
92210db224Sericheng case DL_ATTACH_REQ:
93da14cebeSEric Cheng proto_attach_req(dsp, mp);
94210db224Sericheng break;
95210db224Sericheng case DL_DETACH_REQ:
96da14cebeSEric Cheng proto_detach_req(dsp, mp);
97210db224Sericheng break;
98210db224Sericheng case DL_ENABMULTI_REQ:
99da14cebeSEric Cheng proto_enabmulti_req(dsp, mp);
100210db224Sericheng break;
101210db224Sericheng case DL_DISABMULTI_REQ:
102da14cebeSEric Cheng proto_disabmulti_req(dsp, mp);
103210db224Sericheng break;
104210db224Sericheng case DL_PROMISCON_REQ:
105da14cebeSEric Cheng proto_promiscon_req(dsp, mp);
106210db224Sericheng break;
107210db224Sericheng case DL_PROMISCOFF_REQ:
108da14cebeSEric Cheng proto_promiscoff_req(dsp, mp);
109210db224Sericheng break;
110210db224Sericheng case DL_PHYS_ADDR_REQ:
111da14cebeSEric Cheng proto_physaddr_req(dsp, mp);
112210db224Sericheng break;
113210db224Sericheng case DL_SET_PHYS_ADDR_REQ:
114da14cebeSEric Cheng proto_setphysaddr_req(dsp, mp);
115210db224Sericheng break;
116210db224Sericheng case DL_NOTIFY_REQ:
117da14cebeSEric Cheng proto_notify_req(dsp, mp);
118210db224Sericheng break;
119210db224Sericheng case DL_CAPABILITY_REQ:
120da14cebeSEric Cheng proto_capability_req(dsp, mp);
121210db224Sericheng break;
122210db224Sericheng case DL_PASSIVE_REQ:
123da14cebeSEric Cheng proto_passive_req(dsp, mp);
124210db224Sericheng break;
125210db224Sericheng default:
126da14cebeSEric Cheng proto_req(dsp, mp);
127210db224Sericheng break;
128210db224Sericheng }
129210db224Sericheng }
130210db224Sericheng
131210db224Sericheng #define NEG(x) -(x)
132210db224Sericheng typedef struct dl_info_ack_wrapper {
133210db224Sericheng dl_info_ack_t dl_info;
134ba2e4443Sseb uint8_t dl_addr[MAXMACADDRLEN + sizeof (uint16_t)];
135ba2e4443Sseb uint8_t dl_brdcst_addr[MAXMACADDRLEN];
136210db224Sericheng dl_qos_cl_range1_t dl_qos_range1;
137210db224Sericheng dl_qos_cl_sel1_t dl_qos_sel1;
138210db224Sericheng } dl_info_ack_wrapper_t;
139210db224Sericheng
140210db224Sericheng /*
141210db224Sericheng * DL_INFO_REQ
142210db224Sericheng */
143da14cebeSEric Cheng static void
proto_info_req(dld_str_t * dsp,mblk_t * mp)144da14cebeSEric Cheng proto_info_req(dld_str_t *dsp, mblk_t *mp)
145210db224Sericheng {
146210db224Sericheng dl_info_ack_wrapper_t *dlwp;
147210db224Sericheng dl_info_ack_t *dlp;
148210db224Sericheng dl_qos_cl_sel1_t *selp;
149210db224Sericheng dl_qos_cl_range1_t *rangep;
150210db224Sericheng uint8_t *addr;
151210db224Sericheng uint8_t *brdcst_addr;
152210db224Sericheng uint_t addr_length;
153210db224Sericheng uint_t sap_length;
154210db224Sericheng mac_info_t minfo;
155210db224Sericheng mac_info_t *minfop;
156210db224Sericheng queue_t *q = dsp->ds_wq;
157210db224Sericheng
1587c478bd9Sstevel@tonic-gate /*
159210db224Sericheng * Swap the request message for one large enough to contain the
160210db224Sericheng * wrapper structure defined above.
1617c478bd9Sstevel@tonic-gate */
162210db224Sericheng if ((mp = mexchange(q, mp, sizeof (dl_info_ack_wrapper_t),
163210db224Sericheng M_PCPROTO, 0)) == NULL)
164da14cebeSEric Cheng return;
1657c478bd9Sstevel@tonic-gate
166210db224Sericheng bzero(mp->b_rptr, sizeof (dl_info_ack_wrapper_t));
167210db224Sericheng dlwp = (dl_info_ack_wrapper_t *)mp->b_rptr;
1687c478bd9Sstevel@tonic-gate
169210db224Sericheng dlp = &(dlwp->dl_info);
170210db224Sericheng ASSERT(dlp == (dl_info_ack_t *)mp->b_rptr);
1717c478bd9Sstevel@tonic-gate
172210db224Sericheng dlp->dl_primitive = DL_INFO_ACK;
173210db224Sericheng
174210db224Sericheng /*
175210db224Sericheng * Set up the sub-structure pointers.
176210db224Sericheng */
177210db224Sericheng addr = dlwp->dl_addr;
178210db224Sericheng brdcst_addr = dlwp->dl_brdcst_addr;
179210db224Sericheng rangep = &(dlwp->dl_qos_range1);
180210db224Sericheng selp = &(dlwp->dl_qos_sel1);
1817c478bd9Sstevel@tonic-gate
182210db224Sericheng /*
183210db224Sericheng * This driver supports only version 2 connectionless DLPI provider
184210db224Sericheng * nodes.
185210db224Sericheng */
186210db224Sericheng dlp->dl_service_mode = DL_CLDLS;
187210db224Sericheng dlp->dl_version = DL_VERSION_2;
1887c478bd9Sstevel@tonic-gate
1897c478bd9Sstevel@tonic-gate /*
190210db224Sericheng * Set the style of the provider
1917c478bd9Sstevel@tonic-gate */
192210db224Sericheng dlp->dl_provider_style = dsp->ds_style;
193210db224Sericheng ASSERT(dlp->dl_provider_style == DL_STYLE1 ||
194210db224Sericheng dlp->dl_provider_style == DL_STYLE2);
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate /*
197210db224Sericheng * Set the current DLPI state.
1987c478bd9Sstevel@tonic-gate */
199210db224Sericheng dlp->dl_current_state = dsp->ds_dlstate;
2007c478bd9Sstevel@tonic-gate
201210db224Sericheng /*
202210db224Sericheng * Gratuitously set the media type. This is to deal with modules
203210db224Sericheng * that assume the media type is known prior to DL_ATTACH_REQ
204210db224Sericheng * being completed.
205210db224Sericheng */
206210db224Sericheng dlp->dl_mac_type = DL_ETHER;
2077c478bd9Sstevel@tonic-gate
208210db224Sericheng /*
209210db224Sericheng * If the stream is not at least attached we try to retrieve the
210210db224Sericheng * mac_info using mac_info_get()
211210db224Sericheng */
212210db224Sericheng if (dsp->ds_dlstate == DL_UNATTACHED ||
213210db224Sericheng dsp->ds_dlstate == DL_ATTACH_PENDING ||
214210db224Sericheng dsp->ds_dlstate == DL_DETACH_PENDING) {
215210db224Sericheng if (!mac_info_get(ddi_major_to_name(dsp->ds_major), &minfo)) {
216210db224Sericheng /*
217210db224Sericheng * Cannot find mac_info. giving up.
218210db224Sericheng */
219210db224Sericheng goto done;
220210db224Sericheng }
221210db224Sericheng minfop = &minfo;
222210db224Sericheng } else {
223210db224Sericheng minfop = (mac_info_t *)dsp->ds_mip;
224e7801d59Ssowmini /* We can only get the sdu if we're attached. */
225e7801d59Ssowmini mac_sdu_get(dsp->ds_mh, &dlp->dl_min_sdu, &dlp->dl_max_sdu);
2267c478bd9Sstevel@tonic-gate }
2277c478bd9Sstevel@tonic-gate
228210db224Sericheng /*
229210db224Sericheng * Set the media type (properly this time).
230210db224Sericheng */
2310ba2cbe9Sxc if (dsp->ds_native)
2320ba2cbe9Sxc dlp->dl_mac_type = minfop->mi_nativemedia;
2330ba2cbe9Sxc else
2340ba2cbe9Sxc dlp->dl_mac_type = minfop->mi_media;
2357c478bd9Sstevel@tonic-gate
236210db224Sericheng /*
237210db224Sericheng * Set the DLSAP length. We only support 16 bit values and they
238210db224Sericheng * appear after the MAC address portion of DLSAP addresses.
239210db224Sericheng */
240210db224Sericheng sap_length = sizeof (uint16_t);
241210db224Sericheng dlp->dl_sap_length = NEG(sap_length);
2427c478bd9Sstevel@tonic-gate
243210db224Sericheng addr_length = minfop->mi_addr_length;
2447c478bd9Sstevel@tonic-gate
245210db224Sericheng /*
246210db224Sericheng * Copy in the media broadcast address.
247210db224Sericheng */
248ba2e4443Sseb if (minfop->mi_brdcst_addr != NULL) {
249ba2e4443Sseb dlp->dl_brdcst_addr_offset =
250ba2e4443Sseb (uintptr_t)brdcst_addr - (uintptr_t)dlp;
251ba2e4443Sseb bcopy(minfop->mi_brdcst_addr, brdcst_addr, addr_length);
252ba2e4443Sseb dlp->dl_brdcst_addr_length = addr_length;
253ba2e4443Sseb }
2547c478bd9Sstevel@tonic-gate
255e75f0919SSebastien Roy /* Only VLAN links and links that have a normal tag mode support QOS. */
256a2da5912SSebastien Roy if ((dsp->ds_mch != NULL &&
257a2da5912SSebastien Roy mac_client_vid(dsp->ds_mch) != VLAN_ID_NONE) ||
258a2da5912SSebastien Roy (dsp->ds_dlp != NULL &&
259a2da5912SSebastien Roy dsp->ds_dlp->dl_tagmode == LINK_TAGMODE_NORMAL)) {
260e75f0919SSebastien Roy dlp->dl_qos_range_offset = (uintptr_t)rangep - (uintptr_t)dlp;
261e75f0919SSebastien Roy dlp->dl_qos_range_length = sizeof (dl_qos_cl_range1_t);
262210db224Sericheng
263e75f0919SSebastien Roy rangep->dl_qos_type = DL_QOS_CL_RANGE1;
264e75f0919SSebastien Roy rangep->dl_trans_delay.dl_target_value = DL_UNKNOWN;
265e75f0919SSebastien Roy rangep->dl_trans_delay.dl_accept_value = DL_UNKNOWN;
266e75f0919SSebastien Roy rangep->dl_protection.dl_min = DL_UNKNOWN;
267e75f0919SSebastien Roy rangep->dl_protection.dl_max = DL_UNKNOWN;
268e75f0919SSebastien Roy rangep->dl_residual_error = DL_UNKNOWN;
2697c478bd9Sstevel@tonic-gate
270e75f0919SSebastien Roy /*
271e75f0919SSebastien Roy * Specify the supported range of priorities.
272e75f0919SSebastien Roy */
273e75f0919SSebastien Roy rangep->dl_priority.dl_min = 0;
274e75f0919SSebastien Roy rangep->dl_priority.dl_max = (1 << VLAN_PRI_SIZE) - 1;
275210db224Sericheng
276e75f0919SSebastien Roy dlp->dl_qos_offset = (uintptr_t)selp - (uintptr_t)dlp;
277e75f0919SSebastien Roy dlp->dl_qos_length = sizeof (dl_qos_cl_sel1_t);
278210db224Sericheng
279e75f0919SSebastien Roy selp->dl_qos_type = DL_QOS_CL_SEL1;
280e75f0919SSebastien Roy selp->dl_trans_delay = DL_UNKNOWN;
281e75f0919SSebastien Roy selp->dl_protection = DL_UNKNOWN;
282e75f0919SSebastien Roy selp->dl_residual_error = DL_UNKNOWN;
2837c478bd9Sstevel@tonic-gate
284e75f0919SSebastien Roy /*
285e75f0919SSebastien Roy * Specify the current priority (which can be changed by
286e75f0919SSebastien Roy * the DL_UDQOS_REQ primitive).
287e75f0919SSebastien Roy */
288e75f0919SSebastien Roy selp->dl_priority = dsp->ds_pri;
289e75f0919SSebastien Roy }
2907c478bd9Sstevel@tonic-gate
291210db224Sericheng dlp->dl_addr_length = addr_length + sizeof (uint16_t);
292210db224Sericheng if (dsp->ds_dlstate == DL_IDLE) {
293210db224Sericheng /*
294210db224Sericheng * The stream is bound. Therefore we can formulate a valid
295210db224Sericheng * DLSAP address.
296210db224Sericheng */
297210db224Sericheng dlp->dl_addr_offset = (uintptr_t)addr - (uintptr_t)dlp;
298ba2e4443Sseb if (addr_length > 0)
299da14cebeSEric Cheng mac_unicast_primary_get(dsp->ds_mh, addr);
300da14cebeSEric Cheng
301210db224Sericheng *(uint16_t *)(addr + addr_length) = dsp->ds_sap;
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate
304210db224Sericheng done:
30556f33205SJonathan Adams IMPLY(dlp->dl_qos_offset != 0, dlp->dl_qos_length != 0);
30656f33205SJonathan Adams IMPLY(dlp->dl_qos_range_offset != 0,
30756f33205SJonathan Adams dlp->dl_qos_range_length != 0);
30856f33205SJonathan Adams IMPLY(dlp->dl_addr_offset != 0, dlp->dl_addr_length != 0);
30956f33205SJonathan Adams IMPLY(dlp->dl_brdcst_addr_offset != 0,
31056f33205SJonathan Adams dlp->dl_brdcst_addr_length != 0);
311210db224Sericheng
312210db224Sericheng qreply(q, mp);
3137c478bd9Sstevel@tonic-gate }
3147c478bd9Sstevel@tonic-gate
3157c478bd9Sstevel@tonic-gate /*
3167c478bd9Sstevel@tonic-gate * DL_ATTACH_REQ
3177c478bd9Sstevel@tonic-gate */
318da14cebeSEric Cheng static void
proto_attach_req(dld_str_t * dsp,mblk_t * mp)319da14cebeSEric Cheng proto_attach_req(dld_str_t *dsp, mblk_t *mp)
3207c478bd9Sstevel@tonic-gate {
321da14cebeSEric Cheng dl_attach_req_t *dlp = (dl_attach_req_t *)mp->b_rptr;
322210db224Sericheng int err = 0;
323210db224Sericheng t_uscalar_t dl_err;
324210db224Sericheng queue_t *q = dsp->ds_wq;
3257c478bd9Sstevel@tonic-gate
326210db224Sericheng if (MBLKL(mp) < sizeof (dl_attach_req_t) ||
327210db224Sericheng dlp->dl_ppa < 0 || dsp->ds_style == DL_STYLE1) {
328210db224Sericheng dl_err = DL_BADPRIM;
329210db224Sericheng goto failed;
3307c478bd9Sstevel@tonic-gate }
3317c478bd9Sstevel@tonic-gate
332210db224Sericheng if (dsp->ds_dlstate != DL_UNATTACHED) {
333210db224Sericheng dl_err = DL_OUTSTATE;
334210db224Sericheng goto failed;
3357c478bd9Sstevel@tonic-gate }
3367c478bd9Sstevel@tonic-gate
337210db224Sericheng dsp->ds_dlstate = DL_ATTACH_PENDING;
3387c478bd9Sstevel@tonic-gate
339210db224Sericheng err = dld_str_attach(dsp, dlp->dl_ppa);
340210db224Sericheng if (err != 0) {
341210db224Sericheng switch (err) {
342210db224Sericheng case ENOENT:
343210db224Sericheng dl_err = DL_BADPPA;
344210db224Sericheng err = 0;
345210db224Sericheng break;
346210db224Sericheng default:
347210db224Sericheng dl_err = DL_SYSERR;
348210db224Sericheng break;
349210db224Sericheng }
350210db224Sericheng dsp->ds_dlstate = DL_UNATTACHED;
351210db224Sericheng goto failed;
3527c478bd9Sstevel@tonic-gate }
353210db224Sericheng ASSERT(dsp->ds_dlstate == DL_UNBOUND);
354210db224Sericheng dlokack(q, mp, DL_ATTACH_REQ);
355da14cebeSEric Cheng return;
356da14cebeSEric Cheng
357210db224Sericheng failed:
358210db224Sericheng dlerrorack(q, mp, DL_ATTACH_REQ, dl_err, (t_uscalar_t)err);
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate
361da14cebeSEric Cheng /*
362da14cebeSEric Cheng * DL_DETACH_REQ
363da14cebeSEric Cheng */
364da14cebeSEric Cheng static void
proto_detach_req(dld_str_t * dsp,mblk_t * mp)365da14cebeSEric Cheng proto_detach_req(dld_str_t *dsp, mblk_t *mp)
3667c478bd9Sstevel@tonic-gate {
367210db224Sericheng queue_t *q = dsp->ds_wq;
368210db224Sericheng t_uscalar_t dl_err;
3697c478bd9Sstevel@tonic-gate
3707c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (dl_detach_req_t)) {
371210db224Sericheng dl_err = DL_BADPRIM;
372210db224Sericheng goto failed;
3737c478bd9Sstevel@tonic-gate }
3747c478bd9Sstevel@tonic-gate
375210db224Sericheng if (dsp->ds_dlstate != DL_UNBOUND) {
376210db224Sericheng dl_err = DL_OUTSTATE;
377210db224Sericheng goto failed;
378210db224Sericheng }
379210db224Sericheng
380210db224Sericheng if (dsp->ds_style == DL_STYLE1) {
381210db224Sericheng dl_err = DL_BADPRIM;
382210db224Sericheng goto failed;
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate
385da14cebeSEric Cheng ASSERT(dsp->ds_datathr_cnt == 0);
3867c478bd9Sstevel@tonic-gate dsp->ds_dlstate = DL_DETACH_PENDING;
3877c478bd9Sstevel@tonic-gate
388da14cebeSEric Cheng dld_str_detach(dsp);
389d62bc4baSyz dlokack(dsp->ds_wq, mp, DL_DETACH_REQ);
390da14cebeSEric Cheng return;
391da14cebeSEric Cheng
392210db224Sericheng failed:
393210db224Sericheng dlerrorack(q, mp, DL_DETACH_REQ, dl_err, 0);
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate
3967c478bd9Sstevel@tonic-gate /*
3977c478bd9Sstevel@tonic-gate * DL_BIND_REQ
3987c478bd9Sstevel@tonic-gate */
399da14cebeSEric Cheng static void
proto_bind_req(dld_str_t * dsp,mblk_t * mp)400da14cebeSEric Cheng proto_bind_req(dld_str_t *dsp, mblk_t *mp)
4017c478bd9Sstevel@tonic-gate {
402da14cebeSEric Cheng dl_bind_req_t *dlp = (dl_bind_req_t *)mp->b_rptr;
403210db224Sericheng int err = 0;
4046f45d2aeSyz uint8_t dlsap_addr[MAXMACADDRLEN + sizeof (uint16_t)];
4056f45d2aeSyz uint_t dlsap_addr_length;
406210db224Sericheng t_uscalar_t dl_err;
407210db224Sericheng t_scalar_t sap;
408210db224Sericheng queue_t *q = dsp->ds_wq;
409da14cebeSEric Cheng mac_perim_handle_t mph;
410da14cebeSEric Cheng void *mdip;
411da14cebeSEric Cheng int32_t intr_cpu;
4127c478bd9Sstevel@tonic-gate
4137c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (dl_bind_req_t)) {
414210db224Sericheng dl_err = DL_BADPRIM;
415210db224Sericheng goto failed;
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate
4187c478bd9Sstevel@tonic-gate if (dlp->dl_xidtest_flg != 0) {
419210db224Sericheng dl_err = DL_NOAUTO;
420210db224Sericheng goto failed;
4217c478bd9Sstevel@tonic-gate }
4227c478bd9Sstevel@tonic-gate
4237c478bd9Sstevel@tonic-gate if (dlp->dl_service_mode != DL_CLDLS) {
424210db224Sericheng dl_err = DL_UNSUPPORTED;
425210db224Sericheng goto failed;
4267c478bd9Sstevel@tonic-gate }
4277c478bd9Sstevel@tonic-gate
428210db224Sericheng if (dsp->ds_dlstate != DL_UNBOUND) {
429210db224Sericheng dl_err = DL_OUTSTATE;
430210db224Sericheng goto failed;
431210db224Sericheng }
432210db224Sericheng
433da14cebeSEric Cheng mac_perim_enter_by_mh(dsp->ds_mh, &mph);
434da14cebeSEric Cheng
4355d460eafSCathy Zhou if ((err = dls_active_set(dsp)) != 0) {
436210db224Sericheng dl_err = DL_SYSERR;
437da14cebeSEric Cheng goto failed2;
438210db224Sericheng }
4397c478bd9Sstevel@tonic-gate
440da14cebeSEric Cheng dsp->ds_dlstate = DL_BIND_PENDING;
4417c478bd9Sstevel@tonic-gate /*
4427c478bd9Sstevel@tonic-gate * Set the receive callback.
4437c478bd9Sstevel@tonic-gate */
444da14cebeSEric Cheng dls_rx_set(dsp, (dsp->ds_mode == DLD_RAW) ?
445fd69bb17Syz dld_str_rx_raw : dld_str_rx_unitdata, dsp);
446fd69bb17Syz
447fd69bb17Syz /*
448210db224Sericheng * Bind the channel such that it can receive packets.
449fd69bb17Syz */
450d62bc4baSyz sap = dlp->dl_sap;
4518d4cf8d8S dsp->ds_nonip = !check_mod_above(dsp->ds_rq, "ip") &&
4528d4cf8d8S !check_mod_above(dsp->ds_rq, "arp");
4538d4cf8d8S
454da14cebeSEric Cheng err = dls_bind(dsp, sap);
455210db224Sericheng if (err != 0) {
456210db224Sericheng switch (err) {
457210db224Sericheng case EINVAL:
458210db224Sericheng dl_err = DL_BADADDR;
459210db224Sericheng err = 0;
460210db224Sericheng break;
461210db224Sericheng default:
462210db224Sericheng dl_err = DL_SYSERR;
463210db224Sericheng break;
464210db224Sericheng }
465d62bc4baSyz
466da14cebeSEric Cheng dsp->ds_dlstate = DL_UNBOUND;
4675d460eafSCathy Zhou dls_active_clear(dsp, B_FALSE);
468da14cebeSEric Cheng goto failed2;
469210db224Sericheng }
4707c478bd9Sstevel@tonic-gate
471da14cebeSEric Cheng intr_cpu = mac_client_intr_cpu(dsp->ds_mch);
472da14cebeSEric Cheng mdip = mac_get_devinfo(dsp->ds_mh);
473da14cebeSEric Cheng mac_perim_exit(mph);
474da14cebeSEric Cheng
475da14cebeSEric Cheng /*
476da14cebeSEric Cheng * We do this after we get out of the perim to avoid deadlocks
477da14cebeSEric Cheng * etc. since part of mac_client_retarget_intr is to walk the
478da14cebeSEric Cheng * device tree in order to find and retarget the interrupts.
479da14cebeSEric Cheng */
4800dc2366fSVenugopal Iyer if (intr_cpu != -1)
4810dc2366fSVenugopal Iyer mac_client_set_intr_cpu(mdip, dsp->ds_mch, intr_cpu);
482da14cebeSEric Cheng
4837c478bd9Sstevel@tonic-gate /*
484210db224Sericheng * Copy in MAC address.
4857c478bd9Sstevel@tonic-gate */
4866f45d2aeSyz dlsap_addr_length = dsp->ds_mip->mi_addr_length;
487da14cebeSEric Cheng mac_unicast_primary_get(dsp->ds_mh, dlsap_addr);
488210db224Sericheng
489210db224Sericheng /*
4906f45d2aeSyz * Copy in the SAP.
491210db224Sericheng */
492d62bc4baSyz *(uint16_t *)(dlsap_addr + dlsap_addr_length) = sap;
4936f45d2aeSyz dlsap_addr_length += sizeof (uint16_t);
4947c478bd9Sstevel@tonic-gate
495210db224Sericheng dsp->ds_dlstate = DL_IDLE;
4966f45d2aeSyz dlbindack(q, mp, sap, dlsap_addr, dlsap_addr_length, 0, 0);
497da14cebeSEric Cheng return;
498da14cebeSEric Cheng
499da14cebeSEric Cheng failed2:
500da14cebeSEric Cheng mac_perim_exit(mph);
501210db224Sericheng failed:
502210db224Sericheng dlerrorack(q, mp, DL_BIND_REQ, dl_err, (t_uscalar_t)err);
5037c478bd9Sstevel@tonic-gate }
5047c478bd9Sstevel@tonic-gate
5057c478bd9Sstevel@tonic-gate /*
5067c478bd9Sstevel@tonic-gate * DL_UNBIND_REQ
5077c478bd9Sstevel@tonic-gate */
508da14cebeSEric Cheng static void
proto_unbind_req(dld_str_t * dsp,mblk_t * mp)509da14cebeSEric Cheng proto_unbind_req(dld_str_t *dsp, mblk_t *mp)
5107c478bd9Sstevel@tonic-gate {
511d62bc4baSyz queue_t *q = dsp->ds_wq;
512d62bc4baSyz t_uscalar_t dl_err;
513da14cebeSEric Cheng mac_perim_handle_t mph;
514210db224Sericheng
515d62bc4baSyz if (MBLKL(mp) < sizeof (dl_unbind_req_t)) {
516d62bc4baSyz dl_err = DL_BADPRIM;
517d62bc4baSyz goto failed;
518d62bc4baSyz }
519d62bc4baSyz
520d62bc4baSyz if (dsp->ds_dlstate != DL_IDLE) {
521d62bc4baSyz dl_err = DL_OUTSTATE;
522d62bc4baSyz goto failed;
523d62bc4baSyz }
5247c478bd9Sstevel@tonic-gate
525da14cebeSEric Cheng mutex_enter(&dsp->ds_lock);
526da14cebeSEric Cheng while (dsp->ds_datathr_cnt != 0)
527da14cebeSEric Cheng cv_wait(&dsp->ds_datathr_cv, &dsp->ds_lock);
5287c478bd9Sstevel@tonic-gate
529da14cebeSEric Cheng dsp->ds_dlstate = DL_UNBIND_PENDING;
530da14cebeSEric Cheng mutex_exit(&dsp->ds_lock);
5317c478bd9Sstevel@tonic-gate
532da14cebeSEric Cheng mac_perim_enter_by_mh(dsp->ds_mh, &mph);
533d62bc4baSyz /*
534da14cebeSEric Cheng * Unbind the channel to stop packets being received.
535d62bc4baSyz */
5365ecc58b1SGirish Moodalbail dls_unbind(dsp);
537d62bc4baSyz
5387c478bd9Sstevel@tonic-gate /*
5397c478bd9Sstevel@tonic-gate * Disable polling mode, if it is enabled.
5407c478bd9Sstevel@tonic-gate */
541da14cebeSEric Cheng (void) dld_capab_poll_disable(dsp, NULL);
5428347601bSyl
5437c478bd9Sstevel@tonic-gate /*
544d62bc4baSyz * Clear LSO flags.
5457c478bd9Sstevel@tonic-gate */
546d62bc4baSyz dsp->ds_lso = B_FALSE;
547d62bc4baSyz dsp->ds_lso_max = 0;
5487c478bd9Sstevel@tonic-gate
549da14cebeSEric Cheng /*
550da14cebeSEric Cheng * Clear the receive callback.
551da14cebeSEric Cheng */
552da14cebeSEric Cheng dls_rx_set(dsp, NULL, NULL);
553da14cebeSEric Cheng dsp->ds_direct = B_FALSE;
554da14cebeSEric Cheng
5557c478bd9Sstevel@tonic-gate /*
5567c478bd9Sstevel@tonic-gate * Set the mode back to the default (unitdata).
5577c478bd9Sstevel@tonic-gate */
5587c478bd9Sstevel@tonic-gate dsp->ds_mode = DLD_UNITDATA;
559210db224Sericheng dsp->ds_dlstate = DL_UNBOUND;
560d62bc4baSyz
5615d460eafSCathy Zhou dls_active_clear(dsp, B_FALSE);
562da14cebeSEric Cheng mac_perim_exit(mph);
563da14cebeSEric Cheng dlokack(dsp->ds_wq, mp, DL_UNBIND_REQ);
564da14cebeSEric Cheng return;
565210db224Sericheng failed:
566210db224Sericheng dlerrorack(q, mp, DL_UNBIND_REQ, dl_err, 0);
5677c478bd9Sstevel@tonic-gate }
5687c478bd9Sstevel@tonic-gate
5697c478bd9Sstevel@tonic-gate /*
5707c478bd9Sstevel@tonic-gate * DL_PROMISCON_REQ
5717c478bd9Sstevel@tonic-gate */
572da14cebeSEric Cheng static void
proto_promiscon_req(dld_str_t * dsp,mblk_t * mp)573da14cebeSEric Cheng proto_promiscon_req(dld_str_t *dsp, mblk_t *mp)
5747c478bd9Sstevel@tonic-gate {
575da14cebeSEric Cheng dl_promiscon_req_t *dlp = (dl_promiscon_req_t *)mp->b_rptr;
576210db224Sericheng int err = 0;
577210db224Sericheng t_uscalar_t dl_err;
578cabb4db9SDan McDonald uint32_t new_flags, promisc_saved;
579210db224Sericheng queue_t *q = dsp->ds_wq;
580da14cebeSEric Cheng mac_perim_handle_t mph;
581210db224Sericheng
582210db224Sericheng if (MBLKL(mp) < sizeof (dl_promiscon_req_t)) {
583210db224Sericheng dl_err = DL_BADPRIM;
584210db224Sericheng goto failed;
585210db224Sericheng }
5867c478bd9Sstevel@tonic-gate
5877c478bd9Sstevel@tonic-gate if (dsp->ds_dlstate == DL_UNATTACHED ||
5887c478bd9Sstevel@tonic-gate DL_ACK_PENDING(dsp->ds_dlstate)) {
589210db224Sericheng dl_err = DL_OUTSTATE;
590210db224Sericheng goto failed;
5917c478bd9Sstevel@tonic-gate }
5927c478bd9Sstevel@tonic-gate
593cabb4db9SDan McDonald mac_perim_enter_by_mh(dsp->ds_mh, &mph);
594cabb4db9SDan McDonald
595cabb4db9SDan McDonald new_flags = promisc_saved = dsp->ds_promisc;
5967c478bd9Sstevel@tonic-gate switch (dlp->dl_level) {
5977c478bd9Sstevel@tonic-gate case DL_PROMISC_SAP:
598cabb4db9SDan McDonald new_flags |= DLS_PROMISC_SAP;
5997c478bd9Sstevel@tonic-gate break;
600da14cebeSEric Cheng
6017c478bd9Sstevel@tonic-gate case DL_PROMISC_MULTI:
602cabb4db9SDan McDonald new_flags |= DLS_PROMISC_MULTI;
6037c478bd9Sstevel@tonic-gate break;
604da14cebeSEric Cheng
6057c478bd9Sstevel@tonic-gate case DL_PROMISC_PHYS:
606cabb4db9SDan McDonald new_flags |= DLS_PROMISC_PHYS;
6077c478bd9Sstevel@tonic-gate break;
608da14cebeSEric Cheng
609*115f9ea8SRobert Mustacchi case DL_PROMISC_RX_ONLY:
610*115f9ea8SRobert Mustacchi new_flags |= DLS_PROMISC_RX_ONLY;
611*115f9ea8SRobert Mustacchi break;
612*115f9ea8SRobert Mustacchi
6137c478bd9Sstevel@tonic-gate default:
614210db224Sericheng dl_err = DL_NOTSUPPORTED;
615ad7ed3feSRobert Mustacchi goto failed2;
616210db224Sericheng }
617210db224Sericheng
6185d460eafSCathy Zhou if ((promisc_saved == 0) && (err = dls_active_set(dsp)) != 0) {
619cabb4db9SDan McDonald ASSERT(dsp->ds_promisc == promisc_saved);
620210db224Sericheng dl_err = DL_SYSERR;
621da14cebeSEric Cheng goto failed2;
6227c478bd9Sstevel@tonic-gate }
6237c478bd9Sstevel@tonic-gate
6247c478bd9Sstevel@tonic-gate /*
6257c478bd9Sstevel@tonic-gate * Adjust channel promiscuity.
6267c478bd9Sstevel@tonic-gate */
627cabb4db9SDan McDonald err = dls_promisc(dsp, new_flags);
628da14cebeSEric Cheng
629210db224Sericheng if (err != 0) {
630210db224Sericheng dl_err = DL_SYSERR;
631da14cebeSEric Cheng dsp->ds_promisc = promisc_saved;
6325d460eafSCathy Zhou if (promisc_saved == 0)
6335d460eafSCathy Zhou dls_active_clear(dsp, B_FALSE);
634da14cebeSEric Cheng goto failed2;
635210db224Sericheng }
636210db224Sericheng
637da14cebeSEric Cheng mac_perim_exit(mph);
638da14cebeSEric Cheng
639210db224Sericheng dlokack(q, mp, DL_PROMISCON_REQ);
640da14cebeSEric Cheng return;
641da14cebeSEric Cheng
642da14cebeSEric Cheng failed2:
643da14cebeSEric Cheng mac_perim_exit(mph);
644210db224Sericheng failed:
645210db224Sericheng dlerrorack(q, mp, DL_PROMISCON_REQ, dl_err, (t_uscalar_t)err);
6467c478bd9Sstevel@tonic-gate }
6477c478bd9Sstevel@tonic-gate
6487c478bd9Sstevel@tonic-gate /*
6497c478bd9Sstevel@tonic-gate * DL_PROMISCOFF_REQ
6507c478bd9Sstevel@tonic-gate */
651da14cebeSEric Cheng static void
proto_promiscoff_req(dld_str_t * dsp,mblk_t * mp)652da14cebeSEric Cheng proto_promiscoff_req(dld_str_t *dsp, mblk_t *mp)
6537c478bd9Sstevel@tonic-gate {
654da14cebeSEric Cheng dl_promiscoff_req_t *dlp = (dl_promiscoff_req_t *)mp->b_rptr;
655210db224Sericheng int err = 0;
656210db224Sericheng t_uscalar_t dl_err;
657cabb4db9SDan McDonald uint32_t new_flags;
658210db224Sericheng queue_t *q = dsp->ds_wq;
659da14cebeSEric Cheng mac_perim_handle_t mph;
6607c478bd9Sstevel@tonic-gate
661210db224Sericheng if (MBLKL(mp) < sizeof (dl_promiscoff_req_t)) {
662210db224Sericheng dl_err = DL_BADPRIM;
663210db224Sericheng goto failed;
6647c478bd9Sstevel@tonic-gate }
6657c478bd9Sstevel@tonic-gate
666210db224Sericheng if (dsp->ds_dlstate == DL_UNATTACHED ||
667210db224Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) {
668210db224Sericheng dl_err = DL_OUTSTATE;
669210db224Sericheng goto failed;
6707c478bd9Sstevel@tonic-gate }
6717c478bd9Sstevel@tonic-gate
672cabb4db9SDan McDonald mac_perim_enter_by_mh(dsp->ds_mh, &mph);
673cabb4db9SDan McDonald
674cabb4db9SDan McDonald new_flags = dsp->ds_promisc;
6757c478bd9Sstevel@tonic-gate switch (dlp->dl_level) {
6767c478bd9Sstevel@tonic-gate case DL_PROMISC_SAP:
677da14cebeSEric Cheng if (!(dsp->ds_promisc & DLS_PROMISC_SAP)) {
678da14cebeSEric Cheng dl_err = DL_NOTENAB;
679cb6094b4SDan McDonald goto failed2;
680da14cebeSEric Cheng }
681cabb4db9SDan McDonald new_flags &= ~DLS_PROMISC_SAP;
6827c478bd9Sstevel@tonic-gate break;
683da14cebeSEric Cheng
6847c478bd9Sstevel@tonic-gate case DL_PROMISC_MULTI:
685da14cebeSEric Cheng if (!(dsp->ds_promisc & DLS_PROMISC_MULTI)) {
686da14cebeSEric Cheng dl_err = DL_NOTENAB;
687cb6094b4SDan McDonald goto failed2;
688da14cebeSEric Cheng }
689cabb4db9SDan McDonald new_flags &= ~DLS_PROMISC_MULTI;
6907c478bd9Sstevel@tonic-gate break;
691da14cebeSEric Cheng
6927c478bd9Sstevel@tonic-gate case DL_PROMISC_PHYS:
693da14cebeSEric Cheng if (!(dsp->ds_promisc & DLS_PROMISC_PHYS)) {
694da14cebeSEric Cheng dl_err = DL_NOTENAB;
695cb6094b4SDan McDonald goto failed2;
696da14cebeSEric Cheng }
697cabb4db9SDan McDonald new_flags &= ~DLS_PROMISC_PHYS;
6987c478bd9Sstevel@tonic-gate break;
699da14cebeSEric Cheng
700*115f9ea8SRobert Mustacchi case DL_PROMISC_RX_ONLY:
701*115f9ea8SRobert Mustacchi if (!(dsp->ds_promisc & DLS_PROMISC_RX_ONLY)) {
702*115f9ea8SRobert Mustacchi dl_err = DL_NOTENAB;
703*115f9ea8SRobert Mustacchi goto failed2;
704*115f9ea8SRobert Mustacchi }
705*115f9ea8SRobert Mustacchi new_flags &= ~DLS_PROMISC_RX_ONLY;
706*115f9ea8SRobert Mustacchi break;
707*115f9ea8SRobert Mustacchi
7087c478bd9Sstevel@tonic-gate default:
709210db224Sericheng dl_err = DL_NOTSUPPORTED;
710cb6094b4SDan McDonald goto failed2;
7117c478bd9Sstevel@tonic-gate }
7127c478bd9Sstevel@tonic-gate
713da14cebeSEric Cheng /*
714da14cebeSEric Cheng * Adjust channel promiscuity.
715da14cebeSEric Cheng */
716cabb4db9SDan McDonald err = dls_promisc(dsp, new_flags);
717d62bc4baSyz
718210db224Sericheng if (err != 0) {
719210db224Sericheng dl_err = DL_SYSERR;
720cb6094b4SDan McDonald goto failed2;
721210db224Sericheng }
7225d460eafSCathy Zhou
723cabb4db9SDan McDonald ASSERT(dsp->ds_promisc == new_flags);
7245d460eafSCathy Zhou if (dsp->ds_promisc == 0)
7255d460eafSCathy Zhou dls_active_clear(dsp, B_FALSE);
7265d460eafSCathy Zhou
7275d460eafSCathy Zhou mac_perim_exit(mph);
7285d460eafSCathy Zhou
729210db224Sericheng dlokack(q, mp, DL_PROMISCOFF_REQ);
730da14cebeSEric Cheng return;
731cb6094b4SDan McDonald failed2:
732cb6094b4SDan McDonald mac_perim_exit(mph);
733210db224Sericheng failed:
734210db224Sericheng dlerrorack(q, mp, DL_PROMISCOFF_REQ, dl_err, (t_uscalar_t)err);
7357c478bd9Sstevel@tonic-gate }
7367c478bd9Sstevel@tonic-gate
7377c478bd9Sstevel@tonic-gate /*
7387c478bd9Sstevel@tonic-gate * DL_ENABMULTI_REQ
7397c478bd9Sstevel@tonic-gate */
740da14cebeSEric Cheng static void
proto_enabmulti_req(dld_str_t * dsp,mblk_t * mp)741da14cebeSEric Cheng proto_enabmulti_req(dld_str_t *dsp, mblk_t *mp)
7427c478bd9Sstevel@tonic-gate {
743da14cebeSEric Cheng dl_enabmulti_req_t *dlp = (dl_enabmulti_req_t *)mp->b_rptr;
744210db224Sericheng int err = 0;
745210db224Sericheng t_uscalar_t dl_err;
746210db224Sericheng queue_t *q = dsp->ds_wq;
747da14cebeSEric Cheng mac_perim_handle_t mph;
7487c478bd9Sstevel@tonic-gate
7497c478bd9Sstevel@tonic-gate if (dsp->ds_dlstate == DL_UNATTACHED ||
7507c478bd9Sstevel@tonic-gate DL_ACK_PENDING(dsp->ds_dlstate)) {
751210db224Sericheng dl_err = DL_OUTSTATE;
752210db224Sericheng goto failed;
7537c478bd9Sstevel@tonic-gate }
7547c478bd9Sstevel@tonic-gate
7557c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (dl_enabmulti_req_t) ||
7567c478bd9Sstevel@tonic-gate !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) ||
7577c478bd9Sstevel@tonic-gate dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) {
758210db224Sericheng dl_err = DL_BADPRIM;
759210db224Sericheng goto failed;
760210db224Sericheng }
761210db224Sericheng
762da14cebeSEric Cheng mac_perim_enter_by_mh(dsp->ds_mh, &mph);
763da14cebeSEric Cheng
7645d460eafSCathy Zhou if ((dsp->ds_dmap == NULL) && (err = dls_active_set(dsp)) != 0) {
765210db224Sericheng dl_err = DL_SYSERR;
766da14cebeSEric Cheng goto failed2;
7677c478bd9Sstevel@tonic-gate }
7687c478bd9Sstevel@tonic-gate
769da14cebeSEric Cheng err = dls_multicst_add(dsp, mp->b_rptr + dlp->dl_addr_offset);
770210db224Sericheng if (err != 0) {
771210db224Sericheng switch (err) {
772210db224Sericheng case EINVAL:
773210db224Sericheng dl_err = DL_BADADDR;
774210db224Sericheng err = 0;
775210db224Sericheng break;
776210db224Sericheng case ENOSPC:
777210db224Sericheng dl_err = DL_TOOMANY;
778210db224Sericheng err = 0;
779210db224Sericheng break;
780210db224Sericheng default:
781210db224Sericheng dl_err = DL_SYSERR;
782210db224Sericheng break;
783210db224Sericheng }
7845d460eafSCathy Zhou if (dsp->ds_dmap == NULL)
7855d460eafSCathy Zhou dls_active_clear(dsp, B_FALSE);
786da14cebeSEric Cheng goto failed2;
787210db224Sericheng }
788210db224Sericheng
789da14cebeSEric Cheng mac_perim_exit(mph);
790da14cebeSEric Cheng
791210db224Sericheng dlokack(q, mp, DL_ENABMULTI_REQ);
792da14cebeSEric Cheng return;
793da14cebeSEric Cheng
794da14cebeSEric Cheng failed2:
795da14cebeSEric Cheng mac_perim_exit(mph);
796210db224Sericheng failed:
797210db224Sericheng dlerrorack(q, mp, DL_ENABMULTI_REQ, dl_err, (t_uscalar_t)err);
7987c478bd9Sstevel@tonic-gate }
7997c478bd9Sstevel@tonic-gate
8007c478bd9Sstevel@tonic-gate /*
8017c478bd9Sstevel@tonic-gate * DL_DISABMULTI_REQ
8027c478bd9Sstevel@tonic-gate */
803da14cebeSEric Cheng static void
proto_disabmulti_req(dld_str_t * dsp,mblk_t * mp)804da14cebeSEric Cheng proto_disabmulti_req(dld_str_t *dsp, mblk_t *mp)
8057c478bd9Sstevel@tonic-gate {
806da14cebeSEric Cheng dl_disabmulti_req_t *dlp = (dl_disabmulti_req_t *)mp->b_rptr;
807210db224Sericheng int err = 0;
808210db224Sericheng t_uscalar_t dl_err;
809210db224Sericheng queue_t *q = dsp->ds_wq;
810da14cebeSEric Cheng mac_perim_handle_t mph;
8117c478bd9Sstevel@tonic-gate
8127c478bd9Sstevel@tonic-gate if (dsp->ds_dlstate == DL_UNATTACHED ||
8137c478bd9Sstevel@tonic-gate DL_ACK_PENDING(dsp->ds_dlstate)) {
814210db224Sericheng dl_err = DL_OUTSTATE;
815210db224Sericheng goto failed;
8167c478bd9Sstevel@tonic-gate }
8177c478bd9Sstevel@tonic-gate
8187c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (dl_disabmulti_req_t) ||
8197c478bd9Sstevel@tonic-gate !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) ||
8207c478bd9Sstevel@tonic-gate dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) {
821210db224Sericheng dl_err = DL_BADPRIM;
822210db224Sericheng goto failed;
8237c478bd9Sstevel@tonic-gate }
8247c478bd9Sstevel@tonic-gate
825da14cebeSEric Cheng mac_perim_enter_by_mh(dsp->ds_mh, &mph);
826da14cebeSEric Cheng err = dls_multicst_remove(dsp, mp->b_rptr + dlp->dl_addr_offset);
8275d460eafSCathy Zhou if ((err == 0) && (dsp->ds_dmap == NULL))
8285d460eafSCathy Zhou dls_active_clear(dsp, B_FALSE);
829da14cebeSEric Cheng mac_perim_exit(mph);
830da14cebeSEric Cheng
831210db224Sericheng if (err != 0) {
83215c07adcSJohn Levon switch (err) {
833210db224Sericheng case EINVAL:
834210db224Sericheng dl_err = DL_BADADDR;
835210db224Sericheng err = 0;
836210db224Sericheng break;
837da14cebeSEric Cheng
838210db224Sericheng case ENOENT:
839210db224Sericheng dl_err = DL_NOTENAB;
840210db224Sericheng err = 0;
841210db224Sericheng break;
842da14cebeSEric Cheng
843210db224Sericheng default:
844210db224Sericheng dl_err = DL_SYSERR;
845210db224Sericheng break;
846210db224Sericheng }
847210db224Sericheng goto failed;
848210db224Sericheng }
849210db224Sericheng dlokack(q, mp, DL_DISABMULTI_REQ);
850da14cebeSEric Cheng return;
851210db224Sericheng failed:
852210db224Sericheng dlerrorack(q, mp, DL_DISABMULTI_REQ, dl_err, (t_uscalar_t)err);
8537c478bd9Sstevel@tonic-gate }
8547c478bd9Sstevel@tonic-gate
8557c478bd9Sstevel@tonic-gate /*
8567c478bd9Sstevel@tonic-gate * DL_PHYS_ADDR_REQ
8577c478bd9Sstevel@tonic-gate */
858da14cebeSEric Cheng static void
proto_physaddr_req(dld_str_t * dsp,mblk_t * mp)859da14cebeSEric Cheng proto_physaddr_req(dld_str_t *dsp, mblk_t *mp)
8607c478bd9Sstevel@tonic-gate {
861da14cebeSEric Cheng dl_phys_addr_req_t *dlp = (dl_phys_addr_req_t *)mp->b_rptr;
862210db224Sericheng queue_t *q = dsp->ds_wq;
8632b24ab6bSSebastien Roy t_uscalar_t dl_err = 0;
8642b24ab6bSSebastien Roy char *addr = NULL;
865210db224Sericheng uint_t addr_length;
8667c478bd9Sstevel@tonic-gate
8677c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (dl_phys_addr_req_t)) {
868210db224Sericheng dl_err = DL_BADPRIM;
8692b24ab6bSSebastien Roy goto done;
870210db224Sericheng }
871210db224Sericheng
872210db224Sericheng if (dsp->ds_dlstate == DL_UNATTACHED ||
873210db224Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) {
874210db224Sericheng dl_err = DL_OUTSTATE;
8752b24ab6bSSebastien Roy goto done;
876210db224Sericheng }
877210db224Sericheng
878210db224Sericheng addr_length = dsp->ds_mip->mi_addr_length;
879c08e5e1aSdr if (addr_length > 0) {
880da14cebeSEric Cheng addr = kmem_alloc(addr_length, KM_SLEEP);
8812b24ab6bSSebastien Roy switch (dlp->dl_addr_type) {
8822b24ab6bSSebastien Roy case DL_CURR_PHYS_ADDR:
883da14cebeSEric Cheng mac_unicast_primary_get(dsp->ds_mh, (uint8_t *)addr);
8842b24ab6bSSebastien Roy break;
8852b24ab6bSSebastien Roy case DL_FACT_PHYS_ADDR:
886da14cebeSEric Cheng bcopy(dsp->ds_mip->mi_unicst_addr, addr, addr_length);
8872b24ab6bSSebastien Roy break;
8882b24ab6bSSebastien Roy case DL_CURR_DEST_ADDR:
8892b24ab6bSSebastien Roy if (!mac_dst_get(dsp->ds_mh, (uint8_t *)addr))
8902b24ab6bSSebastien Roy dl_err = DL_NOTSUPPORTED;
8912b24ab6bSSebastien Roy break;
8922b24ab6bSSebastien Roy default:
8932b24ab6bSSebastien Roy dl_err = DL_UNSUPPORTED;
8942b24ab6bSSebastien Roy }
8952b24ab6bSSebastien Roy }
8962b24ab6bSSebastien Roy done:
8972b24ab6bSSebastien Roy if (dl_err == 0)
898c08e5e1aSdr dlphysaddrack(q, mp, addr, (t_uscalar_t)addr_length);
8992b24ab6bSSebastien Roy else
9002b24ab6bSSebastien Roy dlerrorack(q, mp, DL_PHYS_ADDR_REQ, dl_err, 0);
9012b24ab6bSSebastien Roy if (addr != NULL)
902c08e5e1aSdr kmem_free(addr, addr_length);
9037c478bd9Sstevel@tonic-gate }
9047c478bd9Sstevel@tonic-gate
9057c478bd9Sstevel@tonic-gate /*
9067c478bd9Sstevel@tonic-gate * DL_SET_PHYS_ADDR_REQ
9077c478bd9Sstevel@tonic-gate */
908da14cebeSEric Cheng static void
proto_setphysaddr_req(dld_str_t * dsp,mblk_t * mp)909da14cebeSEric Cheng proto_setphysaddr_req(dld_str_t *dsp, mblk_t *mp)
9107c478bd9Sstevel@tonic-gate {
911da14cebeSEric Cheng dl_set_phys_addr_req_t *dlp = (dl_set_phys_addr_req_t *)mp->b_rptr;
912210db224Sericheng int err = 0;
913210db224Sericheng t_uscalar_t dl_err;
914210db224Sericheng queue_t *q = dsp->ds_wq;
915da14cebeSEric Cheng mac_perim_handle_t mph;
9167c478bd9Sstevel@tonic-gate
9177c478bd9Sstevel@tonic-gate if (dsp->ds_dlstate == DL_UNATTACHED ||
9187c478bd9Sstevel@tonic-gate DL_ACK_PENDING(dsp->ds_dlstate)) {
919210db224Sericheng dl_err = DL_OUTSTATE;
920210db224Sericheng goto failed;
9217c478bd9Sstevel@tonic-gate }
9227c478bd9Sstevel@tonic-gate
9237c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (dl_set_phys_addr_req_t) ||
9247c478bd9Sstevel@tonic-gate !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) ||
9257c478bd9Sstevel@tonic-gate dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) {
926210db224Sericheng dl_err = DL_BADPRIM;
927210db224Sericheng goto failed;
928210db224Sericheng }
929210db224Sericheng
930da14cebeSEric Cheng mac_perim_enter_by_mh(dsp->ds_mh, &mph);
931da14cebeSEric Cheng
9325d460eafSCathy Zhou if ((err = dls_active_set(dsp)) != 0) {
933210db224Sericheng dl_err = DL_SYSERR;
934da14cebeSEric Cheng goto failed2;
9357c478bd9Sstevel@tonic-gate }
9367c478bd9Sstevel@tonic-gate
93725ec3e3dSEric Cheng /*
93825ec3e3dSEric Cheng * If mac-nospoof is enabled and the link is owned by a
93925ec3e3dSEric Cheng * non-global zone, changing the mac address is not allowed.
94025ec3e3dSEric Cheng */
94125ec3e3dSEric Cheng if (dsp->ds_dlp->dl_zid != GLOBAL_ZONEID &&
94225ec3e3dSEric Cheng mac_protect_enabled(dsp->ds_mch, MPT_MACNOSPOOF)) {
94325ec3e3dSEric Cheng dls_active_clear(dsp, B_FALSE);
94425ec3e3dSEric Cheng err = EACCES;
94525ec3e3dSEric Cheng goto failed2;
94625ec3e3dSEric Cheng }
94725ec3e3dSEric Cheng
948da14cebeSEric Cheng err = mac_unicast_primary_set(dsp->ds_mh,
949da14cebeSEric Cheng mp->b_rptr + dlp->dl_addr_offset);
950210db224Sericheng if (err != 0) {
951210db224Sericheng switch (err) {
952210db224Sericheng case EINVAL:
953210db224Sericheng dl_err = DL_BADADDR;
954210db224Sericheng err = 0;
955210db224Sericheng break;
956210db224Sericheng
957210db224Sericheng default:
958210db224Sericheng dl_err = DL_SYSERR;
959210db224Sericheng break;
960210db224Sericheng }
9615d460eafSCathy Zhou dls_active_clear(dsp, B_FALSE);
962da14cebeSEric Cheng goto failed2;
963210db224Sericheng
964210db224Sericheng }
965d62bc4baSyz
966da14cebeSEric Cheng mac_perim_exit(mph);
967da14cebeSEric Cheng
968210db224Sericheng dlokack(q, mp, DL_SET_PHYS_ADDR_REQ);
969da14cebeSEric Cheng return;
970da14cebeSEric Cheng
971da14cebeSEric Cheng failed2:
972da14cebeSEric Cheng mac_perim_exit(mph);
973210db224Sericheng failed:
974210db224Sericheng dlerrorack(q, mp, DL_SET_PHYS_ADDR_REQ, dl_err, (t_uscalar_t)err);
9757c478bd9Sstevel@tonic-gate }
9767c478bd9Sstevel@tonic-gate
9777c478bd9Sstevel@tonic-gate /*
9787c478bd9Sstevel@tonic-gate * DL_UDQOS_REQ
9797c478bd9Sstevel@tonic-gate */
980da14cebeSEric Cheng static void
proto_udqos_req(dld_str_t * dsp,mblk_t * mp)981da14cebeSEric Cheng proto_udqos_req(dld_str_t *dsp, mblk_t *mp)
9827c478bd9Sstevel@tonic-gate {
983da14cebeSEric Cheng dl_udqos_req_t *dlp = (dl_udqos_req_t *)mp->b_rptr;
984210db224Sericheng dl_qos_cl_sel1_t *selp;
985210db224Sericheng int off, len;
986210db224Sericheng t_uscalar_t dl_err;
987210db224Sericheng queue_t *q = dsp->ds_wq;
9887c478bd9Sstevel@tonic-gate
9897c478bd9Sstevel@tonic-gate off = dlp->dl_qos_offset;
9907c478bd9Sstevel@tonic-gate len = dlp->dl_qos_length;
9917c478bd9Sstevel@tonic-gate
9927c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (dl_udqos_req_t) || !MBLKIN(mp, off, len)) {
993210db224Sericheng dl_err = DL_BADPRIM;
994210db224Sericheng goto failed;
9957c478bd9Sstevel@tonic-gate }
9967c478bd9Sstevel@tonic-gate
9977c478bd9Sstevel@tonic-gate selp = (dl_qos_cl_sel1_t *)(mp->b_rptr + off);
9987c478bd9Sstevel@tonic-gate if (selp->dl_qos_type != DL_QOS_CL_SEL1) {
999210db224Sericheng dl_err = DL_BADQOSTYPE;
1000210db224Sericheng goto failed;
10017c478bd9Sstevel@tonic-gate }
10027c478bd9Sstevel@tonic-gate
1003605445d5Sdg if (selp->dl_priority > (1 << VLAN_PRI_SIZE) - 1 ||
10047c478bd9Sstevel@tonic-gate selp->dl_priority < 0) {
1005210db224Sericheng dl_err = DL_BADQOSPARAM;
1006210db224Sericheng goto failed;
10077c478bd9Sstevel@tonic-gate }
10087c478bd9Sstevel@tonic-gate
1009d62bc4baSyz dsp->ds_pri = selp->dl_priority;
1010210db224Sericheng dlokack(q, mp, DL_UDQOS_REQ);
1011da14cebeSEric Cheng return;
1012210db224Sericheng failed:
1013210db224Sericheng dlerrorack(q, mp, DL_UDQOS_REQ, dl_err, 0);
10147c478bd9Sstevel@tonic-gate }
10157c478bd9Sstevel@tonic-gate
10164b46d1efSkrgopi static boolean_t
check_mod_above(queue_t * q,const char * mod)10178d4cf8d8S check_mod_above(queue_t *q, const char *mod)
10184b46d1efSkrgopi {
10194b46d1efSkrgopi queue_t *next_q;
10204b46d1efSkrgopi boolean_t ret = B_TRUE;
10214b46d1efSkrgopi
10224b46d1efSkrgopi claimstr(q);
10234b46d1efSkrgopi next_q = q->q_next;
10248d4cf8d8S if (strcmp(next_q->q_qinfo->qi_minfo->mi_idname, mod) != 0)
10254b46d1efSkrgopi ret = B_FALSE;
10264b46d1efSkrgopi releasestr(q);
10274b46d1efSkrgopi return (ret);
10284b46d1efSkrgopi }
10294b46d1efSkrgopi
10307c478bd9Sstevel@tonic-gate /*
10317c478bd9Sstevel@tonic-gate * DL_CAPABILITY_REQ
10327c478bd9Sstevel@tonic-gate */
1033da14cebeSEric Cheng static void
proto_capability_req(dld_str_t * dsp,mblk_t * mp)1034da14cebeSEric Cheng proto_capability_req(dld_str_t *dsp, mblk_t *mp)
10357c478bd9Sstevel@tonic-gate {
1036da14cebeSEric Cheng dl_capability_req_t *dlp = (dl_capability_req_t *)mp->b_rptr;
1037210db224Sericheng dl_capability_sub_t *sp;
1038210db224Sericheng size_t size, len;
1039210db224Sericheng offset_t off, end;
1040210db224Sericheng t_uscalar_t dl_err;
1041210db224Sericheng queue_t *q = dsp->ds_wq;
10427c478bd9Sstevel@tonic-gate
10437c478bd9Sstevel@tonic-gate if (MBLKL(mp) < sizeof (dl_capability_req_t)) {
1044210db224Sericheng dl_err = DL_BADPRIM;
1045210db224Sericheng goto failed;
1046210db224Sericheng }
1047210db224Sericheng
1048210db224Sericheng if (dsp->ds_dlstate == DL_UNATTACHED ||
1049210db224Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) {
1050210db224Sericheng dl_err = DL_OUTSTATE;
1051210db224Sericheng goto failed;
10527c478bd9Sstevel@tonic-gate }
10537c478bd9Sstevel@tonic-gate
10547c478bd9Sstevel@tonic-gate /*
10557c478bd9Sstevel@tonic-gate * This request is overloaded. If there are no requested capabilities
10567c478bd9Sstevel@tonic-gate * then we just want to acknowledge with all the capabilities we
10577c478bd9Sstevel@tonic-gate * support. Otherwise we enable the set of capabilities requested.
10587c478bd9Sstevel@tonic-gate */
10597c478bd9Sstevel@tonic-gate if (dlp->dl_sub_length == 0) {
1060da14cebeSEric Cheng proto_capability_advertise(dsp, mp);
1061da14cebeSEric Cheng return;
10627c478bd9Sstevel@tonic-gate }
10637c478bd9Sstevel@tonic-gate
10647c478bd9Sstevel@tonic-gate if (!MBLKIN(mp, dlp->dl_sub_offset, dlp->dl_sub_length)) {
1065210db224Sericheng dl_err = DL_BADPRIM;
1066210db224Sericheng goto failed;
10677c478bd9Sstevel@tonic-gate }
10687c478bd9Sstevel@tonic-gate
1069210db224Sericheng dlp->dl_primitive = DL_CAPABILITY_ACK;
10707c478bd9Sstevel@tonic-gate
1071210db224Sericheng off = dlp->dl_sub_offset;
1072210db224Sericheng len = dlp->dl_sub_length;
10737c478bd9Sstevel@tonic-gate
1074210db224Sericheng /*
1075210db224Sericheng * Walk the list of capabilities to be enabled.
1076210db224Sericheng */
1077210db224Sericheng for (end = off + len; off < end; ) {
1078210db224Sericheng sp = (dl_capability_sub_t *)(mp->b_rptr + off);
1079210db224Sericheng size = sizeof (dl_capability_sub_t) + sp->dl_length;
10807c478bd9Sstevel@tonic-gate
1081210db224Sericheng if (off + size > end ||
1082210db224Sericheng !IS_P2ALIGNED(off, sizeof (uint32_t))) {
1083210db224Sericheng dl_err = DL_BADPRIM;
1084210db224Sericheng goto failed;
1085210db224Sericheng }
10867c478bd9Sstevel@tonic-gate
1087210db224Sericheng switch (sp->dl_cap) {
1088210db224Sericheng /*
1089210db224Sericheng * TCP/IP checksum offload to hardware.
1090210db224Sericheng */
1091210db224Sericheng case DL_CAPAB_HCKSUM: {
1092210db224Sericheng dl_capab_hcksum_t *hcksump;
1093210db224Sericheng dl_capab_hcksum_t hcksum;
10947c478bd9Sstevel@tonic-gate
1095210db224Sericheng hcksump = (dl_capab_hcksum_t *)&sp[1];
1096210db224Sericheng /*
1097210db224Sericheng * Copy for alignment.
1098210db224Sericheng */
1099210db224Sericheng bcopy(hcksump, &hcksum, sizeof (dl_capab_hcksum_t));
1100210db224Sericheng dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq);
1101210db224Sericheng bcopy(&hcksum, hcksump, sizeof (dl_capab_hcksum_t));
1102210db224Sericheng break;
1103210db224Sericheng }
11047c478bd9Sstevel@tonic-gate
1105da14cebeSEric Cheng case DL_CAPAB_DLD: {
1106da14cebeSEric Cheng dl_capab_dld_t *dldp;
1107da14cebeSEric Cheng dl_capab_dld_t dld;
11084b46d1efSkrgopi
1109da14cebeSEric Cheng dldp = (dl_capab_dld_t *)&sp[1];
11104b46d1efSkrgopi /*
11114b46d1efSkrgopi * Copy for alignment.
11124b46d1efSkrgopi */
1113da14cebeSEric Cheng bcopy(dldp, &dld, sizeof (dl_capab_dld_t));
1114da14cebeSEric Cheng dlcapabsetqid(&(dld.dld_mid), dsp->ds_rq);
1115da14cebeSEric Cheng bcopy(&dld, dldp, sizeof (dl_capab_dld_t));
1116210db224Sericheng break;
1117210db224Sericheng }
1118210db224Sericheng default:
1119210db224Sericheng break;
11207c478bd9Sstevel@tonic-gate }
1121210db224Sericheng off += size;
11227c478bd9Sstevel@tonic-gate }
1123210db224Sericheng qreply(q, mp);
1124da14cebeSEric Cheng return;
1125210db224Sericheng failed:
1126210db224Sericheng dlerrorack(q, mp, DL_CAPABILITY_REQ, dl_err, 0);
11277c478bd9Sstevel@tonic-gate }
11287c478bd9Sstevel@tonic-gate
11297c478bd9Sstevel@tonic-gate /*
1130210db224Sericheng * DL_NOTIFY_REQ
11317c478bd9Sstevel@tonic-gate */
1132da14cebeSEric Cheng static void
proto_notify_req(dld_str_t * dsp,mblk_t * mp)1133da14cebeSEric Cheng proto_notify_req(dld_str_t *dsp, mblk_t *mp)
11347c478bd9Sstevel@tonic-gate {
1135da14cebeSEric Cheng dl_notify_req_t *dlp = (dl_notify_req_t *)mp->b_rptr;
1136210db224Sericheng t_uscalar_t dl_err;
1137210db224Sericheng queue_t *q = dsp->ds_wq;
1138210db224Sericheng uint_t note =
1139210db224Sericheng DL_NOTE_PROMISC_ON_PHYS |
1140210db224Sericheng DL_NOTE_PROMISC_OFF_PHYS |
1141210db224Sericheng DL_NOTE_PHYS_ADDR |
1142210db224Sericheng DL_NOTE_LINK_UP |
1143210db224Sericheng DL_NOTE_LINK_DOWN |
1144ba2e4443Sseb DL_NOTE_CAPAB_RENEG |
1145cef310fdSGirish Moodalbail DL_NOTE_FASTPATH_FLUSH |
11462b24ab6bSSebastien Roy DL_NOTE_SPEED |
1147550b6e40SSowmini Varadhan DL_NOTE_SDU_SIZE|
11481eee170aSErik Nordmark DL_NOTE_SDU_SIZE2|
1149550b6e40SSowmini Varadhan DL_NOTE_ALLOWED_IPS;
11507c478bd9Sstevel@tonic-gate
1151210db224Sericheng if (MBLKL(mp) < sizeof (dl_notify_req_t)) {
1152210db224Sericheng dl_err = DL_BADPRIM;
1153210db224Sericheng goto failed;
11547c478bd9Sstevel@tonic-gate }
11557c478bd9Sstevel@tonic-gate
11567c478bd9Sstevel@tonic-gate if (dsp->ds_dlstate == DL_UNATTACHED ||
1157210db224Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) {
1158210db224Sericheng dl_err = DL_OUTSTATE;
1159210db224Sericheng goto failed;
1160210db224Sericheng }
11617c478bd9Sstevel@tonic-gate
1162d62bc4baSyz note &= ~(mac_no_notification(dsp->ds_mh));
1163d62bc4baSyz
11647c478bd9Sstevel@tonic-gate /*
1165210db224Sericheng * Cache the notifications that are being enabled.
11667c478bd9Sstevel@tonic-gate */
1167210db224Sericheng dsp->ds_notifications = dlp->dl_notifications & note;
11687c478bd9Sstevel@tonic-gate /*
1169210db224Sericheng * The ACK carries all notifications regardless of which set is
1170210db224Sericheng * being enabled.
11717c478bd9Sstevel@tonic-gate */
1172210db224Sericheng dlnotifyack(q, mp, note);
11737c478bd9Sstevel@tonic-gate
11747c478bd9Sstevel@tonic-gate /*
1175da14cebeSEric Cheng * Generate DL_NOTIFY_IND messages for each enabled notification.
11767c478bd9Sstevel@tonic-gate */
1177210db224Sericheng if (dsp->ds_notifications != 0) {
1178210db224Sericheng dld_str_notify_ind(dsp);
11797c478bd9Sstevel@tonic-gate }
1180da14cebeSEric Cheng return;
11817c478bd9Sstevel@tonic-gate failed:
1182210db224Sericheng dlerrorack(q, mp, DL_NOTIFY_REQ, dl_err, 0);
11837c478bd9Sstevel@tonic-gate }
11847c478bd9Sstevel@tonic-gate
11857c478bd9Sstevel@tonic-gate /*
1186da14cebeSEric Cheng * DL_UINTDATA_REQ
11877c478bd9Sstevel@tonic-gate */
1188d62bc4baSyz void
proto_unitdata_req(dld_str_t * dsp,mblk_t * mp)1189da14cebeSEric Cheng proto_unitdata_req(dld_str_t *dsp, mblk_t *mp)
11907c478bd9Sstevel@tonic-gate {
1191210db224Sericheng queue_t *q = dsp->ds_wq;
1192d62bc4baSyz dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr;
1193210db224Sericheng off_t off;
1194210db224Sericheng size_t len, size;
1195210db224Sericheng const uint8_t *addr;
1196210db224Sericheng uint16_t sap;
11977c478bd9Sstevel@tonic-gate uint_t addr_length;
1198ba2e4443Sseb mblk_t *bp, *payload;
1199210db224Sericheng t_uscalar_t dl_err;
1200e7801d59Ssowmini uint_t max_sdu;
12017c478bd9Sstevel@tonic-gate
1202210db224Sericheng if (MBLKL(mp) < sizeof (dl_unitdata_req_t) || mp->b_cont == NULL) {
1203da14cebeSEric Cheng dlerrorack(q, mp, DL_UNITDATA_REQ, DL_BADPRIM, 0);
1204da14cebeSEric Cheng return;
1205210db224Sericheng }
12067c478bd9Sstevel@tonic-gate
1207da14cebeSEric Cheng mutex_enter(&dsp->ds_lock);
1208da14cebeSEric Cheng if (dsp->ds_dlstate != DL_IDLE) {
1209da14cebeSEric Cheng mutex_exit(&dsp->ds_lock);
1210da14cebeSEric Cheng dlerrorack(q, mp, DL_UNITDATA_REQ, DL_OUTSTATE, 0);
1211da14cebeSEric Cheng return;
1212da14cebeSEric Cheng }
1213da14cebeSEric Cheng DLD_DATATHR_INC(dsp);
1214da14cebeSEric Cheng mutex_exit(&dsp->ds_lock);
1215da14cebeSEric Cheng
1216210db224Sericheng addr_length = dsp->ds_mip->mi_addr_length;
12177c478bd9Sstevel@tonic-gate
1218210db224Sericheng off = dlp->dl_dest_addr_offset;
1219210db224Sericheng len = dlp->dl_dest_addr_length;
12207c478bd9Sstevel@tonic-gate
1221210db224Sericheng if (!MBLKIN(mp, off, len) || !IS_P2ALIGNED(off, sizeof (uint16_t))) {
1222210db224Sericheng dl_err = DL_BADPRIM;
1223210db224Sericheng goto failed;
1224210db224Sericheng }
12257c478bd9Sstevel@tonic-gate
1226210db224Sericheng if (len != addr_length + sizeof (uint16_t)) {
1227210db224Sericheng dl_err = DL_BADADDR;
1228210db224Sericheng goto failed;
12297c478bd9Sstevel@tonic-gate }
12307c478bd9Sstevel@tonic-gate
1231210db224Sericheng addr = mp->b_rptr + off;
1232210db224Sericheng sap = *(uint16_t *)(mp->b_rptr + off + addr_length);
12337c478bd9Sstevel@tonic-gate
1234210db224Sericheng /*
1235210db224Sericheng * Check the length of the packet and the block types.
1236210db224Sericheng */
1237210db224Sericheng size = 0;
1238ba2e4443Sseb payload = mp->b_cont;
1239ba2e4443Sseb for (bp = payload; bp != NULL; bp = bp->b_cont) {
1240210db224Sericheng if (DB_TYPE(bp) != M_DATA)
1241210db224Sericheng goto baddata;
12427c478bd9Sstevel@tonic-gate
1243210db224Sericheng size += MBLKL(bp);
1244210db224Sericheng }
12457c478bd9Sstevel@tonic-gate
1246e7801d59Ssowmini mac_sdu_get(dsp->ds_mh, NULL, &max_sdu);
1247e7801d59Ssowmini if (size > max_sdu)
1248210db224Sericheng goto baddata;
12497c478bd9Sstevel@tonic-gate
1250210db224Sericheng /*
1251210db224Sericheng * Build a packet header.
1252210db224Sericheng */
1253da14cebeSEric Cheng if ((bp = dls_header(dsp, addr, sap, dlp->dl_priority.dl_max,
1254605445d5Sdg &payload)) == NULL) {
12557c478bd9Sstevel@tonic-gate dl_err = DL_BADADDR;
1256210db224Sericheng goto failed;
12577c478bd9Sstevel@tonic-gate }
12587c478bd9Sstevel@tonic-gate
1259210db224Sericheng /*
1260210db224Sericheng * We no longer need the M_PROTO header, so free it.
1261210db224Sericheng */
1262210db224Sericheng freeb(mp);
12637c478bd9Sstevel@tonic-gate
1264210db224Sericheng /*
1265210db224Sericheng * Transfer the checksum offload information if it is present.
1266210db224Sericheng */
1267ec71f88eSPatrick Mooney mac_hcksum_clone(payload, bp);
12687c478bd9Sstevel@tonic-gate
12697c478bd9Sstevel@tonic-gate /*
1270210db224Sericheng * Link the payload onto the new header.
12717c478bd9Sstevel@tonic-gate */
1272210db224Sericheng ASSERT(bp->b_cont == NULL);
1273ba2e4443Sseb bp->b_cont = payload;
1274da14cebeSEric Cheng
1275da14cebeSEric Cheng /*
1276da14cebeSEric Cheng * No lock can be held across modules and putnext()'s,
1277da14cebeSEric Cheng * which can happen here with the call from DLD_TX().
1278da14cebeSEric Cheng */
12798648b7dbSToomas Soome if (DLD_TX(dsp, bp, 0, 0) != 0) {
1280da14cebeSEric Cheng /* flow-controlled */
1281da14cebeSEric Cheng DLD_SETQFULL(dsp);
1282da14cebeSEric Cheng }
1283da14cebeSEric Cheng DLD_DATATHR_DCR(dsp);
1284d62bc4baSyz return;
1285da14cebeSEric Cheng
1286210db224Sericheng failed:
1287210db224Sericheng dlerrorack(q, mp, DL_UNITDATA_REQ, dl_err, 0);
1288da14cebeSEric Cheng DLD_DATATHR_DCR(dsp);
1289d62bc4baSyz return;
1290210db224Sericheng
1291210db224Sericheng baddata:
1292210db224Sericheng dluderrorind(q, mp, (void *)addr, len, DL_BADDATA, 0);
1293da14cebeSEric Cheng DLD_DATATHR_DCR(dsp);
12947c478bd9Sstevel@tonic-gate }
12957c478bd9Sstevel@tonic-gate
12967c478bd9Sstevel@tonic-gate /*
1297210db224Sericheng * DL_PASSIVE_REQ
12987c478bd9Sstevel@tonic-gate */
1299da14cebeSEric Cheng static void
proto_passive_req(dld_str_t * dsp,mblk_t * mp)1300da14cebeSEric Cheng proto_passive_req(dld_str_t *dsp, mblk_t *mp)
13017c478bd9Sstevel@tonic-gate {
1302210db224Sericheng t_uscalar_t dl_err;
13037c478bd9Sstevel@tonic-gate
1304210db224Sericheng /*
1305210db224Sericheng * If we've already become active by issuing an active primitive,
1306210db224Sericheng * then it's too late to try to become passive.
1307210db224Sericheng */
1308210db224Sericheng if (dsp->ds_passivestate == DLD_ACTIVE) {
1309210db224Sericheng dl_err = DL_OUTSTATE;
13107c478bd9Sstevel@tonic-gate goto failed;
1311210db224Sericheng }
13127c478bd9Sstevel@tonic-gate
1313210db224Sericheng if (MBLKL(mp) < sizeof (dl_passive_req_t)) {
1314210db224Sericheng dl_err = DL_BADPRIM;
1315210db224Sericheng goto failed;
13167c478bd9Sstevel@tonic-gate }
13177c478bd9Sstevel@tonic-gate
1318210db224Sericheng dsp->ds_passivestate = DLD_PASSIVE;
1319210db224Sericheng dlokack(dsp->ds_wq, mp, DL_PASSIVE_REQ);
1320da14cebeSEric Cheng return;
1321210db224Sericheng failed:
1322210db224Sericheng dlerrorack(dsp->ds_wq, mp, DL_PASSIVE_REQ, dl_err, 0);
13237c478bd9Sstevel@tonic-gate }
13247c478bd9Sstevel@tonic-gate
1325da14cebeSEric Cheng
13267c478bd9Sstevel@tonic-gate /*
1327210db224Sericheng * Catch-all handler.
13287c478bd9Sstevel@tonic-gate */
1329da14cebeSEric Cheng static void
proto_req(dld_str_t * dsp,mblk_t * mp)1330da14cebeSEric Cheng proto_req(dld_str_t *dsp, mblk_t *mp)
13317c478bd9Sstevel@tonic-gate {
1332da14cebeSEric Cheng union DL_primitives *dlp = (union DL_primitives *)mp->b_rptr;
1333da14cebeSEric Cheng
1334210db224Sericheng dlerrorack(dsp->ds_wq, mp, dlp->dl_primitive, DL_UNSUPPORTED, 0);
13357c478bd9Sstevel@tonic-gate }
13367c478bd9Sstevel@tonic-gate
1337da14cebeSEric Cheng static int
dld_capab_perim(dld_str_t * dsp,void * data,uint_t flags)1338da14cebeSEric Cheng dld_capab_perim(dld_str_t *dsp, void *data, uint_t flags)
13397c478bd9Sstevel@tonic-gate {
1340da14cebeSEric Cheng switch (flags) {
1341da14cebeSEric Cheng case DLD_ENABLE:
1342da14cebeSEric Cheng mac_perim_enter_by_mh(dsp->ds_mh, (mac_perim_handle_t *)data);
1343da14cebeSEric Cheng return (0);
13447c478bd9Sstevel@tonic-gate
1345da14cebeSEric Cheng case DLD_DISABLE:
1346da14cebeSEric Cheng mac_perim_exit((mac_perim_handle_t)data);
1347da14cebeSEric Cheng return (0);
1348210db224Sericheng
1349da14cebeSEric Cheng case DLD_QUERY:
1350da14cebeSEric Cheng return (mac_perim_held(dsp->ds_mh));
1351da14cebeSEric Cheng }
1352da14cebeSEric Cheng return (0);
1353da14cebeSEric Cheng }
13547c478bd9Sstevel@tonic-gate
1355da14cebeSEric Cheng static int
dld_capab_direct(dld_str_t * dsp,void * data,uint_t flags)1356da14cebeSEric Cheng dld_capab_direct(dld_str_t *dsp, void *data, uint_t flags)
1357da14cebeSEric Cheng {
1358da14cebeSEric Cheng dld_capab_direct_t *direct = data;
13597c478bd9Sstevel@tonic-gate
1360da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
13617c478bd9Sstevel@tonic-gate
1362da14cebeSEric Cheng switch (flags) {
1363da14cebeSEric Cheng case DLD_ENABLE:
1364da14cebeSEric Cheng dls_rx_set(dsp, (dls_rx_t)direct->di_rx_cf,
1365da14cebeSEric Cheng direct->di_rx_ch);
1366ae6aa22aSVenugopal Iyer
1367da14cebeSEric Cheng direct->di_tx_df = (uintptr_t)str_mdata_fastpath_put;
1368da14cebeSEric Cheng direct->di_tx_dh = dsp;
1369da14cebeSEric Cheng direct->di_tx_cb_df = (uintptr_t)mac_client_tx_notify;
1370da14cebeSEric Cheng direct->di_tx_cb_dh = dsp->ds_mch;
1371ae6aa22aSVenugopal Iyer direct->di_tx_fctl_df = (uintptr_t)mac_tx_is_flow_blocked;
1372ae6aa22aSVenugopal Iyer direct->di_tx_fctl_dh = dsp->ds_mch;
1373ae6aa22aSVenugopal Iyer
1374da14cebeSEric Cheng dsp->ds_direct = B_TRUE;
1375da14cebeSEric Cheng
1376da14cebeSEric Cheng return (0);
1377da14cebeSEric Cheng
1378da14cebeSEric Cheng case DLD_DISABLE:
1379da14cebeSEric Cheng dls_rx_set(dsp, (dsp->ds_mode == DLD_FASTPATH) ?
1380da14cebeSEric Cheng dld_str_rx_fastpath : dld_str_rx_unitdata, (void *)dsp);
1381da14cebeSEric Cheng dsp->ds_direct = B_FALSE;
1382da14cebeSEric Cheng
1383da14cebeSEric Cheng return (0);
1384da14cebeSEric Cheng }
1385da14cebeSEric Cheng return (ENOTSUP);
13867c478bd9Sstevel@tonic-gate }
13877c478bd9Sstevel@tonic-gate
1388da14cebeSEric Cheng /*
138984de666eSRyan Zezeski * This function is misnamed. All polling and fanouts are run out of
139084de666eSRyan Zezeski * the lower MAC for VNICs and out of the MAC for NICs. The
139184de666eSRyan Zezeski * availability of Rx rings and promiscous mode is taken care of
139284de666eSRyan Zezeski * between the soft ring set (mac_srs), the Rx ring, and the SW
139384de666eSRyan Zezeski * classifier. Fanout, if necessary, is done by the soft rings that
139484de666eSRyan Zezeski * are part of the SRS. By default the SRS divvies up the packets
139584de666eSRyan Zezeski * based on protocol: TCP, UDP, or Other (OTH).
1396da14cebeSEric Cheng *
139784de666eSRyan Zezeski * The SRS (or its associated soft rings) always store the ill_rx_ring
1398da14cebeSEric Cheng * (the cookie returned when they registered with IP during plumb) as their
1399da14cebeSEric Cheng * 2nd argument which is passed up as mac_resource_handle_t. The upcall
1400da14cebeSEric Cheng * function and 1st argument is what the caller registered when they
1401da14cebeSEric Cheng * called mac_rx_classify_flow_add() to register the flow. For VNIC,
1402da14cebeSEric Cheng * the function is vnic_rx and argument is vnic_t. For regular NIC
1403da14cebeSEric Cheng * case, it mac_rx_default and mac_handle_t. As explained above, the
140484de666eSRyan Zezeski * SRS (or its soft ring) will add the ill_rx_ring (mac_resource_handle_t)
1405da14cebeSEric Cheng * from its stored 2nd argument.
1406da14cebeSEric Cheng */
1407da14cebeSEric Cheng static int
dld_capab_poll_enable(dld_str_t * dsp,dld_capab_poll_t * poll)1408da14cebeSEric Cheng dld_capab_poll_enable(dld_str_t *dsp, dld_capab_poll_t *poll)
14097c478bd9Sstevel@tonic-gate {
1410da14cebeSEric Cheng if (dsp->ds_polling)
1411da14cebeSEric Cheng return (EINVAL);
14127c478bd9Sstevel@tonic-gate
1413da14cebeSEric Cheng if ((dld_opt & DLD_OPT_NO_POLL) != 0 || dsp->ds_mode == DLD_RAW)
1414da14cebeSEric Cheng return (ENOTSUP);
14157c478bd9Sstevel@tonic-gate
14167c478bd9Sstevel@tonic-gate /*
141784de666eSRyan Zezeski * Enable client polling if and only if DLS bypass is
141884de666eSRyan Zezeski * possible. Some traffic requires DLS processing in the Rx
141984de666eSRyan Zezeski * data path. In such a case we can neither allow the client
142084de666eSRyan Zezeski * (IP) to directly poll the soft ring (since DLS processing
142184de666eSRyan Zezeski * hasn't been done) nor can we allow DLS bypass.
14227c478bd9Sstevel@tonic-gate */
1423da14cebeSEric Cheng if (!mac_rx_bypass_set(dsp->ds_mch, dsp->ds_rx, dsp->ds_rx_arg))
1424da14cebeSEric Cheng return (ENOTSUP);
14257c478bd9Sstevel@tonic-gate
14267c478bd9Sstevel@tonic-gate /*
1427da14cebeSEric Cheng * Register soft ring resources. This will come in handy later if
1428da14cebeSEric Cheng * the user decides to modify CPU bindings to use more CPUs for the
1429da14cebeSEric Cheng * device in which case we will switch to fanout using soft rings.
14307c478bd9Sstevel@tonic-gate */
1431da14cebeSEric Cheng mac_resource_set_common(dsp->ds_mch,
1432da14cebeSEric Cheng (mac_resource_add_t)poll->poll_ring_add_cf,
1433da14cebeSEric Cheng (mac_resource_remove_t)poll->poll_ring_remove_cf,
1434da14cebeSEric Cheng (mac_resource_quiesce_t)poll->poll_ring_quiesce_cf,
1435da14cebeSEric Cheng (mac_resource_restart_t)poll->poll_ring_restart_cf,
1436da14cebeSEric Cheng (mac_resource_bind_t)poll->poll_ring_bind_cf,
1437da14cebeSEric Cheng poll->poll_ring_ch);
14387c478bd9Sstevel@tonic-gate
1439da14cebeSEric Cheng mac_client_poll_enable(dsp->ds_mch);
14407c478bd9Sstevel@tonic-gate
14417c478bd9Sstevel@tonic-gate dsp->ds_polling = B_TRUE;
1442da14cebeSEric Cheng return (0);
14437c478bd9Sstevel@tonic-gate }
14447c478bd9Sstevel@tonic-gate
1445da14cebeSEric Cheng /* ARGSUSED */
1446da14cebeSEric Cheng static int
dld_capab_poll_disable(dld_str_t * dsp,dld_capab_poll_t * poll)1447da14cebeSEric Cheng dld_capab_poll_disable(dld_str_t *dsp, dld_capab_poll_t *poll)
14484b46d1efSkrgopi {
1449da14cebeSEric Cheng if (!dsp->ds_polling)
1450da14cebeSEric Cheng return (EINVAL);
14514b46d1efSkrgopi
1452da14cebeSEric Cheng mac_client_poll_disable(dsp->ds_mch);
1453da14cebeSEric Cheng mac_resource_set(dsp->ds_mch, NULL, NULL);
14544b46d1efSkrgopi
1455da14cebeSEric Cheng dsp->ds_polling = B_FALSE;
1456da14cebeSEric Cheng return (0);
14574b46d1efSkrgopi }
14584b46d1efSkrgopi
1459da14cebeSEric Cheng static int
dld_capab_poll(dld_str_t * dsp,void * data,uint_t flags)1460da14cebeSEric Cheng dld_capab_poll(dld_str_t *dsp, void *data, uint_t flags)
14614b46d1efSkrgopi {
1462da14cebeSEric Cheng dld_capab_poll_t *poll = data;
14634b46d1efSkrgopi
1464da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
14654b46d1efSkrgopi
1466da14cebeSEric Cheng switch (flags) {
1467da14cebeSEric Cheng case DLD_ENABLE:
1468da14cebeSEric Cheng return (dld_capab_poll_enable(dsp, poll));
1469da14cebeSEric Cheng case DLD_DISABLE:
1470da14cebeSEric Cheng return (dld_capab_poll_disable(dsp, poll));
1471da14cebeSEric Cheng }
1472da14cebeSEric Cheng return (ENOTSUP);
1473da14cebeSEric Cheng }
14744b46d1efSkrgopi
1475da14cebeSEric Cheng static int
dld_capab_lso(dld_str_t * dsp,void * data,uint_t flags)1476da14cebeSEric Cheng dld_capab_lso(dld_str_t *dsp, void *data, uint_t flags)
1477da14cebeSEric Cheng {
1478da14cebeSEric Cheng dld_capab_lso_t *lso = data;
1479da14cebeSEric Cheng
1480da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
1481da14cebeSEric Cheng
1482da14cebeSEric Cheng switch (flags) {
1483da14cebeSEric Cheng case DLD_ENABLE: {
1484da14cebeSEric Cheng mac_capab_lso_t mac_lso;
1485da14cebeSEric Cheng
1486da14cebeSEric Cheng /*
1487da14cebeSEric Cheng * Check if LSO is supported on this MAC & enable LSO
1488da14cebeSEric Cheng * accordingly.
1489da14cebeSEric Cheng */
1490da14cebeSEric Cheng if (mac_capab_get(dsp->ds_mh, MAC_CAPAB_LSO, &mac_lso)) {
149162366fbbSRobert Mustacchi lso->lso_max_tcpv4 = mac_lso.lso_basic_tcp_ipv4.lso_max;
149262366fbbSRobert Mustacchi lso->lso_max_tcpv6 = mac_lso.lso_basic_tcp_ipv6.lso_max;
1493da14cebeSEric Cheng lso->lso_flags = 0;
1494da14cebeSEric Cheng /* translate the flag for mac clients */
1495da14cebeSEric Cheng if ((mac_lso.lso_flags & LSO_TX_BASIC_TCP_IPV4) != 0)
1496bd670b35SErik Nordmark lso->lso_flags |= DLD_LSO_BASIC_TCP_IPV4;
149762366fbbSRobert Mustacchi if ((mac_lso.lso_flags & LSO_TX_BASIC_TCP_IPV6) != 0)
149862366fbbSRobert Mustacchi lso->lso_flags |= DLD_LSO_BASIC_TCP_IPV6;
149962366fbbSRobert Mustacchi dsp->ds_lso = lso->lso_flags != 0;
150062366fbbSRobert Mustacchi /*
150162366fbbSRobert Mustacchi * DLS uses this to try and make sure that a raw ioctl
150262366fbbSRobert Mustacchi * doesn't send too much data, but doesn't currently
150362366fbbSRobert Mustacchi * check the actual SAP that is sending this (or that
150462366fbbSRobert Mustacchi * it's TCP). So for now, just use the max value here.
150562366fbbSRobert Mustacchi */
150662366fbbSRobert Mustacchi dsp->ds_lso_max = MAX(lso->lso_max_tcpv4,
150762366fbbSRobert Mustacchi lso->lso_max_tcpv6);
1508da14cebeSEric Cheng } else {
1509da14cebeSEric Cheng dsp->ds_lso = B_FALSE;
1510da14cebeSEric Cheng dsp->ds_lso_max = 0;
1511da14cebeSEric Cheng return (ENOTSUP);
1512da14cebeSEric Cheng }
1513da14cebeSEric Cheng return (0);
1514da14cebeSEric Cheng }
1515da14cebeSEric Cheng case DLD_DISABLE: {
1516da14cebeSEric Cheng dsp->ds_lso = B_FALSE;
1517da14cebeSEric Cheng dsp->ds_lso_max = 0;
1518da14cebeSEric Cheng return (0);
1519da14cebeSEric Cheng }
1520da14cebeSEric Cheng }
1521da14cebeSEric Cheng return (ENOTSUP);
15224b46d1efSkrgopi }
15234b46d1efSkrgopi
1524da14cebeSEric Cheng static int
dld_capab(dld_str_t * dsp,uint_t type,void * data,uint_t flags)1525da14cebeSEric Cheng dld_capab(dld_str_t *dsp, uint_t type, void *data, uint_t flags)
15264b46d1efSkrgopi {
1527da14cebeSEric Cheng int err;
15284b46d1efSkrgopi
1529da14cebeSEric Cheng /*
1530da14cebeSEric Cheng * Don't enable direct callback capabilities unless the caller is
1531da14cebeSEric Cheng * the IP client. When a module is inserted in a stream (_I_INSERT)
1532da14cebeSEric Cheng * the stack initiates capability disable, but due to races, the
1533da14cebeSEric Cheng * module insertion may complete before the capability disable
1534da14cebeSEric Cheng * completes. So we limit the check to DLD_ENABLE case.
1535da14cebeSEric Cheng */
1536da14cebeSEric Cheng if ((flags == DLD_ENABLE && type != DLD_CAPAB_PERIM) &&
153762366fbbSRobert Mustacchi (!(dsp->ds_sap == ETHERTYPE_IP || dsp->ds_sap == ETHERTYPE_IPV6) ||
15388d4cf8d8S !check_mod_above(dsp->ds_rq, "ip"))) {
1539da14cebeSEric Cheng return (ENOTSUP);
15404b46d1efSkrgopi }
1541da14cebeSEric Cheng
1542da14cebeSEric Cheng switch (type) {
1543da14cebeSEric Cheng case DLD_CAPAB_DIRECT:
154462366fbbSRobert Mustacchi if (dsp->ds_sap == ETHERTYPE_IPV6) {
154562366fbbSRobert Mustacchi err = ENOTSUP;
154662366fbbSRobert Mustacchi break;
154762366fbbSRobert Mustacchi }
1548da14cebeSEric Cheng err = dld_capab_direct(dsp, data, flags);
1549da14cebeSEric Cheng break;
1550da14cebeSEric Cheng
1551da14cebeSEric Cheng case DLD_CAPAB_POLL:
155262366fbbSRobert Mustacchi if (dsp->ds_sap == ETHERTYPE_IPV6) {
155362366fbbSRobert Mustacchi err = ENOTSUP;
155462366fbbSRobert Mustacchi break;
155562366fbbSRobert Mustacchi }
1556da14cebeSEric Cheng err = dld_capab_poll(dsp, data, flags);
1557da14cebeSEric Cheng break;
1558da14cebeSEric Cheng
1559da14cebeSEric Cheng case DLD_CAPAB_PERIM:
1560da14cebeSEric Cheng err = dld_capab_perim(dsp, data, flags);
1561da14cebeSEric Cheng break;
1562da14cebeSEric Cheng
1563da14cebeSEric Cheng case DLD_CAPAB_LSO:
1564da14cebeSEric Cheng err = dld_capab_lso(dsp, data, flags);
1565da14cebeSEric Cheng break;
1566da14cebeSEric Cheng
1567da14cebeSEric Cheng default:
1568da14cebeSEric Cheng err = ENOTSUP;
1569da14cebeSEric Cheng break;
1570da14cebeSEric Cheng }
1571da14cebeSEric Cheng
1572da14cebeSEric Cheng return (err);
15734b46d1efSkrgopi }
15744b46d1efSkrgopi
15757c478bd9Sstevel@tonic-gate /*
15767c478bd9Sstevel@tonic-gate * DL_CAPABILITY_ACK/DL_ERROR_ACK
15777c478bd9Sstevel@tonic-gate */
1578da14cebeSEric Cheng static void
proto_capability_advertise(dld_str_t * dsp,mblk_t * mp)1579210db224Sericheng proto_capability_advertise(dld_str_t *dsp, mblk_t *mp)
15807c478bd9Sstevel@tonic-gate {
15817c478bd9Sstevel@tonic-gate dl_capability_ack_t *dlap;
15827c478bd9Sstevel@tonic-gate dl_capability_sub_t *dlsp;
15837c478bd9Sstevel@tonic-gate size_t subsize;
1584da14cebeSEric Cheng dl_capab_dld_t dld;
15857c478bd9Sstevel@tonic-gate dl_capab_hcksum_t hcksum;
15867c478bd9Sstevel@tonic-gate dl_capab_zerocopy_t zcopy;
15871cb875aeSCathy Zhou dl_capab_vrrp_t vrrp;
15881cb875aeSCathy Zhou mac_capab_vrrp_t vrrp_capab;
15897c478bd9Sstevel@tonic-gate uint8_t *ptr;
1590210db224Sericheng queue_t *q = dsp->ds_wq;
1591210db224Sericheng mblk_t *mp1;
1592d62bc4baSyz boolean_t hcksum_capable = B_FALSE;
1593d62bc4baSyz boolean_t zcopy_capable = B_FALSE;
1594da14cebeSEric Cheng boolean_t dld_capable = B_FALSE;
15951cb875aeSCathy Zhou boolean_t vrrp_capable = B_FALSE;
15967c478bd9Sstevel@tonic-gate
15977c478bd9Sstevel@tonic-gate /*
15987c478bd9Sstevel@tonic-gate * Initially assume no capabilities.
15997c478bd9Sstevel@tonic-gate */
16007c478bd9Sstevel@tonic-gate subsize = 0;
16017c478bd9Sstevel@tonic-gate
16027c478bd9Sstevel@tonic-gate /*
16039056fcebSCathy Zhou * Check if checksum offload is supported on this MAC.
16047c478bd9Sstevel@tonic-gate */
1605d62bc4baSyz bzero(&hcksum, sizeof (dl_capab_hcksum_t));
16069056fcebSCathy Zhou if (mac_capab_get(dsp->ds_mh, MAC_CAPAB_HCKSUM,
1607ba2e4443Sseb &hcksum.hcksum_txflags)) {
1608d62bc4baSyz if (hcksum.hcksum_txflags != 0) {
1609d62bc4baSyz hcksum_capable = B_TRUE;
1610d62bc4baSyz subsize += sizeof (dl_capability_sub_t) +
1611d62bc4baSyz sizeof (dl_capab_hcksum_t);
1612d62bc4baSyz }
16137c478bd9Sstevel@tonic-gate }
16147c478bd9Sstevel@tonic-gate
16157c478bd9Sstevel@tonic-gate /*
1616d62bc4baSyz * Check if zerocopy is supported on this interface.
1617d62bc4baSyz * If advertising DL_CAPAB_ZEROCOPY has not been explicitly disabled
1618d62bc4baSyz * then reserve space for that capability.
16197c478bd9Sstevel@tonic-gate */
1620d62bc4baSyz if (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_NO_ZCOPY, NULL) &&
1621d62bc4baSyz !(dld_opt & DLD_OPT_NO_ZEROCOPY)) {
1622d62bc4baSyz zcopy_capable = B_TRUE;
16237c478bd9Sstevel@tonic-gate subsize += sizeof (dl_capability_sub_t) +
16247c478bd9Sstevel@tonic-gate sizeof (dl_capab_zerocopy_t);
16257c478bd9Sstevel@tonic-gate }
16267c478bd9Sstevel@tonic-gate
1627da14cebeSEric Cheng /*
1628da14cebeSEric Cheng * Direct capability negotiation interface between IP and DLD
1629da14cebeSEric Cheng */
163062366fbbSRobert Mustacchi if ((dsp->ds_sap == ETHERTYPE_IP || dsp->ds_sap == ETHERTYPE_IPV6) &&
163162366fbbSRobert Mustacchi check_mod_above(dsp->ds_rq, "ip")) {
1632da14cebeSEric Cheng dld_capable = B_TRUE;
1633da14cebeSEric Cheng subsize += sizeof (dl_capability_sub_t) +
1634da14cebeSEric Cheng sizeof (dl_capab_dld_t);
1635da14cebeSEric Cheng }
1636da14cebeSEric Cheng
16371cb875aeSCathy Zhou /*
16381cb875aeSCathy Zhou * Check if vrrp is supported on this interface. If so, reserve
16391cb875aeSCathy Zhou * space for that capability.
16401cb875aeSCathy Zhou */
16411cb875aeSCathy Zhou if (mac_capab_get(dsp->ds_mh, MAC_CAPAB_VRRP, &vrrp_capab)) {
16421cb875aeSCathy Zhou vrrp_capable = B_TRUE;
16431cb875aeSCathy Zhou subsize += sizeof (dl_capability_sub_t) +
16441cb875aeSCathy Zhou sizeof (dl_capab_vrrp_t);
16451cb875aeSCathy Zhou }
16461cb875aeSCathy Zhou
16477c478bd9Sstevel@tonic-gate /*
1648210db224Sericheng * If there are no capabilities to advertise or if we
1649210db224Sericheng * can't allocate a response, send a DL_ERROR_ACK.
16507c478bd9Sstevel@tonic-gate */
16514b46d1efSkrgopi if ((mp1 = reallocb(mp,
1652210db224Sericheng sizeof (dl_capability_ack_t) + subsize, 0)) == NULL) {
1653210db224Sericheng dlerrorack(q, mp, DL_CAPABILITY_REQ, DL_NOTSUPPORTED, 0);
1654da14cebeSEric Cheng return;
16557c478bd9Sstevel@tonic-gate }
16567c478bd9Sstevel@tonic-gate
1657210db224Sericheng mp = mp1;
1658210db224Sericheng DB_TYPE(mp) = M_PROTO;
1659210db224Sericheng mp->b_wptr = mp->b_rptr + sizeof (dl_capability_ack_t) + subsize;
1660210db224Sericheng bzero(mp->b_rptr, MBLKL(mp));
16617c478bd9Sstevel@tonic-gate dlap = (dl_capability_ack_t *)mp->b_rptr;
16627c478bd9Sstevel@tonic-gate dlap->dl_primitive = DL_CAPABILITY_ACK;
16637c478bd9Sstevel@tonic-gate dlap->dl_sub_offset = sizeof (dl_capability_ack_t);
16647c478bd9Sstevel@tonic-gate dlap->dl_sub_length = subsize;
16657c478bd9Sstevel@tonic-gate ptr = (uint8_t *)&dlap[1];
16667c478bd9Sstevel@tonic-gate
16677c478bd9Sstevel@tonic-gate /*
16687c478bd9Sstevel@tonic-gate * TCP/IP checksum offload.
16697c478bd9Sstevel@tonic-gate */
1670d62bc4baSyz if (hcksum_capable) {
16717c478bd9Sstevel@tonic-gate dlsp = (dl_capability_sub_t *)ptr;
16727c478bd9Sstevel@tonic-gate
16737c478bd9Sstevel@tonic-gate dlsp->dl_cap = DL_CAPAB_HCKSUM;
16747c478bd9Sstevel@tonic-gate dlsp->dl_length = sizeof (dl_capab_hcksum_t);
16757c478bd9Sstevel@tonic-gate ptr += sizeof (dl_capability_sub_t);
16767c478bd9Sstevel@tonic-gate
16777c478bd9Sstevel@tonic-gate hcksum.hcksum_version = HCKSUM_VERSION_1;
16787c478bd9Sstevel@tonic-gate dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq);
16797c478bd9Sstevel@tonic-gate bcopy(&hcksum, ptr, sizeof (dl_capab_hcksum_t));
16807c478bd9Sstevel@tonic-gate ptr += sizeof (dl_capab_hcksum_t);
16817c478bd9Sstevel@tonic-gate }
16827c478bd9Sstevel@tonic-gate
16837c478bd9Sstevel@tonic-gate /*
16847c478bd9Sstevel@tonic-gate * Zero copy
16857c478bd9Sstevel@tonic-gate */
1686d62bc4baSyz if (zcopy_capable) {
16877c478bd9Sstevel@tonic-gate dlsp = (dl_capability_sub_t *)ptr;
16887c478bd9Sstevel@tonic-gate
16897c478bd9Sstevel@tonic-gate dlsp->dl_cap = DL_CAPAB_ZEROCOPY;
16907c478bd9Sstevel@tonic-gate dlsp->dl_length = sizeof (dl_capab_zerocopy_t);
16917c478bd9Sstevel@tonic-gate ptr += sizeof (dl_capability_sub_t);
16927c478bd9Sstevel@tonic-gate
16937c478bd9Sstevel@tonic-gate bzero(&zcopy, sizeof (dl_capab_zerocopy_t));
16947c478bd9Sstevel@tonic-gate zcopy.zerocopy_version = ZEROCOPY_VERSION_1;
16957c478bd9Sstevel@tonic-gate zcopy.zerocopy_flags = DL_CAPAB_VMSAFE_MEM;
16967c478bd9Sstevel@tonic-gate
16977c478bd9Sstevel@tonic-gate dlcapabsetqid(&(zcopy.zerocopy_mid), dsp->ds_rq);
16987c478bd9Sstevel@tonic-gate bcopy(&zcopy, ptr, sizeof (dl_capab_zerocopy_t));
16997c478bd9Sstevel@tonic-gate ptr += sizeof (dl_capab_zerocopy_t);
17007c478bd9Sstevel@tonic-gate }
17017c478bd9Sstevel@tonic-gate
17021cb875aeSCathy Zhou /*
17031cb875aeSCathy Zhou * VRRP capability negotiation
17041cb875aeSCathy Zhou */
17051cb875aeSCathy Zhou if (vrrp_capable) {
17061cb875aeSCathy Zhou dlsp = (dl_capability_sub_t *)ptr;
17071cb875aeSCathy Zhou dlsp->dl_cap = DL_CAPAB_VRRP;
17081cb875aeSCathy Zhou dlsp->dl_length = sizeof (dl_capab_vrrp_t);
17091cb875aeSCathy Zhou ptr += sizeof (dl_capability_sub_t);
17101cb875aeSCathy Zhou
17111cb875aeSCathy Zhou bzero(&vrrp, sizeof (dl_capab_vrrp_t));
17121cb875aeSCathy Zhou vrrp.vrrp_af = vrrp_capab.mcv_af;
17131cb875aeSCathy Zhou bcopy(&vrrp, ptr, sizeof (dl_capab_vrrp_t));
17141cb875aeSCathy Zhou ptr += sizeof (dl_capab_vrrp_t);
17151cb875aeSCathy Zhou }
17161cb875aeSCathy Zhou
1717da14cebeSEric Cheng /*
1718da14cebeSEric Cheng * Direct capability negotiation interface between IP and DLD.
1719da14cebeSEric Cheng * Refer to dld.h for details.
1720da14cebeSEric Cheng */
1721da14cebeSEric Cheng if (dld_capable) {
1722da14cebeSEric Cheng dlsp = (dl_capability_sub_t *)ptr;
1723da14cebeSEric Cheng dlsp->dl_cap = DL_CAPAB_DLD;
1724da14cebeSEric Cheng dlsp->dl_length = sizeof (dl_capab_dld_t);
1725da14cebeSEric Cheng ptr += sizeof (dl_capability_sub_t);
17267c478bd9Sstevel@tonic-gate
1727da14cebeSEric Cheng bzero(&dld, sizeof (dl_capab_dld_t));
1728da14cebeSEric Cheng dld.dld_version = DLD_CURRENT_VERSION;
1729da14cebeSEric Cheng dld.dld_capab = (uintptr_t)dld_capab;
1730da14cebeSEric Cheng dld.dld_capab_handle = (uintptr_t)dsp;
1731da14cebeSEric Cheng
1732da14cebeSEric Cheng dlcapabsetqid(&(dld.dld_mid), dsp->ds_rq);
1733da14cebeSEric Cheng bcopy(&dld, ptr, sizeof (dl_capab_dld_t));
1734da14cebeSEric Cheng ptr += sizeof (dl_capab_dld_t);
1735da14cebeSEric Cheng }
1736da14cebeSEric Cheng
1737da14cebeSEric Cheng ASSERT(ptr == mp->b_rptr + sizeof (dl_capability_ack_t) + subsize);
1738210db224Sericheng qreply(q, mp);
17397c478bd9Sstevel@tonic-gate }
17408fb46f24Syz
17418fb46f24Syz /*
17428fb46f24Syz * Disable any enabled capabilities.
17438fb46f24Syz */
17448fb46f24Syz void
dld_capabilities_disable(dld_str_t * dsp)17458fb46f24Syz dld_capabilities_disable(dld_str_t *dsp)
17468fb46f24Syz {
17478fb46f24Syz if (dsp->ds_polling)
1748da14cebeSEric Cheng (void) dld_capab_poll_disable(dsp, NULL);
17498fb46f24Syz }
1750