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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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