10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51502Sericheng * Common Development and Distribution License (the "License"). 61502Sericheng * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*5895Syz147064 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * Data-Link Driver 300Sstevel@tonic-gate */ 310Sstevel@tonic-gate 320Sstevel@tonic-gate #include <sys/types.h> 330Sstevel@tonic-gate #include <sys/debug.h> 340Sstevel@tonic-gate #include <sys/sysmacros.h> 350Sstevel@tonic-gate #include <sys/stream.h> 360Sstevel@tonic-gate #include <sys/ddi.h> 370Sstevel@tonic-gate #include <sys/sunddi.h> 380Sstevel@tonic-gate #include <sys/strsun.h> 391184Skrgopi #include <sys/cpuvar.h> 400Sstevel@tonic-gate #include <sys/dlpi.h> 410Sstevel@tonic-gate #include <netinet/in.h> 420Sstevel@tonic-gate #include <sys/sdt.h> 430Sstevel@tonic-gate #include <sys/strsubr.h> 440Sstevel@tonic-gate #include <sys/vlan.h> 450Sstevel@tonic-gate #include <sys/mac.h> 460Sstevel@tonic-gate #include <sys/dls.h> 470Sstevel@tonic-gate #include <sys/dld.h> 480Sstevel@tonic-gate #include <sys/dld_impl.h> 491184Skrgopi #include <sys/dls_soft_ring.h> 500Sstevel@tonic-gate 510Sstevel@tonic-gate typedef boolean_t proto_reqfunc_t(dld_str_t *, union DL_primitives *, mblk_t *); 520Sstevel@tonic-gate 530Sstevel@tonic-gate static proto_reqfunc_t proto_info_req, proto_attach_req, proto_detach_req, 540Sstevel@tonic-gate proto_bind_req, proto_unbind_req, proto_promiscon_req, proto_promiscoff_req, 550Sstevel@tonic-gate proto_enabmulti_req, proto_disabmulti_req, proto_physaddr_req, 560Sstevel@tonic-gate proto_setphysaddr_req, proto_udqos_req, proto_req, proto_capability_req, 57*5895Syz147064 proto_notify_req, proto_passive_req; 580Sstevel@tonic-gate 59269Sericheng static void proto_poll_disable(dld_str_t *); 601184Skrgopi static boolean_t proto_poll_enable(dld_str_t *, dl_capab_dls_t *); 611353Sericheng 621184Skrgopi static void proto_soft_ring_disable(dld_str_t *); 631184Skrgopi static boolean_t proto_soft_ring_enable(dld_str_t *, dl_capab_dls_t *); 641184Skrgopi static boolean_t proto_capability_advertise(dld_str_t *, mblk_t *); 651184Skrgopi static void proto_change_soft_ring_fanout(dld_str_t *, int); 661184Skrgopi 670Sstevel@tonic-gate #define DL_ACK_PENDING(state) \ 680Sstevel@tonic-gate ((state) == DL_ATTACH_PENDING || \ 690Sstevel@tonic-gate (state) == DL_DETACH_PENDING || \ 700Sstevel@tonic-gate (state) == DL_BIND_PENDING || \ 710Sstevel@tonic-gate (state) == DL_UNBIND_PENDING) 720Sstevel@tonic-gate 730Sstevel@tonic-gate /* 74269Sericheng * Process a DLPI protocol message. 75269Sericheng * The primitives DL_BIND_REQ, DL_ENABMULTI_REQ, DL_PROMISCON_REQ, 76269Sericheng * DL_SET_PHYS_ADDR_REQ put the data link below our dld_str_t into an 77269Sericheng * 'active' state. The primitive DL_PASSIVE_REQ marks our dld_str_t 78269Sericheng * as 'passive' and forbids it from being subsequently made 'active' 79269Sericheng * by the above primitives. 800Sstevel@tonic-gate */ 810Sstevel@tonic-gate void 82*5895Syz147064 dld_wput_proto_nondata(dld_str_t *dsp, mblk_t *mp) 830Sstevel@tonic-gate { 840Sstevel@tonic-gate union DL_primitives *udlp; 850Sstevel@tonic-gate t_uscalar_t prim; 860Sstevel@tonic-gate 87*5895Syz147064 ASSERT(MBLKL(mp) >= sizeof (t_uscalar_t)); 880Sstevel@tonic-gate 890Sstevel@tonic-gate udlp = (union DL_primitives *)mp->b_rptr; 900Sstevel@tonic-gate prim = udlp->dl_primitive; 910Sstevel@tonic-gate 92269Sericheng switch (prim) { 93269Sericheng case DL_INFO_REQ: 94269Sericheng (void) proto_info_req(dsp, udlp, mp); 95269Sericheng break; 96269Sericheng case DL_BIND_REQ: 97269Sericheng (void) proto_bind_req(dsp, udlp, mp); 98269Sericheng break; 99269Sericheng case DL_UNBIND_REQ: 100269Sericheng (void) proto_unbind_req(dsp, udlp, mp); 101269Sericheng break; 102269Sericheng case DL_UDQOS_REQ: 103269Sericheng (void) proto_udqos_req(dsp, udlp, mp); 104269Sericheng break; 105269Sericheng case DL_ATTACH_REQ: 106269Sericheng (void) proto_attach_req(dsp, udlp, mp); 107269Sericheng break; 108269Sericheng case DL_DETACH_REQ: 109269Sericheng (void) proto_detach_req(dsp, udlp, mp); 110269Sericheng break; 111269Sericheng case DL_ENABMULTI_REQ: 112269Sericheng (void) proto_enabmulti_req(dsp, udlp, mp); 113269Sericheng break; 114269Sericheng case DL_DISABMULTI_REQ: 115269Sericheng (void) proto_disabmulti_req(dsp, udlp, mp); 116269Sericheng break; 117269Sericheng case DL_PROMISCON_REQ: 118269Sericheng (void) proto_promiscon_req(dsp, udlp, mp); 119269Sericheng break; 120269Sericheng case DL_PROMISCOFF_REQ: 121269Sericheng (void) proto_promiscoff_req(dsp, udlp, mp); 122269Sericheng break; 123269Sericheng case DL_PHYS_ADDR_REQ: 124269Sericheng (void) proto_physaddr_req(dsp, udlp, mp); 125269Sericheng break; 126269Sericheng case DL_SET_PHYS_ADDR_REQ: 127269Sericheng (void) proto_setphysaddr_req(dsp, udlp, mp); 128269Sericheng break; 129269Sericheng case DL_NOTIFY_REQ: 130269Sericheng (void) proto_notify_req(dsp, udlp, mp); 131269Sericheng break; 132269Sericheng case DL_CAPABILITY_REQ: 133269Sericheng (void) proto_capability_req(dsp, udlp, mp); 134269Sericheng break; 135269Sericheng case DL_PASSIVE_REQ: 136269Sericheng (void) proto_passive_req(dsp, udlp, mp); 137269Sericheng break; 138269Sericheng default: 139269Sericheng (void) proto_req(dsp, udlp, mp); 140269Sericheng break; 1410Sstevel@tonic-gate } 1420Sstevel@tonic-gate } 1430Sstevel@tonic-gate 144269Sericheng #define NEG(x) -(x) 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate typedef struct dl_info_ack_wrapper { 1470Sstevel@tonic-gate dl_info_ack_t dl_info; 1482311Sseb uint8_t dl_addr[MAXMACADDRLEN + sizeof (uint16_t)]; 1492311Sseb uint8_t dl_brdcst_addr[MAXMACADDRLEN]; 1500Sstevel@tonic-gate dl_qos_cl_range1_t dl_qos_range1; 1510Sstevel@tonic-gate dl_qos_cl_sel1_t dl_qos_sel1; 1520Sstevel@tonic-gate } dl_info_ack_wrapper_t; 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate /* 155269Sericheng * DL_INFO_REQ 1560Sstevel@tonic-gate */ 157269Sericheng /*ARGSUSED*/ 158269Sericheng static boolean_t 159269Sericheng proto_info_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 1600Sstevel@tonic-gate { 1610Sstevel@tonic-gate dl_info_ack_wrapper_t *dlwp; 1620Sstevel@tonic-gate dl_info_ack_t *dlp; 1630Sstevel@tonic-gate dl_qos_cl_sel1_t *selp; 1640Sstevel@tonic-gate dl_qos_cl_range1_t *rangep; 1650Sstevel@tonic-gate uint8_t *addr; 1660Sstevel@tonic-gate uint8_t *brdcst_addr; 1670Sstevel@tonic-gate uint_t addr_length; 1680Sstevel@tonic-gate uint_t sap_length; 169269Sericheng mac_info_t minfo; 170269Sericheng mac_info_t *minfop; 171269Sericheng queue_t *q = dsp->ds_wq; 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate /* 1740Sstevel@tonic-gate * Swap the request message for one large enough to contain the 1750Sstevel@tonic-gate * wrapper structure defined above. 1760Sstevel@tonic-gate */ 177269Sericheng if ((mp = mexchange(q, mp, sizeof (dl_info_ack_wrapper_t), 1780Sstevel@tonic-gate M_PCPROTO, 0)) == NULL) 179269Sericheng return (B_FALSE); 180269Sericheng 181269Sericheng rw_enter(&dsp->ds_lock, RW_READER); 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate bzero(mp->b_rptr, sizeof (dl_info_ack_wrapper_t)); 1840Sstevel@tonic-gate dlwp = (dl_info_ack_wrapper_t *)mp->b_rptr; 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate dlp = &(dlwp->dl_info); 1870Sstevel@tonic-gate ASSERT(dlp == (dl_info_ack_t *)mp->b_rptr); 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate dlp->dl_primitive = DL_INFO_ACK; 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate /* 1920Sstevel@tonic-gate * Set up the sub-structure pointers. 1930Sstevel@tonic-gate */ 1940Sstevel@tonic-gate addr = dlwp->dl_addr; 1950Sstevel@tonic-gate brdcst_addr = dlwp->dl_brdcst_addr; 1960Sstevel@tonic-gate rangep = &(dlwp->dl_qos_range1); 1970Sstevel@tonic-gate selp = &(dlwp->dl_qos_sel1); 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate /* 2000Sstevel@tonic-gate * This driver supports only version 2 connectionless DLPI provider 2010Sstevel@tonic-gate * nodes. 2020Sstevel@tonic-gate */ 2030Sstevel@tonic-gate dlp->dl_service_mode = DL_CLDLS; 2040Sstevel@tonic-gate dlp->dl_version = DL_VERSION_2; 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate /* 207269Sericheng * Set the style of the provider 2080Sstevel@tonic-gate */ 209269Sericheng dlp->dl_provider_style = dsp->ds_style; 2100Sstevel@tonic-gate ASSERT(dlp->dl_provider_style == DL_STYLE1 || 2110Sstevel@tonic-gate dlp->dl_provider_style == DL_STYLE2); 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate /* 2140Sstevel@tonic-gate * Set the current DLPI state. 2150Sstevel@tonic-gate */ 2160Sstevel@tonic-gate dlp->dl_current_state = dsp->ds_dlstate; 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate /* 219269Sericheng * Gratuitously set the media type. This is to deal with modules 220269Sericheng * that assume the media type is known prior to DL_ATTACH_REQ 2210Sstevel@tonic-gate * being completed. 2220Sstevel@tonic-gate */ 2230Sstevel@tonic-gate dlp->dl_mac_type = DL_ETHER; 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate /* 226269Sericheng * If the stream is not at least attached we try to retrieve the 227269Sericheng * mac_info using mac_info_get() 2280Sstevel@tonic-gate */ 2290Sstevel@tonic-gate if (dsp->ds_dlstate == DL_UNATTACHED || 2300Sstevel@tonic-gate dsp->ds_dlstate == DL_ATTACH_PENDING || 231269Sericheng dsp->ds_dlstate == DL_DETACH_PENDING) { 232269Sericheng if (!mac_info_get(ddi_major_to_name(dsp->ds_major), &minfo)) { 233269Sericheng /* 234269Sericheng * Cannot find mac_info. giving up. 235269Sericheng */ 236269Sericheng goto done; 237269Sericheng } 238269Sericheng minfop = &minfo; 239269Sericheng } else { 240269Sericheng minfop = (mac_info_t *)dsp->ds_mip; 241269Sericheng } 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate /* 2440Sstevel@tonic-gate * Set the media type (properly this time). 2450Sstevel@tonic-gate */ 2463147Sxc151355 if (dsp->ds_native) 2473147Sxc151355 dlp->dl_mac_type = minfop->mi_nativemedia; 2483147Sxc151355 else 2493147Sxc151355 dlp->dl_mac_type = minfop->mi_media; 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate /* 2520Sstevel@tonic-gate * Set the DLSAP length. We only support 16 bit values and they 2530Sstevel@tonic-gate * appear after the MAC address portion of DLSAP addresses. 2540Sstevel@tonic-gate */ 2550Sstevel@tonic-gate sap_length = sizeof (uint16_t); 2560Sstevel@tonic-gate dlp->dl_sap_length = NEG(sap_length); 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate /* 2590Sstevel@tonic-gate * Set the minimum and maximum payload sizes. 2600Sstevel@tonic-gate */ 261269Sericheng dlp->dl_min_sdu = minfop->mi_sdu_min; 262269Sericheng dlp->dl_max_sdu = minfop->mi_sdu_max; 2630Sstevel@tonic-gate 264269Sericheng addr_length = minfop->mi_addr_length; 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate /* 2670Sstevel@tonic-gate * Copy in the media broadcast address. 2680Sstevel@tonic-gate */ 2692311Sseb if (minfop->mi_brdcst_addr != NULL) { 2702311Sseb dlp->dl_brdcst_addr_offset = 2712311Sseb (uintptr_t)brdcst_addr - (uintptr_t)dlp; 2722311Sseb bcopy(minfop->mi_brdcst_addr, brdcst_addr, addr_length); 2732311Sseb dlp->dl_brdcst_addr_length = addr_length; 2742311Sseb } 2750Sstevel@tonic-gate 2762760Sdg199075 dlp->dl_qos_range_offset = (uintptr_t)rangep - (uintptr_t)dlp; 2772760Sdg199075 dlp->dl_qos_range_length = sizeof (dl_qos_cl_range1_t); 2780Sstevel@tonic-gate 2792760Sdg199075 rangep->dl_qos_type = DL_QOS_CL_RANGE1; 2802760Sdg199075 rangep->dl_trans_delay.dl_target_value = DL_UNKNOWN; 2812760Sdg199075 rangep->dl_trans_delay.dl_accept_value = DL_UNKNOWN; 2822760Sdg199075 rangep->dl_protection.dl_min = DL_UNKNOWN; 2832760Sdg199075 rangep->dl_protection.dl_max = DL_UNKNOWN; 2842760Sdg199075 rangep->dl_residual_error = DL_UNKNOWN; 2850Sstevel@tonic-gate 2862760Sdg199075 /* 2872760Sdg199075 * Specify the supported range of priorities. 2882760Sdg199075 */ 2892760Sdg199075 rangep->dl_priority.dl_min = 0; 2902760Sdg199075 rangep->dl_priority.dl_max = (1 << VLAN_PRI_SIZE) - 1; 2910Sstevel@tonic-gate 2922760Sdg199075 dlp->dl_qos_offset = (uintptr_t)selp - (uintptr_t)dlp; 2932760Sdg199075 dlp->dl_qos_length = sizeof (dl_qos_cl_sel1_t); 2940Sstevel@tonic-gate 2952760Sdg199075 selp->dl_qos_type = DL_QOS_CL_SEL1; 2962760Sdg199075 selp->dl_trans_delay = DL_UNKNOWN; 2972760Sdg199075 selp->dl_protection = DL_UNKNOWN; 2982760Sdg199075 selp->dl_residual_error = DL_UNKNOWN; 2992760Sdg199075 3002760Sdg199075 /* 3012760Sdg199075 * Specify the current priority (which can be changed by 3022760Sdg199075 * the DL_UDQOS_REQ primitive). 3032760Sdg199075 */ 3042760Sdg199075 selp->dl_priority = dsp->ds_pri; 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate dlp->dl_addr_length = addr_length + sizeof (uint16_t); 3070Sstevel@tonic-gate if (dsp->ds_dlstate == DL_IDLE) { 3080Sstevel@tonic-gate /* 3090Sstevel@tonic-gate * The stream is bound. Therefore we can formulate a valid 3100Sstevel@tonic-gate * DLSAP address. 3110Sstevel@tonic-gate */ 3120Sstevel@tonic-gate dlp->dl_addr_offset = (uintptr_t)addr - (uintptr_t)dlp; 3132311Sseb if (addr_length > 0) 3142311Sseb bcopy(dsp->ds_curr_addr, addr, addr_length); 3150Sstevel@tonic-gate *(uint16_t *)(addr + addr_length) = dsp->ds_sap; 3160Sstevel@tonic-gate } 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate done: 3190Sstevel@tonic-gate ASSERT(IMPLY(dlp->dl_qos_offset != 0, dlp->dl_qos_length != 0)); 3200Sstevel@tonic-gate ASSERT(IMPLY(dlp->dl_qos_range_offset != 0, 3210Sstevel@tonic-gate dlp->dl_qos_range_length != 0)); 3220Sstevel@tonic-gate ASSERT(IMPLY(dlp->dl_addr_offset != 0, dlp->dl_addr_length != 0)); 3230Sstevel@tonic-gate ASSERT(IMPLY(dlp->dl_brdcst_addr_offset != 0, 3240Sstevel@tonic-gate dlp->dl_brdcst_addr_length != 0)); 3250Sstevel@tonic-gate 326269Sericheng rw_exit(&dsp->ds_lock); 327269Sericheng 328269Sericheng qreply(q, mp); 329269Sericheng return (B_TRUE); 330269Sericheng } 331269Sericheng 332269Sericheng /* 333269Sericheng * DL_ATTACH_REQ 334269Sericheng */ 335269Sericheng static boolean_t 336269Sericheng proto_attach_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 337269Sericheng { 338269Sericheng dl_attach_req_t *dlp = (dl_attach_req_t *)udlp; 339269Sericheng int err = 0; 340269Sericheng t_uscalar_t dl_err; 341269Sericheng queue_t *q = dsp->ds_wq; 342269Sericheng 343269Sericheng rw_enter(&dsp->ds_lock, RW_WRITER); 344269Sericheng 345269Sericheng if (MBLKL(mp) < sizeof (dl_attach_req_t) || 346269Sericheng dlp->dl_ppa < 0 || dsp->ds_style == DL_STYLE1) { 347269Sericheng dl_err = DL_BADPRIM; 348269Sericheng goto failed; 349269Sericheng } 350269Sericheng 351269Sericheng if (dsp->ds_dlstate != DL_UNATTACHED) { 352269Sericheng dl_err = DL_OUTSTATE; 353269Sericheng goto failed; 354269Sericheng } 355269Sericheng 356269Sericheng dsp->ds_dlstate = DL_ATTACH_PENDING; 357269Sericheng 358269Sericheng err = dld_str_attach(dsp, dlp->dl_ppa); 359269Sericheng if (err != 0) { 360269Sericheng switch (err) { 361269Sericheng case ENOENT: 362269Sericheng dl_err = DL_BADPPA; 363269Sericheng err = 0; 364269Sericheng break; 365269Sericheng default: 366269Sericheng dl_err = DL_SYSERR; 367269Sericheng break; 368269Sericheng } 369269Sericheng dsp->ds_dlstate = DL_UNATTACHED; 370269Sericheng goto failed; 371269Sericheng } 372269Sericheng ASSERT(dsp->ds_dlstate == DL_UNBOUND); 373269Sericheng rw_exit(&dsp->ds_lock); 374269Sericheng 375269Sericheng dlokack(q, mp, DL_ATTACH_REQ); 376269Sericheng return (B_TRUE); 377269Sericheng failed: 378269Sericheng rw_exit(&dsp->ds_lock); 379269Sericheng dlerrorack(q, mp, DL_ATTACH_REQ, dl_err, (t_uscalar_t)err); 380269Sericheng return (B_FALSE); 3810Sstevel@tonic-gate } 3820Sstevel@tonic-gate 383269Sericheng /*ARGSUSED*/ 384269Sericheng static boolean_t 385269Sericheng proto_detach_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 3860Sstevel@tonic-gate { 387269Sericheng queue_t *q = dsp->ds_wq; 388269Sericheng t_uscalar_t dl_err; 3890Sstevel@tonic-gate 390269Sericheng rw_enter(&dsp->ds_lock, RW_WRITER); 3910Sstevel@tonic-gate 392269Sericheng if (MBLKL(mp) < sizeof (dl_detach_req_t)) { 393269Sericheng dl_err = DL_BADPRIM; 394269Sericheng goto failed; 395269Sericheng } 3960Sstevel@tonic-gate 397269Sericheng if (dsp->ds_dlstate != DL_UNBOUND) { 398269Sericheng dl_err = DL_OUTSTATE; 399269Sericheng goto failed; 4000Sstevel@tonic-gate } 4010Sstevel@tonic-gate 402269Sericheng if (dsp->ds_style == DL_STYLE1) { 403269Sericheng dl_err = DL_BADPRIM; 404269Sericheng goto failed; 405269Sericheng } 406269Sericheng 407269Sericheng dsp->ds_dlstate = DL_DETACH_PENDING; 408*5895Syz147064 dld_str_detach(dsp); 409269Sericheng 410269Sericheng rw_exit(&dsp->ds_lock); 411*5895Syz147064 dlokack(dsp->ds_wq, mp, DL_DETACH_REQ); 412269Sericheng return (B_TRUE); 413269Sericheng failed: 414269Sericheng rw_exit(&dsp->ds_lock); 415269Sericheng dlerrorack(q, mp, DL_DETACH_REQ, dl_err, 0); 416269Sericheng return (B_FALSE); 4170Sstevel@tonic-gate } 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate /* 420269Sericheng * DL_BIND_REQ 4210Sstevel@tonic-gate */ 422269Sericheng static boolean_t 423269Sericheng proto_bind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 4240Sstevel@tonic-gate { 425269Sericheng dl_bind_req_t *dlp = (dl_bind_req_t *)udlp; 426269Sericheng int err = 0; 4273037Syz147064 uint8_t dlsap_addr[MAXMACADDRLEN + sizeof (uint16_t)]; 4283037Syz147064 uint_t dlsap_addr_length; 429269Sericheng t_uscalar_t dl_err; 430269Sericheng t_scalar_t sap; 431269Sericheng queue_t *q = dsp->ds_wq; 432269Sericheng 433*5895Syz147064 /* 434*5895Syz147064 * Because control message processing is serialized, we don't need 435*5895Syz147064 * to hold any locks to read any fields of dsp; we only need ds_lock 436*5895Syz147064 * to update the ds_dlstate, ds_sap and ds_passivestate fields. 437*5895Syz147064 */ 438269Sericheng if (MBLKL(mp) < sizeof (dl_bind_req_t)) { 439269Sericheng dl_err = DL_BADPRIM; 440269Sericheng goto failed; 441269Sericheng } 442269Sericheng 443269Sericheng if (dlp->dl_xidtest_flg != 0) { 444269Sericheng dl_err = DL_NOAUTO; 445269Sericheng goto failed; 446269Sericheng } 447269Sericheng 448269Sericheng if (dlp->dl_service_mode != DL_CLDLS) { 449269Sericheng dl_err = DL_UNSUPPORTED; 450269Sericheng goto failed; 451269Sericheng } 452269Sericheng 453269Sericheng if (dsp->ds_dlstate != DL_UNBOUND) { 454269Sericheng dl_err = DL_OUTSTATE; 455269Sericheng goto failed; 456269Sericheng } 4570Sstevel@tonic-gate 458269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED && 459269Sericheng !dls_active_set(dsp->ds_dc)) { 460269Sericheng dl_err = DL_SYSERR; 461269Sericheng err = EBUSY; 462269Sericheng goto failed; 463269Sericheng } 464269Sericheng 465269Sericheng /* 466269Sericheng * Set the receive callback. 467269Sericheng */ 468269Sericheng dls_rx_set(dsp->ds_dc, (dsp->ds_mode == DLD_RAW) ? 469269Sericheng dld_str_rx_raw : dld_str_rx_unitdata, dsp); 4700Sstevel@tonic-gate 471269Sericheng /* 472269Sericheng * Bind the channel such that it can receive packets. 473269Sericheng */ 474*5895Syz147064 sap = dlp->dl_sap; 475*5895Syz147064 err = dls_bind(dsp->ds_dc, sap); 476269Sericheng if (err != 0) { 477269Sericheng switch (err) { 478269Sericheng case EINVAL: 479269Sericheng dl_err = DL_BADADDR; 480269Sericheng err = 0; 481269Sericheng break; 482269Sericheng default: 483269Sericheng dl_err = DL_SYSERR; 484269Sericheng break; 485269Sericheng } 486*5895Syz147064 487269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 488269Sericheng dls_active_clear(dsp->ds_dc); 489269Sericheng 4900Sstevel@tonic-gate goto failed; 491269Sericheng } 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate /* 4940Sstevel@tonic-gate * Copy in MAC address. 4950Sstevel@tonic-gate */ 4963037Syz147064 dlsap_addr_length = dsp->ds_mip->mi_addr_length; 4973037Syz147064 bcopy(dsp->ds_curr_addr, dlsap_addr, dlsap_addr_length); 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate /* 5003037Syz147064 * Copy in the SAP. 5010Sstevel@tonic-gate */ 502*5895Syz147064 *(uint16_t *)(dlsap_addr + dlsap_addr_length) = sap; 5033037Syz147064 dlsap_addr_length += sizeof (uint16_t); 5040Sstevel@tonic-gate 505*5895Syz147064 rw_enter(&dsp->ds_lock, RW_WRITER); 506*5895Syz147064 5070Sstevel@tonic-gate dsp->ds_dlstate = DL_IDLE; 508269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 509269Sericheng dsp->ds_passivestate = DLD_ACTIVE; 510*5895Syz147064 dsp->ds_sap = sap; 511*5895Syz147064 512*5895Syz147064 if (dsp->ds_mode == DLD_FASTPATH) 513*5895Syz147064 dsp->ds_tx = str_mdata_fastpath_put; 514*5895Syz147064 else if (dsp->ds_mode == DLD_RAW) 515*5895Syz147064 dsp->ds_tx = str_mdata_raw_put; 516*5895Syz147064 dsp->ds_unitdata_tx = dld_wput_proto_data; 5170Sstevel@tonic-gate 518269Sericheng rw_exit(&dsp->ds_lock); 519269Sericheng 5203037Syz147064 dlbindack(q, mp, sap, dlsap_addr, dlsap_addr_length, 0, 0); 521269Sericheng return (B_TRUE); 5220Sstevel@tonic-gate failed: 523269Sericheng dlerrorack(q, mp, DL_BIND_REQ, dl_err, (t_uscalar_t)err); 524269Sericheng return (B_FALSE); 5250Sstevel@tonic-gate } 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate /* 528269Sericheng * DL_UNBIND_REQ 5290Sstevel@tonic-gate */ 530269Sericheng /*ARGSUSED*/ 531*5895Syz147064 static boolean_t 532*5895Syz147064 proto_unbind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 5330Sstevel@tonic-gate { 534*5895Syz147064 queue_t *q = dsp->ds_wq; 535*5895Syz147064 t_uscalar_t dl_err; 536269Sericheng 537*5895Syz147064 if (MBLKL(mp) < sizeof (dl_unbind_req_t)) { 538*5895Syz147064 dl_err = DL_BADPRIM; 539*5895Syz147064 goto failed; 540*5895Syz147064 } 541*5895Syz147064 542*5895Syz147064 if (dsp->ds_dlstate != DL_IDLE) { 543*5895Syz147064 dl_err = DL_OUTSTATE; 544*5895Syz147064 goto failed; 545*5895Syz147064 } 546269Sericheng 547269Sericheng /* 548269Sericheng * Flush any remaining packets scheduled for transmission. 549269Sericheng */ 550269Sericheng dld_tx_flush(dsp); 551269Sericheng 552269Sericheng /* 553269Sericheng * Unbind the channel to stop packets being received. 554269Sericheng */ 555269Sericheng dls_unbind(dsp->ds_dc); 556269Sericheng 557269Sericheng /* 558*5895Syz147064 * Clear the receive callback. 559*5895Syz147064 */ 560*5895Syz147064 dls_rx_set(dsp->ds_dc, NULL, NULL); 561*5895Syz147064 562*5895Syz147064 rw_enter(&dsp->ds_lock, RW_WRITER); 563*5895Syz147064 564*5895Syz147064 /* 565269Sericheng * Disable polling mode, if it is enabled. 566269Sericheng */ 567269Sericheng proto_poll_disable(dsp); 568269Sericheng 569269Sericheng /* 570*5895Syz147064 * If soft rings were enabled, the workers should be quiesced. 571*5895Syz147064 */ 572*5895Syz147064 dls_soft_ring_disable(dsp->ds_dc); 573*5895Syz147064 574*5895Syz147064 /* 5753115Syl150051 * Clear LSO flags. 5763115Syl150051 */ 5773115Syl150051 dsp->ds_lso = B_FALSE; 5783115Syl150051 dsp->ds_lso_max = 0; 5793115Syl150051 5803115Syl150051 /* 581269Sericheng * Set the mode back to the default (unitdata). 582269Sericheng */ 583269Sericheng dsp->ds_mode = DLD_UNITDATA; 5841353Sericheng dsp->ds_dlstate = DL_UNBOUND; 585*5895Syz147064 DLD_TX_QUIESCE(dsp); 586*5895Syz147064 rw_exit(&dsp->ds_lock); 5871353Sericheng 588*5895Syz147064 dlokack(q, mp, DL_UNBIND_REQ); 589269Sericheng 590269Sericheng return (B_TRUE); 591269Sericheng failed: 592269Sericheng dlerrorack(q, mp, DL_UNBIND_REQ, dl_err, 0); 593269Sericheng return (B_FALSE); 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate /* 597269Sericheng * DL_PROMISCON_REQ 5980Sstevel@tonic-gate */ 599269Sericheng static boolean_t 600269Sericheng proto_promiscon_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 6010Sstevel@tonic-gate { 602269Sericheng dl_promiscon_req_t *dlp = (dl_promiscon_req_t *)udlp; 603269Sericheng int err = 0; 604269Sericheng t_uscalar_t dl_err; 605*5895Syz147064 uint32_t promisc; 606269Sericheng queue_t *q = dsp->ds_wq; 607269Sericheng 608*5895Syz147064 /* 609*5895Syz147064 * Because control message processing is serialized, we don't need 610*5895Syz147064 * to hold any locks to read any fields of dsp; we only need ds_lock 611*5895Syz147064 * to update the ds_promisc and ds_passivestate fields. 612*5895Syz147064 */ 613269Sericheng if (MBLKL(mp) < sizeof (dl_promiscon_req_t)) { 614269Sericheng dl_err = DL_BADPRIM; 615269Sericheng goto failed; 616269Sericheng } 617269Sericheng 618269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 619269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 620269Sericheng dl_err = DL_OUTSTATE; 6210Sstevel@tonic-gate goto failed; 622269Sericheng } 6230Sstevel@tonic-gate 624269Sericheng switch (dlp->dl_level) { 625269Sericheng case DL_PROMISC_SAP: 626*5895Syz147064 promisc = DLS_PROMISC_SAP; 627269Sericheng break; 628*5895Syz147064 case DL_PROMISC_MULTI: 629*5895Syz147064 promisc = DLS_PROMISC_MULTI; 630*5895Syz147064 break; 631269Sericheng case DL_PROMISC_PHYS: 632*5895Syz147064 promisc = DLS_PROMISC_PHYS; 633269Sericheng break; 634269Sericheng default: 635269Sericheng dl_err = DL_NOTSUPPORTED; 636269Sericheng goto failed; 637269Sericheng } 6380Sstevel@tonic-gate 639269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED && 640269Sericheng !dls_active_set(dsp->ds_dc)) { 641269Sericheng dl_err = DL_SYSERR; 642269Sericheng err = EBUSY; 643269Sericheng goto failed; 644269Sericheng } 645269Sericheng 646269Sericheng /* 647269Sericheng * Adjust channel promiscuity. 648269Sericheng */ 649*5895Syz147064 promisc = (dsp->ds_promisc | promisc); 650*5895Syz147064 err = dls_promisc(dsp->ds_dc, promisc); 651269Sericheng if (err != 0) { 652269Sericheng dl_err = DL_SYSERR; 653269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 654269Sericheng dls_active_clear(dsp->ds_dc); 655269Sericheng goto failed; 656269Sericheng } 657269Sericheng 658*5895Syz147064 rw_enter(&dsp->ds_lock, RW_WRITER); 659269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 660269Sericheng dsp->ds_passivestate = DLD_ACTIVE; 661*5895Syz147064 dsp->ds_promisc = promisc; 662*5895Syz147064 rw_exit(&dsp->ds_lock); 663269Sericheng 664269Sericheng dlokack(q, mp, DL_PROMISCON_REQ); 665269Sericheng return (B_TRUE); 6660Sstevel@tonic-gate failed: 667269Sericheng dlerrorack(q, mp, DL_PROMISCON_REQ, dl_err, (t_uscalar_t)err); 668269Sericheng return (B_FALSE); 6690Sstevel@tonic-gate } 6700Sstevel@tonic-gate 6710Sstevel@tonic-gate /* 672269Sericheng * DL_PROMISCOFF_REQ 6730Sstevel@tonic-gate */ 674269Sericheng static boolean_t 675269Sericheng proto_promiscoff_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 6760Sstevel@tonic-gate { 677269Sericheng dl_promiscoff_req_t *dlp = (dl_promiscoff_req_t *)udlp; 678269Sericheng int err = 0; 679269Sericheng t_uscalar_t dl_err; 680*5895Syz147064 uint32_t promisc; 681269Sericheng queue_t *q = dsp->ds_wq; 682269Sericheng 683*5895Syz147064 /* 684*5895Syz147064 * Because control messages processing is serialized, we don't need 685*5895Syz147064 * to hold any lock to read any field of dsp; we hold ds_lock to 686*5895Syz147064 * update the ds_promisc field. 687*5895Syz147064 */ 688269Sericheng if (MBLKL(mp) < sizeof (dl_promiscoff_req_t)) { 689269Sericheng dl_err = DL_BADPRIM; 6900Sstevel@tonic-gate goto failed; 691269Sericheng } 6920Sstevel@tonic-gate 693269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 694269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 695269Sericheng dl_err = DL_OUTSTATE; 6960Sstevel@tonic-gate goto failed; 697269Sericheng } 6980Sstevel@tonic-gate 699269Sericheng switch (dlp->dl_level) { 700269Sericheng case DL_PROMISC_SAP: 701*5895Syz147064 promisc = DLS_PROMISC_SAP; 7020Sstevel@tonic-gate break; 703269Sericheng case DL_PROMISC_MULTI: 704*5895Syz147064 promisc = DLS_PROMISC_MULTI; 705269Sericheng break; 706269Sericheng case DL_PROMISC_PHYS: 707*5895Syz147064 promisc = DLS_PROMISC_PHYS; 7080Sstevel@tonic-gate break; 7090Sstevel@tonic-gate default: 710269Sericheng dl_err = DL_NOTSUPPORTED; 711269Sericheng goto failed; 712269Sericheng } 713269Sericheng 714*5895Syz147064 if (!(dsp->ds_promisc & promisc)) { 715*5895Syz147064 dl_err = DL_NOTENAB; 716*5895Syz147064 goto failed; 717*5895Syz147064 } 718*5895Syz147064 719*5895Syz147064 promisc = (dsp->ds_promisc & ~promisc); 720*5895Syz147064 err = dls_promisc(dsp->ds_dc, promisc); 721269Sericheng if (err != 0) { 7220Sstevel@tonic-gate dl_err = DL_SYSERR; 723269Sericheng goto failed; 724269Sericheng } 725269Sericheng 726*5895Syz147064 rw_enter(&dsp->ds_lock, RW_WRITER); 727*5895Syz147064 dsp->ds_promisc = promisc; 728269Sericheng rw_exit(&dsp->ds_lock); 729*5895Syz147064 730269Sericheng dlokack(q, mp, DL_PROMISCOFF_REQ); 731269Sericheng return (B_TRUE); 732269Sericheng failed: 733269Sericheng dlerrorack(q, mp, DL_PROMISCOFF_REQ, dl_err, (t_uscalar_t)err); 734269Sericheng return (B_FALSE); 735269Sericheng } 736269Sericheng 737269Sericheng /* 738269Sericheng * DL_ENABMULTI_REQ 739269Sericheng */ 740269Sericheng static boolean_t 741269Sericheng proto_enabmulti_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 742269Sericheng { 743269Sericheng dl_enabmulti_req_t *dlp = (dl_enabmulti_req_t *)udlp; 744269Sericheng int err = 0; 745269Sericheng t_uscalar_t dl_err; 746269Sericheng queue_t *q = dsp->ds_wq; 747269Sericheng 748*5895Syz147064 /* 749*5895Syz147064 * Because control messages processing is serialized, we don't need 750*5895Syz147064 * to hold any lock to read any field of dsp; we hold ds_lock to 751*5895Syz147064 * update the ds_passivestate field. 752*5895Syz147064 */ 753269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 754269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 755269Sericheng dl_err = DL_OUTSTATE; 756269Sericheng goto failed; 757269Sericheng } 758269Sericheng 759269Sericheng if (MBLKL(mp) < sizeof (dl_enabmulti_req_t) || 760269Sericheng !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) || 761269Sericheng dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) { 762269Sericheng dl_err = DL_BADPRIM; 763269Sericheng goto failed; 764269Sericheng } 765269Sericheng 766269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED && 767269Sericheng !dls_active_set(dsp->ds_dc)) { 768269Sericheng dl_err = DL_SYSERR; 769269Sericheng err = EBUSY; 770269Sericheng goto failed; 7710Sstevel@tonic-gate } 7720Sstevel@tonic-gate 773269Sericheng err = dls_multicst_add(dsp->ds_dc, mp->b_rptr + dlp->dl_addr_offset); 774269Sericheng if (err != 0) { 775269Sericheng switch (err) { 776269Sericheng case EINVAL: 777269Sericheng dl_err = DL_BADADDR; 778269Sericheng err = 0; 779269Sericheng break; 780269Sericheng case ENOSPC: 781269Sericheng dl_err = DL_TOOMANY; 782269Sericheng err = 0; 783269Sericheng break; 784269Sericheng default: 785269Sericheng dl_err = DL_SYSERR; 786269Sericheng break; 787269Sericheng } 788*5895Syz147064 789269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 790269Sericheng dls_active_clear(dsp->ds_dc); 791269Sericheng 792269Sericheng goto failed; 793269Sericheng } 794269Sericheng 795*5895Syz147064 rw_enter(&dsp->ds_lock, RW_WRITER); 796269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 797269Sericheng dsp->ds_passivestate = DLD_ACTIVE; 798*5895Syz147064 rw_exit(&dsp->ds_lock); 799269Sericheng 800269Sericheng dlokack(q, mp, DL_ENABMULTI_REQ); 801269Sericheng return (B_TRUE); 802269Sericheng failed: 803269Sericheng dlerrorack(q, mp, DL_ENABMULTI_REQ, dl_err, (t_uscalar_t)err); 804269Sericheng return (B_FALSE); 805269Sericheng } 806269Sericheng 807269Sericheng /* 808269Sericheng * DL_DISABMULTI_REQ 809269Sericheng */ 810269Sericheng static boolean_t 811269Sericheng proto_disabmulti_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 812269Sericheng { 813269Sericheng dl_disabmulti_req_t *dlp = (dl_disabmulti_req_t *)udlp; 814269Sericheng int err = 0; 815269Sericheng t_uscalar_t dl_err; 816269Sericheng queue_t *q = dsp->ds_wq; 817269Sericheng 818*5895Syz147064 /* 819*5895Syz147064 * Because control messages processing is serialized, we don't need 820*5895Syz147064 * to hold any lock to read any field of dsp. 821*5895Syz147064 */ 822269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 823269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 824269Sericheng dl_err = DL_OUTSTATE; 825269Sericheng goto failed; 826269Sericheng } 827269Sericheng 828269Sericheng if (MBLKL(mp) < sizeof (dl_disabmulti_req_t) || 829269Sericheng !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) || 830269Sericheng dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) { 831269Sericheng dl_err = DL_BADPRIM; 832269Sericheng goto failed; 833269Sericheng } 834269Sericheng 835269Sericheng err = dls_multicst_remove(dsp->ds_dc, mp->b_rptr + dlp->dl_addr_offset); 836269Sericheng if (err != 0) { 837*5895Syz147064 switch (err) { 838269Sericheng case EINVAL: 839269Sericheng dl_err = DL_BADADDR; 840269Sericheng err = 0; 841269Sericheng break; 842269Sericheng case ENOENT: 843269Sericheng dl_err = DL_NOTENAB; 844269Sericheng err = 0; 845269Sericheng break; 846269Sericheng default: 847269Sericheng dl_err = DL_SYSERR; 848269Sericheng break; 849269Sericheng } 850269Sericheng goto failed; 851269Sericheng } 852269Sericheng 853269Sericheng dlokack(q, mp, DL_DISABMULTI_REQ); 854269Sericheng return (B_TRUE); 855269Sericheng failed: 856269Sericheng dlerrorack(q, mp, DL_DISABMULTI_REQ, dl_err, (t_uscalar_t)err); 857269Sericheng return (B_FALSE); 8580Sstevel@tonic-gate } 8590Sstevel@tonic-gate 8600Sstevel@tonic-gate /* 861269Sericheng * DL_PHYS_ADDR_REQ 8620Sstevel@tonic-gate */ 863269Sericheng static boolean_t 864269Sericheng proto_physaddr_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 8650Sstevel@tonic-gate { 866269Sericheng dl_phys_addr_req_t *dlp = (dl_phys_addr_req_t *)udlp; 867269Sericheng queue_t *q = dsp->ds_wq; 868269Sericheng t_uscalar_t dl_err; 869269Sericheng char *addr; 870269Sericheng uint_t addr_length; 871269Sericheng 872269Sericheng rw_enter(&dsp->ds_lock, RW_READER); 873269Sericheng 874269Sericheng if (MBLKL(mp) < sizeof (dl_phys_addr_req_t)) { 875269Sericheng dl_err = DL_BADPRIM; 876269Sericheng goto failed; 877269Sericheng } 878269Sericheng 879269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 880269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 881269Sericheng dl_err = DL_OUTSTATE; 882269Sericheng goto failed; 883269Sericheng } 8840Sstevel@tonic-gate 885269Sericheng if (dlp->dl_addr_type != DL_CURR_PHYS_ADDR && 886269Sericheng dlp->dl_addr_type != DL_FACT_PHYS_ADDR) { 887269Sericheng dl_err = DL_UNSUPPORTED; 8880Sstevel@tonic-gate goto failed; 889269Sericheng } 8900Sstevel@tonic-gate 891269Sericheng addr_length = dsp->ds_mip->mi_addr_length; 892269Sericheng addr = kmem_alloc(addr_length, KM_NOSLEEP); 893269Sericheng if (addr == NULL) { 894269Sericheng rw_exit(&dsp->ds_lock); 895269Sericheng merror(q, mp, ENOSR); 896269Sericheng return (B_FALSE); 897269Sericheng } 8980Sstevel@tonic-gate 899269Sericheng /* 900269Sericheng * Copy out the address before we drop the lock; we don't 901269Sericheng * want to call dlphysaddrack() while holding ds_lock. 902269Sericheng */ 903269Sericheng bcopy((dlp->dl_addr_type == DL_CURR_PHYS_ADDR) ? 904269Sericheng dsp->ds_curr_addr : dsp->ds_fact_addr, addr, addr_length); 905269Sericheng 906269Sericheng rw_exit(&dsp->ds_lock); 907269Sericheng dlphysaddrack(q, mp, addr, (t_uscalar_t)addr_length); 908269Sericheng kmem_free(addr, addr_length); 909269Sericheng return (B_TRUE); 9100Sstevel@tonic-gate failed: 911269Sericheng rw_exit(&dsp->ds_lock); 912269Sericheng dlerrorack(q, mp, DL_PHYS_ADDR_REQ, dl_err, 0); 913269Sericheng return (B_FALSE); 914269Sericheng } 9150Sstevel@tonic-gate 916269Sericheng /* 917269Sericheng * DL_SET_PHYS_ADDR_REQ 918269Sericheng */ 919269Sericheng static boolean_t 920269Sericheng proto_setphysaddr_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 921269Sericheng { 922269Sericheng dl_set_phys_addr_req_t *dlp = (dl_set_phys_addr_req_t *)udlp; 923269Sericheng int err = 0; 924269Sericheng t_uscalar_t dl_err; 925269Sericheng queue_t *q = dsp->ds_wq; 9260Sstevel@tonic-gate 927*5895Syz147064 /* 928*5895Syz147064 * Because control message processing is serialized, we don't need 929*5895Syz147064 * to hold any locks to read any fields of dsp; we only need ds_lock 930*5895Syz147064 * to update the ds_passivestate field. 931*5895Syz147064 */ 932269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 933269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 934269Sericheng dl_err = DL_OUTSTATE; 935269Sericheng goto failed; 936269Sericheng } 937269Sericheng 938269Sericheng if (MBLKL(mp) < sizeof (dl_set_phys_addr_req_t) || 939269Sericheng !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) || 940269Sericheng dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) { 941269Sericheng dl_err = DL_BADPRIM; 942269Sericheng goto failed; 9430Sstevel@tonic-gate } 9440Sstevel@tonic-gate 945269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED && 946269Sericheng !dls_active_set(dsp->ds_dc)) { 947269Sericheng dl_err = DL_SYSERR; 948269Sericheng err = EBUSY; 949269Sericheng goto failed; 950269Sericheng } 951269Sericheng 952269Sericheng err = mac_unicst_set(dsp->ds_mh, mp->b_rptr + dlp->dl_addr_offset); 953269Sericheng if (err != 0) { 954269Sericheng switch (err) { 955269Sericheng case EINVAL: 956269Sericheng dl_err = DL_BADADDR; 957269Sericheng err = 0; 958269Sericheng break; 959269Sericheng 960269Sericheng default: 961269Sericheng dl_err = DL_SYSERR; 962269Sericheng break; 963269Sericheng } 964*5895Syz147064 965269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 966269Sericheng dls_active_clear(dsp->ds_dc); 967269Sericheng 968269Sericheng goto failed; 969269Sericheng } 970*5895Syz147064 971*5895Syz147064 rw_enter(&dsp->ds_lock, RW_WRITER); 972269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 973269Sericheng dsp->ds_passivestate = DLD_ACTIVE; 974*5895Syz147064 rw_exit(&dsp->ds_lock); 975269Sericheng 976269Sericheng dlokack(q, mp, DL_SET_PHYS_ADDR_REQ); 977269Sericheng return (B_TRUE); 978269Sericheng failed: 979269Sericheng dlerrorack(q, mp, DL_SET_PHYS_ADDR_REQ, dl_err, (t_uscalar_t)err); 980269Sericheng return (B_FALSE); 981269Sericheng } 982269Sericheng 983269Sericheng /* 984269Sericheng * DL_UDQOS_REQ 985269Sericheng */ 986269Sericheng static boolean_t 987269Sericheng proto_udqos_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 988269Sericheng { 989269Sericheng dl_udqos_req_t *dlp = (dl_udqos_req_t *)udlp; 990269Sericheng dl_qos_cl_sel1_t *selp; 991269Sericheng int off, len; 992269Sericheng t_uscalar_t dl_err; 993269Sericheng queue_t *q = dsp->ds_wq; 994269Sericheng 995269Sericheng off = dlp->dl_qos_offset; 996269Sericheng len = dlp->dl_qos_length; 997269Sericheng 998269Sericheng if (MBLKL(mp) < sizeof (dl_udqos_req_t) || !MBLKIN(mp, off, len)) { 999269Sericheng dl_err = DL_BADPRIM; 1000269Sericheng goto failed; 1001269Sericheng } 1002269Sericheng 1003269Sericheng selp = (dl_qos_cl_sel1_t *)(mp->b_rptr + off); 1004269Sericheng if (selp->dl_qos_type != DL_QOS_CL_SEL1) { 1005269Sericheng dl_err = DL_BADQOSTYPE; 1006269Sericheng goto failed; 1007269Sericheng } 1008269Sericheng 10092760Sdg199075 if (selp->dl_priority > (1 << VLAN_PRI_SIZE) - 1 || 1010269Sericheng selp->dl_priority < 0) { 1011269Sericheng dl_err = DL_BADQOSPARAM; 1012269Sericheng goto failed; 1013269Sericheng } 1014269Sericheng 1015*5895Syz147064 if (dsp->ds_dlstate == DL_UNATTACHED || 1016*5895Syz147064 DL_ACK_PENDING(dsp->ds_dlstate)) { 1017*5895Syz147064 dl_err = DL_OUTSTATE; 1018*5895Syz147064 goto failed; 1019*5895Syz147064 } 1020269Sericheng 1021*5895Syz147064 rw_enter(&dsp->ds_lock, RW_WRITER); 1022*5895Syz147064 dsp->ds_pri = selp->dl_priority; 1023269Sericheng rw_exit(&dsp->ds_lock); 1024*5895Syz147064 1025269Sericheng dlokack(q, mp, DL_UDQOS_REQ); 1026269Sericheng return (B_TRUE); 1027269Sericheng failed: 1028269Sericheng dlerrorack(q, mp, DL_UDQOS_REQ, dl_err, 0); 1029269Sericheng return (B_FALSE); 10300Sstevel@tonic-gate } 10310Sstevel@tonic-gate 10321184Skrgopi static boolean_t 10331184Skrgopi check_ip_above(queue_t *q) 10341184Skrgopi { 10351184Skrgopi queue_t *next_q; 10361184Skrgopi boolean_t ret = B_TRUE; 10371184Skrgopi 10381184Skrgopi claimstr(q); 10391184Skrgopi next_q = q->q_next; 10401184Skrgopi if (strcmp(next_q->q_qinfo->qi_minfo->mi_idname, "ip") != 0) 10411184Skrgopi ret = B_FALSE; 10421184Skrgopi releasestr(q); 10431184Skrgopi return (ret); 10441184Skrgopi } 10451184Skrgopi 10460Sstevel@tonic-gate /* 1047269Sericheng * DL_CAPABILITY_REQ 10480Sstevel@tonic-gate */ 1049269Sericheng /*ARGSUSED*/ 1050269Sericheng static boolean_t 1051269Sericheng proto_capability_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 10520Sstevel@tonic-gate { 1053269Sericheng dl_capability_req_t *dlp = (dl_capability_req_t *)udlp; 1054269Sericheng dl_capability_sub_t *sp; 1055269Sericheng size_t size, len; 1056269Sericheng offset_t off, end; 1057269Sericheng t_uscalar_t dl_err; 1058269Sericheng queue_t *q = dsp->ds_wq; 1059269Sericheng 1060*5895Syz147064 rw_enter(&dsp->ds_lock, RW_WRITER); 1061269Sericheng 1062269Sericheng if (MBLKL(mp) < sizeof (dl_capability_req_t)) { 1063269Sericheng dl_err = DL_BADPRIM; 1064269Sericheng goto failed; 1065269Sericheng } 1066269Sericheng 1067269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 1068269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 1069269Sericheng dl_err = DL_OUTSTATE; 1070269Sericheng goto failed; 1071269Sericheng } 1072269Sericheng 1073269Sericheng /* 1074269Sericheng * This request is overloaded. If there are no requested capabilities 1075269Sericheng * then we just want to acknowledge with all the capabilities we 1076269Sericheng * support. Otherwise we enable the set of capabilities requested. 1077269Sericheng */ 1078269Sericheng if (dlp->dl_sub_length == 0) { 1079269Sericheng /* callee drops lock */ 1080269Sericheng return (proto_capability_advertise(dsp, mp)); 1081269Sericheng } 1082269Sericheng 1083269Sericheng if (!MBLKIN(mp, dlp->dl_sub_offset, dlp->dl_sub_length)) { 1084269Sericheng dl_err = DL_BADPRIM; 1085269Sericheng goto failed; 1086269Sericheng } 1087269Sericheng 1088269Sericheng dlp->dl_primitive = DL_CAPABILITY_ACK; 1089269Sericheng 1090269Sericheng off = dlp->dl_sub_offset; 1091269Sericheng len = dlp->dl_sub_length; 10920Sstevel@tonic-gate 10930Sstevel@tonic-gate /* 1094269Sericheng * Walk the list of capabilities to be enabled. 10950Sstevel@tonic-gate */ 1096269Sericheng for (end = off + len; off < end; ) { 1097269Sericheng sp = (dl_capability_sub_t *)(mp->b_rptr + off); 1098269Sericheng size = sizeof (dl_capability_sub_t) + sp->dl_length; 1099269Sericheng 1100269Sericheng if (off + size > end || 1101269Sericheng !IS_P2ALIGNED(off, sizeof (uint32_t))) { 1102269Sericheng dl_err = DL_BADPRIM; 1103269Sericheng goto failed; 1104269Sericheng } 1105269Sericheng 1106269Sericheng switch (sp->dl_cap) { 1107269Sericheng /* 1108269Sericheng * TCP/IP checksum offload to hardware. 1109269Sericheng */ 1110269Sericheng case DL_CAPAB_HCKSUM: { 1111269Sericheng dl_capab_hcksum_t *hcksump; 1112269Sericheng dl_capab_hcksum_t hcksum; 1113269Sericheng 1114269Sericheng hcksump = (dl_capab_hcksum_t *)&sp[1]; 1115269Sericheng /* 1116269Sericheng * Copy for alignment. 1117269Sericheng */ 1118269Sericheng bcopy(hcksump, &hcksum, sizeof (dl_capab_hcksum_t)); 1119269Sericheng dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq); 1120269Sericheng bcopy(&hcksum, hcksump, sizeof (dl_capab_hcksum_t)); 1121269Sericheng break; 1122269Sericheng } 1123269Sericheng 1124269Sericheng /* 11253115Syl150051 * Large segment offload. (LSO) 11263115Syl150051 */ 11273115Syl150051 case DL_CAPAB_LSO: { 11283115Syl150051 dl_capab_lso_t *lsop; 11293115Syl150051 dl_capab_lso_t lso; 11303115Syl150051 11313115Syl150051 lsop = (dl_capab_lso_t *)&sp[1]; 11323115Syl150051 /* 11333115Syl150051 * Copy for alignment. 11343115Syl150051 */ 11353115Syl150051 bcopy(lsop, &lso, sizeof (dl_capab_lso_t)); 11363115Syl150051 dlcapabsetqid(&(lso.lso_mid), dsp->ds_rq); 11373115Syl150051 bcopy(&lso, lsop, sizeof (dl_capab_lso_t)); 11383115Syl150051 break; 11393115Syl150051 } 11403115Syl150051 11413115Syl150051 /* 1142269Sericheng * IP polling interface. 1143269Sericheng */ 1144269Sericheng case DL_CAPAB_POLL: { 11451184Skrgopi dl_capab_dls_t *pollp; 11461184Skrgopi dl_capab_dls_t poll; 1147269Sericheng 11481184Skrgopi pollp = (dl_capab_dls_t *)&sp[1]; 1149269Sericheng /* 1150269Sericheng * Copy for alignment. 1151269Sericheng */ 11521184Skrgopi bcopy(pollp, &poll, sizeof (dl_capab_dls_t)); 1153269Sericheng 11541184Skrgopi switch (poll.dls_flags) { 1155269Sericheng default: 1156269Sericheng /*FALLTHRU*/ 1157269Sericheng case POLL_DISABLE: 1158269Sericheng proto_poll_disable(dsp); 1159269Sericheng break; 1160269Sericheng 1161269Sericheng case POLL_ENABLE: 1162269Sericheng ASSERT(!(dld_opt & DLD_OPT_NO_POLL)); 1163269Sericheng 1164269Sericheng /* 1165269Sericheng * Make sure polling is disabled. 1166269Sericheng */ 1167269Sericheng proto_poll_disable(dsp); 1168269Sericheng 1169269Sericheng /* 1170*5895Syz147064 * Note that only IP should enable POLL. 1171269Sericheng */ 11721184Skrgopi if (check_ip_above(dsp->ds_rq) && 11731184Skrgopi proto_poll_enable(dsp, &poll)) { 11741184Skrgopi bzero(&poll, sizeof (dl_capab_dls_t)); 11751184Skrgopi poll.dls_flags = POLL_ENABLE; 1176*5895Syz147064 } else { 1177*5895Syz147064 bzero(&poll, sizeof (dl_capab_dls_t)); 1178*5895Syz147064 poll.dls_flags = POLL_DISABLE; 11791184Skrgopi } 1180269Sericheng break; 1181269Sericheng } 1182269Sericheng 11831184Skrgopi dlcapabsetqid(&(poll.dls_mid), dsp->ds_rq); 11841184Skrgopi bcopy(&poll, pollp, sizeof (dl_capab_dls_t)); 11851184Skrgopi break; 11861184Skrgopi } 11871184Skrgopi case DL_CAPAB_SOFT_RING: { 11881184Skrgopi dl_capab_dls_t *soft_ringp; 11891184Skrgopi dl_capab_dls_t soft_ring; 11901184Skrgopi 11911184Skrgopi soft_ringp = (dl_capab_dls_t *)&sp[1]; 11921184Skrgopi /* 11931184Skrgopi * Copy for alignment. 11941184Skrgopi */ 11951184Skrgopi bcopy(soft_ringp, &soft_ring, 11961184Skrgopi sizeof (dl_capab_dls_t)); 11971184Skrgopi 11981184Skrgopi switch (soft_ring.dls_flags) { 11991184Skrgopi default: 12001184Skrgopi /*FALLTHRU*/ 12011184Skrgopi case SOFT_RING_DISABLE: 12021184Skrgopi proto_soft_ring_disable(dsp); 12031184Skrgopi break; 12041184Skrgopi 12051184Skrgopi case SOFT_RING_ENABLE: 12064114Sja97890 ASSERT(!(dld_opt & DLD_OPT_NO_SOFTRING)); 12071184Skrgopi /* 12081184Skrgopi * Make sure soft_ring is disabled. 12091184Skrgopi */ 12101184Skrgopi proto_soft_ring_disable(dsp); 12111184Skrgopi 12121184Skrgopi /* 1213*5895Syz147064 * Note that only IP can enable soft ring. 12141184Skrgopi */ 12151184Skrgopi if (check_ip_above(dsp->ds_rq) && 12161184Skrgopi proto_soft_ring_enable(dsp, &soft_ring)) { 12171184Skrgopi bzero(&soft_ring, 12181184Skrgopi sizeof (dl_capab_dls_t)); 1219*5895Syz147064 soft_ring.dls_flags = SOFT_RING_ENABLE; 12201184Skrgopi } else { 12211184Skrgopi bzero(&soft_ring, 12221184Skrgopi sizeof (dl_capab_dls_t)); 1223*5895Syz147064 soft_ring.dls_flags = SOFT_RING_DISABLE; 12241184Skrgopi } 12251184Skrgopi break; 12261184Skrgopi } 12271184Skrgopi 12281184Skrgopi dlcapabsetqid(&(soft_ring.dls_mid), dsp->ds_rq); 12291184Skrgopi bcopy(&soft_ring, soft_ringp, 12301184Skrgopi sizeof (dl_capab_dls_t)); 1231269Sericheng break; 1232269Sericheng } 1233269Sericheng default: 1234269Sericheng break; 1235269Sericheng } 1236269Sericheng 1237269Sericheng off += size; 1238269Sericheng } 1239269Sericheng rw_exit(&dsp->ds_lock); 1240269Sericheng qreply(q, mp); 1241269Sericheng return (B_TRUE); 1242269Sericheng failed: 1243269Sericheng rw_exit(&dsp->ds_lock); 1244269Sericheng dlerrorack(q, mp, DL_CAPABILITY_REQ, dl_err, 0); 1245269Sericheng return (B_FALSE); 12460Sstevel@tonic-gate } 12470Sstevel@tonic-gate 12480Sstevel@tonic-gate /* 1249269Sericheng * DL_NOTIFY_REQ 12500Sstevel@tonic-gate */ 1251269Sericheng static boolean_t 1252269Sericheng proto_notify_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 12530Sstevel@tonic-gate { 1254269Sericheng dl_notify_req_t *dlp = (dl_notify_req_t *)udlp; 1255269Sericheng t_uscalar_t dl_err; 1256269Sericheng queue_t *q = dsp->ds_wq; 1257269Sericheng uint_t note = 1258269Sericheng DL_NOTE_PROMISC_ON_PHYS | 1259269Sericheng DL_NOTE_PROMISC_OFF_PHYS | 1260269Sericheng DL_NOTE_PHYS_ADDR | 1261269Sericheng DL_NOTE_LINK_UP | 1262269Sericheng DL_NOTE_LINK_DOWN | 12632311Sseb DL_NOTE_CAPAB_RENEG | 12642311Sseb DL_NOTE_SPEED; 12650Sstevel@tonic-gate 12661521Syz147064 rw_enter(&dsp->ds_lock, RW_WRITER); 12671521Syz147064 1268269Sericheng if (MBLKL(mp) < sizeof (dl_notify_req_t)) { 1269269Sericheng dl_err = DL_BADPRIM; 1270269Sericheng goto failed; 1271269Sericheng } 12720Sstevel@tonic-gate 1273269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 1274269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 1275269Sericheng dl_err = DL_OUTSTATE; 1276269Sericheng goto failed; 12770Sstevel@tonic-gate } 12780Sstevel@tonic-gate 1279*5895Syz147064 note &= ~(mac_no_notification(dsp->ds_mh)); 1280*5895Syz147064 1281269Sericheng /* 1282269Sericheng * Cache the notifications that are being enabled. 1283269Sericheng */ 1284269Sericheng dsp->ds_notifications = dlp->dl_notifications & note; 1285269Sericheng rw_exit(&dsp->ds_lock); 1286269Sericheng /* 1287269Sericheng * The ACK carries all notifications regardless of which set is 1288269Sericheng * being enabled. 1289269Sericheng */ 1290269Sericheng dlnotifyack(q, mp, note); 1291269Sericheng 1292269Sericheng /* 1293269Sericheng * Solicit DL_NOTIFY_IND messages for each enabled notification. 1294269Sericheng */ 1295269Sericheng rw_enter(&dsp->ds_lock, RW_READER); 1296269Sericheng if (dsp->ds_notifications != 0) { 1297269Sericheng rw_exit(&dsp->ds_lock); 1298269Sericheng dld_str_notify_ind(dsp); 1299269Sericheng } else { 1300269Sericheng rw_exit(&dsp->ds_lock); 1301269Sericheng } 1302269Sericheng return (B_TRUE); 1303269Sericheng failed: 1304269Sericheng rw_exit(&dsp->ds_lock); 1305269Sericheng dlerrorack(q, mp, DL_NOTIFY_REQ, dl_err, 0); 1306269Sericheng return (B_FALSE); 13070Sstevel@tonic-gate } 13080Sstevel@tonic-gate 13090Sstevel@tonic-gate /* 1310*5895Syz147064 * DL_UNITDATA_REQ 13110Sstevel@tonic-gate */ 1312*5895Syz147064 void 1313*5895Syz147064 dld_wput_proto_data(dld_str_t *dsp, mblk_t *mp) 13140Sstevel@tonic-gate { 1315269Sericheng queue_t *q = dsp->ds_wq; 1316*5895Syz147064 dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr; 1317269Sericheng off_t off; 1318269Sericheng size_t len, size; 1319269Sericheng const uint8_t *addr; 1320269Sericheng uint16_t sap; 1321269Sericheng uint_t addr_length; 13222311Sseb mblk_t *bp, *payload; 1323269Sericheng uint32_t start, stuff, end, value, flags; 1324269Sericheng t_uscalar_t dl_err; 1325269Sericheng 1326269Sericheng if (MBLKL(mp) < sizeof (dl_unitdata_req_t) || mp->b_cont == NULL) { 1327269Sericheng dl_err = DL_BADPRIM; 1328269Sericheng goto failed; 1329269Sericheng } 1330269Sericheng 1331269Sericheng addr_length = dsp->ds_mip->mi_addr_length; 1332269Sericheng 1333269Sericheng off = dlp->dl_dest_addr_offset; 1334269Sericheng len = dlp->dl_dest_addr_length; 1335269Sericheng 1336269Sericheng if (!MBLKIN(mp, off, len) || !IS_P2ALIGNED(off, sizeof (uint16_t))) { 1337269Sericheng dl_err = DL_BADPRIM; 1338269Sericheng goto failed; 1339269Sericheng } 1340269Sericheng 1341269Sericheng if (len != addr_length + sizeof (uint16_t)) { 1342269Sericheng dl_err = DL_BADADDR; 1343269Sericheng goto failed; 1344269Sericheng } 1345269Sericheng 1346269Sericheng addr = mp->b_rptr + off; 1347269Sericheng sap = *(uint16_t *)(mp->b_rptr + off + addr_length); 1348269Sericheng 1349269Sericheng /* 1350269Sericheng * Check the length of the packet and the block types. 1351269Sericheng */ 1352269Sericheng size = 0; 13532311Sseb payload = mp->b_cont; 13542311Sseb for (bp = payload; bp != NULL; bp = bp->b_cont) { 1355269Sericheng if (DB_TYPE(bp) != M_DATA) 1356269Sericheng goto baddata; 1357269Sericheng 1358269Sericheng size += MBLKL(bp); 1359269Sericheng } 1360269Sericheng 1361269Sericheng if (size > dsp->ds_mip->mi_sdu_max) 1362269Sericheng goto baddata; 1363269Sericheng 1364269Sericheng /* 1365269Sericheng * Build a packet header. 1366269Sericheng */ 13672760Sdg199075 if ((bp = dls_header(dsp->ds_dc, addr, sap, dlp->dl_priority.dl_max, 13682760Sdg199075 &payload)) == NULL) { 1369269Sericheng dl_err = DL_BADADDR; 1370269Sericheng goto failed; 1371269Sericheng } 1372269Sericheng 1373269Sericheng /* 1374269Sericheng * We no longer need the M_PROTO header, so free it. 1375269Sericheng */ 1376269Sericheng freeb(mp); 1377269Sericheng 1378269Sericheng /* 1379269Sericheng * Transfer the checksum offload information if it is present. 1380269Sericheng */ 13812311Sseb hcksum_retrieve(payload, NULL, NULL, &start, &stuff, &end, &value, 1382269Sericheng &flags); 13832311Sseb (void) hcksum_assoc(bp, NULL, NULL, start, stuff, end, value, flags, 0); 1384269Sericheng 1385269Sericheng /* 1386269Sericheng * Link the payload onto the new header. 1387269Sericheng */ 1388269Sericheng ASSERT(bp->b_cont == NULL); 13892311Sseb bp->b_cont = payload; 13902760Sdg199075 dld_tx_single(dsp, bp); 1391*5895Syz147064 return; 1392269Sericheng failed: 1393269Sericheng dlerrorack(q, mp, DL_UNITDATA_REQ, dl_err, 0); 1394*5895Syz147064 return; 1395269Sericheng 1396269Sericheng baddata: 1397269Sericheng dluderrorind(q, mp, (void *)addr, len, DL_BADDATA, 0); 1398269Sericheng } 1399269Sericheng 1400269Sericheng /* 1401269Sericheng * DL_PASSIVE_REQ 1402269Sericheng */ 1403269Sericheng /* ARGSUSED */ 1404269Sericheng static boolean_t 1405269Sericheng proto_passive_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 1406269Sericheng { 1407269Sericheng t_uscalar_t dl_err; 1408269Sericheng 1409*5895Syz147064 /* 1410*5895Syz147064 * READER lock is enough because ds_passivestate can only be changed 1411*5895Syz147064 * as the result of non-data message processing. 1412*5895Syz147064 */ 1413*5895Syz147064 rw_enter(&dsp->ds_lock, RW_READER); 1414*5895Syz147064 1415269Sericheng /* 1416269Sericheng * If we've already become active by issuing an active primitive, 1417269Sericheng * then it's too late to try to become passive. 1418269Sericheng */ 1419269Sericheng if (dsp->ds_passivestate == DLD_ACTIVE) { 1420269Sericheng dl_err = DL_OUTSTATE; 1421269Sericheng goto failed; 1422269Sericheng } 1423269Sericheng 1424269Sericheng if (MBLKL(mp) < sizeof (dl_passive_req_t)) { 1425269Sericheng dl_err = DL_BADPRIM; 1426269Sericheng goto failed; 1427269Sericheng } 1428269Sericheng 1429269Sericheng dsp->ds_passivestate = DLD_PASSIVE; 1430269Sericheng rw_exit(&dsp->ds_lock); 1431269Sericheng dlokack(dsp->ds_wq, mp, DL_PASSIVE_REQ); 1432269Sericheng return (B_TRUE); 1433269Sericheng failed: 1434269Sericheng rw_exit(&dsp->ds_lock); 1435269Sericheng dlerrorack(dsp->ds_wq, mp, DL_PASSIVE_REQ, dl_err, 0); 1436269Sericheng return (B_FALSE); 1437269Sericheng } 1438269Sericheng 1439269Sericheng /* 1440269Sericheng * Catch-all handler. 1441269Sericheng */ 1442269Sericheng static boolean_t 1443269Sericheng proto_req(dld_str_t *dsp, union DL_primitives *dlp, mblk_t *mp) 1444269Sericheng { 1445269Sericheng dlerrorack(dsp->ds_wq, mp, dlp->dl_primitive, DL_UNSUPPORTED, 0); 1446269Sericheng return (B_FALSE); 14470Sstevel@tonic-gate } 14480Sstevel@tonic-gate 14490Sstevel@tonic-gate static void 14500Sstevel@tonic-gate proto_poll_disable(dld_str_t *dsp) 14510Sstevel@tonic-gate { 14520Sstevel@tonic-gate mac_handle_t mh; 14530Sstevel@tonic-gate 1454*5895Syz147064 ASSERT(RW_WRITE_HELD(&dsp->ds_lock)); 1455269Sericheng 14560Sstevel@tonic-gate if (!dsp->ds_polling) 14570Sstevel@tonic-gate return; 14580Sstevel@tonic-gate 14590Sstevel@tonic-gate /* 14600Sstevel@tonic-gate * It should be impossible to enable raw mode if polling is turned on. 14610Sstevel@tonic-gate */ 14620Sstevel@tonic-gate ASSERT(dsp->ds_mode != DLD_RAW); 14630Sstevel@tonic-gate 14640Sstevel@tonic-gate /* 14650Sstevel@tonic-gate * Reset the resource_add callback. 14660Sstevel@tonic-gate */ 14670Sstevel@tonic-gate mh = dls_mac(dsp->ds_dc); 14680Sstevel@tonic-gate mac_resource_set(mh, NULL, NULL); 14691184Skrgopi mac_resources(mh); 14700Sstevel@tonic-gate 14710Sstevel@tonic-gate /* 14720Sstevel@tonic-gate * Set receive function back to default. 14730Sstevel@tonic-gate */ 14740Sstevel@tonic-gate dls_rx_set(dsp->ds_dc, (dsp->ds_mode == DLD_FASTPATH) ? 1475*5895Syz147064 dld_str_rx_fastpath : dld_str_rx_unitdata, dsp); 14760Sstevel@tonic-gate 14770Sstevel@tonic-gate /* 14780Sstevel@tonic-gate * Note that polling is disabled. 14790Sstevel@tonic-gate */ 14800Sstevel@tonic-gate dsp->ds_polling = B_FALSE; 14810Sstevel@tonic-gate } 14820Sstevel@tonic-gate 14830Sstevel@tonic-gate static boolean_t 14841184Skrgopi proto_poll_enable(dld_str_t *dsp, dl_capab_dls_t *pollp) 14850Sstevel@tonic-gate { 14860Sstevel@tonic-gate mac_handle_t mh; 14870Sstevel@tonic-gate 1488269Sericheng ASSERT(RW_WRITE_HELD(&dsp->ds_lock)); 14890Sstevel@tonic-gate ASSERT(!dsp->ds_polling); 14900Sstevel@tonic-gate 14910Sstevel@tonic-gate /* 14920Sstevel@tonic-gate * We cannot enable polling if raw mode 14930Sstevel@tonic-gate * has been enabled. 14940Sstevel@tonic-gate */ 14950Sstevel@tonic-gate if (dsp->ds_mode == DLD_RAW) 14960Sstevel@tonic-gate return (B_FALSE); 14970Sstevel@tonic-gate 14980Sstevel@tonic-gate mh = dls_mac(dsp->ds_dc); 14990Sstevel@tonic-gate 15000Sstevel@tonic-gate /* 15010Sstevel@tonic-gate * Register resources. 15020Sstevel@tonic-gate */ 15031184Skrgopi mac_resource_set(mh, (mac_resource_add_t)pollp->dls_ring_add, 15041184Skrgopi (void *)pollp->dls_rx_handle); 1505*5895Syz147064 15060Sstevel@tonic-gate mac_resources(mh); 15070Sstevel@tonic-gate 15080Sstevel@tonic-gate /* 1509*5895Syz147064 * Set the upstream receive function. 15100Sstevel@tonic-gate */ 15111184Skrgopi dls_rx_set(dsp->ds_dc, (dls_rx_t)pollp->dls_rx, 15121184Skrgopi (void *)pollp->dls_rx_handle); 15130Sstevel@tonic-gate 15140Sstevel@tonic-gate /* 15150Sstevel@tonic-gate * Note that polling is enabled. This prevents further DLIOCHDRINFO 15160Sstevel@tonic-gate * ioctls from overwriting the receive function pointer. 15170Sstevel@tonic-gate */ 15180Sstevel@tonic-gate dsp->ds_polling = B_TRUE; 15190Sstevel@tonic-gate return (B_TRUE); 15200Sstevel@tonic-gate } 15210Sstevel@tonic-gate 15221184Skrgopi static void 15231184Skrgopi proto_soft_ring_disable(dld_str_t *dsp) 15241184Skrgopi { 15251184Skrgopi ASSERT(RW_WRITE_HELD(&dsp->ds_lock)); 15261184Skrgopi 15271184Skrgopi if (!dsp->ds_soft_ring) 15281184Skrgopi return; 15291184Skrgopi 15301184Skrgopi /* 15311184Skrgopi * It should be impossible to enable raw mode if soft_ring is turned on. 15321184Skrgopi */ 15331184Skrgopi ASSERT(dsp->ds_mode != DLD_RAW); 15341184Skrgopi proto_change_soft_ring_fanout(dsp, SOFT_RING_NONE); 15351184Skrgopi /* 15361184Skrgopi * Note that fanout is disabled. 15371184Skrgopi */ 15381184Skrgopi dsp->ds_soft_ring = B_FALSE; 15391184Skrgopi } 15401184Skrgopi 15411184Skrgopi static boolean_t 15421184Skrgopi proto_soft_ring_enable(dld_str_t *dsp, dl_capab_dls_t *soft_ringp) 15431184Skrgopi { 15441184Skrgopi ASSERT(RW_WRITE_HELD(&dsp->ds_lock)); 15451184Skrgopi ASSERT(!dsp->ds_soft_ring); 15461184Skrgopi 15471184Skrgopi /* 15481184Skrgopi * We cannot enable soft_ring if raw mode 15491184Skrgopi * has been enabled. 15501184Skrgopi */ 15511184Skrgopi if (dsp->ds_mode == DLD_RAW) 15521184Skrgopi return (B_FALSE); 15531184Skrgopi 15541184Skrgopi if (dls_soft_ring_enable(dsp->ds_dc, soft_ringp) == B_FALSE) 15551184Skrgopi return (B_FALSE); 15561184Skrgopi 15571184Skrgopi dsp->ds_soft_ring = B_TRUE; 15581184Skrgopi return (B_TRUE); 15591184Skrgopi } 15601184Skrgopi 15611184Skrgopi static void 15621184Skrgopi proto_change_soft_ring_fanout(dld_str_t *dsp, int type) 15631184Skrgopi { 1564*5895Syz147064 dls_channel_t dc = dsp->ds_dc; 15651184Skrgopi 15661184Skrgopi if (type == SOFT_RING_NONE) { 1567*5895Syz147064 dls_rx_set(dc, (dsp->ds_mode == DLD_FASTPATH) ? 1568*5895Syz147064 dld_str_rx_fastpath : dld_str_rx_unitdata, dsp); 1569*5895Syz147064 } else if (type != SOFT_RING_NONE) { 1570*5895Syz147064 dls_rx_set(dc, (dls_rx_t)dls_soft_ring_fanout, dc); 15711184Skrgopi } 15721184Skrgopi } 15731184Skrgopi 15740Sstevel@tonic-gate /* 15750Sstevel@tonic-gate * DL_CAPABILITY_ACK/DL_ERROR_ACK 15760Sstevel@tonic-gate */ 1577269Sericheng static boolean_t 1578269Sericheng proto_capability_advertise(dld_str_t *dsp, mblk_t *mp) 15790Sstevel@tonic-gate { 15800Sstevel@tonic-gate dl_capability_ack_t *dlap; 15810Sstevel@tonic-gate dl_capability_sub_t *dlsp; 15820Sstevel@tonic-gate size_t subsize; 15831184Skrgopi dl_capab_dls_t poll; 15843115Syl150051 dl_capab_dls_t soft_ring; 15850Sstevel@tonic-gate dl_capab_hcksum_t hcksum; 15863115Syl150051 dl_capab_lso_t lso; 15870Sstevel@tonic-gate dl_capab_zerocopy_t zcopy; 15880Sstevel@tonic-gate uint8_t *ptr; 1589269Sericheng queue_t *q = dsp->ds_wq; 1590269Sericheng mblk_t *mp1; 1591*5895Syz147064 boolean_t is_vlan = (dsp->ds_vid != VLAN_ID_NONE); 1592*5895Syz147064 boolean_t poll_capable = B_FALSE; 1593*5895Syz147064 boolean_t soft_ring_capable = B_FALSE; 1594*5895Syz147064 boolean_t hcksum_capable = B_FALSE; 1595*5895Syz147064 boolean_t zcopy_capable = B_FALSE; 1596*5895Syz147064 boolean_t lso_capable = B_FALSE; 1597*5895Syz147064 mac_capab_lso_t mac_lso; 1598269Sericheng 1599*5895Syz147064 ASSERT(RW_WRITE_HELD(&dsp->ds_lock)); 16000Sstevel@tonic-gate 16010Sstevel@tonic-gate /* 16020Sstevel@tonic-gate * Initially assume no capabilities. 16030Sstevel@tonic-gate */ 16040Sstevel@tonic-gate subsize = 0; 16050Sstevel@tonic-gate 16061555Skrgopi /* 1607*5895Syz147064 * Check if soft ring can be enabled on this interface. Note that we 1608*5895Syz147064 * do not enable softring on any legacy drivers, because doing that 1609*5895Syz147064 * would hurt the performance if the legacy driver has its own taskq 1610*5895Syz147064 * implementation. Further, most high-performance legacy drivers do 1611*5895Syz147064 * have their own taskq implementation. 1612*5895Syz147064 * 1613*5895Syz147064 * If advertising DL_CAPAB_SOFT_RING has not been explicitly disabled, 1614*5895Syz147064 * reserve space for that capability. 16151555Skrgopi */ 1616*5895Syz147064 if (!mac_is_legacy(dsp->ds_mh) && !(dld_opt & DLD_OPT_NO_SOFTRING)) { 1617*5895Syz147064 soft_ring_capable = B_TRUE; 16181555Skrgopi subsize += sizeof (dl_capability_sub_t) + 16195113Syz147064 sizeof (dl_capab_dls_t); 16204114Sja97890 } 16211184Skrgopi 16220Sstevel@tonic-gate /* 16230Sstevel@tonic-gate * Check if polling can be enabled on this interface. 16240Sstevel@tonic-gate * If advertising DL_CAPAB_POLL has not been explicitly disabled 16250Sstevel@tonic-gate * then reserve space for that capability. 16260Sstevel@tonic-gate */ 1627*5895Syz147064 if (mac_capab_get(dsp->ds_mh, MAC_CAPAB_POLL, NULL) && 1628*5895Syz147064 !(dld_opt & DLD_OPT_NO_POLL) && !is_vlan) { 1629*5895Syz147064 poll_capable = B_TRUE; 16300Sstevel@tonic-gate subsize += sizeof (dl_capability_sub_t) + 16311184Skrgopi sizeof (dl_capab_dls_t); 16320Sstevel@tonic-gate } 16330Sstevel@tonic-gate 16340Sstevel@tonic-gate /* 1635*5895Syz147064 * Check if checksum offload is supported on this MAC. Don't 1636*5895Syz147064 * advertise DL_CAPAB_HCKSUM if the underlying MAC is VLAN incapable, 1637*5895Syz147064 * since it might not be able to do the hardware checksum offload 1638*5895Syz147064 * with the correct offset. 16390Sstevel@tonic-gate */ 1640*5895Syz147064 bzero(&hcksum, sizeof (dl_capab_hcksum_t)); 1641*5895Syz147064 if ((!is_vlan || (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_NO_NATIVEVLAN, 1642*5895Syz147064 NULL))) && mac_capab_get(dsp->ds_mh, MAC_CAPAB_HCKSUM, 16432311Sseb &hcksum.hcksum_txflags)) { 1644*5895Syz147064 if (hcksum.hcksum_txflags != 0) { 1645*5895Syz147064 hcksum_capable = B_TRUE; 1646*5895Syz147064 subsize += sizeof (dl_capability_sub_t) + 1647*5895Syz147064 sizeof (dl_capab_hcksum_t); 1648*5895Syz147064 } 16490Sstevel@tonic-gate } 16500Sstevel@tonic-gate 16510Sstevel@tonic-gate /* 1652*5895Syz147064 * Check if LSO is supported on this MAC, then reserve space for 1653*5895Syz147064 * the DL_CAPAB_LSO capability. 16543115Syl150051 */ 1655*5895Syz147064 if (mac_capab_get(dsp->ds_mh, MAC_CAPAB_LSO, &mac_lso)) { 1656*5895Syz147064 lso_capable = B_TRUE; 16573115Syl150051 subsize += sizeof (dl_capability_sub_t) + 16583115Syl150051 sizeof (dl_capab_lso_t); 16593115Syl150051 } 16603115Syl150051 16613115Syl150051 /* 1662*5895Syz147064 * Check if zerocopy is supported on this interface. 1663*5895Syz147064 * If advertising DL_CAPAB_ZEROCOPY has not been explicitly disabled 1664*5895Syz147064 * then reserve space for that capability. 16650Sstevel@tonic-gate */ 1666*5895Syz147064 if (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_NO_ZCOPY, NULL) && 1667*5895Syz147064 !(dld_opt & DLD_OPT_NO_ZEROCOPY)) { 1668*5895Syz147064 zcopy_capable = B_TRUE; 16690Sstevel@tonic-gate subsize += sizeof (dl_capability_sub_t) + 16700Sstevel@tonic-gate sizeof (dl_capab_zerocopy_t); 16710Sstevel@tonic-gate } 16720Sstevel@tonic-gate 16730Sstevel@tonic-gate /* 1674269Sericheng * If there are no capabilities to advertise or if we 1675269Sericheng * can't allocate a response, send a DL_ERROR_ACK. 16760Sstevel@tonic-gate */ 16771184Skrgopi if ((mp1 = reallocb(mp, 1678269Sericheng sizeof (dl_capability_ack_t) + subsize, 0)) == NULL) { 1679269Sericheng rw_exit(&dsp->ds_lock); 1680269Sericheng dlerrorack(q, mp, DL_CAPABILITY_REQ, DL_NOTSUPPORTED, 0); 1681269Sericheng return (B_FALSE); 16820Sstevel@tonic-gate } 16830Sstevel@tonic-gate 1684269Sericheng mp = mp1; 1685269Sericheng DB_TYPE(mp) = M_PROTO; 1686269Sericheng mp->b_wptr = mp->b_rptr + sizeof (dl_capability_ack_t) + subsize; 1687269Sericheng bzero(mp->b_rptr, MBLKL(mp)); 16880Sstevel@tonic-gate dlap = (dl_capability_ack_t *)mp->b_rptr; 16890Sstevel@tonic-gate dlap->dl_primitive = DL_CAPABILITY_ACK; 16900Sstevel@tonic-gate dlap->dl_sub_offset = sizeof (dl_capability_ack_t); 16910Sstevel@tonic-gate dlap->dl_sub_length = subsize; 16920Sstevel@tonic-gate ptr = (uint8_t *)&dlap[1]; 16930Sstevel@tonic-gate 16940Sstevel@tonic-gate /* 16950Sstevel@tonic-gate * IP polling interface. 16960Sstevel@tonic-gate */ 1697*5895Syz147064 if (poll_capable) { 16980Sstevel@tonic-gate /* 1699269Sericheng * Attempt to disable just in case this is a re-negotiation; 1700*5895Syz147064 * READER lock is enough because ds_polling can only be 1701*5895Syz147064 * changed as the result of non-data message processing. 1702269Sericheng */ 1703*5895Syz147064 proto_poll_disable(dsp); 17040Sstevel@tonic-gate 1705*5895Syz147064 dlsp = (dl_capability_sub_t *)ptr; 17060Sstevel@tonic-gate 1707*5895Syz147064 dlsp->dl_cap = DL_CAPAB_POLL; 1708*5895Syz147064 dlsp->dl_length = sizeof (dl_capab_dls_t); 1709*5895Syz147064 ptr += sizeof (dl_capability_sub_t); 1710269Sericheng 1711*5895Syz147064 bzero(&poll, sizeof (dl_capab_dls_t)); 1712*5895Syz147064 poll.dls_version = POLL_VERSION_1; 1713*5895Syz147064 poll.dls_flags = POLL_CAPABLE; 1714*5895Syz147064 poll.dls_tx_handle = (uintptr_t)dsp; 1715*5895Syz147064 poll.dls_tx = (uintptr_t)str_mdata_fastpath_put; 1716*5895Syz147064 dlcapabsetqid(&(poll.dls_mid), dsp->ds_rq); 1717*5895Syz147064 bcopy(&poll, ptr, sizeof (dl_capab_dls_t)); 1718*5895Syz147064 ptr += sizeof (dl_capab_dls_t); 17190Sstevel@tonic-gate } 17200Sstevel@tonic-gate 1721269Sericheng 1722*5895Syz147064 if (soft_ring_capable) { 17231555Skrgopi dlsp = (dl_capability_sub_t *)ptr; 17241184Skrgopi 17251555Skrgopi dlsp->dl_cap = DL_CAPAB_SOFT_RING; 17261555Skrgopi dlsp->dl_length = sizeof (dl_capab_dls_t); 17271555Skrgopi ptr += sizeof (dl_capability_sub_t); 17281184Skrgopi 17291555Skrgopi bzero(&soft_ring, sizeof (dl_capab_dls_t)); 17301555Skrgopi soft_ring.dls_version = SOFT_RING_VERSION_1; 17311555Skrgopi soft_ring.dls_flags = SOFT_RING_CAPABLE; 17321555Skrgopi soft_ring.dls_tx_handle = (uintptr_t)dsp; 17331555Skrgopi soft_ring.dls_tx = (uintptr_t)str_mdata_fastpath_put; 17341555Skrgopi soft_ring.dls_ring_change_status = 17351555Skrgopi (uintptr_t)proto_change_soft_ring_fanout; 17361555Skrgopi soft_ring.dls_ring_bind = (uintptr_t)soft_ring_bind; 17371555Skrgopi soft_ring.dls_ring_unbind = (uintptr_t)soft_ring_unbind; 17381184Skrgopi 17391555Skrgopi dlcapabsetqid(&(soft_ring.dls_mid), dsp->ds_rq); 17401555Skrgopi bcopy(&soft_ring, ptr, sizeof (dl_capab_dls_t)); 17411555Skrgopi ptr += sizeof (dl_capab_dls_t); 17421555Skrgopi } 17431184Skrgopi 17440Sstevel@tonic-gate /* 17450Sstevel@tonic-gate * TCP/IP checksum offload. 17460Sstevel@tonic-gate */ 1747*5895Syz147064 if (hcksum_capable) { 17480Sstevel@tonic-gate dlsp = (dl_capability_sub_t *)ptr; 17490Sstevel@tonic-gate 17500Sstevel@tonic-gate dlsp->dl_cap = DL_CAPAB_HCKSUM; 17510Sstevel@tonic-gate dlsp->dl_length = sizeof (dl_capab_hcksum_t); 17520Sstevel@tonic-gate ptr += sizeof (dl_capability_sub_t); 17530Sstevel@tonic-gate 17540Sstevel@tonic-gate hcksum.hcksum_version = HCKSUM_VERSION_1; 17550Sstevel@tonic-gate dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq); 17560Sstevel@tonic-gate bcopy(&hcksum, ptr, sizeof (dl_capab_hcksum_t)); 17570Sstevel@tonic-gate ptr += sizeof (dl_capab_hcksum_t); 17580Sstevel@tonic-gate } 17590Sstevel@tonic-gate 17600Sstevel@tonic-gate /* 17613115Syl150051 * Large segment offload. (LSO) 17623115Syl150051 */ 1763*5895Syz147064 if (lso_capable) { 17643115Syl150051 dlsp = (dl_capability_sub_t *)ptr; 17653115Syl150051 17663115Syl150051 dlsp->dl_cap = DL_CAPAB_LSO; 17673115Syl150051 dlsp->dl_length = sizeof (dl_capab_lso_t); 17683115Syl150051 ptr += sizeof (dl_capability_sub_t); 17693115Syl150051 17703115Syl150051 lso.lso_version = LSO_VERSION_1; 17713115Syl150051 lso.lso_flags = mac_lso.lso_flags; 17723115Syl150051 lso.lso_max = mac_lso.lso_basic_tcp_ipv4.lso_max; 17733115Syl150051 17743115Syl150051 /* Simply enable LSO with DLD */ 17753115Syl150051 dsp->ds_lso = B_TRUE; 17763115Syl150051 dsp->ds_lso_max = lso.lso_max; 17773115Syl150051 17783115Syl150051 dlcapabsetqid(&(lso.lso_mid), dsp->ds_rq); 17793115Syl150051 bcopy(&lso, ptr, sizeof (dl_capab_lso_t)); 17803115Syl150051 ptr += sizeof (dl_capab_lso_t); 17813115Syl150051 } else { 17823115Syl150051 dsp->ds_lso = B_FALSE; 17833115Syl150051 dsp->ds_lso_max = 0; 17843115Syl150051 } 17853115Syl150051 17863115Syl150051 /* 17870Sstevel@tonic-gate * Zero copy 17880Sstevel@tonic-gate */ 1789*5895Syz147064 if (zcopy_capable) { 17900Sstevel@tonic-gate dlsp = (dl_capability_sub_t *)ptr; 17910Sstevel@tonic-gate 17920Sstevel@tonic-gate dlsp->dl_cap = DL_CAPAB_ZEROCOPY; 17930Sstevel@tonic-gate dlsp->dl_length = sizeof (dl_capab_zerocopy_t); 17940Sstevel@tonic-gate ptr += sizeof (dl_capability_sub_t); 17950Sstevel@tonic-gate 17960Sstevel@tonic-gate bzero(&zcopy, sizeof (dl_capab_zerocopy_t)); 17970Sstevel@tonic-gate zcopy.zerocopy_version = ZEROCOPY_VERSION_1; 17980Sstevel@tonic-gate zcopy.zerocopy_flags = DL_CAPAB_VMSAFE_MEM; 17990Sstevel@tonic-gate 18000Sstevel@tonic-gate dlcapabsetqid(&(zcopy.zerocopy_mid), dsp->ds_rq); 18010Sstevel@tonic-gate bcopy(&zcopy, ptr, sizeof (dl_capab_zerocopy_t)); 18020Sstevel@tonic-gate ptr += sizeof (dl_capab_zerocopy_t); 18030Sstevel@tonic-gate } 18040Sstevel@tonic-gate 18050Sstevel@tonic-gate ASSERT(ptr == mp->b_rptr + sizeof (dl_capability_ack_t) + subsize); 1806269Sericheng 1807269Sericheng rw_exit(&dsp->ds_lock); 1808269Sericheng qreply(q, mp); 1809269Sericheng return (B_TRUE); 18100Sstevel@tonic-gate } 18115113Syz147064 18125113Syz147064 /* 18135113Syz147064 * Disable any enabled capabilities. 18145113Syz147064 */ 18155113Syz147064 void 18165113Syz147064 dld_capabilities_disable(dld_str_t *dsp) 18175113Syz147064 { 18185113Syz147064 if (dsp->ds_polling) 18195113Syz147064 proto_poll_disable(dsp); 18205113Syz147064 18215113Syz147064 if (dsp->ds_soft_ring) 18225113Syz147064 proto_soft_ring_disable(dsp); 18235113Syz147064 } 1824