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 /* 225895Syz147064 * 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, 575895Syz147064 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 825895Syz147064 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 875895Syz147064 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; 2415903Ssowmini /* We can only get the sdu if we're attached. */ 2425903Ssowmini mac_sdu_get(dsp->ds_mh, &dlp->dl_min_sdu, &dlp->dl_max_sdu); 243269Sericheng } 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate /* 2460Sstevel@tonic-gate * Set the media type (properly this time). 2470Sstevel@tonic-gate */ 2483147Sxc151355 if (dsp->ds_native) 2493147Sxc151355 dlp->dl_mac_type = minfop->mi_nativemedia; 2503147Sxc151355 else 2513147Sxc151355 dlp->dl_mac_type = minfop->mi_media; 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate /* 2540Sstevel@tonic-gate * Set the DLSAP length. We only support 16 bit values and they 2550Sstevel@tonic-gate * appear after the MAC address portion of DLSAP addresses. 2560Sstevel@tonic-gate */ 2570Sstevel@tonic-gate sap_length = sizeof (uint16_t); 2580Sstevel@tonic-gate dlp->dl_sap_length = NEG(sap_length); 2590Sstevel@tonic-gate 260269Sericheng addr_length = minfop->mi_addr_length; 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate /* 2630Sstevel@tonic-gate * Copy in the media broadcast address. 2640Sstevel@tonic-gate */ 2652311Sseb if (minfop->mi_brdcst_addr != NULL) { 2662311Sseb dlp->dl_brdcst_addr_offset = 2672311Sseb (uintptr_t)brdcst_addr - (uintptr_t)dlp; 2682311Sseb bcopy(minfop->mi_brdcst_addr, brdcst_addr, addr_length); 2692311Sseb dlp->dl_brdcst_addr_length = addr_length; 2702311Sseb } 2710Sstevel@tonic-gate 2722760Sdg199075 dlp->dl_qos_range_offset = (uintptr_t)rangep - (uintptr_t)dlp; 2732760Sdg199075 dlp->dl_qos_range_length = sizeof (dl_qos_cl_range1_t); 2740Sstevel@tonic-gate 2752760Sdg199075 rangep->dl_qos_type = DL_QOS_CL_RANGE1; 2762760Sdg199075 rangep->dl_trans_delay.dl_target_value = DL_UNKNOWN; 2772760Sdg199075 rangep->dl_trans_delay.dl_accept_value = DL_UNKNOWN; 2782760Sdg199075 rangep->dl_protection.dl_min = DL_UNKNOWN; 2792760Sdg199075 rangep->dl_protection.dl_max = DL_UNKNOWN; 2802760Sdg199075 rangep->dl_residual_error = DL_UNKNOWN; 2810Sstevel@tonic-gate 2822760Sdg199075 /* 2832760Sdg199075 * Specify the supported range of priorities. 2842760Sdg199075 */ 2852760Sdg199075 rangep->dl_priority.dl_min = 0; 2862760Sdg199075 rangep->dl_priority.dl_max = (1 << VLAN_PRI_SIZE) - 1; 2870Sstevel@tonic-gate 2882760Sdg199075 dlp->dl_qos_offset = (uintptr_t)selp - (uintptr_t)dlp; 2892760Sdg199075 dlp->dl_qos_length = sizeof (dl_qos_cl_sel1_t); 2900Sstevel@tonic-gate 2912760Sdg199075 selp->dl_qos_type = DL_QOS_CL_SEL1; 2922760Sdg199075 selp->dl_trans_delay = DL_UNKNOWN; 2932760Sdg199075 selp->dl_protection = DL_UNKNOWN; 2942760Sdg199075 selp->dl_residual_error = DL_UNKNOWN; 2952760Sdg199075 2962760Sdg199075 /* 2972760Sdg199075 * Specify the current priority (which can be changed by 2982760Sdg199075 * the DL_UDQOS_REQ primitive). 2992760Sdg199075 */ 3002760Sdg199075 selp->dl_priority = dsp->ds_pri; 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate dlp->dl_addr_length = addr_length + sizeof (uint16_t); 3030Sstevel@tonic-gate if (dsp->ds_dlstate == DL_IDLE) { 3040Sstevel@tonic-gate /* 3050Sstevel@tonic-gate * The stream is bound. Therefore we can formulate a valid 3060Sstevel@tonic-gate * DLSAP address. 3070Sstevel@tonic-gate */ 3080Sstevel@tonic-gate dlp->dl_addr_offset = (uintptr_t)addr - (uintptr_t)dlp; 3092311Sseb if (addr_length > 0) 3102311Sseb bcopy(dsp->ds_curr_addr, addr, addr_length); 3110Sstevel@tonic-gate *(uint16_t *)(addr + addr_length) = dsp->ds_sap; 3120Sstevel@tonic-gate } 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate done: 3150Sstevel@tonic-gate ASSERT(IMPLY(dlp->dl_qos_offset != 0, dlp->dl_qos_length != 0)); 3160Sstevel@tonic-gate ASSERT(IMPLY(dlp->dl_qos_range_offset != 0, 3170Sstevel@tonic-gate dlp->dl_qos_range_length != 0)); 3180Sstevel@tonic-gate ASSERT(IMPLY(dlp->dl_addr_offset != 0, dlp->dl_addr_length != 0)); 3190Sstevel@tonic-gate ASSERT(IMPLY(dlp->dl_brdcst_addr_offset != 0, 3200Sstevel@tonic-gate dlp->dl_brdcst_addr_length != 0)); 3210Sstevel@tonic-gate 322269Sericheng rw_exit(&dsp->ds_lock); 323269Sericheng 324269Sericheng qreply(q, mp); 325269Sericheng return (B_TRUE); 326269Sericheng } 327269Sericheng 328269Sericheng /* 329269Sericheng * DL_ATTACH_REQ 330269Sericheng */ 331269Sericheng static boolean_t 332269Sericheng proto_attach_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 333269Sericheng { 334269Sericheng dl_attach_req_t *dlp = (dl_attach_req_t *)udlp; 335269Sericheng int err = 0; 336269Sericheng t_uscalar_t dl_err; 337269Sericheng queue_t *q = dsp->ds_wq; 338269Sericheng 339269Sericheng rw_enter(&dsp->ds_lock, RW_WRITER); 340269Sericheng 341269Sericheng if (MBLKL(mp) < sizeof (dl_attach_req_t) || 342269Sericheng dlp->dl_ppa < 0 || dsp->ds_style == DL_STYLE1) { 343269Sericheng dl_err = DL_BADPRIM; 344269Sericheng goto failed; 345269Sericheng } 346269Sericheng 347269Sericheng if (dsp->ds_dlstate != DL_UNATTACHED) { 348269Sericheng dl_err = DL_OUTSTATE; 349269Sericheng goto failed; 350269Sericheng } 351269Sericheng 352269Sericheng dsp->ds_dlstate = DL_ATTACH_PENDING; 353269Sericheng 354269Sericheng err = dld_str_attach(dsp, dlp->dl_ppa); 355269Sericheng if (err != 0) { 356269Sericheng switch (err) { 357269Sericheng case ENOENT: 358269Sericheng dl_err = DL_BADPPA; 359269Sericheng err = 0; 360269Sericheng break; 361269Sericheng default: 362269Sericheng dl_err = DL_SYSERR; 363269Sericheng break; 364269Sericheng } 365269Sericheng dsp->ds_dlstate = DL_UNATTACHED; 366269Sericheng goto failed; 367269Sericheng } 368269Sericheng ASSERT(dsp->ds_dlstate == DL_UNBOUND); 369269Sericheng rw_exit(&dsp->ds_lock); 370269Sericheng 371269Sericheng dlokack(q, mp, DL_ATTACH_REQ); 372269Sericheng return (B_TRUE); 373269Sericheng failed: 374269Sericheng rw_exit(&dsp->ds_lock); 375269Sericheng dlerrorack(q, mp, DL_ATTACH_REQ, dl_err, (t_uscalar_t)err); 376269Sericheng return (B_FALSE); 3770Sstevel@tonic-gate } 3780Sstevel@tonic-gate 379269Sericheng /*ARGSUSED*/ 380269Sericheng static boolean_t 381269Sericheng proto_detach_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 3820Sstevel@tonic-gate { 383269Sericheng queue_t *q = dsp->ds_wq; 384269Sericheng t_uscalar_t dl_err; 3850Sstevel@tonic-gate 386269Sericheng rw_enter(&dsp->ds_lock, RW_WRITER); 3870Sstevel@tonic-gate 388269Sericheng if (MBLKL(mp) < sizeof (dl_detach_req_t)) { 389269Sericheng dl_err = DL_BADPRIM; 390269Sericheng goto failed; 391269Sericheng } 3920Sstevel@tonic-gate 393269Sericheng if (dsp->ds_dlstate != DL_UNBOUND) { 394269Sericheng dl_err = DL_OUTSTATE; 395269Sericheng goto failed; 3960Sstevel@tonic-gate } 3970Sstevel@tonic-gate 398269Sericheng if (dsp->ds_style == DL_STYLE1) { 399269Sericheng dl_err = DL_BADPRIM; 400269Sericheng goto failed; 401269Sericheng } 402269Sericheng 403269Sericheng dsp->ds_dlstate = DL_DETACH_PENDING; 4045895Syz147064 dld_str_detach(dsp); 405269Sericheng 406269Sericheng rw_exit(&dsp->ds_lock); 4075895Syz147064 dlokack(dsp->ds_wq, mp, DL_DETACH_REQ); 408269Sericheng return (B_TRUE); 409269Sericheng failed: 410269Sericheng rw_exit(&dsp->ds_lock); 411269Sericheng dlerrorack(q, mp, DL_DETACH_REQ, dl_err, 0); 412269Sericheng return (B_FALSE); 4130Sstevel@tonic-gate } 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate /* 416269Sericheng * DL_BIND_REQ 4170Sstevel@tonic-gate */ 418269Sericheng static boolean_t 419269Sericheng proto_bind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 4200Sstevel@tonic-gate { 421269Sericheng dl_bind_req_t *dlp = (dl_bind_req_t *)udlp; 422269Sericheng int err = 0; 4233037Syz147064 uint8_t dlsap_addr[MAXMACADDRLEN + sizeof (uint16_t)]; 4243037Syz147064 uint_t dlsap_addr_length; 425269Sericheng t_uscalar_t dl_err; 426269Sericheng t_scalar_t sap; 427269Sericheng queue_t *q = dsp->ds_wq; 428269Sericheng 4295895Syz147064 /* 4305895Syz147064 * Because control message processing is serialized, we don't need 4315895Syz147064 * to hold any locks to read any fields of dsp; we only need ds_lock 4325895Syz147064 * to update the ds_dlstate, ds_sap and ds_passivestate fields. 4335895Syz147064 */ 434269Sericheng if (MBLKL(mp) < sizeof (dl_bind_req_t)) { 435269Sericheng dl_err = DL_BADPRIM; 436269Sericheng goto failed; 437269Sericheng } 438269Sericheng 439269Sericheng if (dlp->dl_xidtest_flg != 0) { 440269Sericheng dl_err = DL_NOAUTO; 441269Sericheng goto failed; 442269Sericheng } 443269Sericheng 444269Sericheng if (dlp->dl_service_mode != DL_CLDLS) { 445269Sericheng dl_err = DL_UNSUPPORTED; 446269Sericheng goto failed; 447269Sericheng } 448269Sericheng 449269Sericheng if (dsp->ds_dlstate != DL_UNBOUND) { 450269Sericheng dl_err = DL_OUTSTATE; 451269Sericheng goto failed; 452269Sericheng } 4530Sstevel@tonic-gate 454269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED && 455269Sericheng !dls_active_set(dsp->ds_dc)) { 456269Sericheng dl_err = DL_SYSERR; 457269Sericheng err = EBUSY; 458269Sericheng goto failed; 459269Sericheng } 460269Sericheng 461269Sericheng /* 462269Sericheng * Set the receive callback. 463269Sericheng */ 464269Sericheng dls_rx_set(dsp->ds_dc, (dsp->ds_mode == DLD_RAW) ? 465269Sericheng dld_str_rx_raw : dld_str_rx_unitdata, dsp); 4660Sstevel@tonic-gate 467269Sericheng /* 468269Sericheng * Bind the channel such that it can receive packets. 469269Sericheng */ 4705895Syz147064 sap = dlp->dl_sap; 4715895Syz147064 err = dls_bind(dsp->ds_dc, sap); 472269Sericheng if (err != 0) { 473269Sericheng switch (err) { 474269Sericheng case EINVAL: 475269Sericheng dl_err = DL_BADADDR; 476269Sericheng err = 0; 477269Sericheng break; 478269Sericheng default: 479269Sericheng dl_err = DL_SYSERR; 480269Sericheng break; 481269Sericheng } 4825895Syz147064 483269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 484269Sericheng dls_active_clear(dsp->ds_dc); 485269Sericheng 4860Sstevel@tonic-gate goto failed; 487269Sericheng } 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate /* 4900Sstevel@tonic-gate * Copy in MAC address. 4910Sstevel@tonic-gate */ 4923037Syz147064 dlsap_addr_length = dsp->ds_mip->mi_addr_length; 4933037Syz147064 bcopy(dsp->ds_curr_addr, dlsap_addr, dlsap_addr_length); 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate /* 4963037Syz147064 * Copy in the SAP. 4970Sstevel@tonic-gate */ 4985895Syz147064 *(uint16_t *)(dlsap_addr + dlsap_addr_length) = sap; 4993037Syz147064 dlsap_addr_length += sizeof (uint16_t); 5000Sstevel@tonic-gate 5015895Syz147064 rw_enter(&dsp->ds_lock, RW_WRITER); 5025895Syz147064 5030Sstevel@tonic-gate dsp->ds_dlstate = DL_IDLE; 504269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 505269Sericheng dsp->ds_passivestate = DLD_ACTIVE; 5065895Syz147064 dsp->ds_sap = sap; 5075895Syz147064 5085895Syz147064 if (dsp->ds_mode == DLD_FASTPATH) 5095895Syz147064 dsp->ds_tx = str_mdata_fastpath_put; 5105895Syz147064 else if (dsp->ds_mode == DLD_RAW) 5115895Syz147064 dsp->ds_tx = str_mdata_raw_put; 5125895Syz147064 dsp->ds_unitdata_tx = dld_wput_proto_data; 5130Sstevel@tonic-gate 514269Sericheng rw_exit(&dsp->ds_lock); 515269Sericheng 5163037Syz147064 dlbindack(q, mp, sap, dlsap_addr, dlsap_addr_length, 0, 0); 517269Sericheng return (B_TRUE); 5180Sstevel@tonic-gate failed: 519269Sericheng dlerrorack(q, mp, DL_BIND_REQ, dl_err, (t_uscalar_t)err); 520269Sericheng return (B_FALSE); 5210Sstevel@tonic-gate } 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate /* 524269Sericheng * DL_UNBIND_REQ 5250Sstevel@tonic-gate */ 526269Sericheng /*ARGSUSED*/ 5275895Syz147064 static boolean_t 5285895Syz147064 proto_unbind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 5290Sstevel@tonic-gate { 5305895Syz147064 queue_t *q = dsp->ds_wq; 5315895Syz147064 t_uscalar_t dl_err; 532269Sericheng 5335895Syz147064 if (MBLKL(mp) < sizeof (dl_unbind_req_t)) { 5345895Syz147064 dl_err = DL_BADPRIM; 5355895Syz147064 goto failed; 5365895Syz147064 } 5375895Syz147064 5385895Syz147064 if (dsp->ds_dlstate != DL_IDLE) { 5395895Syz147064 dl_err = DL_OUTSTATE; 5405895Syz147064 goto failed; 5415895Syz147064 } 542269Sericheng 543269Sericheng /* 544269Sericheng * Flush any remaining packets scheduled for transmission. 545269Sericheng */ 546269Sericheng dld_tx_flush(dsp); 547269Sericheng 548269Sericheng /* 549269Sericheng * Unbind the channel to stop packets being received. 550269Sericheng */ 551269Sericheng dls_unbind(dsp->ds_dc); 552269Sericheng 553269Sericheng /* 5545895Syz147064 * Clear the receive callback. 5555895Syz147064 */ 5565895Syz147064 dls_rx_set(dsp->ds_dc, NULL, NULL); 5575895Syz147064 5585895Syz147064 rw_enter(&dsp->ds_lock, RW_WRITER); 5595895Syz147064 5605895Syz147064 /* 561269Sericheng * Disable polling mode, if it is enabled. 562269Sericheng */ 563269Sericheng proto_poll_disable(dsp); 564269Sericheng 565269Sericheng /* 5665895Syz147064 * If soft rings were enabled, the workers should be quiesced. 5675895Syz147064 */ 5685895Syz147064 dls_soft_ring_disable(dsp->ds_dc); 5695895Syz147064 5705895Syz147064 /* 5713115Syl150051 * Clear LSO flags. 5723115Syl150051 */ 5733115Syl150051 dsp->ds_lso = B_FALSE; 5743115Syl150051 dsp->ds_lso_max = 0; 5753115Syl150051 5763115Syl150051 /* 577269Sericheng * Set the mode back to the default (unitdata). 578269Sericheng */ 579269Sericheng dsp->ds_mode = DLD_UNITDATA; 5801353Sericheng dsp->ds_dlstate = DL_UNBOUND; 5815895Syz147064 DLD_TX_QUIESCE(dsp); 5825895Syz147064 rw_exit(&dsp->ds_lock); 5831353Sericheng 5845895Syz147064 dlokack(q, mp, DL_UNBIND_REQ); 585269Sericheng 586269Sericheng return (B_TRUE); 587269Sericheng failed: 588269Sericheng dlerrorack(q, mp, DL_UNBIND_REQ, dl_err, 0); 589269Sericheng return (B_FALSE); 5900Sstevel@tonic-gate } 5910Sstevel@tonic-gate 5920Sstevel@tonic-gate /* 593269Sericheng * DL_PROMISCON_REQ 5940Sstevel@tonic-gate */ 595269Sericheng static boolean_t 596269Sericheng proto_promiscon_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 5970Sstevel@tonic-gate { 598269Sericheng dl_promiscon_req_t *dlp = (dl_promiscon_req_t *)udlp; 599269Sericheng int err = 0; 600269Sericheng t_uscalar_t dl_err; 6015895Syz147064 uint32_t promisc; 602269Sericheng queue_t *q = dsp->ds_wq; 603269Sericheng 6045895Syz147064 /* 6055895Syz147064 * Because control message processing is serialized, we don't need 6065895Syz147064 * to hold any locks to read any fields of dsp; we only need ds_lock 6075895Syz147064 * to update the ds_promisc and ds_passivestate fields. 6085895Syz147064 */ 609269Sericheng if (MBLKL(mp) < sizeof (dl_promiscon_req_t)) { 610269Sericheng dl_err = DL_BADPRIM; 611269Sericheng goto failed; 612269Sericheng } 613269Sericheng 614269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 615269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 616269Sericheng dl_err = DL_OUTSTATE; 6170Sstevel@tonic-gate goto failed; 618269Sericheng } 6190Sstevel@tonic-gate 620269Sericheng switch (dlp->dl_level) { 621269Sericheng case DL_PROMISC_SAP: 6225895Syz147064 promisc = DLS_PROMISC_SAP; 623269Sericheng break; 6245895Syz147064 case DL_PROMISC_MULTI: 6255895Syz147064 promisc = DLS_PROMISC_MULTI; 6265895Syz147064 break; 627269Sericheng case DL_PROMISC_PHYS: 6285895Syz147064 promisc = DLS_PROMISC_PHYS; 629269Sericheng break; 630269Sericheng default: 631269Sericheng dl_err = DL_NOTSUPPORTED; 632269Sericheng goto failed; 633269Sericheng } 6340Sstevel@tonic-gate 635269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED && 636269Sericheng !dls_active_set(dsp->ds_dc)) { 637269Sericheng dl_err = DL_SYSERR; 638269Sericheng err = EBUSY; 639269Sericheng goto failed; 640269Sericheng } 641269Sericheng 642269Sericheng /* 643269Sericheng * Adjust channel promiscuity. 644269Sericheng */ 6455895Syz147064 promisc = (dsp->ds_promisc | promisc); 6465895Syz147064 err = dls_promisc(dsp->ds_dc, promisc); 647269Sericheng if (err != 0) { 648269Sericheng dl_err = DL_SYSERR; 649269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 650269Sericheng dls_active_clear(dsp->ds_dc); 651269Sericheng goto failed; 652269Sericheng } 653269Sericheng 6545895Syz147064 rw_enter(&dsp->ds_lock, RW_WRITER); 655269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 656269Sericheng dsp->ds_passivestate = DLD_ACTIVE; 6575895Syz147064 dsp->ds_promisc = promisc; 6585895Syz147064 rw_exit(&dsp->ds_lock); 659269Sericheng 660269Sericheng dlokack(q, mp, DL_PROMISCON_REQ); 661269Sericheng return (B_TRUE); 6620Sstevel@tonic-gate failed: 663269Sericheng dlerrorack(q, mp, DL_PROMISCON_REQ, dl_err, (t_uscalar_t)err); 664269Sericheng return (B_FALSE); 6650Sstevel@tonic-gate } 6660Sstevel@tonic-gate 6670Sstevel@tonic-gate /* 668269Sericheng * DL_PROMISCOFF_REQ 6690Sstevel@tonic-gate */ 670269Sericheng static boolean_t 671269Sericheng proto_promiscoff_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 6720Sstevel@tonic-gate { 673269Sericheng dl_promiscoff_req_t *dlp = (dl_promiscoff_req_t *)udlp; 674269Sericheng int err = 0; 675269Sericheng t_uscalar_t dl_err; 6765895Syz147064 uint32_t promisc; 677269Sericheng queue_t *q = dsp->ds_wq; 678269Sericheng 6795895Syz147064 /* 6805895Syz147064 * Because control messages processing is serialized, we don't need 6815895Syz147064 * to hold any lock to read any field of dsp; we hold ds_lock to 6825895Syz147064 * update the ds_promisc field. 6835895Syz147064 */ 684269Sericheng if (MBLKL(mp) < sizeof (dl_promiscoff_req_t)) { 685269Sericheng dl_err = DL_BADPRIM; 6860Sstevel@tonic-gate goto failed; 687269Sericheng } 6880Sstevel@tonic-gate 689269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 690269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 691269Sericheng dl_err = DL_OUTSTATE; 6920Sstevel@tonic-gate goto failed; 693269Sericheng } 6940Sstevel@tonic-gate 695269Sericheng switch (dlp->dl_level) { 696269Sericheng case DL_PROMISC_SAP: 6975895Syz147064 promisc = DLS_PROMISC_SAP; 6980Sstevel@tonic-gate break; 699269Sericheng case DL_PROMISC_MULTI: 7005895Syz147064 promisc = DLS_PROMISC_MULTI; 701269Sericheng break; 702269Sericheng case DL_PROMISC_PHYS: 7035895Syz147064 promisc = DLS_PROMISC_PHYS; 7040Sstevel@tonic-gate break; 7050Sstevel@tonic-gate default: 706269Sericheng dl_err = DL_NOTSUPPORTED; 707269Sericheng goto failed; 708269Sericheng } 709269Sericheng 7105895Syz147064 if (!(dsp->ds_promisc & promisc)) { 7115895Syz147064 dl_err = DL_NOTENAB; 7125895Syz147064 goto failed; 7135895Syz147064 } 7145895Syz147064 7155895Syz147064 promisc = (dsp->ds_promisc & ~promisc); 7165895Syz147064 err = dls_promisc(dsp->ds_dc, promisc); 717269Sericheng if (err != 0) { 7180Sstevel@tonic-gate dl_err = DL_SYSERR; 719269Sericheng goto failed; 720269Sericheng } 721269Sericheng 7225895Syz147064 rw_enter(&dsp->ds_lock, RW_WRITER); 7235895Syz147064 dsp->ds_promisc = promisc; 724269Sericheng rw_exit(&dsp->ds_lock); 7255895Syz147064 726269Sericheng dlokack(q, mp, DL_PROMISCOFF_REQ); 727269Sericheng return (B_TRUE); 728269Sericheng failed: 729269Sericheng dlerrorack(q, mp, DL_PROMISCOFF_REQ, dl_err, (t_uscalar_t)err); 730269Sericheng return (B_FALSE); 731269Sericheng } 732269Sericheng 733269Sericheng /* 734269Sericheng * DL_ENABMULTI_REQ 735269Sericheng */ 736269Sericheng static boolean_t 737269Sericheng proto_enabmulti_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 738269Sericheng { 739269Sericheng dl_enabmulti_req_t *dlp = (dl_enabmulti_req_t *)udlp; 740269Sericheng int err = 0; 741269Sericheng t_uscalar_t dl_err; 742269Sericheng queue_t *q = dsp->ds_wq; 743269Sericheng 7445895Syz147064 /* 7455895Syz147064 * Because control messages processing is serialized, we don't need 7465895Syz147064 * to hold any lock to read any field of dsp; we hold ds_lock to 7475895Syz147064 * update the ds_passivestate field. 7485895Syz147064 */ 749269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 750269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 751269Sericheng dl_err = DL_OUTSTATE; 752269Sericheng goto failed; 753269Sericheng } 754269Sericheng 755269Sericheng if (MBLKL(mp) < sizeof (dl_enabmulti_req_t) || 756269Sericheng !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) || 757269Sericheng dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) { 758269Sericheng dl_err = DL_BADPRIM; 759269Sericheng goto failed; 760269Sericheng } 761269Sericheng 762269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED && 763269Sericheng !dls_active_set(dsp->ds_dc)) { 764269Sericheng dl_err = DL_SYSERR; 765269Sericheng err = EBUSY; 766269Sericheng goto failed; 7670Sstevel@tonic-gate } 7680Sstevel@tonic-gate 769269Sericheng err = dls_multicst_add(dsp->ds_dc, mp->b_rptr + dlp->dl_addr_offset); 770269Sericheng if (err != 0) { 771269Sericheng switch (err) { 772269Sericheng case EINVAL: 773269Sericheng dl_err = DL_BADADDR; 774269Sericheng err = 0; 775269Sericheng break; 776269Sericheng case ENOSPC: 777269Sericheng dl_err = DL_TOOMANY; 778269Sericheng err = 0; 779269Sericheng break; 780269Sericheng default: 781269Sericheng dl_err = DL_SYSERR; 782269Sericheng break; 783269Sericheng } 7845895Syz147064 785269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 786269Sericheng dls_active_clear(dsp->ds_dc); 787269Sericheng 788269Sericheng goto failed; 789269Sericheng } 790269Sericheng 7915895Syz147064 rw_enter(&dsp->ds_lock, RW_WRITER); 792269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 793269Sericheng dsp->ds_passivestate = DLD_ACTIVE; 7945895Syz147064 rw_exit(&dsp->ds_lock); 795269Sericheng 796269Sericheng dlokack(q, mp, DL_ENABMULTI_REQ); 797269Sericheng return (B_TRUE); 798269Sericheng failed: 799269Sericheng dlerrorack(q, mp, DL_ENABMULTI_REQ, dl_err, (t_uscalar_t)err); 800269Sericheng return (B_FALSE); 801269Sericheng } 802269Sericheng 803269Sericheng /* 804269Sericheng * DL_DISABMULTI_REQ 805269Sericheng */ 806269Sericheng static boolean_t 807269Sericheng proto_disabmulti_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 808269Sericheng { 809269Sericheng dl_disabmulti_req_t *dlp = (dl_disabmulti_req_t *)udlp; 810269Sericheng int err = 0; 811269Sericheng t_uscalar_t dl_err; 812269Sericheng queue_t *q = dsp->ds_wq; 813269Sericheng 8145895Syz147064 /* 8155895Syz147064 * Because control messages processing is serialized, we don't need 8165895Syz147064 * to hold any lock to read any field of dsp. 8175895Syz147064 */ 818269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 819269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 820269Sericheng dl_err = DL_OUTSTATE; 821269Sericheng goto failed; 822269Sericheng } 823269Sericheng 824269Sericheng if (MBLKL(mp) < sizeof (dl_disabmulti_req_t) || 825269Sericheng !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) || 826269Sericheng dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) { 827269Sericheng dl_err = DL_BADPRIM; 828269Sericheng goto failed; 829269Sericheng } 830269Sericheng 831269Sericheng err = dls_multicst_remove(dsp->ds_dc, mp->b_rptr + dlp->dl_addr_offset); 832269Sericheng if (err != 0) { 8335895Syz147064 switch (err) { 834269Sericheng case EINVAL: 835269Sericheng dl_err = DL_BADADDR; 836269Sericheng err = 0; 837269Sericheng break; 838269Sericheng case ENOENT: 839269Sericheng dl_err = DL_NOTENAB; 840269Sericheng err = 0; 841269Sericheng break; 842269Sericheng default: 843269Sericheng dl_err = DL_SYSERR; 844269Sericheng break; 845269Sericheng } 846269Sericheng goto failed; 847269Sericheng } 848269Sericheng 849269Sericheng dlokack(q, mp, DL_DISABMULTI_REQ); 850269Sericheng return (B_TRUE); 851269Sericheng failed: 852269Sericheng dlerrorack(q, mp, DL_DISABMULTI_REQ, dl_err, (t_uscalar_t)err); 853269Sericheng return (B_FALSE); 8540Sstevel@tonic-gate } 8550Sstevel@tonic-gate 8560Sstevel@tonic-gate /* 857269Sericheng * DL_PHYS_ADDR_REQ 8580Sstevel@tonic-gate */ 859269Sericheng static boolean_t 860269Sericheng proto_physaddr_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 8610Sstevel@tonic-gate { 862269Sericheng dl_phys_addr_req_t *dlp = (dl_phys_addr_req_t *)udlp; 863269Sericheng queue_t *q = dsp->ds_wq; 864269Sericheng t_uscalar_t dl_err; 865269Sericheng char *addr; 866269Sericheng uint_t addr_length; 867269Sericheng 868269Sericheng rw_enter(&dsp->ds_lock, RW_READER); 869269Sericheng 870269Sericheng if (MBLKL(mp) < sizeof (dl_phys_addr_req_t)) { 871269Sericheng dl_err = DL_BADPRIM; 872269Sericheng goto failed; 873269Sericheng } 874269Sericheng 875269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 876269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 877269Sericheng dl_err = DL_OUTSTATE; 878269Sericheng goto failed; 879269Sericheng } 8800Sstevel@tonic-gate 881269Sericheng if (dlp->dl_addr_type != DL_CURR_PHYS_ADDR && 882269Sericheng dlp->dl_addr_type != DL_FACT_PHYS_ADDR) { 883269Sericheng dl_err = DL_UNSUPPORTED; 8840Sstevel@tonic-gate goto failed; 885269Sericheng } 8860Sstevel@tonic-gate 887269Sericheng addr_length = dsp->ds_mip->mi_addr_length; 888*6353Sdr146992 if (addr_length > 0) { 889*6353Sdr146992 addr = kmem_alloc(addr_length, KM_NOSLEEP); 890*6353Sdr146992 if (addr == NULL) { 891*6353Sdr146992 rw_exit(&dsp->ds_lock); 892*6353Sdr146992 merror(q, mp, ENOSR); 893*6353Sdr146992 return (B_FALSE); 894*6353Sdr146992 } 8950Sstevel@tonic-gate 896*6353Sdr146992 /* 897*6353Sdr146992 * Copy out the address before we drop the lock; we don't 898*6353Sdr146992 * want to call dlphysaddrack() while holding ds_lock. 899*6353Sdr146992 */ 900*6353Sdr146992 bcopy((dlp->dl_addr_type == DL_CURR_PHYS_ADDR) ? 901*6353Sdr146992 dsp->ds_curr_addr : dsp->ds_fact_addr, addr, addr_length); 902269Sericheng 903*6353Sdr146992 rw_exit(&dsp->ds_lock); 904*6353Sdr146992 dlphysaddrack(q, mp, addr, (t_uscalar_t)addr_length); 905*6353Sdr146992 kmem_free(addr, addr_length); 906*6353Sdr146992 } else { 907*6353Sdr146992 rw_exit(&dsp->ds_lock); 908*6353Sdr146992 dlphysaddrack(q, mp, NULL, 0); 909*6353Sdr146992 } 910269Sericheng return (B_TRUE); 9110Sstevel@tonic-gate failed: 912269Sericheng rw_exit(&dsp->ds_lock); 913269Sericheng dlerrorack(q, mp, DL_PHYS_ADDR_REQ, dl_err, 0); 914269Sericheng return (B_FALSE); 915269Sericheng } 9160Sstevel@tonic-gate 917269Sericheng /* 918269Sericheng * DL_SET_PHYS_ADDR_REQ 919269Sericheng */ 920269Sericheng static boolean_t 921269Sericheng proto_setphysaddr_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 922269Sericheng { 923269Sericheng dl_set_phys_addr_req_t *dlp = (dl_set_phys_addr_req_t *)udlp; 924269Sericheng int err = 0; 925269Sericheng t_uscalar_t dl_err; 926269Sericheng queue_t *q = dsp->ds_wq; 9270Sstevel@tonic-gate 9285895Syz147064 /* 9295895Syz147064 * Because control message processing is serialized, we don't need 9305895Syz147064 * to hold any locks to read any fields of dsp; we only need ds_lock 9315895Syz147064 * to update the ds_passivestate field. 9325895Syz147064 */ 933269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 934269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 935269Sericheng dl_err = DL_OUTSTATE; 936269Sericheng goto failed; 937269Sericheng } 938269Sericheng 939269Sericheng if (MBLKL(mp) < sizeof (dl_set_phys_addr_req_t) || 940269Sericheng !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) || 941269Sericheng dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) { 942269Sericheng dl_err = DL_BADPRIM; 943269Sericheng goto failed; 9440Sstevel@tonic-gate } 9450Sstevel@tonic-gate 946269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED && 947269Sericheng !dls_active_set(dsp->ds_dc)) { 948269Sericheng dl_err = DL_SYSERR; 949269Sericheng err = EBUSY; 950269Sericheng goto failed; 951269Sericheng } 952269Sericheng 953269Sericheng err = mac_unicst_set(dsp->ds_mh, mp->b_rptr + dlp->dl_addr_offset); 954269Sericheng if (err != 0) { 955269Sericheng switch (err) { 956269Sericheng case EINVAL: 957269Sericheng dl_err = DL_BADADDR; 958269Sericheng err = 0; 959269Sericheng break; 960269Sericheng 961269Sericheng default: 962269Sericheng dl_err = DL_SYSERR; 963269Sericheng break; 964269Sericheng } 9655895Syz147064 966269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 967269Sericheng dls_active_clear(dsp->ds_dc); 968269Sericheng 969269Sericheng goto failed; 970269Sericheng } 9715895Syz147064 9725895Syz147064 rw_enter(&dsp->ds_lock, RW_WRITER); 973269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 974269Sericheng dsp->ds_passivestate = DLD_ACTIVE; 9755895Syz147064 rw_exit(&dsp->ds_lock); 976269Sericheng 977269Sericheng dlokack(q, mp, DL_SET_PHYS_ADDR_REQ); 978269Sericheng return (B_TRUE); 979269Sericheng failed: 980269Sericheng dlerrorack(q, mp, DL_SET_PHYS_ADDR_REQ, dl_err, (t_uscalar_t)err); 981269Sericheng return (B_FALSE); 982269Sericheng } 983269Sericheng 984269Sericheng /* 985269Sericheng * DL_UDQOS_REQ 986269Sericheng */ 987269Sericheng static boolean_t 988269Sericheng proto_udqos_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 989269Sericheng { 990269Sericheng dl_udqos_req_t *dlp = (dl_udqos_req_t *)udlp; 991269Sericheng dl_qos_cl_sel1_t *selp; 992269Sericheng int off, len; 993269Sericheng t_uscalar_t dl_err; 994269Sericheng queue_t *q = dsp->ds_wq; 995269Sericheng 996269Sericheng off = dlp->dl_qos_offset; 997269Sericheng len = dlp->dl_qos_length; 998269Sericheng 999269Sericheng if (MBLKL(mp) < sizeof (dl_udqos_req_t) || !MBLKIN(mp, off, len)) { 1000269Sericheng dl_err = DL_BADPRIM; 1001269Sericheng goto failed; 1002269Sericheng } 1003269Sericheng 1004269Sericheng selp = (dl_qos_cl_sel1_t *)(mp->b_rptr + off); 1005269Sericheng if (selp->dl_qos_type != DL_QOS_CL_SEL1) { 1006269Sericheng dl_err = DL_BADQOSTYPE; 1007269Sericheng goto failed; 1008269Sericheng } 1009269Sericheng 10102760Sdg199075 if (selp->dl_priority > (1 << VLAN_PRI_SIZE) - 1 || 1011269Sericheng selp->dl_priority < 0) { 1012269Sericheng dl_err = DL_BADQOSPARAM; 1013269Sericheng goto failed; 1014269Sericheng } 1015269Sericheng 10165895Syz147064 if (dsp->ds_dlstate == DL_UNATTACHED || 10175895Syz147064 DL_ACK_PENDING(dsp->ds_dlstate)) { 10185895Syz147064 dl_err = DL_OUTSTATE; 10195895Syz147064 goto failed; 10205895Syz147064 } 1021269Sericheng 10225895Syz147064 rw_enter(&dsp->ds_lock, RW_WRITER); 10235895Syz147064 dsp->ds_pri = selp->dl_priority; 1024269Sericheng rw_exit(&dsp->ds_lock); 10255895Syz147064 1026269Sericheng dlokack(q, mp, DL_UDQOS_REQ); 1027269Sericheng return (B_TRUE); 1028269Sericheng failed: 1029269Sericheng dlerrorack(q, mp, DL_UDQOS_REQ, dl_err, 0); 1030269Sericheng return (B_FALSE); 10310Sstevel@tonic-gate } 10320Sstevel@tonic-gate 10331184Skrgopi static boolean_t 10341184Skrgopi check_ip_above(queue_t *q) 10351184Skrgopi { 10361184Skrgopi queue_t *next_q; 10371184Skrgopi boolean_t ret = B_TRUE; 10381184Skrgopi 10391184Skrgopi claimstr(q); 10401184Skrgopi next_q = q->q_next; 10411184Skrgopi if (strcmp(next_q->q_qinfo->qi_minfo->mi_idname, "ip") != 0) 10421184Skrgopi ret = B_FALSE; 10431184Skrgopi releasestr(q); 10441184Skrgopi return (ret); 10451184Skrgopi } 10461184Skrgopi 10470Sstevel@tonic-gate /* 1048269Sericheng * DL_CAPABILITY_REQ 10490Sstevel@tonic-gate */ 1050269Sericheng /*ARGSUSED*/ 1051269Sericheng static boolean_t 1052269Sericheng proto_capability_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 10530Sstevel@tonic-gate { 1054269Sericheng dl_capability_req_t *dlp = (dl_capability_req_t *)udlp; 1055269Sericheng dl_capability_sub_t *sp; 1056269Sericheng size_t size, len; 1057269Sericheng offset_t off, end; 1058269Sericheng t_uscalar_t dl_err; 1059269Sericheng queue_t *q = dsp->ds_wq; 1060269Sericheng 10615895Syz147064 rw_enter(&dsp->ds_lock, RW_WRITER); 1062269Sericheng 1063269Sericheng if (MBLKL(mp) < sizeof (dl_capability_req_t)) { 1064269Sericheng dl_err = DL_BADPRIM; 1065269Sericheng goto failed; 1066269Sericheng } 1067269Sericheng 1068269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 1069269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 1070269Sericheng dl_err = DL_OUTSTATE; 1071269Sericheng goto failed; 1072269Sericheng } 1073269Sericheng 1074269Sericheng /* 1075269Sericheng * This request is overloaded. If there are no requested capabilities 1076269Sericheng * then we just want to acknowledge with all the capabilities we 1077269Sericheng * support. Otherwise we enable the set of capabilities requested. 1078269Sericheng */ 1079269Sericheng if (dlp->dl_sub_length == 0) { 1080269Sericheng /* callee drops lock */ 1081269Sericheng return (proto_capability_advertise(dsp, mp)); 1082269Sericheng } 1083269Sericheng 1084269Sericheng if (!MBLKIN(mp, dlp->dl_sub_offset, dlp->dl_sub_length)) { 1085269Sericheng dl_err = DL_BADPRIM; 1086269Sericheng goto failed; 1087269Sericheng } 1088269Sericheng 1089269Sericheng dlp->dl_primitive = DL_CAPABILITY_ACK; 1090269Sericheng 1091269Sericheng off = dlp->dl_sub_offset; 1092269Sericheng len = dlp->dl_sub_length; 10930Sstevel@tonic-gate 10940Sstevel@tonic-gate /* 1095269Sericheng * Walk the list of capabilities to be enabled. 10960Sstevel@tonic-gate */ 1097269Sericheng for (end = off + len; off < end; ) { 1098269Sericheng sp = (dl_capability_sub_t *)(mp->b_rptr + off); 1099269Sericheng size = sizeof (dl_capability_sub_t) + sp->dl_length; 1100269Sericheng 1101269Sericheng if (off + size > end || 1102269Sericheng !IS_P2ALIGNED(off, sizeof (uint32_t))) { 1103269Sericheng dl_err = DL_BADPRIM; 1104269Sericheng goto failed; 1105269Sericheng } 1106269Sericheng 1107269Sericheng switch (sp->dl_cap) { 1108269Sericheng /* 1109269Sericheng * TCP/IP checksum offload to hardware. 1110269Sericheng */ 1111269Sericheng case DL_CAPAB_HCKSUM: { 1112269Sericheng dl_capab_hcksum_t *hcksump; 1113269Sericheng dl_capab_hcksum_t hcksum; 1114269Sericheng 1115269Sericheng hcksump = (dl_capab_hcksum_t *)&sp[1]; 1116269Sericheng /* 1117269Sericheng * Copy for alignment. 1118269Sericheng */ 1119269Sericheng bcopy(hcksump, &hcksum, sizeof (dl_capab_hcksum_t)); 1120269Sericheng dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq); 1121269Sericheng bcopy(&hcksum, hcksump, sizeof (dl_capab_hcksum_t)); 1122269Sericheng break; 1123269Sericheng } 1124269Sericheng 1125269Sericheng /* 11263115Syl150051 * Large segment offload. (LSO) 11273115Syl150051 */ 11283115Syl150051 case DL_CAPAB_LSO: { 11293115Syl150051 dl_capab_lso_t *lsop; 11303115Syl150051 dl_capab_lso_t lso; 11313115Syl150051 11323115Syl150051 lsop = (dl_capab_lso_t *)&sp[1]; 11333115Syl150051 /* 11343115Syl150051 * Copy for alignment. 11353115Syl150051 */ 11363115Syl150051 bcopy(lsop, &lso, sizeof (dl_capab_lso_t)); 11373115Syl150051 dlcapabsetqid(&(lso.lso_mid), dsp->ds_rq); 11383115Syl150051 bcopy(&lso, lsop, sizeof (dl_capab_lso_t)); 11393115Syl150051 break; 11403115Syl150051 } 11413115Syl150051 11423115Syl150051 /* 1143269Sericheng * IP polling interface. 1144269Sericheng */ 1145269Sericheng case DL_CAPAB_POLL: { 11461184Skrgopi dl_capab_dls_t *pollp; 11471184Skrgopi dl_capab_dls_t poll; 1148269Sericheng 11491184Skrgopi pollp = (dl_capab_dls_t *)&sp[1]; 1150269Sericheng /* 1151269Sericheng * Copy for alignment. 1152269Sericheng */ 11531184Skrgopi bcopy(pollp, &poll, sizeof (dl_capab_dls_t)); 1154269Sericheng 11551184Skrgopi switch (poll.dls_flags) { 1156269Sericheng default: 1157269Sericheng /*FALLTHRU*/ 1158269Sericheng case POLL_DISABLE: 1159269Sericheng proto_poll_disable(dsp); 1160269Sericheng break; 1161269Sericheng 1162269Sericheng case POLL_ENABLE: 1163269Sericheng ASSERT(!(dld_opt & DLD_OPT_NO_POLL)); 1164269Sericheng 1165269Sericheng /* 1166269Sericheng * Make sure polling is disabled. 1167269Sericheng */ 1168269Sericheng proto_poll_disable(dsp); 1169269Sericheng 1170269Sericheng /* 11715895Syz147064 * Note that only IP should enable POLL. 1172269Sericheng */ 11731184Skrgopi if (check_ip_above(dsp->ds_rq) && 11741184Skrgopi proto_poll_enable(dsp, &poll)) { 11751184Skrgopi bzero(&poll, sizeof (dl_capab_dls_t)); 11761184Skrgopi poll.dls_flags = POLL_ENABLE; 11775895Syz147064 } else { 11785895Syz147064 bzero(&poll, sizeof (dl_capab_dls_t)); 11795895Syz147064 poll.dls_flags = POLL_DISABLE; 11801184Skrgopi } 1181269Sericheng break; 1182269Sericheng } 1183269Sericheng 11841184Skrgopi dlcapabsetqid(&(poll.dls_mid), dsp->ds_rq); 11851184Skrgopi bcopy(&poll, pollp, sizeof (dl_capab_dls_t)); 11861184Skrgopi break; 11871184Skrgopi } 11881184Skrgopi case DL_CAPAB_SOFT_RING: { 11891184Skrgopi dl_capab_dls_t *soft_ringp; 11901184Skrgopi dl_capab_dls_t soft_ring; 11911184Skrgopi 11921184Skrgopi soft_ringp = (dl_capab_dls_t *)&sp[1]; 11931184Skrgopi /* 11941184Skrgopi * Copy for alignment. 11951184Skrgopi */ 11961184Skrgopi bcopy(soft_ringp, &soft_ring, 11971184Skrgopi sizeof (dl_capab_dls_t)); 11981184Skrgopi 11991184Skrgopi switch (soft_ring.dls_flags) { 12001184Skrgopi default: 12011184Skrgopi /*FALLTHRU*/ 12021184Skrgopi case SOFT_RING_DISABLE: 12031184Skrgopi proto_soft_ring_disable(dsp); 12041184Skrgopi break; 12051184Skrgopi 12061184Skrgopi case SOFT_RING_ENABLE: 12074114Sja97890 ASSERT(!(dld_opt & DLD_OPT_NO_SOFTRING)); 12081184Skrgopi /* 12091184Skrgopi * Make sure soft_ring is disabled. 12101184Skrgopi */ 12111184Skrgopi proto_soft_ring_disable(dsp); 12121184Skrgopi 12131184Skrgopi /* 12145895Syz147064 * Note that only IP can enable soft ring. 12151184Skrgopi */ 12161184Skrgopi if (check_ip_above(dsp->ds_rq) && 12171184Skrgopi proto_soft_ring_enable(dsp, &soft_ring)) { 12181184Skrgopi bzero(&soft_ring, 12191184Skrgopi sizeof (dl_capab_dls_t)); 12205895Syz147064 soft_ring.dls_flags = SOFT_RING_ENABLE; 12211184Skrgopi } else { 12221184Skrgopi bzero(&soft_ring, 12231184Skrgopi sizeof (dl_capab_dls_t)); 12245895Syz147064 soft_ring.dls_flags = SOFT_RING_DISABLE; 12251184Skrgopi } 12261184Skrgopi break; 12271184Skrgopi } 12281184Skrgopi 12291184Skrgopi dlcapabsetqid(&(soft_ring.dls_mid), dsp->ds_rq); 12301184Skrgopi bcopy(&soft_ring, soft_ringp, 12311184Skrgopi sizeof (dl_capab_dls_t)); 1232269Sericheng break; 1233269Sericheng } 1234269Sericheng default: 1235269Sericheng break; 1236269Sericheng } 1237269Sericheng 1238269Sericheng off += size; 1239269Sericheng } 1240269Sericheng rw_exit(&dsp->ds_lock); 1241269Sericheng qreply(q, mp); 1242269Sericheng return (B_TRUE); 1243269Sericheng failed: 1244269Sericheng rw_exit(&dsp->ds_lock); 1245269Sericheng dlerrorack(q, mp, DL_CAPABILITY_REQ, dl_err, 0); 1246269Sericheng return (B_FALSE); 12470Sstevel@tonic-gate } 12480Sstevel@tonic-gate 12490Sstevel@tonic-gate /* 1250269Sericheng * DL_NOTIFY_REQ 12510Sstevel@tonic-gate */ 1252269Sericheng static boolean_t 1253269Sericheng proto_notify_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 12540Sstevel@tonic-gate { 1255269Sericheng dl_notify_req_t *dlp = (dl_notify_req_t *)udlp; 1256269Sericheng t_uscalar_t dl_err; 1257269Sericheng queue_t *q = dsp->ds_wq; 1258269Sericheng uint_t note = 1259269Sericheng DL_NOTE_PROMISC_ON_PHYS | 1260269Sericheng DL_NOTE_PROMISC_OFF_PHYS | 1261269Sericheng DL_NOTE_PHYS_ADDR | 1262269Sericheng DL_NOTE_LINK_UP | 1263269Sericheng DL_NOTE_LINK_DOWN | 12642311Sseb DL_NOTE_CAPAB_RENEG | 12652311Sseb DL_NOTE_SPEED; 12660Sstevel@tonic-gate 12671521Syz147064 rw_enter(&dsp->ds_lock, RW_WRITER); 12681521Syz147064 1269269Sericheng if (MBLKL(mp) < sizeof (dl_notify_req_t)) { 1270269Sericheng dl_err = DL_BADPRIM; 1271269Sericheng goto failed; 1272269Sericheng } 12730Sstevel@tonic-gate 1274269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 1275269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 1276269Sericheng dl_err = DL_OUTSTATE; 1277269Sericheng goto failed; 12780Sstevel@tonic-gate } 12790Sstevel@tonic-gate 12805895Syz147064 note &= ~(mac_no_notification(dsp->ds_mh)); 12815895Syz147064 1282269Sericheng /* 1283269Sericheng * Cache the notifications that are being enabled. 1284269Sericheng */ 1285269Sericheng dsp->ds_notifications = dlp->dl_notifications & note; 1286269Sericheng rw_exit(&dsp->ds_lock); 1287269Sericheng /* 1288269Sericheng * The ACK carries all notifications regardless of which set is 1289269Sericheng * being enabled. 1290269Sericheng */ 1291269Sericheng dlnotifyack(q, mp, note); 1292269Sericheng 1293269Sericheng /* 1294269Sericheng * Solicit DL_NOTIFY_IND messages for each enabled notification. 1295269Sericheng */ 1296269Sericheng rw_enter(&dsp->ds_lock, RW_READER); 1297269Sericheng if (dsp->ds_notifications != 0) { 1298269Sericheng rw_exit(&dsp->ds_lock); 1299269Sericheng dld_str_notify_ind(dsp); 1300269Sericheng } else { 1301269Sericheng rw_exit(&dsp->ds_lock); 1302269Sericheng } 1303269Sericheng return (B_TRUE); 1304269Sericheng failed: 1305269Sericheng rw_exit(&dsp->ds_lock); 1306269Sericheng dlerrorack(q, mp, DL_NOTIFY_REQ, dl_err, 0); 1307269Sericheng return (B_FALSE); 13080Sstevel@tonic-gate } 13090Sstevel@tonic-gate 13100Sstevel@tonic-gate /* 13115895Syz147064 * DL_UNITDATA_REQ 13120Sstevel@tonic-gate */ 13135895Syz147064 void 13145895Syz147064 dld_wput_proto_data(dld_str_t *dsp, mblk_t *mp) 13150Sstevel@tonic-gate { 1316269Sericheng queue_t *q = dsp->ds_wq; 13175895Syz147064 dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr; 1318269Sericheng off_t off; 1319269Sericheng size_t len, size; 1320269Sericheng const uint8_t *addr; 1321269Sericheng uint16_t sap; 1322269Sericheng uint_t addr_length; 13232311Sseb mblk_t *bp, *payload; 1324269Sericheng uint32_t start, stuff, end, value, flags; 1325269Sericheng t_uscalar_t dl_err; 13265903Ssowmini uint_t max_sdu; 1327269Sericheng 1328269Sericheng if (MBLKL(mp) < sizeof (dl_unitdata_req_t) || mp->b_cont == NULL) { 1329269Sericheng dl_err = DL_BADPRIM; 1330269Sericheng goto failed; 1331269Sericheng } 1332269Sericheng 1333269Sericheng addr_length = dsp->ds_mip->mi_addr_length; 1334269Sericheng 1335269Sericheng off = dlp->dl_dest_addr_offset; 1336269Sericheng len = dlp->dl_dest_addr_length; 1337269Sericheng 1338269Sericheng if (!MBLKIN(mp, off, len) || !IS_P2ALIGNED(off, sizeof (uint16_t))) { 1339269Sericheng dl_err = DL_BADPRIM; 1340269Sericheng goto failed; 1341269Sericheng } 1342269Sericheng 1343269Sericheng if (len != addr_length + sizeof (uint16_t)) { 1344269Sericheng dl_err = DL_BADADDR; 1345269Sericheng goto failed; 1346269Sericheng } 1347269Sericheng 1348269Sericheng addr = mp->b_rptr + off; 1349269Sericheng sap = *(uint16_t *)(mp->b_rptr + off + addr_length); 1350269Sericheng 1351269Sericheng /* 1352269Sericheng * Check the length of the packet and the block types. 1353269Sericheng */ 1354269Sericheng size = 0; 13552311Sseb payload = mp->b_cont; 13562311Sseb for (bp = payload; bp != NULL; bp = bp->b_cont) { 1357269Sericheng if (DB_TYPE(bp) != M_DATA) 1358269Sericheng goto baddata; 1359269Sericheng 1360269Sericheng size += MBLKL(bp); 1361269Sericheng } 1362269Sericheng 13635903Ssowmini mac_sdu_get(dsp->ds_mh, NULL, &max_sdu); 13645903Ssowmini if (size > max_sdu) 1365269Sericheng goto baddata; 1366269Sericheng 1367269Sericheng /* 1368269Sericheng * Build a packet header. 1369269Sericheng */ 13702760Sdg199075 if ((bp = dls_header(dsp->ds_dc, addr, sap, dlp->dl_priority.dl_max, 13712760Sdg199075 &payload)) == NULL) { 1372269Sericheng dl_err = DL_BADADDR; 1373269Sericheng goto failed; 1374269Sericheng } 1375269Sericheng 1376269Sericheng /* 1377269Sericheng * We no longer need the M_PROTO header, so free it. 1378269Sericheng */ 1379269Sericheng freeb(mp); 1380269Sericheng 1381269Sericheng /* 1382269Sericheng * Transfer the checksum offload information if it is present. 1383269Sericheng */ 13842311Sseb hcksum_retrieve(payload, NULL, NULL, &start, &stuff, &end, &value, 1385269Sericheng &flags); 13862311Sseb (void) hcksum_assoc(bp, NULL, NULL, start, stuff, end, value, flags, 0); 1387269Sericheng 1388269Sericheng /* 1389269Sericheng * Link the payload onto the new header. 1390269Sericheng */ 1391269Sericheng ASSERT(bp->b_cont == NULL); 13922311Sseb bp->b_cont = payload; 13932760Sdg199075 dld_tx_single(dsp, bp); 13945895Syz147064 return; 1395269Sericheng failed: 1396269Sericheng dlerrorack(q, mp, DL_UNITDATA_REQ, dl_err, 0); 13975895Syz147064 return; 1398269Sericheng 1399269Sericheng baddata: 1400269Sericheng dluderrorind(q, mp, (void *)addr, len, DL_BADDATA, 0); 1401269Sericheng } 1402269Sericheng 1403269Sericheng /* 1404269Sericheng * DL_PASSIVE_REQ 1405269Sericheng */ 1406269Sericheng /* ARGSUSED */ 1407269Sericheng static boolean_t 1408269Sericheng proto_passive_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 1409269Sericheng { 1410269Sericheng t_uscalar_t dl_err; 1411269Sericheng 14125895Syz147064 /* 14135895Syz147064 * READER lock is enough because ds_passivestate can only be changed 14145895Syz147064 * as the result of non-data message processing. 14155895Syz147064 */ 14165895Syz147064 rw_enter(&dsp->ds_lock, RW_READER); 14175895Syz147064 1418269Sericheng /* 1419269Sericheng * If we've already become active by issuing an active primitive, 1420269Sericheng * then it's too late to try to become passive. 1421269Sericheng */ 1422269Sericheng if (dsp->ds_passivestate == DLD_ACTIVE) { 1423269Sericheng dl_err = DL_OUTSTATE; 1424269Sericheng goto failed; 1425269Sericheng } 1426269Sericheng 1427269Sericheng if (MBLKL(mp) < sizeof (dl_passive_req_t)) { 1428269Sericheng dl_err = DL_BADPRIM; 1429269Sericheng goto failed; 1430269Sericheng } 1431269Sericheng 1432269Sericheng dsp->ds_passivestate = DLD_PASSIVE; 1433269Sericheng rw_exit(&dsp->ds_lock); 1434269Sericheng dlokack(dsp->ds_wq, mp, DL_PASSIVE_REQ); 1435269Sericheng return (B_TRUE); 1436269Sericheng failed: 1437269Sericheng rw_exit(&dsp->ds_lock); 1438269Sericheng dlerrorack(dsp->ds_wq, mp, DL_PASSIVE_REQ, dl_err, 0); 1439269Sericheng return (B_FALSE); 1440269Sericheng } 1441269Sericheng 1442269Sericheng /* 1443269Sericheng * Catch-all handler. 1444269Sericheng */ 1445269Sericheng static boolean_t 1446269Sericheng proto_req(dld_str_t *dsp, union DL_primitives *dlp, mblk_t *mp) 1447269Sericheng { 1448269Sericheng dlerrorack(dsp->ds_wq, mp, dlp->dl_primitive, DL_UNSUPPORTED, 0); 1449269Sericheng return (B_FALSE); 14500Sstevel@tonic-gate } 14510Sstevel@tonic-gate 14520Sstevel@tonic-gate static void 14530Sstevel@tonic-gate proto_poll_disable(dld_str_t *dsp) 14540Sstevel@tonic-gate { 14550Sstevel@tonic-gate mac_handle_t mh; 14560Sstevel@tonic-gate 14575895Syz147064 ASSERT(RW_WRITE_HELD(&dsp->ds_lock)); 1458269Sericheng 14590Sstevel@tonic-gate if (!dsp->ds_polling) 14600Sstevel@tonic-gate return; 14610Sstevel@tonic-gate 14620Sstevel@tonic-gate /* 14630Sstevel@tonic-gate * It should be impossible to enable raw mode if polling is turned on. 14640Sstevel@tonic-gate */ 14650Sstevel@tonic-gate ASSERT(dsp->ds_mode != DLD_RAW); 14660Sstevel@tonic-gate 14670Sstevel@tonic-gate /* 14680Sstevel@tonic-gate * Reset the resource_add callback. 14690Sstevel@tonic-gate */ 14700Sstevel@tonic-gate mh = dls_mac(dsp->ds_dc); 14710Sstevel@tonic-gate mac_resource_set(mh, NULL, NULL); 14721184Skrgopi mac_resources(mh); 14730Sstevel@tonic-gate 14740Sstevel@tonic-gate /* 14750Sstevel@tonic-gate * Set receive function back to default. 14760Sstevel@tonic-gate */ 14770Sstevel@tonic-gate dls_rx_set(dsp->ds_dc, (dsp->ds_mode == DLD_FASTPATH) ? 14785895Syz147064 dld_str_rx_fastpath : dld_str_rx_unitdata, dsp); 14790Sstevel@tonic-gate 14800Sstevel@tonic-gate /* 14810Sstevel@tonic-gate * Note that polling is disabled. 14820Sstevel@tonic-gate */ 14830Sstevel@tonic-gate dsp->ds_polling = B_FALSE; 14840Sstevel@tonic-gate } 14850Sstevel@tonic-gate 14860Sstevel@tonic-gate static boolean_t 14871184Skrgopi proto_poll_enable(dld_str_t *dsp, dl_capab_dls_t *pollp) 14880Sstevel@tonic-gate { 14890Sstevel@tonic-gate mac_handle_t mh; 14900Sstevel@tonic-gate 1491269Sericheng ASSERT(RW_WRITE_HELD(&dsp->ds_lock)); 14920Sstevel@tonic-gate ASSERT(!dsp->ds_polling); 14930Sstevel@tonic-gate 14940Sstevel@tonic-gate /* 14950Sstevel@tonic-gate * We cannot enable polling if raw mode 14960Sstevel@tonic-gate * has been enabled. 14970Sstevel@tonic-gate */ 14980Sstevel@tonic-gate if (dsp->ds_mode == DLD_RAW) 14990Sstevel@tonic-gate return (B_FALSE); 15000Sstevel@tonic-gate 15010Sstevel@tonic-gate mh = dls_mac(dsp->ds_dc); 15020Sstevel@tonic-gate 15030Sstevel@tonic-gate /* 15040Sstevel@tonic-gate * Register resources. 15050Sstevel@tonic-gate */ 15061184Skrgopi mac_resource_set(mh, (mac_resource_add_t)pollp->dls_ring_add, 15071184Skrgopi (void *)pollp->dls_rx_handle); 15085895Syz147064 15090Sstevel@tonic-gate mac_resources(mh); 15100Sstevel@tonic-gate 15110Sstevel@tonic-gate /* 15125895Syz147064 * Set the upstream receive function. 15130Sstevel@tonic-gate */ 15141184Skrgopi dls_rx_set(dsp->ds_dc, (dls_rx_t)pollp->dls_rx, 15151184Skrgopi (void *)pollp->dls_rx_handle); 15160Sstevel@tonic-gate 15170Sstevel@tonic-gate /* 15180Sstevel@tonic-gate * Note that polling is enabled. This prevents further DLIOCHDRINFO 15190Sstevel@tonic-gate * ioctls from overwriting the receive function pointer. 15200Sstevel@tonic-gate */ 15210Sstevel@tonic-gate dsp->ds_polling = B_TRUE; 15220Sstevel@tonic-gate return (B_TRUE); 15230Sstevel@tonic-gate } 15240Sstevel@tonic-gate 15251184Skrgopi static void 15261184Skrgopi proto_soft_ring_disable(dld_str_t *dsp) 15271184Skrgopi { 15281184Skrgopi ASSERT(RW_WRITE_HELD(&dsp->ds_lock)); 15291184Skrgopi 15301184Skrgopi if (!dsp->ds_soft_ring) 15311184Skrgopi return; 15321184Skrgopi 15331184Skrgopi /* 15341184Skrgopi * It should be impossible to enable raw mode if soft_ring is turned on. 15351184Skrgopi */ 15361184Skrgopi ASSERT(dsp->ds_mode != DLD_RAW); 15371184Skrgopi proto_change_soft_ring_fanout(dsp, SOFT_RING_NONE); 15381184Skrgopi /* 15391184Skrgopi * Note that fanout is disabled. 15401184Skrgopi */ 15411184Skrgopi dsp->ds_soft_ring = B_FALSE; 15421184Skrgopi } 15431184Skrgopi 15441184Skrgopi static boolean_t 15451184Skrgopi proto_soft_ring_enable(dld_str_t *dsp, dl_capab_dls_t *soft_ringp) 15461184Skrgopi { 15471184Skrgopi ASSERT(RW_WRITE_HELD(&dsp->ds_lock)); 15481184Skrgopi ASSERT(!dsp->ds_soft_ring); 15491184Skrgopi 15501184Skrgopi /* 15511184Skrgopi * We cannot enable soft_ring if raw mode 15521184Skrgopi * has been enabled. 15531184Skrgopi */ 15541184Skrgopi if (dsp->ds_mode == DLD_RAW) 15551184Skrgopi return (B_FALSE); 15561184Skrgopi 15571184Skrgopi if (dls_soft_ring_enable(dsp->ds_dc, soft_ringp) == B_FALSE) 15581184Skrgopi return (B_FALSE); 15591184Skrgopi 15601184Skrgopi dsp->ds_soft_ring = B_TRUE; 15611184Skrgopi return (B_TRUE); 15621184Skrgopi } 15631184Skrgopi 15641184Skrgopi static void 15651184Skrgopi proto_change_soft_ring_fanout(dld_str_t *dsp, int type) 15661184Skrgopi { 15675895Syz147064 dls_channel_t dc = dsp->ds_dc; 15681184Skrgopi 15691184Skrgopi if (type == SOFT_RING_NONE) { 15705895Syz147064 dls_rx_set(dc, (dsp->ds_mode == DLD_FASTPATH) ? 15715895Syz147064 dld_str_rx_fastpath : dld_str_rx_unitdata, dsp); 15725895Syz147064 } else if (type != SOFT_RING_NONE) { 15735895Syz147064 dls_rx_set(dc, (dls_rx_t)dls_soft_ring_fanout, dc); 15741184Skrgopi } 15751184Skrgopi } 15761184Skrgopi 15770Sstevel@tonic-gate /* 15780Sstevel@tonic-gate * DL_CAPABILITY_ACK/DL_ERROR_ACK 15790Sstevel@tonic-gate */ 1580269Sericheng static boolean_t 1581269Sericheng proto_capability_advertise(dld_str_t *dsp, mblk_t *mp) 15820Sstevel@tonic-gate { 15830Sstevel@tonic-gate dl_capability_ack_t *dlap; 15840Sstevel@tonic-gate dl_capability_sub_t *dlsp; 15850Sstevel@tonic-gate size_t subsize; 15861184Skrgopi dl_capab_dls_t poll; 15873115Syl150051 dl_capab_dls_t soft_ring; 15880Sstevel@tonic-gate dl_capab_hcksum_t hcksum; 15893115Syl150051 dl_capab_lso_t lso; 15900Sstevel@tonic-gate dl_capab_zerocopy_t zcopy; 15910Sstevel@tonic-gate uint8_t *ptr; 1592269Sericheng queue_t *q = dsp->ds_wq; 1593269Sericheng mblk_t *mp1; 15945895Syz147064 boolean_t is_vlan = (dsp->ds_vid != VLAN_ID_NONE); 15955895Syz147064 boolean_t poll_capable = B_FALSE; 15965895Syz147064 boolean_t soft_ring_capable = B_FALSE; 15975895Syz147064 boolean_t hcksum_capable = B_FALSE; 15985895Syz147064 boolean_t zcopy_capable = B_FALSE; 15995895Syz147064 boolean_t lso_capable = B_FALSE; 16005895Syz147064 mac_capab_lso_t mac_lso; 1601269Sericheng 16025895Syz147064 ASSERT(RW_WRITE_HELD(&dsp->ds_lock)); 16030Sstevel@tonic-gate 16040Sstevel@tonic-gate /* 16050Sstevel@tonic-gate * Initially assume no capabilities. 16060Sstevel@tonic-gate */ 16070Sstevel@tonic-gate subsize = 0; 16080Sstevel@tonic-gate 16091555Skrgopi /* 16105895Syz147064 * Check if soft ring can be enabled on this interface. Note that we 16115895Syz147064 * do not enable softring on any legacy drivers, because doing that 16125895Syz147064 * would hurt the performance if the legacy driver has its own taskq 16135895Syz147064 * implementation. Further, most high-performance legacy drivers do 16145895Syz147064 * have their own taskq implementation. 16155895Syz147064 * 16165895Syz147064 * If advertising DL_CAPAB_SOFT_RING has not been explicitly disabled, 16175895Syz147064 * reserve space for that capability. 16181555Skrgopi */ 16195895Syz147064 if (!mac_is_legacy(dsp->ds_mh) && !(dld_opt & DLD_OPT_NO_SOFTRING)) { 16205895Syz147064 soft_ring_capable = B_TRUE; 16211555Skrgopi subsize += sizeof (dl_capability_sub_t) + 16225113Syz147064 sizeof (dl_capab_dls_t); 16234114Sja97890 } 16241184Skrgopi 16250Sstevel@tonic-gate /* 16260Sstevel@tonic-gate * Check if polling can be enabled on this interface. 16270Sstevel@tonic-gate * If advertising DL_CAPAB_POLL has not been explicitly disabled 16280Sstevel@tonic-gate * then reserve space for that capability. 16290Sstevel@tonic-gate */ 16305895Syz147064 if (mac_capab_get(dsp->ds_mh, MAC_CAPAB_POLL, NULL) && 16315895Syz147064 !(dld_opt & DLD_OPT_NO_POLL) && !is_vlan) { 16325895Syz147064 poll_capable = B_TRUE; 16330Sstevel@tonic-gate subsize += sizeof (dl_capability_sub_t) + 16341184Skrgopi sizeof (dl_capab_dls_t); 16350Sstevel@tonic-gate } 16360Sstevel@tonic-gate 16370Sstevel@tonic-gate /* 16385895Syz147064 * Check if checksum offload is supported on this MAC. Don't 16395895Syz147064 * advertise DL_CAPAB_HCKSUM if the underlying MAC is VLAN incapable, 16405895Syz147064 * since it might not be able to do the hardware checksum offload 16415895Syz147064 * with the correct offset. 16420Sstevel@tonic-gate */ 16435895Syz147064 bzero(&hcksum, sizeof (dl_capab_hcksum_t)); 16445895Syz147064 if ((!is_vlan || (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_NO_NATIVEVLAN, 16455895Syz147064 NULL))) && mac_capab_get(dsp->ds_mh, MAC_CAPAB_HCKSUM, 16462311Sseb &hcksum.hcksum_txflags)) { 16475895Syz147064 if (hcksum.hcksum_txflags != 0) { 16485895Syz147064 hcksum_capable = B_TRUE; 16495895Syz147064 subsize += sizeof (dl_capability_sub_t) + 16505895Syz147064 sizeof (dl_capab_hcksum_t); 16515895Syz147064 } 16520Sstevel@tonic-gate } 16530Sstevel@tonic-gate 16540Sstevel@tonic-gate /* 16555895Syz147064 * Check if LSO is supported on this MAC, then reserve space for 16565895Syz147064 * the DL_CAPAB_LSO capability. 16573115Syl150051 */ 16585895Syz147064 if (mac_capab_get(dsp->ds_mh, MAC_CAPAB_LSO, &mac_lso)) { 16595895Syz147064 lso_capable = B_TRUE; 16603115Syl150051 subsize += sizeof (dl_capability_sub_t) + 16613115Syl150051 sizeof (dl_capab_lso_t); 16623115Syl150051 } 16633115Syl150051 16643115Syl150051 /* 16655895Syz147064 * Check if zerocopy is supported on this interface. 16665895Syz147064 * If advertising DL_CAPAB_ZEROCOPY has not been explicitly disabled 16675895Syz147064 * then reserve space for that capability. 16680Sstevel@tonic-gate */ 16695895Syz147064 if (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_NO_ZCOPY, NULL) && 16705895Syz147064 !(dld_opt & DLD_OPT_NO_ZEROCOPY)) { 16715895Syz147064 zcopy_capable = B_TRUE; 16720Sstevel@tonic-gate subsize += sizeof (dl_capability_sub_t) + 16730Sstevel@tonic-gate sizeof (dl_capab_zerocopy_t); 16740Sstevel@tonic-gate } 16750Sstevel@tonic-gate 16760Sstevel@tonic-gate /* 1677269Sericheng * If there are no capabilities to advertise or if we 1678269Sericheng * can't allocate a response, send a DL_ERROR_ACK. 16790Sstevel@tonic-gate */ 16801184Skrgopi if ((mp1 = reallocb(mp, 1681269Sericheng sizeof (dl_capability_ack_t) + subsize, 0)) == NULL) { 1682269Sericheng rw_exit(&dsp->ds_lock); 1683269Sericheng dlerrorack(q, mp, DL_CAPABILITY_REQ, DL_NOTSUPPORTED, 0); 1684269Sericheng return (B_FALSE); 16850Sstevel@tonic-gate } 16860Sstevel@tonic-gate 1687269Sericheng mp = mp1; 1688269Sericheng DB_TYPE(mp) = M_PROTO; 1689269Sericheng mp->b_wptr = mp->b_rptr + sizeof (dl_capability_ack_t) + subsize; 1690269Sericheng bzero(mp->b_rptr, MBLKL(mp)); 16910Sstevel@tonic-gate dlap = (dl_capability_ack_t *)mp->b_rptr; 16920Sstevel@tonic-gate dlap->dl_primitive = DL_CAPABILITY_ACK; 16930Sstevel@tonic-gate dlap->dl_sub_offset = sizeof (dl_capability_ack_t); 16940Sstevel@tonic-gate dlap->dl_sub_length = subsize; 16950Sstevel@tonic-gate ptr = (uint8_t *)&dlap[1]; 16960Sstevel@tonic-gate 16970Sstevel@tonic-gate /* 16980Sstevel@tonic-gate * IP polling interface. 16990Sstevel@tonic-gate */ 17005895Syz147064 if (poll_capable) { 17010Sstevel@tonic-gate /* 1702269Sericheng * Attempt to disable just in case this is a re-negotiation; 17035895Syz147064 * READER lock is enough because ds_polling can only be 17045895Syz147064 * changed as the result of non-data message processing. 1705269Sericheng */ 17065895Syz147064 proto_poll_disable(dsp); 17070Sstevel@tonic-gate 17085895Syz147064 dlsp = (dl_capability_sub_t *)ptr; 17090Sstevel@tonic-gate 17105895Syz147064 dlsp->dl_cap = DL_CAPAB_POLL; 17115895Syz147064 dlsp->dl_length = sizeof (dl_capab_dls_t); 17125895Syz147064 ptr += sizeof (dl_capability_sub_t); 1713269Sericheng 17145895Syz147064 bzero(&poll, sizeof (dl_capab_dls_t)); 17155895Syz147064 poll.dls_version = POLL_VERSION_1; 17165895Syz147064 poll.dls_flags = POLL_CAPABLE; 17175895Syz147064 poll.dls_tx_handle = (uintptr_t)dsp; 17185895Syz147064 poll.dls_tx = (uintptr_t)str_mdata_fastpath_put; 17195895Syz147064 dlcapabsetqid(&(poll.dls_mid), dsp->ds_rq); 17205895Syz147064 bcopy(&poll, ptr, sizeof (dl_capab_dls_t)); 17215895Syz147064 ptr += sizeof (dl_capab_dls_t); 17220Sstevel@tonic-gate } 17230Sstevel@tonic-gate 1724269Sericheng 17255895Syz147064 if (soft_ring_capable) { 17261555Skrgopi dlsp = (dl_capability_sub_t *)ptr; 17271184Skrgopi 17281555Skrgopi dlsp->dl_cap = DL_CAPAB_SOFT_RING; 17291555Skrgopi dlsp->dl_length = sizeof (dl_capab_dls_t); 17301555Skrgopi ptr += sizeof (dl_capability_sub_t); 17311184Skrgopi 17321555Skrgopi bzero(&soft_ring, sizeof (dl_capab_dls_t)); 17331555Skrgopi soft_ring.dls_version = SOFT_RING_VERSION_1; 17341555Skrgopi soft_ring.dls_flags = SOFT_RING_CAPABLE; 17351555Skrgopi soft_ring.dls_tx_handle = (uintptr_t)dsp; 17361555Skrgopi soft_ring.dls_tx = (uintptr_t)str_mdata_fastpath_put; 17371555Skrgopi soft_ring.dls_ring_change_status = 17381555Skrgopi (uintptr_t)proto_change_soft_ring_fanout; 17391555Skrgopi soft_ring.dls_ring_bind = (uintptr_t)soft_ring_bind; 17401555Skrgopi soft_ring.dls_ring_unbind = (uintptr_t)soft_ring_unbind; 17411184Skrgopi 17421555Skrgopi dlcapabsetqid(&(soft_ring.dls_mid), dsp->ds_rq); 17431555Skrgopi bcopy(&soft_ring, ptr, sizeof (dl_capab_dls_t)); 17441555Skrgopi ptr += sizeof (dl_capab_dls_t); 17451555Skrgopi } 17461184Skrgopi 17470Sstevel@tonic-gate /* 17480Sstevel@tonic-gate * TCP/IP checksum offload. 17490Sstevel@tonic-gate */ 17505895Syz147064 if (hcksum_capable) { 17510Sstevel@tonic-gate dlsp = (dl_capability_sub_t *)ptr; 17520Sstevel@tonic-gate 17530Sstevel@tonic-gate dlsp->dl_cap = DL_CAPAB_HCKSUM; 17540Sstevel@tonic-gate dlsp->dl_length = sizeof (dl_capab_hcksum_t); 17550Sstevel@tonic-gate ptr += sizeof (dl_capability_sub_t); 17560Sstevel@tonic-gate 17570Sstevel@tonic-gate hcksum.hcksum_version = HCKSUM_VERSION_1; 17580Sstevel@tonic-gate dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq); 17590Sstevel@tonic-gate bcopy(&hcksum, ptr, sizeof (dl_capab_hcksum_t)); 17600Sstevel@tonic-gate ptr += sizeof (dl_capab_hcksum_t); 17610Sstevel@tonic-gate } 17620Sstevel@tonic-gate 17630Sstevel@tonic-gate /* 17643115Syl150051 * Large segment offload. (LSO) 17653115Syl150051 */ 17665895Syz147064 if (lso_capable) { 17673115Syl150051 dlsp = (dl_capability_sub_t *)ptr; 17683115Syl150051 17693115Syl150051 dlsp->dl_cap = DL_CAPAB_LSO; 17703115Syl150051 dlsp->dl_length = sizeof (dl_capab_lso_t); 17713115Syl150051 ptr += sizeof (dl_capability_sub_t); 17723115Syl150051 17733115Syl150051 lso.lso_version = LSO_VERSION_1; 17743115Syl150051 lso.lso_flags = mac_lso.lso_flags; 17753115Syl150051 lso.lso_max = mac_lso.lso_basic_tcp_ipv4.lso_max; 17763115Syl150051 17773115Syl150051 /* Simply enable LSO with DLD */ 17783115Syl150051 dsp->ds_lso = B_TRUE; 17793115Syl150051 dsp->ds_lso_max = lso.lso_max; 17803115Syl150051 17813115Syl150051 dlcapabsetqid(&(lso.lso_mid), dsp->ds_rq); 17823115Syl150051 bcopy(&lso, ptr, sizeof (dl_capab_lso_t)); 17833115Syl150051 ptr += sizeof (dl_capab_lso_t); 17843115Syl150051 } else { 17853115Syl150051 dsp->ds_lso = B_FALSE; 17863115Syl150051 dsp->ds_lso_max = 0; 17873115Syl150051 } 17883115Syl150051 17893115Syl150051 /* 17900Sstevel@tonic-gate * Zero copy 17910Sstevel@tonic-gate */ 17925895Syz147064 if (zcopy_capable) { 17930Sstevel@tonic-gate dlsp = (dl_capability_sub_t *)ptr; 17940Sstevel@tonic-gate 17950Sstevel@tonic-gate dlsp->dl_cap = DL_CAPAB_ZEROCOPY; 17960Sstevel@tonic-gate dlsp->dl_length = sizeof (dl_capab_zerocopy_t); 17970Sstevel@tonic-gate ptr += sizeof (dl_capability_sub_t); 17980Sstevel@tonic-gate 17990Sstevel@tonic-gate bzero(&zcopy, sizeof (dl_capab_zerocopy_t)); 18000Sstevel@tonic-gate zcopy.zerocopy_version = ZEROCOPY_VERSION_1; 18010Sstevel@tonic-gate zcopy.zerocopy_flags = DL_CAPAB_VMSAFE_MEM; 18020Sstevel@tonic-gate 18030Sstevel@tonic-gate dlcapabsetqid(&(zcopy.zerocopy_mid), dsp->ds_rq); 18040Sstevel@tonic-gate bcopy(&zcopy, ptr, sizeof (dl_capab_zerocopy_t)); 18050Sstevel@tonic-gate ptr += sizeof (dl_capab_zerocopy_t); 18060Sstevel@tonic-gate } 18070Sstevel@tonic-gate 18080Sstevel@tonic-gate ASSERT(ptr == mp->b_rptr + sizeof (dl_capability_ack_t) + subsize); 1809269Sericheng 1810269Sericheng rw_exit(&dsp->ds_lock); 1811269Sericheng qreply(q, mp); 1812269Sericheng return (B_TRUE); 18130Sstevel@tonic-gate } 18145113Syz147064 18155113Syz147064 /* 18165113Syz147064 * Disable any enabled capabilities. 18175113Syz147064 */ 18185113Syz147064 void 18195113Syz147064 dld_capabilities_disable(dld_str_t *dsp) 18205113Syz147064 { 18215113Syz147064 if (dsp->ds_polling) 18225113Syz147064 proto_poll_disable(dsp); 18235113Syz147064 18245113Syz147064 if (dsp->ds_soft_ring) 18255113Syz147064 proto_soft_ring_disable(dsp); 18265113Syz147064 } 1827