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.
24*4962fb4cSDan McDonald * Copyright 2017 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,
45d62bc4baSyz147064 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 }
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate
131210db224Sericheng #define NEG(x) -(x)
1327c478bd9Sstevel@tonic-gate typedef struct dl_info_ack_wrapper {
1337c478bd9Sstevel@tonic-gate dl_info_ack_t dl_info;
134ba2e4443Sseb uint8_t dl_addr[MAXMACADDRLEN + sizeof (uint16_t)];
135ba2e4443Sseb uint8_t dl_brdcst_addr[MAXMACADDRLEN];
1367c478bd9Sstevel@tonic-gate dl_qos_cl_range1_t dl_qos_range1;
1377c478bd9Sstevel@tonic-gate dl_qos_cl_sel1_t dl_qos_sel1;
1387c478bd9Sstevel@tonic-gate } dl_info_ack_wrapper_t;
1397c478bd9Sstevel@tonic-gate
1407c478bd9Sstevel@tonic-gate /*
141210db224Sericheng * DL_INFO_REQ
1427c478bd9Sstevel@tonic-gate */
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)
1457c478bd9Sstevel@tonic-gate {
1467c478bd9Sstevel@tonic-gate dl_info_ack_wrapper_t *dlwp;
1477c478bd9Sstevel@tonic-gate dl_info_ack_t *dlp;
1487c478bd9Sstevel@tonic-gate dl_qos_cl_sel1_t *selp;
1497c478bd9Sstevel@tonic-gate dl_qos_cl_range1_t *rangep;
1507c478bd9Sstevel@tonic-gate uint8_t *addr;
1517c478bd9Sstevel@tonic-gate uint8_t *brdcst_addr;
1527c478bd9Sstevel@tonic-gate uint_t addr_length;
1537c478bd9Sstevel@tonic-gate uint_t sap_length;
154210db224Sericheng mac_info_t minfo;
155210db224Sericheng mac_info_t *minfop;
156210db224Sericheng queue_t *q = dsp->ds_wq;
1577c478bd9Sstevel@tonic-gate
1587c478bd9Sstevel@tonic-gate /*
1597c478bd9Sstevel@tonic-gate * Swap the request message for one large enough to contain the
1607c478bd9Sstevel@tonic-gate * wrapper structure defined above.
1617c478bd9Sstevel@tonic-gate */
162210db224Sericheng if ((mp = mexchange(q, mp, sizeof (dl_info_ack_wrapper_t),
1637c478bd9Sstevel@tonic-gate M_PCPROTO, 0)) == NULL)
164da14cebeSEric Cheng return;
1657c478bd9Sstevel@tonic-gate
1667c478bd9Sstevel@tonic-gate bzero(mp->b_rptr, sizeof (dl_info_ack_wrapper_t));
1677c478bd9Sstevel@tonic-gate dlwp = (dl_info_ack_wrapper_t *)mp->b_rptr;
1687c478bd9Sstevel@tonic-gate
1697c478bd9Sstevel@tonic-gate dlp = &(dlwp->dl_info);
1707c478bd9Sstevel@tonic-gate ASSERT(dlp == (dl_info_ack_t *)mp->b_rptr);
1717c478bd9Sstevel@tonic-gate
1727c478bd9Sstevel@tonic-gate dlp->dl_primitive = DL_INFO_ACK;
1737c478bd9Sstevel@tonic-gate
1747c478bd9Sstevel@tonic-gate /*
1757c478bd9Sstevel@tonic-gate * Set up the sub-structure pointers.
1767c478bd9Sstevel@tonic-gate */
1777c478bd9Sstevel@tonic-gate addr = dlwp->dl_addr;
1787c478bd9Sstevel@tonic-gate brdcst_addr = dlwp->dl_brdcst_addr;
1797c478bd9Sstevel@tonic-gate rangep = &(dlwp->dl_qos_range1);
1807c478bd9Sstevel@tonic-gate selp = &(dlwp->dl_qos_sel1);
1817c478bd9Sstevel@tonic-gate
1827c478bd9Sstevel@tonic-gate /*
1837c478bd9Sstevel@tonic-gate * This driver supports only version 2 connectionless DLPI provider
1847c478bd9Sstevel@tonic-gate * nodes.
1857c478bd9Sstevel@tonic-gate */
1867c478bd9Sstevel@tonic-gate dlp->dl_service_mode = DL_CLDLS;
1877c478bd9Sstevel@tonic-gate 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;
1937c478bd9Sstevel@tonic-gate ASSERT(dlp->dl_provider_style == DL_STYLE1 ||
1947c478bd9Sstevel@tonic-gate dlp->dl_provider_style == DL_STYLE2);
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate /*
1977c478bd9Sstevel@tonic-gate * Set the current DLPI state.
1987c478bd9Sstevel@tonic-gate */
1997c478bd9Sstevel@tonic-gate dlp->dl_current_state = dsp->ds_dlstate;
2007c478bd9Sstevel@tonic-gate
2017c478bd9Sstevel@tonic-gate /*
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
2047c478bd9Sstevel@tonic-gate * being completed.
2057c478bd9Sstevel@tonic-gate */
2067c478bd9Sstevel@tonic-gate dlp->dl_mac_type = DL_ETHER;
2077c478bd9Sstevel@tonic-gate
2087c478bd9Sstevel@tonic-gate /*
209210db224Sericheng * If the stream is not at least attached we try to retrieve the
210210db224Sericheng * mac_info using mac_info_get()
2117c478bd9Sstevel@tonic-gate */
2127c478bd9Sstevel@tonic-gate if (dsp->ds_dlstate == DL_UNATTACHED ||
2137c478bd9Sstevel@tonic-gate 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 */
2197c478bd9Sstevel@tonic-gate 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);
226210db224Sericheng }
2277c478bd9Sstevel@tonic-gate
2287c478bd9Sstevel@tonic-gate /*
2297c478bd9Sstevel@tonic-gate * Set the media type (properly this time).
2307c478bd9Sstevel@tonic-gate */
2310ba2cbe9Sxc151355 if (dsp->ds_native)
2320ba2cbe9Sxc151355 dlp->dl_mac_type = minfop->mi_nativemedia;
2330ba2cbe9Sxc151355 else
234210db224Sericheng dlp->dl_mac_type = minfop->mi_media;
2357c478bd9Sstevel@tonic-gate
2367c478bd9Sstevel@tonic-gate /*
2377c478bd9Sstevel@tonic-gate * Set the DLSAP length. We only support 16 bit values and they
2387c478bd9Sstevel@tonic-gate * appear after the MAC address portion of DLSAP addresses.
2397c478bd9Sstevel@tonic-gate */
2407c478bd9Sstevel@tonic-gate sap_length = sizeof (uint16_t);
2417c478bd9Sstevel@tonic-gate dlp->dl_sap_length = NEG(sap_length);
2427c478bd9Sstevel@tonic-gate
243210db224Sericheng addr_length = minfop->mi_addr_length;
2447c478bd9Sstevel@tonic-gate
2457c478bd9Sstevel@tonic-gate /*
2467c478bd9Sstevel@tonic-gate * Copy in the media broadcast address.
2477c478bd9Sstevel@tonic-gate */
248ba2e4443Sseb if (minfop->mi_brdcst_addr != NULL) {
249ba2e4443Sseb dlp->dl_brdcst_addr_offset =
250ba2e4443Sseb (uintptr_t)brdcst_addr - (uintptr_t)dlp;
251210db224Sericheng bcopy(minfop->mi_brdcst_addr, brdcst_addr, addr_length);
2527c478bd9Sstevel@tonic-gate 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)) {
2607c478bd9Sstevel@tonic-gate dlp->dl_qos_range_offset = (uintptr_t)rangep - (uintptr_t)dlp;
2617c478bd9Sstevel@tonic-gate dlp->dl_qos_range_length = sizeof (dl_qos_cl_range1_t);
2627c478bd9Sstevel@tonic-gate
2637c478bd9Sstevel@tonic-gate rangep->dl_qos_type = DL_QOS_CL_RANGE1;
2647c478bd9Sstevel@tonic-gate rangep->dl_trans_delay.dl_target_value = DL_UNKNOWN;
2657c478bd9Sstevel@tonic-gate rangep->dl_trans_delay.dl_accept_value = DL_UNKNOWN;
2667c478bd9Sstevel@tonic-gate rangep->dl_protection.dl_min = DL_UNKNOWN;
2677c478bd9Sstevel@tonic-gate rangep->dl_protection.dl_max = DL_UNKNOWN;
2687c478bd9Sstevel@tonic-gate rangep->dl_residual_error = DL_UNKNOWN;
2697c478bd9Sstevel@tonic-gate
2707c478bd9Sstevel@tonic-gate /*
2717c478bd9Sstevel@tonic-gate * Specify the supported range of priorities.
2727c478bd9Sstevel@tonic-gate */
2737c478bd9Sstevel@tonic-gate rangep->dl_priority.dl_min = 0;
2747c478bd9Sstevel@tonic-gate rangep->dl_priority.dl_max = (1 << VLAN_PRI_SIZE) - 1;
2757c478bd9Sstevel@tonic-gate
2767c478bd9Sstevel@tonic-gate dlp->dl_qos_offset = (uintptr_t)selp - (uintptr_t)dlp;
2777c478bd9Sstevel@tonic-gate dlp->dl_qos_length = sizeof (dl_qos_cl_sel1_t);
2787c478bd9Sstevel@tonic-gate
2797c478bd9Sstevel@tonic-gate selp->dl_qos_type = DL_QOS_CL_SEL1;
2807c478bd9Sstevel@tonic-gate selp->dl_trans_delay = DL_UNKNOWN;
2817c478bd9Sstevel@tonic-gate selp->dl_protection = DL_UNKNOWN;
2827c478bd9Sstevel@tonic-gate selp->dl_residual_error = DL_UNKNOWN;
2837c478bd9Sstevel@tonic-gate
2847c478bd9Sstevel@tonic-gate /*
2857c478bd9Sstevel@tonic-gate * Specify the current priority (which can be changed by
2867c478bd9Sstevel@tonic-gate * the DL_UDQOS_REQ primitive).
2877c478bd9Sstevel@tonic-gate */
2887c478bd9Sstevel@tonic-gate selp->dl_priority = dsp->ds_pri;
289e75f0919SSebastien Roy }
2907c478bd9Sstevel@tonic-gate
2917c478bd9Sstevel@tonic-gate dlp->dl_addr_length = addr_length + sizeof (uint16_t);
2927c478bd9Sstevel@tonic-gate if (dsp->ds_dlstate == DL_IDLE) {
2937c478bd9Sstevel@tonic-gate /*
2947c478bd9Sstevel@tonic-gate * The stream is bound. Therefore we can formulate a valid
2957c478bd9Sstevel@tonic-gate * DLSAP address.
2967c478bd9Sstevel@tonic-gate */
2977c478bd9Sstevel@tonic-gate 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
3017c478bd9Sstevel@tonic-gate *(uint16_t *)(addr + addr_length) = dsp->ds_sap;
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate 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);
3117c478bd9Sstevel@tonic-gate
312210db224Sericheng qreply(q, mp);
3137c478bd9Sstevel@tonic-gate }
3147c478bd9Sstevel@tonic-gate
3157c478bd9Sstevel@tonic-gate /*
316210db224Sericheng * 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;
3297c478bd9Sstevel@tonic-gate goto failed;
330210db224Sericheng }
3317c478bd9Sstevel@tonic-gate
332210db224Sericheng if (dsp->ds_dlstate != DL_UNATTACHED) {
333210db224Sericheng dl_err = DL_OUTSTATE;
334210db224Sericheng goto failed;
335210db224Sericheng }
3367c478bd9Sstevel@tonic-gate
337210db224Sericheng dsp->ds_dlstate = DL_ATTACH_PENDING;
338210db224Sericheng
339210db224Sericheng err = dld_str_attach(dsp, dlp->dl_ppa);
340210db224Sericheng if (err != 0) {
3417c478bd9Sstevel@tonic-gate switch (err) {
3427c478bd9Sstevel@tonic-gate case ENOENT:
3437c478bd9Sstevel@tonic-gate dl_err = DL_BADPPA;
3447c478bd9Sstevel@tonic-gate err = 0;
3457c478bd9Sstevel@tonic-gate break;
3467c478bd9Sstevel@tonic-gate default:
3477c478bd9Sstevel@tonic-gate dl_err = DL_SYSERR;
3487c478bd9Sstevel@tonic-gate break;
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate dsp->ds_dlstate = DL_UNATTACHED;
351210db224Sericheng goto failed;
352210db224Sericheng }
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;
369210db224Sericheng
370210db224Sericheng if (MBLKL(mp) < sizeof (dl_detach_req_t)) {
371210db224Sericheng dl_err = DL_BADPRIM;
372210db224Sericheng goto failed;
373210db224Sericheng }
374210db224Sericheng
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;
383210db224Sericheng }
384210db224Sericheng
385da14cebeSEric Cheng ASSERT(dsp->ds_datathr_cnt == 0);
386210db224Sericheng dsp->ds_dlstate = DL_DETACH_PENDING;
387210db224Sericheng
388da14cebeSEric Cheng dld_str_detach(dsp);
389d62bc4baSyz147064 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 /*
397210db224Sericheng * 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;
4046f45d2aeSyz147064 uint8_t dlsap_addr[MAXMACADDRLEN + sizeof (uint16_t)];
4056f45d2aeSyz147064 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
413210db224Sericheng if (MBLKL(mp) < sizeof (dl_bind_req_t)) {
414210db224Sericheng dl_err = DL_BADPRIM;
4157c478bd9Sstevel@tonic-gate goto failed;
416210db224Sericheng }
417210db224Sericheng
418210db224Sericheng if (dlp->dl_xidtest_flg != 0) {
419210db224Sericheng dl_err = DL_NOAUTO;
420210db224Sericheng goto failed;
421210db224Sericheng }
422210db224Sericheng
423210db224Sericheng if (dlp->dl_service_mode != DL_CLDLS) {
424210db224Sericheng dl_err = DL_UNSUPPORTED;
425210db224Sericheng goto failed;
426210db224Sericheng }
427210db224Sericheng
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 }
439210db224Sericheng
440da14cebeSEric Cheng dsp->ds_dlstate = DL_BIND_PENDING;
441210db224Sericheng /*
442210db224Sericheng * Set the receive callback.
443210db224Sericheng */
444da14cebeSEric Cheng dls_rx_set(dsp, (dsp->ds_mode == DLD_RAW) ?
445210db224Sericheng dld_str_rx_raw : dld_str_rx_unitdata, dsp);
446210db224Sericheng
447210db224Sericheng /*
448210db224Sericheng * Bind the channel such that it can receive packets.
449210db224Sericheng */
450d62bc4baSyz147064 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 }
465d62bc4baSyz147064
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)
481da14cebeSEric Cheng mac_client_set_intr_cpu(mdip, dsp->ds_mch, intr_cpu);
482da14cebeSEric Cheng
4837c478bd9Sstevel@tonic-gate /*
4847c478bd9Sstevel@tonic-gate * Copy in MAC address.
4857c478bd9Sstevel@tonic-gate */
4866f45d2aeSyz147064 dlsap_addr_length = dsp->ds_mip->mi_addr_length;
487da14cebeSEric Cheng mac_unicast_primary_get(dsp->ds_mh, dlsap_addr);
4887c478bd9Sstevel@tonic-gate
4897c478bd9Sstevel@tonic-gate /*
4906f45d2aeSyz147064 * Copy in the SAP.
4917c478bd9Sstevel@tonic-gate */
492d62bc4baSyz147064 *(uint16_t *)(dlsap_addr + dlsap_addr_length) = sap;
4936f45d2aeSyz147064 dlsap_addr_length += sizeof (uint16_t);
4947c478bd9Sstevel@tonic-gate
4957c478bd9Sstevel@tonic-gate dsp->ds_dlstate = DL_IDLE;
4966f45d2aeSyz147064 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);
5017c478bd9Sstevel@tonic-gate failed:
502210db224Sericheng dlerrorack(q, mp, DL_BIND_REQ, dl_err, (t_uscalar_t)err);
503210db224Sericheng }
504210db224Sericheng
505210db224Sericheng /*
506210db224Sericheng * DL_UNBIND_REQ
507210db224Sericheng */
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)
510210db224Sericheng {
511d62bc4baSyz147064 queue_t *q = dsp->ds_wq;
512d62bc4baSyz147064 t_uscalar_t dl_err;
513da14cebeSEric Cheng mac_perim_handle_t mph;
514210db224Sericheng
515d62bc4baSyz147064 if (MBLKL(mp) < sizeof (dl_unbind_req_t)) {
516d62bc4baSyz147064 dl_err = DL_BADPRIM;
517d62bc4baSyz147064 goto failed;
518d62bc4baSyz147064 }
519d62bc4baSyz147064
520d62bc4baSyz147064 if (dsp->ds_dlstate != DL_IDLE) {
521d62bc4baSyz147064 dl_err = DL_OUTSTATE;
522d62bc4baSyz147064 goto failed;
523d62bc4baSyz147064 }
524210db224Sericheng
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);
528210db224Sericheng
529da14cebeSEric Cheng dsp->ds_dlstate = DL_UNBIND_PENDING;
530da14cebeSEric Cheng mutex_exit(&dsp->ds_lock);
531da14cebeSEric Cheng
532da14cebeSEric Cheng mac_perim_enter_by_mh(dsp->ds_mh, &mph);
533210db224Sericheng /*
534210db224Sericheng * Unbind the channel to stop packets being received.
535210db224Sericheng */
5365ecc58b1SGirish Moodalbail dls_unbind(dsp);
537d62bc4baSyz147064
538d62bc4baSyz147064 /*
539210db224Sericheng * Disable polling mode, if it is enabled.
540210db224Sericheng */
541da14cebeSEric Cheng (void) dld_capab_poll_disable(dsp, NULL);
542d62bc4baSyz147064
543d62bc4baSyz147064 /*
5448347601bSyl150051 * Clear LSO flags.
5458347601bSyl150051 */
5468347601bSyl150051 dsp->ds_lso = B_FALSE;
5478347601bSyl150051 dsp->ds_lso_max = 0;
5488347601bSyl150051
5498347601bSyl150051 /*
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
555da14cebeSEric Cheng /*
556210db224Sericheng * Set the mode back to the default (unitdata).
557210db224Sericheng */
558210db224Sericheng dsp->ds_mode = DLD_UNITDATA;
5596a0b2badSericheng dsp->ds_dlstate = DL_UNBOUND;
560210db224Sericheng
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);
567210db224Sericheng }
568210db224Sericheng
569210db224Sericheng /*
570210db224Sericheng * DL_PROMISCON_REQ
571210db224Sericheng */
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)
574210db224Sericheng {
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 }
586210db224Sericheng
587210db224Sericheng if (dsp->ds_dlstate == DL_UNATTACHED ||
588210db224Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) {
589210db224Sericheng dl_err = DL_OUTSTATE;
590210db224Sericheng goto failed;
591210db224Sericheng }
592210db224Sericheng
593cabb4db9SDan McDonald mac_perim_enter_by_mh(dsp->ds_mh, &mph);
594cabb4db9SDan McDonald
595cabb4db9SDan McDonald new_flags = promisc_saved = dsp->ds_promisc;
596210db224Sericheng switch (dlp->dl_level) {
597210db224Sericheng case DL_PROMISC_SAP:
598cabb4db9SDan McDonald new_flags |= DLS_PROMISC_SAP;
599210db224Sericheng break;
600da14cebeSEric Cheng
601210db224Sericheng case DL_PROMISC_MULTI:
602cabb4db9SDan McDonald new_flags |= DLS_PROMISC_MULTI;
603210db224Sericheng break;
604da14cebeSEric Cheng
605210db224Sericheng case DL_PROMISC_PHYS:
606cabb4db9SDan McDonald new_flags |= DLS_PROMISC_PHYS;
6077c478bd9Sstevel@tonic-gate break;
608da14cebeSEric Cheng
6097c478bd9Sstevel@tonic-gate default:
610210db224Sericheng dl_err = DL_NOTSUPPORTED;
611ad7ed3feSRobert Mustacchi goto failed2;
612210db224Sericheng }
613210db224Sericheng
6145d460eafSCathy Zhou if ((promisc_saved == 0) && (err = dls_active_set(dsp)) != 0) {
615cabb4db9SDan McDonald ASSERT(dsp->ds_promisc == promisc_saved);
6167c478bd9Sstevel@tonic-gate dl_err = DL_SYSERR;
617da14cebeSEric Cheng goto failed2;
618210db224Sericheng }
619210db224Sericheng
620210db224Sericheng /*
621210db224Sericheng * Adjust channel promiscuity.
622210db224Sericheng */
623cabb4db9SDan McDonald err = dls_promisc(dsp, new_flags);
624da14cebeSEric Cheng
625210db224Sericheng if (err != 0) {
626210db224Sericheng dl_err = DL_SYSERR;
627da14cebeSEric Cheng dsp->ds_promisc = promisc_saved;
6285d460eafSCathy Zhou if (promisc_saved == 0)
6295d460eafSCathy Zhou dls_active_clear(dsp, B_FALSE);
630da14cebeSEric Cheng goto failed2;
631210db224Sericheng }
632210db224Sericheng
633da14cebeSEric Cheng mac_perim_exit(mph);
634da14cebeSEric Cheng
635210db224Sericheng dlokack(q, mp, DL_PROMISCON_REQ);
636da14cebeSEric Cheng return;
637da14cebeSEric Cheng
638da14cebeSEric Cheng failed2:
639da14cebeSEric Cheng mac_perim_exit(mph);
640210db224Sericheng failed:
641210db224Sericheng dlerrorack(q, mp, DL_PROMISCON_REQ, dl_err, (t_uscalar_t)err);
642210db224Sericheng }
643210db224Sericheng
644210db224Sericheng /*
645210db224Sericheng * DL_PROMISCOFF_REQ
646210db224Sericheng */
647da14cebeSEric Cheng static void
proto_promiscoff_req(dld_str_t * dsp,mblk_t * mp)648da14cebeSEric Cheng proto_promiscoff_req(dld_str_t *dsp, mblk_t *mp)
649210db224Sericheng {
650da14cebeSEric Cheng dl_promiscoff_req_t *dlp = (dl_promiscoff_req_t *)mp->b_rptr;
651210db224Sericheng int err = 0;
652210db224Sericheng t_uscalar_t dl_err;
653cabb4db9SDan McDonald uint32_t new_flags;
654210db224Sericheng queue_t *q = dsp->ds_wq;
655da14cebeSEric Cheng mac_perim_handle_t mph;
656210db224Sericheng
657210db224Sericheng if (MBLKL(mp) < sizeof (dl_promiscoff_req_t)) {
658210db224Sericheng dl_err = DL_BADPRIM;
659210db224Sericheng goto failed;
660210db224Sericheng }
661210db224Sericheng
662210db224Sericheng if (dsp->ds_dlstate == DL_UNATTACHED ||
663210db224Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) {
664210db224Sericheng dl_err = DL_OUTSTATE;
665210db224Sericheng goto failed;
666210db224Sericheng }
667210db224Sericheng
668cabb4db9SDan McDonald mac_perim_enter_by_mh(dsp->ds_mh, &mph);
669cabb4db9SDan McDonald
670cabb4db9SDan McDonald new_flags = dsp->ds_promisc;
671210db224Sericheng switch (dlp->dl_level) {
672210db224Sericheng case DL_PROMISC_SAP:
673da14cebeSEric Cheng if (!(dsp->ds_promisc & DLS_PROMISC_SAP)) {
674da14cebeSEric Cheng dl_err = DL_NOTENAB;
675*4962fb4cSDan McDonald goto failed2;
676da14cebeSEric Cheng }
677cabb4db9SDan McDonald new_flags &= ~DLS_PROMISC_SAP;
6787c478bd9Sstevel@tonic-gate break;
679da14cebeSEric Cheng
680210db224Sericheng case DL_PROMISC_MULTI:
681da14cebeSEric Cheng if (!(dsp->ds_promisc & DLS_PROMISC_MULTI)) {
682da14cebeSEric Cheng dl_err = DL_NOTENAB;
683*4962fb4cSDan McDonald goto failed2;
684da14cebeSEric Cheng }
685cabb4db9SDan McDonald new_flags &= ~DLS_PROMISC_MULTI;
686210db224Sericheng break;
687da14cebeSEric Cheng
688210db224Sericheng case DL_PROMISC_PHYS:
689da14cebeSEric Cheng if (!(dsp->ds_promisc & DLS_PROMISC_PHYS)) {
690da14cebeSEric Cheng dl_err = DL_NOTENAB;
691*4962fb4cSDan McDonald goto failed2;
692da14cebeSEric Cheng }
693cabb4db9SDan McDonald new_flags &= ~DLS_PROMISC_PHYS;
694210db224Sericheng break;
695da14cebeSEric Cheng
696210db224Sericheng default:
697210db224Sericheng dl_err = DL_NOTSUPPORTED;
698*4962fb4cSDan McDonald goto failed2;
6997c478bd9Sstevel@tonic-gate }
7007c478bd9Sstevel@tonic-gate
701da14cebeSEric Cheng /*
702da14cebeSEric Cheng * Adjust channel promiscuity.
703da14cebeSEric Cheng */
704cabb4db9SDan McDonald err = dls_promisc(dsp, new_flags);
705d62bc4baSyz147064
706210db224Sericheng if (err != 0) {
707210db224Sericheng dl_err = DL_SYSERR;
708*4962fb4cSDan McDonald goto failed2;
709210db224Sericheng }
7105d460eafSCathy Zhou
711cabb4db9SDan McDonald ASSERT(dsp->ds_promisc == new_flags);
7125d460eafSCathy Zhou if (dsp->ds_promisc == 0)
7135d460eafSCathy Zhou dls_active_clear(dsp, B_FALSE);
7145d460eafSCathy Zhou
7155d460eafSCathy Zhou mac_perim_exit(mph);
7165d460eafSCathy Zhou
717210db224Sericheng dlokack(q, mp, DL_PROMISCOFF_REQ);
718da14cebeSEric Cheng return;
719*4962fb4cSDan McDonald failed2:
720*4962fb4cSDan McDonald mac_perim_exit(mph);
7217c478bd9Sstevel@tonic-gate failed:
722210db224Sericheng dlerrorack(q, mp, DL_PROMISCOFF_REQ, dl_err, (t_uscalar_t)err);
7237c478bd9Sstevel@tonic-gate }
7247c478bd9Sstevel@tonic-gate
7257c478bd9Sstevel@tonic-gate /*
726210db224Sericheng * DL_ENABMULTI_REQ
7277c478bd9Sstevel@tonic-gate */
728da14cebeSEric Cheng static void
proto_enabmulti_req(dld_str_t * dsp,mblk_t * mp)729da14cebeSEric Cheng proto_enabmulti_req(dld_str_t *dsp, mblk_t *mp)
7307c478bd9Sstevel@tonic-gate {
731da14cebeSEric Cheng dl_enabmulti_req_t *dlp = (dl_enabmulti_req_t *)mp->b_rptr;
732210db224Sericheng int err = 0;
733210db224Sericheng t_uscalar_t dl_err;
734210db224Sericheng queue_t *q = dsp->ds_wq;
735da14cebeSEric Cheng mac_perim_handle_t mph;
7367c478bd9Sstevel@tonic-gate
737210db224Sericheng if (dsp->ds_dlstate == DL_UNATTACHED ||
738210db224Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) {
739210db224Sericheng dl_err = DL_OUTSTATE;
7407c478bd9Sstevel@tonic-gate goto failed;
741210db224Sericheng }
7427c478bd9Sstevel@tonic-gate
743210db224Sericheng if (MBLKL(mp) < sizeof (dl_enabmulti_req_t) ||
744210db224Sericheng !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) ||
745210db224Sericheng dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) {
746210db224Sericheng dl_err = DL_BADPRIM;
747210db224Sericheng goto failed;
748210db224Sericheng }
7497c478bd9Sstevel@tonic-gate
750da14cebeSEric Cheng mac_perim_enter_by_mh(dsp->ds_mh, &mph);
751da14cebeSEric Cheng
7525d460eafSCathy Zhou if ((dsp->ds_dmap == NULL) && (err = dls_active_set(dsp)) != 0) {
753210db224Sericheng dl_err = DL_SYSERR;
754da14cebeSEric Cheng goto failed2;
755210db224Sericheng }
756210db224Sericheng
757da14cebeSEric Cheng err = dls_multicst_add(dsp, mp->b_rptr + dlp->dl_addr_offset);
758210db224Sericheng if (err != 0) {
7597c478bd9Sstevel@tonic-gate switch (err) {
7607c478bd9Sstevel@tonic-gate case EINVAL:
7617c478bd9Sstevel@tonic-gate dl_err = DL_BADADDR;
7627c478bd9Sstevel@tonic-gate err = 0;
7637c478bd9Sstevel@tonic-gate break;
7647c478bd9Sstevel@tonic-gate case ENOSPC:
7657c478bd9Sstevel@tonic-gate dl_err = DL_TOOMANY;
7667c478bd9Sstevel@tonic-gate err = 0;
7677c478bd9Sstevel@tonic-gate break;
7687c478bd9Sstevel@tonic-gate default:
7697c478bd9Sstevel@tonic-gate dl_err = DL_SYSERR;
7707c478bd9Sstevel@tonic-gate break;
7717c478bd9Sstevel@tonic-gate }
7725d460eafSCathy Zhou if (dsp->ds_dmap == NULL)
7735d460eafSCathy Zhou dls_active_clear(dsp, B_FALSE);
774da14cebeSEric Cheng goto failed2;
775210db224Sericheng }
776210db224Sericheng
777da14cebeSEric Cheng mac_perim_exit(mph);
778da14cebeSEric Cheng
779210db224Sericheng dlokack(q, mp, DL_ENABMULTI_REQ);
780da14cebeSEric Cheng return;
781da14cebeSEric Cheng
782da14cebeSEric Cheng failed2:
783da14cebeSEric Cheng mac_perim_exit(mph);
784210db224Sericheng failed:
785210db224Sericheng dlerrorack(q, mp, DL_ENABMULTI_REQ, dl_err, (t_uscalar_t)err);
7867c478bd9Sstevel@tonic-gate }
7877c478bd9Sstevel@tonic-gate
7887c478bd9Sstevel@tonic-gate /*
789210db224Sericheng * DL_DISABMULTI_REQ
7907c478bd9Sstevel@tonic-gate */
791da14cebeSEric Cheng static void
proto_disabmulti_req(dld_str_t * dsp,mblk_t * mp)792da14cebeSEric Cheng proto_disabmulti_req(dld_str_t *dsp, mblk_t *mp)
7937c478bd9Sstevel@tonic-gate {
794da14cebeSEric Cheng dl_disabmulti_req_t *dlp = (dl_disabmulti_req_t *)mp->b_rptr;
795210db224Sericheng int err = 0;
796210db224Sericheng t_uscalar_t dl_err;
797210db224Sericheng queue_t *q = dsp->ds_wq;
798da14cebeSEric Cheng mac_perim_handle_t mph;
7997c478bd9Sstevel@tonic-gate
800210db224Sericheng if (dsp->ds_dlstate == DL_UNATTACHED ||
801210db224Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) {
802210db224Sericheng dl_err = DL_OUTSTATE;
8037c478bd9Sstevel@tonic-gate goto failed;
804210db224Sericheng }
8057c478bd9Sstevel@tonic-gate
806210db224Sericheng if (MBLKL(mp) < sizeof (dl_disabmulti_req_t) ||
807210db224Sericheng !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) ||
808210db224Sericheng dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) {
809210db224Sericheng dl_err = DL_BADPRIM;
810210db224Sericheng goto failed;
811210db224Sericheng }
8127c478bd9Sstevel@tonic-gate
813da14cebeSEric Cheng mac_perim_enter_by_mh(dsp->ds_mh, &mph);
814da14cebeSEric Cheng err = dls_multicst_remove(dsp, mp->b_rptr + dlp->dl_addr_offset);
8155d460eafSCathy Zhou if ((err == 0) && (dsp->ds_dmap == NULL))
8165d460eafSCathy Zhou dls_active_clear(dsp, B_FALSE);
817da14cebeSEric Cheng mac_perim_exit(mph);
818da14cebeSEric Cheng
819210db224Sericheng if (err != 0) {
8207c478bd9Sstevel@tonic-gate switch (err) {
8217c478bd9Sstevel@tonic-gate case EINVAL:
8227c478bd9Sstevel@tonic-gate dl_err = DL_BADADDR;
8237c478bd9Sstevel@tonic-gate err = 0;
8247c478bd9Sstevel@tonic-gate break;
825da14cebeSEric Cheng
8267c478bd9Sstevel@tonic-gate case ENOENT:
8277c478bd9Sstevel@tonic-gate dl_err = DL_NOTENAB;
8287c478bd9Sstevel@tonic-gate err = 0;
8297c478bd9Sstevel@tonic-gate break;
830da14cebeSEric Cheng
8317c478bd9Sstevel@tonic-gate default:
8327c478bd9Sstevel@tonic-gate dl_err = DL_SYSERR;
8337c478bd9Sstevel@tonic-gate break;
8347c478bd9Sstevel@tonic-gate }
835210db224Sericheng goto failed;
836210db224Sericheng }
837210db224Sericheng dlokack(q, mp, DL_DISABMULTI_REQ);
838da14cebeSEric Cheng return;
839210db224Sericheng failed:
840210db224Sericheng dlerrorack(q, mp, DL_DISABMULTI_REQ, dl_err, (t_uscalar_t)err);
8417c478bd9Sstevel@tonic-gate }
8427c478bd9Sstevel@tonic-gate
8437c478bd9Sstevel@tonic-gate /*
844210db224Sericheng * DL_PHYS_ADDR_REQ
8457c478bd9Sstevel@tonic-gate */
846da14cebeSEric Cheng static void
proto_physaddr_req(dld_str_t * dsp,mblk_t * mp)847da14cebeSEric Cheng proto_physaddr_req(dld_str_t *dsp, mblk_t *mp)
8487c478bd9Sstevel@tonic-gate {
849da14cebeSEric Cheng dl_phys_addr_req_t *dlp = (dl_phys_addr_req_t *)mp->b_rptr;
850210db224Sericheng queue_t *q = dsp->ds_wq;
8512b24ab6bSSebastien Roy t_uscalar_t dl_err = 0;
8522b24ab6bSSebastien Roy char *addr = NULL;
8537c478bd9Sstevel@tonic-gate uint_t addr_length;
8547c478bd9Sstevel@tonic-gate
855210db224Sericheng if (MBLKL(mp) < sizeof (dl_phys_addr_req_t)) {
856210db224Sericheng dl_err = DL_BADPRIM;
8572b24ab6bSSebastien Roy goto done;
858210db224Sericheng }
859210db224Sericheng
860210db224Sericheng if (dsp->ds_dlstate == DL_UNATTACHED ||
861210db224Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) {
862210db224Sericheng dl_err = DL_OUTSTATE;
8632b24ab6bSSebastien Roy goto done;
864210db224Sericheng }
865210db224Sericheng
8667c478bd9Sstevel@tonic-gate addr_length = dsp->ds_mip->mi_addr_length;
867c08e5e1aSdr146992 if (addr_length > 0) {
868da14cebeSEric Cheng addr = kmem_alloc(addr_length, KM_SLEEP);
8692b24ab6bSSebastien Roy switch (dlp->dl_addr_type) {
8702b24ab6bSSebastien Roy case DL_CURR_PHYS_ADDR:
871da14cebeSEric Cheng mac_unicast_primary_get(dsp->ds_mh, (uint8_t *)addr);
8722b24ab6bSSebastien Roy break;
8732b24ab6bSSebastien Roy case DL_FACT_PHYS_ADDR:
874da14cebeSEric Cheng bcopy(dsp->ds_mip->mi_unicst_addr, addr, addr_length);
8752b24ab6bSSebastien Roy break;
8762b24ab6bSSebastien Roy case DL_CURR_DEST_ADDR:
8772b24ab6bSSebastien Roy if (!mac_dst_get(dsp->ds_mh, (uint8_t *)addr))
8782b24ab6bSSebastien Roy dl_err = DL_NOTSUPPORTED;
8792b24ab6bSSebastien Roy break;
8802b24ab6bSSebastien Roy default:
8812b24ab6bSSebastien Roy dl_err = DL_UNSUPPORTED;
882c08e5e1aSdr146992 }
8832b24ab6bSSebastien Roy }
8842b24ab6bSSebastien Roy done:
8852b24ab6bSSebastien Roy if (dl_err == 0)
8862b24ab6bSSebastien Roy dlphysaddrack(q, mp, addr, (t_uscalar_t)addr_length);
8872b24ab6bSSebastien Roy else
888210db224Sericheng dlerrorack(q, mp, DL_PHYS_ADDR_REQ, dl_err, 0);
8892b24ab6bSSebastien Roy if (addr != NULL)
8902b24ab6bSSebastien Roy kmem_free(addr, addr_length);
891210db224Sericheng }
892210db224Sericheng
893210db224Sericheng /*
894210db224Sericheng * DL_SET_PHYS_ADDR_REQ
895210db224Sericheng */
896da14cebeSEric Cheng static void
proto_setphysaddr_req(dld_str_t * dsp,mblk_t * mp)897da14cebeSEric Cheng proto_setphysaddr_req(dld_str_t *dsp, mblk_t *mp)
898210db224Sericheng {
899da14cebeSEric Cheng dl_set_phys_addr_req_t *dlp = (dl_set_phys_addr_req_t *)mp->b_rptr;
900210db224Sericheng int err = 0;
901210db224Sericheng t_uscalar_t dl_err;
902210db224Sericheng queue_t *q = dsp->ds_wq;
903da14cebeSEric Cheng mac_perim_handle_t mph;
904210db224Sericheng
905210db224Sericheng if (dsp->ds_dlstate == DL_UNATTACHED ||
906210db224Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) {
907210db224Sericheng dl_err = DL_OUTSTATE;
908210db224Sericheng goto failed;
909210db224Sericheng }
910210db224Sericheng
911210db224Sericheng if (MBLKL(mp) < sizeof (dl_set_phys_addr_req_t) ||
912210db224Sericheng !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) ||
913210db224Sericheng dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) {
914210db224Sericheng dl_err = DL_BADPRIM;
915210db224Sericheng goto failed;
916210db224Sericheng }
917210db224Sericheng
918da14cebeSEric Cheng mac_perim_enter_by_mh(dsp->ds_mh, &mph);
919da14cebeSEric Cheng
9205d460eafSCathy Zhou if ((err = dls_active_set(dsp)) != 0) {
921210db224Sericheng dl_err = DL_SYSERR;
922da14cebeSEric Cheng goto failed2;
923210db224Sericheng }
924210db224Sericheng
92525ec3e3dSEric Cheng /*
92625ec3e3dSEric Cheng * If mac-nospoof is enabled and the link is owned by a
92725ec3e3dSEric Cheng * non-global zone, changing the mac address is not allowed.
92825ec3e3dSEric Cheng */
92925ec3e3dSEric Cheng if (dsp->ds_dlp->dl_zid != GLOBAL_ZONEID &&
93025ec3e3dSEric Cheng mac_protect_enabled(dsp->ds_mch, MPT_MACNOSPOOF)) {
93125ec3e3dSEric Cheng dls_active_clear(dsp, B_FALSE);
93225ec3e3dSEric Cheng err = EACCES;
93325ec3e3dSEric Cheng goto failed2;
93425ec3e3dSEric Cheng }
93525ec3e3dSEric Cheng
936da14cebeSEric Cheng err = mac_unicast_primary_set(dsp->ds_mh,
937da14cebeSEric Cheng mp->b_rptr + dlp->dl_addr_offset);
938210db224Sericheng if (err != 0) {
9397c478bd9Sstevel@tonic-gate switch (err) {
9407c478bd9Sstevel@tonic-gate case EINVAL:
9417c478bd9Sstevel@tonic-gate dl_err = DL_BADADDR;
9427c478bd9Sstevel@tonic-gate err = 0;
9437c478bd9Sstevel@tonic-gate break;
9447c478bd9Sstevel@tonic-gate
9457c478bd9Sstevel@tonic-gate default:
9467c478bd9Sstevel@tonic-gate dl_err = DL_SYSERR;
9477c478bd9Sstevel@tonic-gate break;
9487c478bd9Sstevel@tonic-gate }
9495d460eafSCathy Zhou dls_active_clear(dsp, B_FALSE);
950da14cebeSEric Cheng goto failed2;
951da14cebeSEric Cheng
952210db224Sericheng }
953d62bc4baSyz147064
954da14cebeSEric Cheng mac_perim_exit(mph);
955da14cebeSEric Cheng
956210db224Sericheng dlokack(q, mp, DL_SET_PHYS_ADDR_REQ);
957da14cebeSEric Cheng return;
958da14cebeSEric Cheng
959da14cebeSEric Cheng failed2:
960da14cebeSEric Cheng mac_perim_exit(mph);
961210db224Sericheng failed:
962210db224Sericheng dlerrorack(q, mp, DL_SET_PHYS_ADDR_REQ, dl_err, (t_uscalar_t)err);
9637c478bd9Sstevel@tonic-gate }
9647c478bd9Sstevel@tonic-gate
9657c478bd9Sstevel@tonic-gate /*
966210db224Sericheng * DL_UDQOS_REQ
9677c478bd9Sstevel@tonic-gate */
968da14cebeSEric Cheng static void
proto_udqos_req(dld_str_t * dsp,mblk_t * mp)969da14cebeSEric Cheng proto_udqos_req(dld_str_t *dsp, mblk_t *mp)
9707c478bd9Sstevel@tonic-gate {
971da14cebeSEric Cheng dl_udqos_req_t *dlp = (dl_udqos_req_t *)mp->b_rptr;
972210db224Sericheng dl_qos_cl_sel1_t *selp;
973210db224Sericheng int off, len;
974210db224Sericheng t_uscalar_t dl_err;
975210db224Sericheng queue_t *q = dsp->ds_wq;
976210db224Sericheng
977210db224Sericheng off = dlp->dl_qos_offset;
978210db224Sericheng len = dlp->dl_qos_length;
979210db224Sericheng
980210db224Sericheng if (MBLKL(mp) < sizeof (dl_udqos_req_t) || !MBLKIN(mp, off, len)) {
981210db224Sericheng dl_err = DL_BADPRIM;
982210db224Sericheng goto failed;
983210db224Sericheng }
984210db224Sericheng
985210db224Sericheng selp = (dl_qos_cl_sel1_t *)(mp->b_rptr + off);
986210db224Sericheng if (selp->dl_qos_type != DL_QOS_CL_SEL1) {
987210db224Sericheng dl_err = DL_BADQOSTYPE;
988210db224Sericheng goto failed;
989210db224Sericheng }
990210db224Sericheng
991605445d5Sdg199075 if (selp->dl_priority > (1 << VLAN_PRI_SIZE) - 1 ||
992210db224Sericheng selp->dl_priority < 0) {
993210db224Sericheng dl_err = DL_BADQOSPARAM;
994210db224Sericheng goto failed;
995210db224Sericheng }
996210db224Sericheng
997d62bc4baSyz147064 dsp->ds_pri = selp->dl_priority;
998210db224Sericheng dlokack(q, mp, DL_UDQOS_REQ);
999da14cebeSEric Cheng return;
1000210db224Sericheng failed:
1001210db224Sericheng dlerrorack(q, mp, DL_UDQOS_REQ, dl_err, 0);
1002210db224Sericheng }
1003210db224Sericheng
10044b46d1efSkrgopi static boolean_t
check_mod_above(queue_t * q,const char * mod)10058d4cf8d8S check_mod_above(queue_t *q, const char *mod)
10064b46d1efSkrgopi {
10074b46d1efSkrgopi queue_t *next_q;
10084b46d1efSkrgopi boolean_t ret = B_TRUE;
10094b46d1efSkrgopi
10104b46d1efSkrgopi claimstr(q);
10114b46d1efSkrgopi next_q = q->q_next;
10128d4cf8d8S if (strcmp(next_q->q_qinfo->qi_minfo->mi_idname, mod) != 0)
10134b46d1efSkrgopi ret = B_FALSE;
10144b46d1efSkrgopi releasestr(q);
10154b46d1efSkrgopi return (ret);
10164b46d1efSkrgopi }
10174b46d1efSkrgopi
1018210db224Sericheng /*
1019210db224Sericheng * DL_CAPABILITY_REQ
1020210db224Sericheng */
1021da14cebeSEric Cheng static void
proto_capability_req(dld_str_t * dsp,mblk_t * mp)1022da14cebeSEric Cheng proto_capability_req(dld_str_t *dsp, mblk_t *mp)
1023210db224Sericheng {
1024da14cebeSEric Cheng dl_capability_req_t *dlp = (dl_capability_req_t *)mp->b_rptr;
1025210db224Sericheng dl_capability_sub_t *sp;
1026210db224Sericheng size_t size, len;
1027210db224Sericheng offset_t off, end;
1028210db224Sericheng t_uscalar_t dl_err;
1029210db224Sericheng queue_t *q = dsp->ds_wq;
1030210db224Sericheng
1031210db224Sericheng if (MBLKL(mp) < sizeof (dl_capability_req_t)) {
1032210db224Sericheng dl_err = DL_BADPRIM;
1033210db224Sericheng goto failed;
1034210db224Sericheng }
1035210db224Sericheng
1036210db224Sericheng if (dsp->ds_dlstate == DL_UNATTACHED ||
1037210db224Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) {
1038210db224Sericheng dl_err = DL_OUTSTATE;
1039210db224Sericheng goto failed;
1040210db224Sericheng }
1041210db224Sericheng
1042210db224Sericheng /*
1043210db224Sericheng * This request is overloaded. If there are no requested capabilities
1044210db224Sericheng * then we just want to acknowledge with all the capabilities we
1045210db224Sericheng * support. Otherwise we enable the set of capabilities requested.
1046210db224Sericheng */
1047210db224Sericheng if (dlp->dl_sub_length == 0) {
1048da14cebeSEric Cheng proto_capability_advertise(dsp, mp);
1049da14cebeSEric Cheng return;
1050210db224Sericheng }
1051210db224Sericheng
1052210db224Sericheng if (!MBLKIN(mp, dlp->dl_sub_offset, dlp->dl_sub_length)) {
1053210db224Sericheng dl_err = DL_BADPRIM;
1054210db224Sericheng goto failed;
1055210db224Sericheng }
1056210db224Sericheng
1057210db224Sericheng dlp->dl_primitive = DL_CAPABILITY_ACK;
1058210db224Sericheng
1059210db224Sericheng off = dlp->dl_sub_offset;
1060210db224Sericheng len = dlp->dl_sub_length;
1061210db224Sericheng
1062210db224Sericheng /*
1063210db224Sericheng * Walk the list of capabilities to be enabled.
1064210db224Sericheng */
1065210db224Sericheng for (end = off + len; off < end; ) {
1066210db224Sericheng sp = (dl_capability_sub_t *)(mp->b_rptr + off);
1067210db224Sericheng size = sizeof (dl_capability_sub_t) + sp->dl_length;
1068210db224Sericheng
1069210db224Sericheng if (off + size > end ||
1070210db224Sericheng !IS_P2ALIGNED(off, sizeof (uint32_t))) {
1071210db224Sericheng dl_err = DL_BADPRIM;
1072210db224Sericheng goto failed;
1073210db224Sericheng }
1074210db224Sericheng
1075210db224Sericheng switch (sp->dl_cap) {
1076210db224Sericheng /*
1077210db224Sericheng * TCP/IP checksum offload to hardware.
1078210db224Sericheng */
1079210db224Sericheng case DL_CAPAB_HCKSUM: {
1080210db224Sericheng dl_capab_hcksum_t *hcksump;
1081210db224Sericheng dl_capab_hcksum_t hcksum;
1082210db224Sericheng
1083210db224Sericheng hcksump = (dl_capab_hcksum_t *)&sp[1];
1084210db224Sericheng /*
1085210db224Sericheng * Copy for alignment.
1086210db224Sericheng */
1087210db224Sericheng bcopy(hcksump, &hcksum, sizeof (dl_capab_hcksum_t));
1088210db224Sericheng dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq);
1089210db224Sericheng bcopy(&hcksum, hcksump, sizeof (dl_capab_hcksum_t));
1090210db224Sericheng break;
1091210db224Sericheng }
1092210db224Sericheng
1093da14cebeSEric Cheng case DL_CAPAB_DLD: {
1094da14cebeSEric Cheng dl_capab_dld_t *dldp;
1095da14cebeSEric Cheng dl_capab_dld_t dld;
10968347601bSyl150051
1097da14cebeSEric Cheng dldp = (dl_capab_dld_t *)&sp[1];
10988347601bSyl150051 /*
10998347601bSyl150051 * Copy for alignment.
11008347601bSyl150051 */
1101da14cebeSEric Cheng bcopy(dldp, &dld, sizeof (dl_capab_dld_t));
1102da14cebeSEric Cheng dlcapabsetqid(&(dld.dld_mid), dsp->ds_rq);
1103da14cebeSEric Cheng bcopy(&dld, dldp, sizeof (dl_capab_dld_t));
1104210db224Sericheng break;
1105210db224Sericheng }
1106210db224Sericheng default:
1107210db224Sericheng break;
1108210db224Sericheng }
1109210db224Sericheng off += size;
1110210db224Sericheng }
1111210db224Sericheng qreply(q, mp);
1112da14cebeSEric Cheng return;
1113210db224Sericheng failed:
1114210db224Sericheng dlerrorack(q, mp, DL_CAPABILITY_REQ, dl_err, 0);
1115210db224Sericheng }
1116210db224Sericheng
1117210db224Sericheng /*
1118210db224Sericheng * DL_NOTIFY_REQ
1119210db224Sericheng */
1120da14cebeSEric Cheng static void
proto_notify_req(dld_str_t * dsp,mblk_t * mp)1121da14cebeSEric Cheng proto_notify_req(dld_str_t *dsp, mblk_t *mp)
1122210db224Sericheng {
1123da14cebeSEric Cheng dl_notify_req_t *dlp = (dl_notify_req_t *)mp->b_rptr;
1124210db224Sericheng t_uscalar_t dl_err;
1125210db224Sericheng queue_t *q = dsp->ds_wq;
1126210db224Sericheng uint_t note =
1127210db224Sericheng DL_NOTE_PROMISC_ON_PHYS |
1128210db224Sericheng DL_NOTE_PROMISC_OFF_PHYS |
1129210db224Sericheng DL_NOTE_PHYS_ADDR |
1130210db224Sericheng DL_NOTE_LINK_UP |
1131210db224Sericheng DL_NOTE_LINK_DOWN |
1132ba2e4443Sseb DL_NOTE_CAPAB_RENEG |
1133cef310fdSGirish Moodalbail DL_NOTE_FASTPATH_FLUSH |
11342b24ab6bSSebastien Roy DL_NOTE_SPEED |
1135550b6e40SSowmini Varadhan DL_NOTE_SDU_SIZE|
11361eee170aSErik Nordmark DL_NOTE_SDU_SIZE2|
1137550b6e40SSowmini Varadhan DL_NOTE_ALLOWED_IPS;
1138210db224Sericheng
1139210db224Sericheng if (MBLKL(mp) < sizeof (dl_notify_req_t)) {
1140210db224Sericheng dl_err = DL_BADPRIM;
1141210db224Sericheng goto failed;
1142210db224Sericheng }
1143210db224Sericheng
1144210db224Sericheng if (dsp->ds_dlstate == DL_UNATTACHED ||
1145210db224Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) {
1146210db224Sericheng dl_err = DL_OUTSTATE;
1147210db224Sericheng goto failed;
1148210db224Sericheng }
1149210db224Sericheng
1150d62bc4baSyz147064 note &= ~(mac_no_notification(dsp->ds_mh));
1151d62bc4baSyz147064
1152210db224Sericheng /*
1153210db224Sericheng * Cache the notifications that are being enabled.
1154210db224Sericheng */
1155210db224Sericheng dsp->ds_notifications = dlp->dl_notifications & note;
1156210db224Sericheng /*
1157210db224Sericheng * The ACK carries all notifications regardless of which set is
1158210db224Sericheng * being enabled.
1159210db224Sericheng */
1160210db224Sericheng dlnotifyack(q, mp, note);
1161210db224Sericheng
1162210db224Sericheng /*
1163da14cebeSEric Cheng * Generate DL_NOTIFY_IND messages for each enabled notification.
1164210db224Sericheng */
1165210db224Sericheng if (dsp->ds_notifications != 0) {
1166210db224Sericheng dld_str_notify_ind(dsp);
1167210db224Sericheng }
1168da14cebeSEric Cheng return;
1169210db224Sericheng failed:
1170210db224Sericheng dlerrorack(q, mp, DL_NOTIFY_REQ, dl_err, 0);
1171210db224Sericheng }
1172210db224Sericheng
1173210db224Sericheng /*
1174da14cebeSEric Cheng * DL_UINTDATA_REQ
1175210db224Sericheng */
1176d62bc4baSyz147064 void
proto_unitdata_req(dld_str_t * dsp,mblk_t * mp)1177da14cebeSEric Cheng proto_unitdata_req(dld_str_t *dsp, mblk_t *mp)
1178210db224Sericheng {
1179210db224Sericheng queue_t *q = dsp->ds_wq;
1180d62bc4baSyz147064 dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr;
1181210db224Sericheng off_t off;
1182210db224Sericheng size_t len, size;
1183210db224Sericheng const uint8_t *addr;
1184210db224Sericheng uint16_t sap;
1185210db224Sericheng uint_t addr_length;
1186ba2e4443Sseb mblk_t *bp, *payload;
1187210db224Sericheng uint32_t start, stuff, end, value, flags;
1188210db224Sericheng t_uscalar_t dl_err;
1189e7801d59Ssowmini uint_t max_sdu;
1190210db224Sericheng
1191210db224Sericheng if (MBLKL(mp) < sizeof (dl_unitdata_req_t) || mp->b_cont == NULL) {
1192da14cebeSEric Cheng dlerrorack(q, mp, DL_UNITDATA_REQ, DL_BADPRIM, 0);
1193da14cebeSEric Cheng return;
1194210db224Sericheng }
1195210db224Sericheng
1196da14cebeSEric Cheng mutex_enter(&dsp->ds_lock);
1197da14cebeSEric Cheng if (dsp->ds_dlstate != DL_IDLE) {
1198da14cebeSEric Cheng mutex_exit(&dsp->ds_lock);
1199da14cebeSEric Cheng dlerrorack(q, mp, DL_UNITDATA_REQ, DL_OUTSTATE, 0);
1200da14cebeSEric Cheng return;
1201da14cebeSEric Cheng }
1202da14cebeSEric Cheng DLD_DATATHR_INC(dsp);
1203da14cebeSEric Cheng mutex_exit(&dsp->ds_lock);
1204da14cebeSEric Cheng
1205210db224Sericheng addr_length = dsp->ds_mip->mi_addr_length;
1206210db224Sericheng
1207210db224Sericheng off = dlp->dl_dest_addr_offset;
1208210db224Sericheng len = dlp->dl_dest_addr_length;
1209210db224Sericheng
1210210db224Sericheng if (!MBLKIN(mp, off, len) || !IS_P2ALIGNED(off, sizeof (uint16_t))) {
1211210db224Sericheng dl_err = DL_BADPRIM;
1212210db224Sericheng goto failed;
1213210db224Sericheng }
1214210db224Sericheng
1215210db224Sericheng if (len != addr_length + sizeof (uint16_t)) {
1216210db224Sericheng dl_err = DL_BADADDR;
1217210db224Sericheng goto failed;
1218210db224Sericheng }
1219210db224Sericheng
1220210db224Sericheng addr = mp->b_rptr + off;
1221210db224Sericheng sap = *(uint16_t *)(mp->b_rptr + off + addr_length);
1222210db224Sericheng
1223210db224Sericheng /*
1224210db224Sericheng * Check the length of the packet and the block types.
1225210db224Sericheng */
1226210db224Sericheng size = 0;
1227ba2e4443Sseb payload = mp->b_cont;
1228ba2e4443Sseb for (bp = payload; bp != NULL; bp = bp->b_cont) {
1229210db224Sericheng if (DB_TYPE(bp) != M_DATA)
1230210db224Sericheng goto baddata;
1231210db224Sericheng
1232210db224Sericheng size += MBLKL(bp);
1233210db224Sericheng }
1234210db224Sericheng
1235e7801d59Ssowmini mac_sdu_get(dsp->ds_mh, NULL, &max_sdu);
1236e7801d59Ssowmini if (size > max_sdu)
1237210db224Sericheng goto baddata;
1238210db224Sericheng
1239210db224Sericheng /*
1240210db224Sericheng * Build a packet header.
1241210db224Sericheng */
1242da14cebeSEric Cheng if ((bp = dls_header(dsp, addr, sap, dlp->dl_priority.dl_max,
1243605445d5Sdg199075 &payload)) == NULL) {
1244210db224Sericheng dl_err = DL_BADADDR;
1245210db224Sericheng goto failed;
1246210db224Sericheng }
1247210db224Sericheng
1248210db224Sericheng /*
1249210db224Sericheng * We no longer need the M_PROTO header, so free it.
1250210db224Sericheng */
1251210db224Sericheng freeb(mp);
1252210db224Sericheng
1253210db224Sericheng /*
1254210db224Sericheng * Transfer the checksum offload information if it is present.
1255210db224Sericheng */
1256ba2e4443Sseb hcksum_retrieve(payload, NULL, NULL, &start, &stuff, &end, &value,
1257210db224Sericheng &flags);
1258ba2e4443Sseb (void) hcksum_assoc(bp, NULL, NULL, start, stuff, end, value, flags, 0);
1259210db224Sericheng
1260210db224Sericheng /*
1261210db224Sericheng * Link the payload onto the new header.
1262210db224Sericheng */
1263210db224Sericheng ASSERT(bp->b_cont == NULL);
1264ba2e4443Sseb bp->b_cont = payload;
1265da14cebeSEric Cheng
1266da14cebeSEric Cheng /*
1267da14cebeSEric Cheng * No lock can be held across modules and putnext()'s,
1268da14cebeSEric Cheng * which can happen here with the call from DLD_TX().
1269da14cebeSEric Cheng */
1270da14cebeSEric Cheng if (DLD_TX(dsp, bp, 0, 0) != NULL) {
1271da14cebeSEric Cheng /* flow-controlled */
1272da14cebeSEric Cheng DLD_SETQFULL(dsp);
1273da14cebeSEric Cheng }
1274da14cebeSEric Cheng DLD_DATATHR_DCR(dsp);
1275d62bc4baSyz147064 return;
1276da14cebeSEric Cheng
1277210db224Sericheng failed:
1278210db224Sericheng dlerrorack(q, mp, DL_UNITDATA_REQ, dl_err, 0);
1279da14cebeSEric Cheng DLD_DATATHR_DCR(dsp);
1280d62bc4baSyz147064 return;
1281210db224Sericheng
1282210db224Sericheng baddata:
1283210db224Sericheng dluderrorind(q, mp, (void *)addr, len, DL_BADDATA, 0);
1284da14cebeSEric Cheng DLD_DATATHR_DCR(dsp);
1285210db224Sericheng }
1286210db224Sericheng
1287210db224Sericheng /*
1288210db224Sericheng * DL_PASSIVE_REQ
1289210db224Sericheng */
1290da14cebeSEric Cheng static void
proto_passive_req(dld_str_t * dsp,mblk_t * mp)1291da14cebeSEric Cheng proto_passive_req(dld_str_t *dsp, mblk_t *mp)
1292210db224Sericheng {
1293210db224Sericheng t_uscalar_t dl_err;
1294210db224Sericheng
1295d62bc4baSyz147064 /*
1296210db224Sericheng * If we've already become active by issuing an active primitive,
1297210db224Sericheng * then it's too late to try to become passive.
1298210db224Sericheng */
1299210db224Sericheng if (dsp->ds_passivestate == DLD_ACTIVE) {
1300210db224Sericheng dl_err = DL_OUTSTATE;
1301210db224Sericheng goto failed;
1302210db224Sericheng }
1303210db224Sericheng
1304210db224Sericheng if (MBLKL(mp) < sizeof (dl_passive_req_t)) {
1305210db224Sericheng dl_err = DL_BADPRIM;
1306210db224Sericheng goto failed;
1307210db224Sericheng }
1308210db224Sericheng
1309210db224Sericheng dsp->ds_passivestate = DLD_PASSIVE;
1310210db224Sericheng dlokack(dsp->ds_wq, mp, DL_PASSIVE_REQ);
1311da14cebeSEric Cheng return;
1312210db224Sericheng failed:
1313210db224Sericheng dlerrorack(dsp->ds_wq, mp, DL_PASSIVE_REQ, dl_err, 0);
1314210db224Sericheng }
1315210db224Sericheng
1316da14cebeSEric Cheng
1317210db224Sericheng /*
1318210db224Sericheng * Catch-all handler.
1319210db224Sericheng */
1320da14cebeSEric Cheng static void
proto_req(dld_str_t * dsp,mblk_t * mp)1321da14cebeSEric Cheng proto_req(dld_str_t *dsp, mblk_t *mp)
1322210db224Sericheng {
1323da14cebeSEric Cheng union DL_primitives *dlp = (union DL_primitives *)mp->b_rptr;
1324da14cebeSEric Cheng
1325210db224Sericheng dlerrorack(dsp->ds_wq, mp, dlp->dl_primitive, DL_UNSUPPORTED, 0);
13267c478bd9Sstevel@tonic-gate }
13277c478bd9Sstevel@tonic-gate
1328da14cebeSEric Cheng static int
dld_capab_perim(dld_str_t * dsp,void * data,uint_t flags)1329da14cebeSEric Cheng dld_capab_perim(dld_str_t *dsp, void *data, uint_t flags)
13307c478bd9Sstevel@tonic-gate {
1331da14cebeSEric Cheng switch (flags) {
1332da14cebeSEric Cheng case DLD_ENABLE:
1333da14cebeSEric Cheng mac_perim_enter_by_mh(dsp->ds_mh, (mac_perim_handle_t *)data);
1334da14cebeSEric Cheng return (0);
13357c478bd9Sstevel@tonic-gate
1336da14cebeSEric Cheng case DLD_DISABLE:
1337da14cebeSEric Cheng mac_perim_exit((mac_perim_handle_t)data);
1338da14cebeSEric Cheng return (0);
1339210db224Sericheng
1340da14cebeSEric Cheng case DLD_QUERY:
1341da14cebeSEric Cheng return (mac_perim_held(dsp->ds_mh));
1342da14cebeSEric Cheng }
1343da14cebeSEric Cheng return (0);
13447c478bd9Sstevel@tonic-gate }
13457c478bd9Sstevel@tonic-gate
1346da14cebeSEric Cheng static int
dld_capab_direct(dld_str_t * dsp,void * data,uint_t flags)1347da14cebeSEric Cheng dld_capab_direct(dld_str_t *dsp, void *data, uint_t flags)
13487c478bd9Sstevel@tonic-gate {
1349da14cebeSEric Cheng dld_capab_direct_t *direct = data;
13507c478bd9Sstevel@tonic-gate
1351da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
1352da14cebeSEric Cheng
1353da14cebeSEric Cheng switch (flags) {
1354da14cebeSEric Cheng case DLD_ENABLE:
1355da14cebeSEric Cheng dls_rx_set(dsp, (dls_rx_t)direct->di_rx_cf,
1356da14cebeSEric Cheng direct->di_rx_ch);
1357ae6aa22aSVenugopal Iyer
1358da14cebeSEric Cheng direct->di_tx_df = (uintptr_t)str_mdata_fastpath_put;
1359da14cebeSEric Cheng direct->di_tx_dh = dsp;
1360da14cebeSEric Cheng direct->di_tx_cb_df = (uintptr_t)mac_client_tx_notify;
1361da14cebeSEric Cheng direct->di_tx_cb_dh = dsp->ds_mch;
1362ae6aa22aSVenugopal Iyer direct->di_tx_fctl_df = (uintptr_t)mac_tx_is_flow_blocked;
1363ae6aa22aSVenugopal Iyer direct->di_tx_fctl_dh = dsp->ds_mch;
1364ae6aa22aSVenugopal Iyer
1365da14cebeSEric Cheng dsp->ds_direct = B_TRUE;
1366da14cebeSEric Cheng
1367da14cebeSEric Cheng return (0);
1368da14cebeSEric Cheng
1369da14cebeSEric Cheng case DLD_DISABLE:
1370da14cebeSEric Cheng dls_rx_set(dsp, (dsp->ds_mode == DLD_FASTPATH) ?
1371da14cebeSEric Cheng dld_str_rx_fastpath : dld_str_rx_unitdata, (void *)dsp);
1372da14cebeSEric Cheng dsp->ds_direct = B_FALSE;
1373da14cebeSEric Cheng
1374da14cebeSEric Cheng return (0);
1375da14cebeSEric Cheng }
1376da14cebeSEric Cheng return (ENOTSUP);
1377da14cebeSEric Cheng }
13787c478bd9Sstevel@tonic-gate
13797c478bd9Sstevel@tonic-gate /*
1380da14cebeSEric Cheng * dld_capab_poll_enable()
1381da14cebeSEric Cheng *
1382da14cebeSEric Cheng * This function is misnamed. All polling and fanouts are run out of the
1383da14cebeSEric Cheng * lower mac (in case of VNIC and the only mac in case of NICs). The
1384da14cebeSEric Cheng * availability of Rx ring and promiscous mode is all taken care between
1385da14cebeSEric Cheng * the soft ring set (mac_srs), the Rx ring, and S/W classifier. Any
1386da14cebeSEric Cheng * fanout necessary is done by the soft rings that are part of the
1387da14cebeSEric Cheng * mac_srs (by default mac_srs sends the packets up via a TCP and
1388da14cebeSEric Cheng * non TCP soft ring).
1389da14cebeSEric Cheng *
1390da14cebeSEric Cheng * The mac_srs (or its associated soft rings) always store the ill_rx_ring
1391da14cebeSEric Cheng * (the cookie returned when they registered with IP during plumb) as their
1392da14cebeSEric Cheng * 2nd argument which is passed up as mac_resource_handle_t. The upcall
1393da14cebeSEric Cheng * function and 1st argument is what the caller registered when they
1394da14cebeSEric Cheng * called mac_rx_classify_flow_add() to register the flow. For VNIC,
1395da14cebeSEric Cheng * the function is vnic_rx and argument is vnic_t. For regular NIC
1396da14cebeSEric Cheng * case, it mac_rx_default and mac_handle_t. As explained above, the
1397da14cebeSEric Cheng * mac_srs (or its soft ring) will add the ill_rx_ring (mac_resource_handle_t)
1398da14cebeSEric Cheng * from its stored 2nd argument.
13997c478bd9Sstevel@tonic-gate */
1400da14cebeSEric Cheng static int
dld_capab_poll_enable(dld_str_t * dsp,dld_capab_poll_t * poll)1401da14cebeSEric Cheng dld_capab_poll_enable(dld_str_t *dsp, dld_capab_poll_t *poll)
1402da14cebeSEric Cheng {
1403da14cebeSEric Cheng if (dsp->ds_polling)
1404da14cebeSEric Cheng return (EINVAL);
14057c478bd9Sstevel@tonic-gate
1406da14cebeSEric Cheng if ((dld_opt & DLD_OPT_NO_POLL) != 0 || dsp->ds_mode == DLD_RAW)
1407da14cebeSEric Cheng return (ENOTSUP);
14087c478bd9Sstevel@tonic-gate
14097c478bd9Sstevel@tonic-gate /*
1410da14cebeSEric Cheng * Enable client polling if and only if DLS bypass is possible.
1411da14cebeSEric Cheng * Special cases like VLANs need DLS processing in the Rx data path.
1412da14cebeSEric Cheng * In such a case we can neither allow the client (IP) to directly
1413da14cebeSEric Cheng * poll the softring (since DLS processing hasn't been done) nor can
1414da14cebeSEric Cheng * we allow DLS bypass.
14157c478bd9Sstevel@tonic-gate */
1416da14cebeSEric Cheng if (!mac_rx_bypass_set(dsp->ds_mch, dsp->ds_rx, dsp->ds_rx_arg))
1417da14cebeSEric Cheng return (ENOTSUP);
14187c478bd9Sstevel@tonic-gate
14197c478bd9Sstevel@tonic-gate /*
1420da14cebeSEric Cheng * Register soft ring resources. This will come in handy later if
1421da14cebeSEric Cheng * the user decides to modify CPU bindings to use more CPUs for the
1422da14cebeSEric Cheng * device in which case we will switch to fanout using soft rings.
14237c478bd9Sstevel@tonic-gate */
1424da14cebeSEric Cheng mac_resource_set_common(dsp->ds_mch,
1425da14cebeSEric Cheng (mac_resource_add_t)poll->poll_ring_add_cf,
1426da14cebeSEric Cheng (mac_resource_remove_t)poll->poll_ring_remove_cf,
1427da14cebeSEric Cheng (mac_resource_quiesce_t)poll->poll_ring_quiesce_cf,
1428da14cebeSEric Cheng (mac_resource_restart_t)poll->poll_ring_restart_cf,
1429da14cebeSEric Cheng (mac_resource_bind_t)poll->poll_ring_bind_cf,
1430da14cebeSEric Cheng poll->poll_ring_ch);
14317c478bd9Sstevel@tonic-gate
1432da14cebeSEric Cheng mac_client_poll_enable(dsp->ds_mch);
1433da14cebeSEric Cheng
14347c478bd9Sstevel@tonic-gate dsp->ds_polling = B_TRUE;
1435da14cebeSEric Cheng return (0);
14367c478bd9Sstevel@tonic-gate }
14377c478bd9Sstevel@tonic-gate
1438da14cebeSEric Cheng /* ARGSUSED */
1439da14cebeSEric Cheng static int
dld_capab_poll_disable(dld_str_t * dsp,dld_capab_poll_t * poll)1440da14cebeSEric Cheng dld_capab_poll_disable(dld_str_t *dsp, dld_capab_poll_t *poll)
14414b46d1efSkrgopi {
1442da14cebeSEric Cheng if (!dsp->ds_polling)
1443da14cebeSEric Cheng return (EINVAL);
14444b46d1efSkrgopi
1445da14cebeSEric Cheng mac_client_poll_disable(dsp->ds_mch);
1446da14cebeSEric Cheng mac_resource_set(dsp->ds_mch, NULL, NULL);
1447da14cebeSEric Cheng
1448da14cebeSEric Cheng dsp->ds_polling = B_FALSE;
1449da14cebeSEric Cheng return (0);
1450da14cebeSEric Cheng }
1451da14cebeSEric Cheng
1452da14cebeSEric Cheng static int
dld_capab_poll(dld_str_t * dsp,void * data,uint_t flags)1453da14cebeSEric Cheng dld_capab_poll(dld_str_t *dsp, void *data, uint_t flags)
1454da14cebeSEric Cheng {
1455da14cebeSEric Cheng dld_capab_poll_t *poll = data;
1456da14cebeSEric Cheng
1457da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
1458da14cebeSEric Cheng
1459da14cebeSEric Cheng switch (flags) {
1460da14cebeSEric Cheng case DLD_ENABLE:
1461da14cebeSEric Cheng return (dld_capab_poll_enable(dsp, poll));
1462da14cebeSEric Cheng case DLD_DISABLE:
1463da14cebeSEric Cheng return (dld_capab_poll_disable(dsp, poll));
1464da14cebeSEric Cheng }
1465da14cebeSEric Cheng return (ENOTSUP);
1466da14cebeSEric Cheng }
1467da14cebeSEric Cheng
1468da14cebeSEric Cheng static int
dld_capab_lso(dld_str_t * dsp,void * data,uint_t flags)1469da14cebeSEric Cheng dld_capab_lso(dld_str_t *dsp, void *data, uint_t flags)
1470da14cebeSEric Cheng {
1471da14cebeSEric Cheng dld_capab_lso_t *lso = data;
1472da14cebeSEric Cheng
1473da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
1474da14cebeSEric Cheng
1475da14cebeSEric Cheng switch (flags) {
1476da14cebeSEric Cheng case DLD_ENABLE: {
1477da14cebeSEric Cheng mac_capab_lso_t mac_lso;
14784b46d1efSkrgopi
14794b46d1efSkrgopi /*
1480da14cebeSEric Cheng * Check if LSO is supported on this MAC & enable LSO
1481da14cebeSEric Cheng * accordingly.
14824b46d1efSkrgopi */
1483da14cebeSEric Cheng if (mac_capab_get(dsp->ds_mh, MAC_CAPAB_LSO, &mac_lso)) {
1484da14cebeSEric Cheng lso->lso_max = mac_lso.lso_basic_tcp_ipv4.lso_max;
1485da14cebeSEric Cheng lso->lso_flags = 0;
1486da14cebeSEric Cheng /* translate the flag for mac clients */
1487da14cebeSEric Cheng if ((mac_lso.lso_flags & LSO_TX_BASIC_TCP_IPV4) != 0)
1488bd670b35SErik Nordmark lso->lso_flags |= DLD_LSO_BASIC_TCP_IPV4;
1489da14cebeSEric Cheng dsp->ds_lso = B_TRUE;
1490da14cebeSEric Cheng dsp->ds_lso_max = lso->lso_max;
1491da14cebeSEric Cheng } else {
1492da14cebeSEric Cheng dsp->ds_lso = B_FALSE;
1493da14cebeSEric Cheng dsp->ds_lso_max = 0;
1494da14cebeSEric Cheng return (ENOTSUP);
1495da14cebeSEric Cheng }
1496da14cebeSEric Cheng return (0);
1497da14cebeSEric Cheng }
1498da14cebeSEric Cheng case DLD_DISABLE: {
1499da14cebeSEric Cheng dsp->ds_lso = B_FALSE;
1500da14cebeSEric Cheng dsp->ds_lso_max = 0;
1501da14cebeSEric Cheng return (0);
1502da14cebeSEric Cheng }
1503da14cebeSEric Cheng }
1504da14cebeSEric Cheng return (ENOTSUP);
15054b46d1efSkrgopi }
15064b46d1efSkrgopi
1507da14cebeSEric Cheng static int
dld_capab(dld_str_t * dsp,uint_t type,void * data,uint_t flags)1508da14cebeSEric Cheng dld_capab(dld_str_t *dsp, uint_t type, void *data, uint_t flags)
15094b46d1efSkrgopi {
1510da14cebeSEric Cheng int err;
15114b46d1efSkrgopi
15124b46d1efSkrgopi /*
1513da14cebeSEric Cheng * Don't enable direct callback capabilities unless the caller is
1514da14cebeSEric Cheng * the IP client. When a module is inserted in a stream (_I_INSERT)
1515da14cebeSEric Cheng * the stack initiates capability disable, but due to races, the
1516da14cebeSEric Cheng * module insertion may complete before the capability disable
1517da14cebeSEric Cheng * completes. So we limit the check to DLD_ENABLE case.
15184b46d1efSkrgopi */
1519da14cebeSEric Cheng if ((flags == DLD_ENABLE && type != DLD_CAPAB_PERIM) &&
15208d4cf8d8S (dsp->ds_sap != ETHERTYPE_IP ||
15218d4cf8d8S !check_mod_above(dsp->ds_rq, "ip"))) {
1522da14cebeSEric Cheng return (ENOTSUP);
15234b46d1efSkrgopi }
15244b46d1efSkrgopi
1525da14cebeSEric Cheng switch (type) {
1526da14cebeSEric Cheng case DLD_CAPAB_DIRECT:
1527da14cebeSEric Cheng err = dld_capab_direct(dsp, data, flags);
1528da14cebeSEric Cheng break;
15294b46d1efSkrgopi
1530da14cebeSEric Cheng case DLD_CAPAB_POLL:
1531da14cebeSEric Cheng err = dld_capab_poll(dsp, data, flags);
1532da14cebeSEric Cheng break;
1533da14cebeSEric Cheng
1534da14cebeSEric Cheng case DLD_CAPAB_PERIM:
1535da14cebeSEric Cheng err = dld_capab_perim(dsp, data, flags);
1536da14cebeSEric Cheng break;
1537da14cebeSEric Cheng
1538da14cebeSEric Cheng case DLD_CAPAB_LSO:
1539da14cebeSEric Cheng err = dld_capab_lso(dsp, data, flags);
1540da14cebeSEric Cheng break;
1541da14cebeSEric Cheng
1542da14cebeSEric Cheng default:
1543da14cebeSEric Cheng err = ENOTSUP;
1544da14cebeSEric Cheng break;
15454b46d1efSkrgopi }
1546da14cebeSEric Cheng
1547da14cebeSEric Cheng return (err);
15484b46d1efSkrgopi }
15494b46d1efSkrgopi
15507c478bd9Sstevel@tonic-gate /*
15517c478bd9Sstevel@tonic-gate * DL_CAPABILITY_ACK/DL_ERROR_ACK
15527c478bd9Sstevel@tonic-gate */
1553da14cebeSEric Cheng static void
proto_capability_advertise(dld_str_t * dsp,mblk_t * mp)1554210db224Sericheng proto_capability_advertise(dld_str_t *dsp, mblk_t *mp)
15557c478bd9Sstevel@tonic-gate {
15567c478bd9Sstevel@tonic-gate dl_capability_ack_t *dlap;
15577c478bd9Sstevel@tonic-gate dl_capability_sub_t *dlsp;
15587c478bd9Sstevel@tonic-gate size_t subsize;
1559da14cebeSEric Cheng dl_capab_dld_t dld;
15607c478bd9Sstevel@tonic-gate dl_capab_hcksum_t hcksum;
15617c478bd9Sstevel@tonic-gate dl_capab_zerocopy_t zcopy;
15621cb875aeSCathy Zhou dl_capab_vrrp_t vrrp;
15631cb875aeSCathy Zhou mac_capab_vrrp_t vrrp_capab;
15647c478bd9Sstevel@tonic-gate uint8_t *ptr;
1565210db224Sericheng queue_t *q = dsp->ds_wq;
1566210db224Sericheng mblk_t *mp1;
1567d62bc4baSyz147064 boolean_t hcksum_capable = B_FALSE;
1568d62bc4baSyz147064 boolean_t zcopy_capable = B_FALSE;
1569da14cebeSEric Cheng boolean_t dld_capable = B_FALSE;
15701cb875aeSCathy Zhou boolean_t vrrp_capable = B_FALSE;
15717c478bd9Sstevel@tonic-gate
15727c478bd9Sstevel@tonic-gate /*
15737c478bd9Sstevel@tonic-gate * Initially assume no capabilities.
15747c478bd9Sstevel@tonic-gate */
15757c478bd9Sstevel@tonic-gate subsize = 0;
15767c478bd9Sstevel@tonic-gate
15777c478bd9Sstevel@tonic-gate /*
15789056fcebSCathy Zhou * Check if checksum offload is supported on this MAC.
15797c478bd9Sstevel@tonic-gate */
1580d62bc4baSyz147064 bzero(&hcksum, sizeof (dl_capab_hcksum_t));
15819056fcebSCathy Zhou if (mac_capab_get(dsp->ds_mh, MAC_CAPAB_HCKSUM,
1582ba2e4443Sseb &hcksum.hcksum_txflags)) {
1583d62bc4baSyz147064 if (hcksum.hcksum_txflags != 0) {
1584d62bc4baSyz147064 hcksum_capable = B_TRUE;
15857c478bd9Sstevel@tonic-gate subsize += sizeof (dl_capability_sub_t) +
15867c478bd9Sstevel@tonic-gate sizeof (dl_capab_hcksum_t);
15877c478bd9Sstevel@tonic-gate }
1588d62bc4baSyz147064 }
15897c478bd9Sstevel@tonic-gate
15907c478bd9Sstevel@tonic-gate /*
1591d62bc4baSyz147064 * Check if zerocopy is supported on this interface.
1592d62bc4baSyz147064 * If advertising DL_CAPAB_ZEROCOPY has not been explicitly disabled
1593d62bc4baSyz147064 * then reserve space for that capability.
15947c478bd9Sstevel@tonic-gate */
1595d62bc4baSyz147064 if (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_NO_ZCOPY, NULL) &&
1596d62bc4baSyz147064 !(dld_opt & DLD_OPT_NO_ZEROCOPY)) {
1597d62bc4baSyz147064 zcopy_capable = B_TRUE;
15987c478bd9Sstevel@tonic-gate subsize += sizeof (dl_capability_sub_t) +
15997c478bd9Sstevel@tonic-gate sizeof (dl_capab_zerocopy_t);
16007c478bd9Sstevel@tonic-gate }
16017c478bd9Sstevel@tonic-gate
16027c478bd9Sstevel@tonic-gate /*
1603da14cebeSEric Cheng * Direct capability negotiation interface between IP and DLD
1604da14cebeSEric Cheng */
16058d4cf8d8S if (dsp->ds_sap == ETHERTYPE_IP && check_mod_above(dsp->ds_rq, "ip")) {
1606da14cebeSEric Cheng dld_capable = B_TRUE;
1607da14cebeSEric Cheng subsize += sizeof (dl_capability_sub_t) +
1608da14cebeSEric Cheng sizeof (dl_capab_dld_t);
1609da14cebeSEric Cheng }
1610da14cebeSEric Cheng
1611da14cebeSEric Cheng /*
16121cb875aeSCathy Zhou * Check if vrrp is supported on this interface. If so, reserve
16131cb875aeSCathy Zhou * space for that capability.
16141cb875aeSCathy Zhou */
16151cb875aeSCathy Zhou if (mac_capab_get(dsp->ds_mh, MAC_CAPAB_VRRP, &vrrp_capab)) {
16161cb875aeSCathy Zhou vrrp_capable = B_TRUE;
16171cb875aeSCathy Zhou subsize += sizeof (dl_capability_sub_t) +
16181cb875aeSCathy Zhou sizeof (dl_capab_vrrp_t);
16191cb875aeSCathy Zhou }
16201cb875aeSCathy Zhou
16211cb875aeSCathy Zhou /*
1622210db224Sericheng * If there are no capabilities to advertise or if we
1623210db224Sericheng * can't allocate a response, send a DL_ERROR_ACK.
16247c478bd9Sstevel@tonic-gate */
16254b46d1efSkrgopi if ((mp1 = reallocb(mp,
1626210db224Sericheng sizeof (dl_capability_ack_t) + subsize, 0)) == NULL) {
1627210db224Sericheng dlerrorack(q, mp, DL_CAPABILITY_REQ, DL_NOTSUPPORTED, 0);
1628da14cebeSEric Cheng return;
16297c478bd9Sstevel@tonic-gate }
16307c478bd9Sstevel@tonic-gate
1631210db224Sericheng mp = mp1;
1632210db224Sericheng DB_TYPE(mp) = M_PROTO;
1633210db224Sericheng mp->b_wptr = mp->b_rptr + sizeof (dl_capability_ack_t) + subsize;
1634210db224Sericheng bzero(mp->b_rptr, MBLKL(mp));
16357c478bd9Sstevel@tonic-gate dlap = (dl_capability_ack_t *)mp->b_rptr;
16367c478bd9Sstevel@tonic-gate dlap->dl_primitive = DL_CAPABILITY_ACK;
16377c478bd9Sstevel@tonic-gate dlap->dl_sub_offset = sizeof (dl_capability_ack_t);
16387c478bd9Sstevel@tonic-gate dlap->dl_sub_length = subsize;
16397c478bd9Sstevel@tonic-gate ptr = (uint8_t *)&dlap[1];
16407c478bd9Sstevel@tonic-gate
16417c478bd9Sstevel@tonic-gate /*
16427c478bd9Sstevel@tonic-gate * TCP/IP checksum offload.
16437c478bd9Sstevel@tonic-gate */
1644d62bc4baSyz147064 if (hcksum_capable) {
16457c478bd9Sstevel@tonic-gate dlsp = (dl_capability_sub_t *)ptr;
16467c478bd9Sstevel@tonic-gate
16477c478bd9Sstevel@tonic-gate dlsp->dl_cap = DL_CAPAB_HCKSUM;
16487c478bd9Sstevel@tonic-gate dlsp->dl_length = sizeof (dl_capab_hcksum_t);
16497c478bd9Sstevel@tonic-gate ptr += sizeof (dl_capability_sub_t);
16507c478bd9Sstevel@tonic-gate
16517c478bd9Sstevel@tonic-gate hcksum.hcksum_version = HCKSUM_VERSION_1;
16527c478bd9Sstevel@tonic-gate dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq);
16537c478bd9Sstevel@tonic-gate bcopy(&hcksum, ptr, sizeof (dl_capab_hcksum_t));
16547c478bd9Sstevel@tonic-gate ptr += sizeof (dl_capab_hcksum_t);
16557c478bd9Sstevel@tonic-gate }
16567c478bd9Sstevel@tonic-gate
16577c478bd9Sstevel@tonic-gate /*
16587c478bd9Sstevel@tonic-gate * Zero copy
16597c478bd9Sstevel@tonic-gate */
1660d62bc4baSyz147064 if (zcopy_capable) {
16617c478bd9Sstevel@tonic-gate dlsp = (dl_capability_sub_t *)ptr;
16627c478bd9Sstevel@tonic-gate
16637c478bd9Sstevel@tonic-gate dlsp->dl_cap = DL_CAPAB_ZEROCOPY;
16647c478bd9Sstevel@tonic-gate dlsp->dl_length = sizeof (dl_capab_zerocopy_t);
16657c478bd9Sstevel@tonic-gate ptr += sizeof (dl_capability_sub_t);
16667c478bd9Sstevel@tonic-gate
16677c478bd9Sstevel@tonic-gate bzero(&zcopy, sizeof (dl_capab_zerocopy_t));
16687c478bd9Sstevel@tonic-gate zcopy.zerocopy_version = ZEROCOPY_VERSION_1;
16697c478bd9Sstevel@tonic-gate zcopy.zerocopy_flags = DL_CAPAB_VMSAFE_MEM;
16707c478bd9Sstevel@tonic-gate
16717c478bd9Sstevel@tonic-gate dlcapabsetqid(&(zcopy.zerocopy_mid), dsp->ds_rq);
16727c478bd9Sstevel@tonic-gate bcopy(&zcopy, ptr, sizeof (dl_capab_zerocopy_t));
16737c478bd9Sstevel@tonic-gate ptr += sizeof (dl_capab_zerocopy_t);
16747c478bd9Sstevel@tonic-gate }
16757c478bd9Sstevel@tonic-gate
1676da14cebeSEric Cheng /*
16771cb875aeSCathy Zhou * VRRP capability negotiation
16781cb875aeSCathy Zhou */
16791cb875aeSCathy Zhou if (vrrp_capable) {
16801cb875aeSCathy Zhou dlsp = (dl_capability_sub_t *)ptr;
16811cb875aeSCathy Zhou dlsp->dl_cap = DL_CAPAB_VRRP;
16821cb875aeSCathy Zhou dlsp->dl_length = sizeof (dl_capab_vrrp_t);
16831cb875aeSCathy Zhou ptr += sizeof (dl_capability_sub_t);
16841cb875aeSCathy Zhou
16851cb875aeSCathy Zhou bzero(&vrrp, sizeof (dl_capab_vrrp_t));
16861cb875aeSCathy Zhou vrrp.vrrp_af = vrrp_capab.mcv_af;
16871cb875aeSCathy Zhou bcopy(&vrrp, ptr, sizeof (dl_capab_vrrp_t));
16881cb875aeSCathy Zhou ptr += sizeof (dl_capab_vrrp_t);
16891cb875aeSCathy Zhou }
16901cb875aeSCathy Zhou
16911cb875aeSCathy Zhou /*
1692da14cebeSEric Cheng * Direct capability negotiation interface between IP and DLD.
1693da14cebeSEric Cheng * Refer to dld.h for details.
1694da14cebeSEric Cheng */
1695da14cebeSEric Cheng if (dld_capable) {
1696da14cebeSEric Cheng dlsp = (dl_capability_sub_t *)ptr;
1697da14cebeSEric Cheng dlsp->dl_cap = DL_CAPAB_DLD;
1698da14cebeSEric Cheng dlsp->dl_length = sizeof (dl_capab_dld_t);
1699da14cebeSEric Cheng ptr += sizeof (dl_capability_sub_t);
17007c478bd9Sstevel@tonic-gate
1701da14cebeSEric Cheng bzero(&dld, sizeof (dl_capab_dld_t));
1702da14cebeSEric Cheng dld.dld_version = DLD_CURRENT_VERSION;
1703da14cebeSEric Cheng dld.dld_capab = (uintptr_t)dld_capab;
1704da14cebeSEric Cheng dld.dld_capab_handle = (uintptr_t)dsp;
1705da14cebeSEric Cheng
1706da14cebeSEric Cheng dlcapabsetqid(&(dld.dld_mid), dsp->ds_rq);
1707da14cebeSEric Cheng bcopy(&dld, ptr, sizeof (dl_capab_dld_t));
1708da14cebeSEric Cheng ptr += sizeof (dl_capab_dld_t);
1709da14cebeSEric Cheng }
1710da14cebeSEric Cheng
1711da14cebeSEric Cheng ASSERT(ptr == mp->b_rptr + sizeof (dl_capability_ack_t) + subsize);
1712210db224Sericheng qreply(q, mp);
17138fb46f24Syz147064 }
17148fb46f24Syz147064
17158fb46f24Syz147064 /*
17168fb46f24Syz147064 * Disable any enabled capabilities.
17178fb46f24Syz147064 */
17188fb46f24Syz147064 void
dld_capabilities_disable(dld_str_t * dsp)17198fb46f24Syz147064 dld_capabilities_disable(dld_str_t *dsp)
17208fb46f24Syz147064 {
17218fb46f24Syz147064 if (dsp->ds_polling)
1722da14cebeSEric Cheng (void) dld_capab_poll_disable(dsp, NULL);
17237c478bd9Sstevel@tonic-gate }
1724