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 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * Data-Link Driver 310Sstevel@tonic-gate */ 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include <sys/types.h> 340Sstevel@tonic-gate #include <sys/debug.h> 350Sstevel@tonic-gate #include <sys/sysmacros.h> 360Sstevel@tonic-gate #include <sys/stream.h> 370Sstevel@tonic-gate #include <sys/ddi.h> 380Sstevel@tonic-gate #include <sys/sunddi.h> 390Sstevel@tonic-gate #include <sys/strsun.h> 40*1184Skrgopi #include <sys/cpuvar.h> 410Sstevel@tonic-gate #include <sys/dlpi.h> 420Sstevel@tonic-gate #include <netinet/in.h> 430Sstevel@tonic-gate #include <sys/sdt.h> 440Sstevel@tonic-gate #include <sys/strsubr.h> 450Sstevel@tonic-gate #include <sys/vlan.h> 460Sstevel@tonic-gate #include <sys/mac.h> 470Sstevel@tonic-gate #include <sys/dls.h> 480Sstevel@tonic-gate #include <sys/dld.h> 490Sstevel@tonic-gate #include <sys/dld_impl.h> 50*1184Skrgopi #include <sys/dls_soft_ring.h> 510Sstevel@tonic-gate 520Sstevel@tonic-gate typedef boolean_t proto_reqfunc_t(dld_str_t *, union DL_primitives *, mblk_t *); 530Sstevel@tonic-gate 540Sstevel@tonic-gate static proto_reqfunc_t proto_info_req, proto_attach_req, proto_detach_req, 550Sstevel@tonic-gate proto_bind_req, proto_unbind_req, proto_promiscon_req, proto_promiscoff_req, 560Sstevel@tonic-gate proto_enabmulti_req, proto_disabmulti_req, proto_physaddr_req, 570Sstevel@tonic-gate proto_setphysaddr_req, proto_udqos_req, proto_req, proto_capability_req, 580Sstevel@tonic-gate proto_notify_req, proto_unitdata_req, proto_passive_req; 590Sstevel@tonic-gate 60269Sericheng static void proto_poll_disable(dld_str_t *); 61*1184Skrgopi static boolean_t proto_poll_enable(dld_str_t *, dl_capab_dls_t *); 62269Sericheng static boolean_t proto_capability_advertise(dld_str_t *, mblk_t *); 630Sstevel@tonic-gate 64*1184Skrgopi static void proto_soft_ring_disable(dld_str_t *); 65*1184Skrgopi static boolean_t proto_soft_ring_enable(dld_str_t *, dl_capab_dls_t *); 66*1184Skrgopi static boolean_t proto_capability_advertise(dld_str_t *, mblk_t *); 67*1184Skrgopi static void proto_change_soft_ring_fanout(dld_str_t *, int); 68*1184Skrgopi static void proto_stop_soft_ring_threads(void *); 69*1184Skrgopi 700Sstevel@tonic-gate #define DL_ACK_PENDING(state) \ 710Sstevel@tonic-gate ((state) == DL_ATTACH_PENDING || \ 720Sstevel@tonic-gate (state) == DL_DETACH_PENDING || \ 730Sstevel@tonic-gate (state) == DL_BIND_PENDING || \ 740Sstevel@tonic-gate (state) == DL_UNBIND_PENDING) 750Sstevel@tonic-gate 760Sstevel@tonic-gate /* 77269Sericheng * Process a DLPI protocol message. 78269Sericheng * The primitives DL_BIND_REQ, DL_ENABMULTI_REQ, DL_PROMISCON_REQ, 79269Sericheng * DL_SET_PHYS_ADDR_REQ put the data link below our dld_str_t into an 80269Sericheng * 'active' state. The primitive DL_PASSIVE_REQ marks our dld_str_t 81269Sericheng * as 'passive' and forbids it from being subsequently made 'active' 82269Sericheng * by the above primitives. 830Sstevel@tonic-gate */ 840Sstevel@tonic-gate void 850Sstevel@tonic-gate dld_proto(dld_str_t *dsp, mblk_t *mp) 860Sstevel@tonic-gate { 870Sstevel@tonic-gate union DL_primitives *udlp; 880Sstevel@tonic-gate t_uscalar_t prim; 890Sstevel@tonic-gate 900Sstevel@tonic-gate if (MBLKL(mp) < sizeof (t_uscalar_t)) { 910Sstevel@tonic-gate freemsg(mp); 920Sstevel@tonic-gate return; 930Sstevel@tonic-gate } 940Sstevel@tonic-gate 950Sstevel@tonic-gate udlp = (union DL_primitives *)mp->b_rptr; 960Sstevel@tonic-gate prim = udlp->dl_primitive; 970Sstevel@tonic-gate 98269Sericheng switch (prim) { 99269Sericheng case DL_INFO_REQ: 100269Sericheng (void) proto_info_req(dsp, udlp, mp); 101269Sericheng break; 102269Sericheng case DL_BIND_REQ: 103269Sericheng (void) proto_bind_req(dsp, udlp, mp); 104269Sericheng break; 105269Sericheng case DL_UNBIND_REQ: 106269Sericheng (void) proto_unbind_req(dsp, udlp, mp); 107269Sericheng break; 108269Sericheng case DL_UNITDATA_REQ: 109269Sericheng (void) proto_unitdata_req(dsp, udlp, mp); 110269Sericheng break; 111269Sericheng case DL_UDQOS_REQ: 112269Sericheng (void) proto_udqos_req(dsp, udlp, mp); 113269Sericheng break; 114269Sericheng case DL_ATTACH_REQ: 115269Sericheng (void) proto_attach_req(dsp, udlp, mp); 116269Sericheng break; 117269Sericheng case DL_DETACH_REQ: 118269Sericheng (void) proto_detach_req(dsp, udlp, mp); 119269Sericheng break; 120269Sericheng case DL_ENABMULTI_REQ: 121269Sericheng (void) proto_enabmulti_req(dsp, udlp, mp); 122269Sericheng break; 123269Sericheng case DL_DISABMULTI_REQ: 124269Sericheng (void) proto_disabmulti_req(dsp, udlp, mp); 125269Sericheng break; 126269Sericheng case DL_PROMISCON_REQ: 127269Sericheng (void) proto_promiscon_req(dsp, udlp, mp); 128269Sericheng break; 129269Sericheng case DL_PROMISCOFF_REQ: 130269Sericheng (void) proto_promiscoff_req(dsp, udlp, mp); 131269Sericheng break; 132269Sericheng case DL_PHYS_ADDR_REQ: 133269Sericheng (void) proto_physaddr_req(dsp, udlp, mp); 134269Sericheng break; 135269Sericheng case DL_SET_PHYS_ADDR_REQ: 136269Sericheng (void) proto_setphysaddr_req(dsp, udlp, mp); 137269Sericheng break; 138269Sericheng case DL_NOTIFY_REQ: 139269Sericheng (void) proto_notify_req(dsp, udlp, mp); 140269Sericheng break; 141269Sericheng case DL_CAPABILITY_REQ: 142269Sericheng (void) proto_capability_req(dsp, udlp, mp); 143269Sericheng break; 144269Sericheng case DL_PASSIVE_REQ: 145269Sericheng (void) proto_passive_req(dsp, udlp, mp); 146269Sericheng break; 147269Sericheng default: 148269Sericheng (void) proto_req(dsp, udlp, mp); 149269Sericheng break; 1500Sstevel@tonic-gate } 1510Sstevel@tonic-gate } 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate /* 154269Sericheng * Finish any pending operations. At this moment we are single-threaded, 155269Sericheng * hence there is no need to hold ds_lock as writer because we're already 156269Sericheng * exclusive. 1570Sstevel@tonic-gate */ 158269Sericheng void 159269Sericheng dld_finish_pending_ops(dld_str_t *dsp) 1600Sstevel@tonic-gate { 161269Sericheng ASSERT(MUTEX_HELD(&dsp->ds_thr_lock)); 162269Sericheng ASSERT(dsp->ds_thr == 0); 1630Sstevel@tonic-gate 164269Sericheng /* Pending DL_DETACH_REQ? */ 165269Sericheng if (dsp->ds_detach_req != NULL) { 166269Sericheng mblk_t *mp; 1670Sstevel@tonic-gate 168269Sericheng ASSERT(dsp->ds_dlstate == DL_DETACH_PENDING); 169269Sericheng dld_str_detach(dsp); 1700Sstevel@tonic-gate 171269Sericheng mp = dsp->ds_detach_req; 172269Sericheng dsp->ds_detach_req = NULL; 1730Sstevel@tonic-gate 174269Sericheng mutex_exit(&dsp->ds_thr_lock); 175269Sericheng dlokack(dsp->ds_wq, mp, DL_DETACH_REQ); 176269Sericheng } else { 177269Sericheng mutex_exit(&dsp->ds_thr_lock); 1780Sstevel@tonic-gate } 1790Sstevel@tonic-gate } 1800Sstevel@tonic-gate 181269Sericheng #define NEG(x) -(x) 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate typedef struct dl_info_ack_wrapper { 1840Sstevel@tonic-gate dl_info_ack_t dl_info; 1850Sstevel@tonic-gate uint8_t dl_addr[MAXADDRLEN + sizeof (uint16_t)]; 1860Sstevel@tonic-gate uint8_t dl_brdcst_addr[MAXADDRLEN]; 1870Sstevel@tonic-gate dl_qos_cl_range1_t dl_qos_range1; 1880Sstevel@tonic-gate dl_qos_cl_sel1_t dl_qos_sel1; 1890Sstevel@tonic-gate } dl_info_ack_wrapper_t; 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate /* 192269Sericheng * DL_INFO_REQ 1930Sstevel@tonic-gate */ 194269Sericheng /*ARGSUSED*/ 195269Sericheng static boolean_t 196269Sericheng proto_info_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 1970Sstevel@tonic-gate { 1980Sstevel@tonic-gate dl_info_ack_wrapper_t *dlwp; 1990Sstevel@tonic-gate dl_info_ack_t *dlp; 2000Sstevel@tonic-gate dl_qos_cl_sel1_t *selp; 2010Sstevel@tonic-gate dl_qos_cl_range1_t *rangep; 2020Sstevel@tonic-gate uint8_t *addr; 2030Sstevel@tonic-gate uint8_t *brdcst_addr; 2040Sstevel@tonic-gate uint_t addr_length; 2050Sstevel@tonic-gate uint_t sap_length; 206269Sericheng mac_info_t minfo; 207269Sericheng mac_info_t *minfop; 208269Sericheng queue_t *q = dsp->ds_wq; 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate /* 2110Sstevel@tonic-gate * Swap the request message for one large enough to contain the 2120Sstevel@tonic-gate * wrapper structure defined above. 2130Sstevel@tonic-gate */ 214269Sericheng if ((mp = mexchange(q, mp, sizeof (dl_info_ack_wrapper_t), 2150Sstevel@tonic-gate M_PCPROTO, 0)) == NULL) 216269Sericheng return (B_FALSE); 217269Sericheng 218269Sericheng rw_enter(&dsp->ds_lock, RW_READER); 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate bzero(mp->b_rptr, sizeof (dl_info_ack_wrapper_t)); 2210Sstevel@tonic-gate dlwp = (dl_info_ack_wrapper_t *)mp->b_rptr; 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate dlp = &(dlwp->dl_info); 2240Sstevel@tonic-gate ASSERT(dlp == (dl_info_ack_t *)mp->b_rptr); 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate dlp->dl_primitive = DL_INFO_ACK; 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate /* 2290Sstevel@tonic-gate * Set up the sub-structure pointers. 2300Sstevel@tonic-gate */ 2310Sstevel@tonic-gate addr = dlwp->dl_addr; 2320Sstevel@tonic-gate brdcst_addr = dlwp->dl_brdcst_addr; 2330Sstevel@tonic-gate rangep = &(dlwp->dl_qos_range1); 2340Sstevel@tonic-gate selp = &(dlwp->dl_qos_sel1); 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate /* 2370Sstevel@tonic-gate * This driver supports only version 2 connectionless DLPI provider 2380Sstevel@tonic-gate * nodes. 2390Sstevel@tonic-gate */ 2400Sstevel@tonic-gate dlp->dl_service_mode = DL_CLDLS; 2410Sstevel@tonic-gate dlp->dl_version = DL_VERSION_2; 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate /* 244269Sericheng * Set the style of the provider 2450Sstevel@tonic-gate */ 246269Sericheng dlp->dl_provider_style = dsp->ds_style; 2470Sstevel@tonic-gate ASSERT(dlp->dl_provider_style == DL_STYLE1 || 2480Sstevel@tonic-gate dlp->dl_provider_style == DL_STYLE2); 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate /* 2510Sstevel@tonic-gate * Set the current DLPI state. 2520Sstevel@tonic-gate */ 2530Sstevel@tonic-gate dlp->dl_current_state = dsp->ds_dlstate; 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate /* 256269Sericheng * Gratuitously set the media type. This is to deal with modules 257269Sericheng * that assume the media type is known prior to DL_ATTACH_REQ 2580Sstevel@tonic-gate * being completed. 2590Sstevel@tonic-gate */ 2600Sstevel@tonic-gate dlp->dl_mac_type = DL_ETHER; 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate /* 263269Sericheng * If the stream is not at least attached we try to retrieve the 264269Sericheng * mac_info using mac_info_get() 2650Sstevel@tonic-gate */ 2660Sstevel@tonic-gate if (dsp->ds_dlstate == DL_UNATTACHED || 2670Sstevel@tonic-gate dsp->ds_dlstate == DL_ATTACH_PENDING || 268269Sericheng dsp->ds_dlstate == DL_DETACH_PENDING) { 269269Sericheng if (!mac_info_get(ddi_major_to_name(dsp->ds_major), &minfo)) { 270269Sericheng /* 271269Sericheng * Cannot find mac_info. giving up. 272269Sericheng */ 273269Sericheng goto done; 274269Sericheng } 275269Sericheng minfop = &minfo; 276269Sericheng } else { 277269Sericheng minfop = (mac_info_t *)dsp->ds_mip; 278269Sericheng } 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate /* 2810Sstevel@tonic-gate * Set the media type (properly this time). 2820Sstevel@tonic-gate */ 283269Sericheng dlp->dl_mac_type = minfop->mi_media; 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate /* 2860Sstevel@tonic-gate * Set the DLSAP length. We only support 16 bit values and they 2870Sstevel@tonic-gate * appear after the MAC address portion of DLSAP addresses. 2880Sstevel@tonic-gate */ 2890Sstevel@tonic-gate sap_length = sizeof (uint16_t); 2900Sstevel@tonic-gate dlp->dl_sap_length = NEG(sap_length); 2910Sstevel@tonic-gate 2920Sstevel@tonic-gate /* 2930Sstevel@tonic-gate * Set the minimum and maximum payload sizes. 2940Sstevel@tonic-gate */ 295269Sericheng dlp->dl_min_sdu = minfop->mi_sdu_min; 296269Sericheng dlp->dl_max_sdu = minfop->mi_sdu_max; 2970Sstevel@tonic-gate 298269Sericheng addr_length = minfop->mi_addr_length; 2990Sstevel@tonic-gate ASSERT(addr_length != 0); 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate /* 3020Sstevel@tonic-gate * Copy in the media broadcast address. 3030Sstevel@tonic-gate */ 3040Sstevel@tonic-gate dlp->dl_brdcst_addr_offset = (uintptr_t)brdcst_addr - (uintptr_t)dlp; 305269Sericheng bcopy(minfop->mi_brdcst_addr, brdcst_addr, addr_length); 3060Sstevel@tonic-gate dlp->dl_brdcst_addr_length = addr_length; 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate /* 3090Sstevel@tonic-gate * We only support QoS information for VLAN interfaces. 3100Sstevel@tonic-gate */ 3110Sstevel@tonic-gate if (dsp->ds_vid != VLAN_ID_NONE) { 3120Sstevel@tonic-gate dlp->dl_qos_range_offset = (uintptr_t)rangep - (uintptr_t)dlp; 3130Sstevel@tonic-gate dlp->dl_qos_range_length = sizeof (dl_qos_cl_range1_t); 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate rangep->dl_qos_type = DL_QOS_CL_RANGE1; 3160Sstevel@tonic-gate rangep->dl_trans_delay.dl_target_value = DL_UNKNOWN; 3170Sstevel@tonic-gate rangep->dl_trans_delay.dl_accept_value = DL_UNKNOWN; 3180Sstevel@tonic-gate rangep->dl_protection.dl_min = DL_UNKNOWN; 3190Sstevel@tonic-gate rangep->dl_protection.dl_max = DL_UNKNOWN; 3200Sstevel@tonic-gate rangep->dl_residual_error = DL_UNKNOWN; 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate /* 3230Sstevel@tonic-gate * Specify the supported range of priorities. 3240Sstevel@tonic-gate */ 3250Sstevel@tonic-gate rangep->dl_priority.dl_min = 0; 3260Sstevel@tonic-gate rangep->dl_priority.dl_max = (1 << VLAN_PRI_SIZE) - 1; 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate dlp->dl_qos_offset = (uintptr_t)selp - (uintptr_t)dlp; 3290Sstevel@tonic-gate dlp->dl_qos_length = sizeof (dl_qos_cl_sel1_t); 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate selp->dl_qos_type = DL_QOS_CL_SEL1; 3320Sstevel@tonic-gate selp->dl_trans_delay = DL_UNKNOWN; 3330Sstevel@tonic-gate selp->dl_protection = DL_UNKNOWN; 3340Sstevel@tonic-gate selp->dl_residual_error = DL_UNKNOWN; 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate /* 3370Sstevel@tonic-gate * Specify the current priority (which can be changed by 3380Sstevel@tonic-gate * the DL_UDQOS_REQ primitive). 3390Sstevel@tonic-gate */ 3400Sstevel@tonic-gate selp->dl_priority = dsp->ds_pri; 3410Sstevel@tonic-gate } else { 3420Sstevel@tonic-gate /* 3430Sstevel@tonic-gate * Shorten the buffer to lose the unused QoS information 344269Sericheng * structures. 3450Sstevel@tonic-gate */ 3460Sstevel@tonic-gate mp->b_wptr = (uint8_t *)rangep; 3470Sstevel@tonic-gate } 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate dlp->dl_addr_length = addr_length + sizeof (uint16_t); 3500Sstevel@tonic-gate if (dsp->ds_dlstate == DL_IDLE) { 3510Sstevel@tonic-gate /* 3520Sstevel@tonic-gate * The stream is bound. Therefore we can formulate a valid 3530Sstevel@tonic-gate * DLSAP address. 3540Sstevel@tonic-gate */ 3550Sstevel@tonic-gate dlp->dl_addr_offset = (uintptr_t)addr - (uintptr_t)dlp; 3560Sstevel@tonic-gate bcopy(dsp->ds_curr_addr, addr, addr_length); 3570Sstevel@tonic-gate *(uint16_t *)(addr + addr_length) = dsp->ds_sap; 3580Sstevel@tonic-gate } 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate done: 3610Sstevel@tonic-gate ASSERT(IMPLY(dlp->dl_qos_offset != 0, dlp->dl_qos_length != 0)); 3620Sstevel@tonic-gate ASSERT(IMPLY(dlp->dl_qos_range_offset != 0, 3630Sstevel@tonic-gate dlp->dl_qos_range_length != 0)); 3640Sstevel@tonic-gate ASSERT(IMPLY(dlp->dl_addr_offset != 0, dlp->dl_addr_length != 0)); 3650Sstevel@tonic-gate ASSERT(IMPLY(dlp->dl_brdcst_addr_offset != 0, 3660Sstevel@tonic-gate dlp->dl_brdcst_addr_length != 0)); 3670Sstevel@tonic-gate 368269Sericheng rw_exit(&dsp->ds_lock); 369269Sericheng 370269Sericheng qreply(q, mp); 371269Sericheng return (B_TRUE); 372269Sericheng } 373269Sericheng 374269Sericheng /* 375269Sericheng * DL_ATTACH_REQ 376269Sericheng */ 377269Sericheng static boolean_t 378269Sericheng proto_attach_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 379269Sericheng { 380269Sericheng dl_attach_req_t *dlp = (dl_attach_req_t *)udlp; 381269Sericheng int err = 0; 382269Sericheng t_uscalar_t dl_err; 383269Sericheng queue_t *q = dsp->ds_wq; 384269Sericheng 385269Sericheng rw_enter(&dsp->ds_lock, RW_WRITER); 386269Sericheng 387269Sericheng if (MBLKL(mp) < sizeof (dl_attach_req_t) || 388269Sericheng dlp->dl_ppa < 0 || dsp->ds_style == DL_STYLE1) { 389269Sericheng dl_err = DL_BADPRIM; 390269Sericheng goto failed; 391269Sericheng } 392269Sericheng 393269Sericheng if (dsp->ds_dlstate != DL_UNATTACHED) { 394269Sericheng dl_err = DL_OUTSTATE; 395269Sericheng goto failed; 396269Sericheng } 397269Sericheng 398269Sericheng dsp->ds_dlstate = DL_ATTACH_PENDING; 399269Sericheng 400269Sericheng err = dld_str_attach(dsp, dlp->dl_ppa); 401269Sericheng if (err != 0) { 402269Sericheng switch (err) { 403269Sericheng case ENOENT: 404269Sericheng dl_err = DL_BADPPA; 405269Sericheng err = 0; 406269Sericheng break; 407269Sericheng default: 408269Sericheng dl_err = DL_SYSERR; 409269Sericheng break; 410269Sericheng } 411269Sericheng dsp->ds_dlstate = DL_UNATTACHED; 412269Sericheng goto failed; 413269Sericheng } 414269Sericheng ASSERT(dsp->ds_dlstate == DL_UNBOUND); 415269Sericheng rw_exit(&dsp->ds_lock); 416269Sericheng 417269Sericheng dlokack(q, mp, DL_ATTACH_REQ); 418269Sericheng return (B_TRUE); 419269Sericheng failed: 420269Sericheng rw_exit(&dsp->ds_lock); 421269Sericheng dlerrorack(q, mp, DL_ATTACH_REQ, dl_err, (t_uscalar_t)err); 422269Sericheng return (B_FALSE); 4230Sstevel@tonic-gate } 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate /* 426269Sericheng * DL_DETACH_REQ 4270Sstevel@tonic-gate */ 428269Sericheng /*ARGSUSED*/ 429269Sericheng static boolean_t 430269Sericheng proto_detach_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 4310Sstevel@tonic-gate { 432269Sericheng queue_t *q = dsp->ds_wq; 433269Sericheng t_uscalar_t dl_err; 4340Sstevel@tonic-gate 435269Sericheng rw_enter(&dsp->ds_lock, RW_WRITER); 4360Sstevel@tonic-gate 437269Sericheng if (MBLKL(mp) < sizeof (dl_detach_req_t)) { 438269Sericheng dl_err = DL_BADPRIM; 439269Sericheng goto failed; 440269Sericheng } 4410Sstevel@tonic-gate 442269Sericheng if (dsp->ds_dlstate != DL_UNBOUND) { 443269Sericheng dl_err = DL_OUTSTATE; 444269Sericheng goto failed; 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate 447269Sericheng if (dsp->ds_style == DL_STYLE1) { 448269Sericheng dl_err = DL_BADPRIM; 449269Sericheng goto failed; 450269Sericheng } 451269Sericheng 452269Sericheng dsp->ds_dlstate = DL_DETACH_PENDING; 453269Sericheng 454269Sericheng /* 455269Sericheng * Complete the detach when the driver is single-threaded. 456269Sericheng */ 457269Sericheng mutex_enter(&dsp->ds_thr_lock); 458269Sericheng ASSERT(dsp->ds_detach_req == NULL); 459269Sericheng dsp->ds_detach_req = mp; 460269Sericheng mutex_exit(&dsp->ds_thr_lock); 461269Sericheng rw_exit(&dsp->ds_lock); 462269Sericheng 463269Sericheng return (B_TRUE); 464269Sericheng failed: 465269Sericheng rw_exit(&dsp->ds_lock); 466269Sericheng dlerrorack(q, mp, DL_DETACH_REQ, dl_err, 0); 467269Sericheng return (B_FALSE); 4680Sstevel@tonic-gate } 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate /* 471269Sericheng * DL_BIND_REQ 4720Sstevel@tonic-gate */ 473269Sericheng static boolean_t 474269Sericheng proto_bind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 4750Sstevel@tonic-gate { 476269Sericheng dl_bind_req_t *dlp = (dl_bind_req_t *)udlp; 477269Sericheng int err = 0; 478269Sericheng uint8_t addr[MAXADDRLEN]; 479269Sericheng uint_t addr_length; 480269Sericheng t_uscalar_t dl_err; 481269Sericheng t_scalar_t sap; 482269Sericheng queue_t *q = dsp->ds_wq; 483269Sericheng 484269Sericheng if (MBLKL(mp) < sizeof (dl_bind_req_t)) { 485269Sericheng dl_err = DL_BADPRIM; 486269Sericheng goto failed; 487269Sericheng } 488269Sericheng 489269Sericheng if (dlp->dl_xidtest_flg != 0) { 490269Sericheng dl_err = DL_NOAUTO; 491269Sericheng goto failed; 492269Sericheng } 493269Sericheng 494269Sericheng if (dlp->dl_service_mode != DL_CLDLS) { 495269Sericheng dl_err = DL_UNSUPPORTED; 496269Sericheng goto failed; 497269Sericheng } 498269Sericheng 499269Sericheng rw_enter(&dsp->ds_lock, RW_WRITER); 500269Sericheng 501269Sericheng if (dsp->ds_dlstate != DL_UNBOUND) { 502269Sericheng dl_err = DL_OUTSTATE; 503269Sericheng goto failed; 504269Sericheng } 5050Sstevel@tonic-gate 506269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED && 507269Sericheng !dls_active_set(dsp->ds_dc)) { 508269Sericheng dl_err = DL_SYSERR; 509269Sericheng err = EBUSY; 510269Sericheng goto failed; 511269Sericheng } 512269Sericheng 513269Sericheng dsp->ds_dlstate = DL_BIND_PENDING; 514269Sericheng /* 515269Sericheng * Set the receive callback. 516269Sericheng */ 517269Sericheng dls_rx_set(dsp->ds_dc, (dsp->ds_mode == DLD_RAW) ? 518269Sericheng dld_str_rx_raw : dld_str_rx_unitdata, dsp); 5190Sstevel@tonic-gate 520269Sericheng /* 521269Sericheng * Bind the channel such that it can receive packets. 522269Sericheng */ 523269Sericheng sap = dsp->ds_sap = dlp->dl_sap; 524269Sericheng err = dls_bind(dsp->ds_dc, dlp->dl_sap); 525269Sericheng if (err != 0) { 526269Sericheng switch (err) { 527269Sericheng case EINVAL: 528269Sericheng dl_err = DL_BADADDR; 529269Sericheng err = 0; 530269Sericheng break; 531269Sericheng default: 532269Sericheng dl_err = DL_SYSERR; 533269Sericheng break; 534269Sericheng } 535269Sericheng dsp->ds_dlstate = DL_UNBOUND; 536269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 537269Sericheng dls_active_clear(dsp->ds_dc); 538269Sericheng 5390Sstevel@tonic-gate goto failed; 540269Sericheng } 5410Sstevel@tonic-gate 5420Sstevel@tonic-gate /* 5430Sstevel@tonic-gate * Copy in MAC address. 5440Sstevel@tonic-gate */ 5450Sstevel@tonic-gate addr_length = dsp->ds_mip->mi_addr_length; 5460Sstevel@tonic-gate bcopy(dsp->ds_curr_addr, addr, addr_length); 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate /* 5490Sstevel@tonic-gate * Copy in the DLSAP. 5500Sstevel@tonic-gate */ 5510Sstevel@tonic-gate *(uint16_t *)(addr + addr_length) = dsp->ds_sap; 5520Sstevel@tonic-gate addr_length += sizeof (uint16_t); 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate dsp->ds_dlstate = DL_IDLE; 555269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 556269Sericheng dsp->ds_passivestate = DLD_ACTIVE; 5570Sstevel@tonic-gate 558269Sericheng rw_exit(&dsp->ds_lock); 559269Sericheng 560269Sericheng dlbindack(q, mp, sap, (void *)addr, addr_length, 0, 0); 561269Sericheng return (B_TRUE); 5620Sstevel@tonic-gate failed: 563269Sericheng rw_exit(&dsp->ds_lock); 564269Sericheng dlerrorack(q, mp, DL_BIND_REQ, dl_err, (t_uscalar_t)err); 565269Sericheng return (B_FALSE); 5660Sstevel@tonic-gate } 5670Sstevel@tonic-gate 5680Sstevel@tonic-gate /* 569269Sericheng * DL_UNBIND_REQ 5700Sstevel@tonic-gate */ 571269Sericheng /*ARGSUSED*/ 572269Sericheng static boolean_t 573269Sericheng proto_unbind_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 5740Sstevel@tonic-gate { 575269Sericheng queue_t *q = dsp->ds_wq; 576269Sericheng t_uscalar_t dl_err; 577269Sericheng 578269Sericheng rw_enter(&dsp->ds_lock, RW_WRITER); 579269Sericheng 580269Sericheng if (MBLKL(mp) < sizeof (dl_unbind_req_t)) { 581269Sericheng dl_err = DL_BADPRIM; 582269Sericheng goto failed; 583269Sericheng } 584269Sericheng 585269Sericheng if (dsp->ds_dlstate != DL_IDLE) { 586269Sericheng dl_err = DL_OUTSTATE; 587269Sericheng goto failed; 588269Sericheng } 589269Sericheng 590269Sericheng dsp->ds_dlstate = DL_UNBIND_PENDING; 591269Sericheng 592269Sericheng /* 593269Sericheng * Flush any remaining packets scheduled for transmission. 594269Sericheng */ 595269Sericheng dld_tx_flush(dsp); 596269Sericheng 597269Sericheng /* 598269Sericheng * Unbind the channel to stop packets being received. 599269Sericheng */ 600269Sericheng dls_unbind(dsp->ds_dc); 601269Sericheng 602269Sericheng /* 603269Sericheng * Disable polling mode, if it is enabled. 604269Sericheng */ 605269Sericheng proto_poll_disable(dsp); 606269Sericheng 607269Sericheng /* 608269Sericheng * Clear the receive callback. 609269Sericheng */ 610269Sericheng dls_rx_set(dsp->ds_dc, NULL, NULL); 611269Sericheng 612269Sericheng /* 613269Sericheng * Set the mode back to the default (unitdata). 614269Sericheng */ 615269Sericheng dsp->ds_mode = DLD_UNITDATA; 616269Sericheng 617*1184Skrgopi /* 618*1184Skrgopi * If soft rings were enabled, the workers 619*1184Skrgopi * should be quiesced. Start a task that will 620*1184Skrgopi * get this in motion. We cannot check for 621*1184Skrgopi * ds_soft_ring flag because 622*1184Skrgopi * proto_soft_ring_disable() called from 623*1184Skrgopi * proto_capability_req() would have reset it. 624*1184Skrgopi */ 625*1184Skrgopi if (dls_soft_ring_workers(dsp->ds_dc)) { 626*1184Skrgopi dsp->ds_unbind_req = mp; 627*1184Skrgopi dsp->ds_task_id = taskq_dispatch(system_taskq, 628*1184Skrgopi proto_stop_soft_ring_threads, (void *)dsp, TQ_SLEEP); 629*1184Skrgopi rw_exit(&dsp->ds_lock); 630*1184Skrgopi return (B_TRUE); 631*1184Skrgopi } 632*1184Skrgopi 6330Sstevel@tonic-gate dsp->ds_dlstate = DL_UNBOUND; 634269Sericheng rw_exit(&dsp->ds_lock); 635269Sericheng 636269Sericheng dlokack(q, mp, DL_UNBIND_REQ); 637269Sericheng return (B_TRUE); 638269Sericheng failed: 639269Sericheng rw_exit(&dsp->ds_lock); 640269Sericheng dlerrorack(q, mp, DL_UNBIND_REQ, dl_err, 0); 641269Sericheng return (B_FALSE); 6420Sstevel@tonic-gate } 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate /* 645269Sericheng * DL_PROMISCON_REQ 6460Sstevel@tonic-gate */ 647269Sericheng static boolean_t 648269Sericheng proto_promiscon_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 6490Sstevel@tonic-gate { 650269Sericheng dl_promiscon_req_t *dlp = (dl_promiscon_req_t *)udlp; 651269Sericheng int err = 0; 652269Sericheng t_uscalar_t dl_err; 653269Sericheng uint32_t promisc_saved; 654269Sericheng queue_t *q = dsp->ds_wq; 655269Sericheng 656269Sericheng if (MBLKL(mp) < sizeof (dl_promiscon_req_t)) { 657269Sericheng dl_err = DL_BADPRIM; 658269Sericheng goto failed; 659269Sericheng } 660269Sericheng 661269Sericheng rw_enter(&dsp->ds_lock, RW_WRITER); 662269Sericheng 663269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 664269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 665269Sericheng dl_err = DL_OUTSTATE; 6660Sstevel@tonic-gate goto failed; 667269Sericheng } 6680Sstevel@tonic-gate 669269Sericheng promisc_saved = dsp->ds_promisc; 670269Sericheng switch (dlp->dl_level) { 671269Sericheng case DL_PROMISC_SAP: 672269Sericheng dsp->ds_promisc |= DLS_PROMISC_SAP; 673269Sericheng break; 674269Sericheng 675269Sericheng case DL_PROMISC_MULTI: 676269Sericheng dsp->ds_promisc |= DLS_PROMISC_MULTI; 677269Sericheng break; 678269Sericheng 679269Sericheng case DL_PROMISC_PHYS: 680269Sericheng dsp->ds_promisc |= DLS_PROMISC_PHYS; 681269Sericheng break; 682269Sericheng 683269Sericheng default: 684269Sericheng dl_err = DL_NOTSUPPORTED; 685269Sericheng goto failed; 686269Sericheng } 6870Sstevel@tonic-gate 688269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED && 689269Sericheng !dls_active_set(dsp->ds_dc)) { 690269Sericheng dsp->ds_promisc = promisc_saved; 691269Sericheng dl_err = DL_SYSERR; 692269Sericheng err = EBUSY; 693269Sericheng goto failed; 694269Sericheng } 695269Sericheng 696269Sericheng /* 697269Sericheng * Adjust channel promiscuity. 698269Sericheng */ 699269Sericheng err = dls_promisc(dsp->ds_dc, dsp->ds_promisc); 700269Sericheng if (err != 0) { 701269Sericheng dl_err = DL_SYSERR; 702269Sericheng dsp->ds_promisc = promisc_saved; 703269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 704269Sericheng dls_active_clear(dsp->ds_dc); 705269Sericheng 706269Sericheng goto failed; 707269Sericheng } 708269Sericheng 709269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 710269Sericheng dsp->ds_passivestate = DLD_ACTIVE; 711269Sericheng 712269Sericheng rw_exit(&dsp->ds_lock); 713269Sericheng dlokack(q, mp, DL_PROMISCON_REQ); 714269Sericheng return (B_TRUE); 7150Sstevel@tonic-gate failed: 716269Sericheng rw_exit(&dsp->ds_lock); 717269Sericheng dlerrorack(q, mp, DL_PROMISCON_REQ, dl_err, (t_uscalar_t)err); 718269Sericheng return (B_FALSE); 7190Sstevel@tonic-gate } 7200Sstevel@tonic-gate 7210Sstevel@tonic-gate /* 722269Sericheng * DL_PROMISCOFF_REQ 7230Sstevel@tonic-gate */ 724269Sericheng static boolean_t 725269Sericheng proto_promiscoff_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 7260Sstevel@tonic-gate { 727269Sericheng dl_promiscoff_req_t *dlp = (dl_promiscoff_req_t *)udlp; 728269Sericheng int err = 0; 729269Sericheng t_uscalar_t dl_err; 730269Sericheng uint32_t promisc_saved; 731269Sericheng queue_t *q = dsp->ds_wq; 732269Sericheng 733269Sericheng 734269Sericheng if (MBLKL(mp) < sizeof (dl_promiscoff_req_t)) { 735269Sericheng dl_err = DL_BADPRIM; 7360Sstevel@tonic-gate goto failed; 737269Sericheng } 7380Sstevel@tonic-gate 739269Sericheng rw_enter(&dsp->ds_lock, RW_WRITER); 7400Sstevel@tonic-gate 741269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 742269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 743269Sericheng dl_err = DL_OUTSTATE; 7440Sstevel@tonic-gate goto failed; 745269Sericheng } 7460Sstevel@tonic-gate 747269Sericheng promisc_saved = dsp->ds_promisc; 748269Sericheng switch (dlp->dl_level) { 749269Sericheng case DL_PROMISC_SAP: 750269Sericheng if (!(dsp->ds_promisc & DLS_PROMISC_SAP)) { 751269Sericheng dl_err = DL_NOTENAB; 752269Sericheng goto failed; 753269Sericheng } 754269Sericheng dsp->ds_promisc &= ~DLS_PROMISC_SAP; 7550Sstevel@tonic-gate break; 7560Sstevel@tonic-gate 757269Sericheng case DL_PROMISC_MULTI: 758269Sericheng if (!(dsp->ds_promisc & DLS_PROMISC_MULTI)) { 759269Sericheng dl_err = DL_NOTENAB; 760269Sericheng goto failed; 761269Sericheng } 762269Sericheng dsp->ds_promisc &= ~DLS_PROMISC_MULTI; 763269Sericheng break; 764269Sericheng 765269Sericheng case DL_PROMISC_PHYS: 766269Sericheng if (!(dsp->ds_promisc & DLS_PROMISC_PHYS)) { 767269Sericheng dl_err = DL_NOTENAB; 768269Sericheng goto failed; 769269Sericheng } 770269Sericheng dsp->ds_promisc &= ~DLS_PROMISC_PHYS; 7710Sstevel@tonic-gate break; 7720Sstevel@tonic-gate 7730Sstevel@tonic-gate default: 774269Sericheng dl_err = DL_NOTSUPPORTED; 775269Sericheng goto failed; 776269Sericheng } 777269Sericheng 778269Sericheng /* 779269Sericheng * Adjust channel promiscuity. 780269Sericheng */ 781269Sericheng err = dls_promisc(dsp->ds_dc, dsp->ds_promisc); 782269Sericheng if (err != 0) { 783269Sericheng dsp->ds_promisc = promisc_saved; 7840Sstevel@tonic-gate dl_err = DL_SYSERR; 785269Sericheng goto failed; 786269Sericheng } 787269Sericheng 788269Sericheng rw_exit(&dsp->ds_lock); 789269Sericheng dlokack(q, mp, DL_PROMISCOFF_REQ); 790269Sericheng return (B_TRUE); 791269Sericheng failed: 792269Sericheng rw_exit(&dsp->ds_lock); 793269Sericheng dlerrorack(q, mp, DL_PROMISCOFF_REQ, dl_err, (t_uscalar_t)err); 794269Sericheng return (B_FALSE); 795269Sericheng } 796269Sericheng 797269Sericheng /* 798269Sericheng * DL_ENABMULTI_REQ 799269Sericheng */ 800269Sericheng static boolean_t 801269Sericheng proto_enabmulti_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 802269Sericheng { 803269Sericheng dl_enabmulti_req_t *dlp = (dl_enabmulti_req_t *)udlp; 804269Sericheng int err = 0; 805269Sericheng t_uscalar_t dl_err; 806269Sericheng queue_t *q = dsp->ds_wq; 807269Sericheng 808269Sericheng rw_enter(&dsp->ds_lock, RW_WRITER); 809269Sericheng 810269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 811269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 812269Sericheng dl_err = DL_OUTSTATE; 813269Sericheng goto failed; 814269Sericheng } 815269Sericheng 816269Sericheng if (MBLKL(mp) < sizeof (dl_enabmulti_req_t) || 817269Sericheng !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) || 818269Sericheng dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) { 819269Sericheng dl_err = DL_BADPRIM; 820269Sericheng goto failed; 821269Sericheng } 822269Sericheng 823269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED && 824269Sericheng !dls_active_set(dsp->ds_dc)) { 825269Sericheng dl_err = DL_SYSERR; 826269Sericheng err = EBUSY; 827269Sericheng goto failed; 8280Sstevel@tonic-gate } 8290Sstevel@tonic-gate 830269Sericheng err = dls_multicst_add(dsp->ds_dc, mp->b_rptr + dlp->dl_addr_offset); 831269Sericheng if (err != 0) { 832269Sericheng switch (err) { 833269Sericheng case EINVAL: 834269Sericheng dl_err = DL_BADADDR; 835269Sericheng err = 0; 836269Sericheng break; 837269Sericheng case ENOSPC: 838269Sericheng dl_err = DL_TOOMANY; 839269Sericheng err = 0; 840269Sericheng break; 841269Sericheng default: 842269Sericheng dl_err = DL_SYSERR; 843269Sericheng break; 844269Sericheng } 845269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 846269Sericheng dls_active_clear(dsp->ds_dc); 847269Sericheng 848269Sericheng goto failed; 849269Sericheng } 850269Sericheng 851269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 852269Sericheng dsp->ds_passivestate = DLD_ACTIVE; 853269Sericheng 854269Sericheng rw_exit(&dsp->ds_lock); 855269Sericheng dlokack(q, mp, DL_ENABMULTI_REQ); 856269Sericheng return (B_TRUE); 857269Sericheng failed: 858269Sericheng rw_exit(&dsp->ds_lock); 859269Sericheng dlerrorack(q, mp, DL_ENABMULTI_REQ, dl_err, (t_uscalar_t)err); 860269Sericheng return (B_FALSE); 861269Sericheng } 862269Sericheng 863269Sericheng /* 864269Sericheng * DL_DISABMULTI_REQ 865269Sericheng */ 866269Sericheng static boolean_t 867269Sericheng proto_disabmulti_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 868269Sericheng { 869269Sericheng dl_disabmulti_req_t *dlp = (dl_disabmulti_req_t *)udlp; 870269Sericheng int err = 0; 871269Sericheng t_uscalar_t dl_err; 872269Sericheng queue_t *q = dsp->ds_wq; 873269Sericheng 874269Sericheng rw_enter(&dsp->ds_lock, RW_READER); 875269Sericheng 876269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 877269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 878269Sericheng dl_err = DL_OUTSTATE; 879269Sericheng goto failed; 880269Sericheng } 881269Sericheng 882269Sericheng if (MBLKL(mp) < sizeof (dl_disabmulti_req_t) || 883269Sericheng !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) || 884269Sericheng dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) { 885269Sericheng dl_err = DL_BADPRIM; 886269Sericheng goto failed; 887269Sericheng } 888269Sericheng 889269Sericheng err = dls_multicst_remove(dsp->ds_dc, mp->b_rptr + dlp->dl_addr_offset); 890269Sericheng if (err != 0) { 891269Sericheng switch (err) { 892269Sericheng case EINVAL: 893269Sericheng dl_err = DL_BADADDR; 894269Sericheng err = 0; 895269Sericheng break; 896269Sericheng 897269Sericheng case ENOENT: 898269Sericheng dl_err = DL_NOTENAB; 899269Sericheng err = 0; 900269Sericheng break; 901269Sericheng 902269Sericheng default: 903269Sericheng dl_err = DL_SYSERR; 904269Sericheng break; 905269Sericheng } 906269Sericheng goto failed; 907269Sericheng } 908269Sericheng 909269Sericheng rw_exit(&dsp->ds_lock); 910269Sericheng dlokack(q, mp, DL_DISABMULTI_REQ); 911269Sericheng return (B_TRUE); 912269Sericheng failed: 913269Sericheng rw_exit(&dsp->ds_lock); 914269Sericheng dlerrorack(q, mp, DL_DISABMULTI_REQ, dl_err, (t_uscalar_t)err); 915269Sericheng return (B_FALSE); 9160Sstevel@tonic-gate } 9170Sstevel@tonic-gate 9180Sstevel@tonic-gate /* 919269Sericheng * DL_PHYS_ADDR_REQ 9200Sstevel@tonic-gate */ 921269Sericheng static boolean_t 922269Sericheng proto_physaddr_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 9230Sstevel@tonic-gate { 924269Sericheng dl_phys_addr_req_t *dlp = (dl_phys_addr_req_t *)udlp; 925269Sericheng queue_t *q = dsp->ds_wq; 926269Sericheng t_uscalar_t dl_err; 927269Sericheng char *addr; 928269Sericheng uint_t addr_length; 929269Sericheng 930269Sericheng rw_enter(&dsp->ds_lock, RW_READER); 931269Sericheng 932269Sericheng if (MBLKL(mp) < sizeof (dl_phys_addr_req_t)) { 933269Sericheng dl_err = DL_BADPRIM; 934269Sericheng goto failed; 935269Sericheng } 936269Sericheng 937269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 938269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 939269Sericheng dl_err = DL_OUTSTATE; 940269Sericheng goto failed; 941269Sericheng } 9420Sstevel@tonic-gate 943269Sericheng if (dlp->dl_addr_type != DL_CURR_PHYS_ADDR && 944269Sericheng dlp->dl_addr_type != DL_FACT_PHYS_ADDR) { 945269Sericheng dl_err = DL_UNSUPPORTED; 9460Sstevel@tonic-gate goto failed; 947269Sericheng } 9480Sstevel@tonic-gate 949269Sericheng addr_length = dsp->ds_mip->mi_addr_length; 950269Sericheng addr = kmem_alloc(addr_length, KM_NOSLEEP); 951269Sericheng if (addr == NULL) { 952269Sericheng rw_exit(&dsp->ds_lock); 953269Sericheng merror(q, mp, ENOSR); 954269Sericheng return (B_FALSE); 955269Sericheng } 9560Sstevel@tonic-gate 957269Sericheng /* 958269Sericheng * Copy out the address before we drop the lock; we don't 959269Sericheng * want to call dlphysaddrack() while holding ds_lock. 960269Sericheng */ 961269Sericheng bcopy((dlp->dl_addr_type == DL_CURR_PHYS_ADDR) ? 962269Sericheng dsp->ds_curr_addr : dsp->ds_fact_addr, addr, addr_length); 963269Sericheng 964269Sericheng rw_exit(&dsp->ds_lock); 965269Sericheng dlphysaddrack(q, mp, addr, (t_uscalar_t)addr_length); 966269Sericheng kmem_free(addr, addr_length); 967269Sericheng return (B_TRUE); 9680Sstevel@tonic-gate failed: 969269Sericheng rw_exit(&dsp->ds_lock); 970269Sericheng dlerrorack(q, mp, DL_PHYS_ADDR_REQ, dl_err, 0); 971269Sericheng return (B_FALSE); 972269Sericheng } 9730Sstevel@tonic-gate 974269Sericheng /* 975269Sericheng * DL_SET_PHYS_ADDR_REQ 976269Sericheng */ 977269Sericheng static boolean_t 978269Sericheng proto_setphysaddr_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 979269Sericheng { 980269Sericheng dl_set_phys_addr_req_t *dlp = (dl_set_phys_addr_req_t *)udlp; 981269Sericheng int err = 0; 982269Sericheng t_uscalar_t dl_err; 983269Sericheng queue_t *q = dsp->ds_wq; 9840Sstevel@tonic-gate 985269Sericheng rw_enter(&dsp->ds_lock, RW_WRITER); 986269Sericheng 987269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 988269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 989269Sericheng dl_err = DL_OUTSTATE; 990269Sericheng goto failed; 991269Sericheng } 992269Sericheng 993269Sericheng if (MBLKL(mp) < sizeof (dl_set_phys_addr_req_t) || 994269Sericheng !MBLKIN(mp, dlp->dl_addr_offset, dlp->dl_addr_length) || 995269Sericheng dlp->dl_addr_length != dsp->ds_mip->mi_addr_length) { 996269Sericheng dl_err = DL_BADPRIM; 997269Sericheng goto failed; 9980Sstevel@tonic-gate } 9990Sstevel@tonic-gate 1000269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED && 1001269Sericheng !dls_active_set(dsp->ds_dc)) { 1002269Sericheng dl_err = DL_SYSERR; 1003269Sericheng err = EBUSY; 1004269Sericheng goto failed; 1005269Sericheng } 1006269Sericheng 1007269Sericheng err = mac_unicst_set(dsp->ds_mh, mp->b_rptr + dlp->dl_addr_offset); 1008269Sericheng if (err != 0) { 1009269Sericheng switch (err) { 1010269Sericheng case EINVAL: 1011269Sericheng dl_err = DL_BADADDR; 1012269Sericheng err = 0; 1013269Sericheng break; 1014269Sericheng 1015269Sericheng default: 1016269Sericheng dl_err = DL_SYSERR; 1017269Sericheng break; 1018269Sericheng } 1019269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 1020269Sericheng dls_active_clear(dsp->ds_dc); 1021269Sericheng 1022269Sericheng goto failed; 1023269Sericheng } 1024269Sericheng if (dsp->ds_passivestate == DLD_UNINITIALIZED) 1025269Sericheng dsp->ds_passivestate = DLD_ACTIVE; 1026269Sericheng 1027269Sericheng rw_exit(&dsp->ds_lock); 1028269Sericheng dlokack(q, mp, DL_SET_PHYS_ADDR_REQ); 1029269Sericheng return (B_TRUE); 1030269Sericheng failed: 1031269Sericheng rw_exit(&dsp->ds_lock); 1032269Sericheng dlerrorack(q, mp, DL_SET_PHYS_ADDR_REQ, dl_err, (t_uscalar_t)err); 1033269Sericheng return (B_FALSE); 1034269Sericheng } 1035269Sericheng 1036269Sericheng /* 1037269Sericheng * DL_UDQOS_REQ 1038269Sericheng */ 1039269Sericheng static boolean_t 1040269Sericheng proto_udqos_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 1041269Sericheng { 1042269Sericheng dl_udqos_req_t *dlp = (dl_udqos_req_t *)udlp; 1043269Sericheng dl_qos_cl_sel1_t *selp; 1044269Sericheng int off, len; 1045269Sericheng t_uscalar_t dl_err; 1046269Sericheng queue_t *q = dsp->ds_wq; 1047269Sericheng 1048269Sericheng off = dlp->dl_qos_offset; 1049269Sericheng len = dlp->dl_qos_length; 1050269Sericheng 1051269Sericheng if (MBLKL(mp) < sizeof (dl_udqos_req_t) || !MBLKIN(mp, off, len)) { 1052269Sericheng dl_err = DL_BADPRIM; 1053269Sericheng goto failed; 1054269Sericheng } 1055269Sericheng 1056269Sericheng selp = (dl_qos_cl_sel1_t *)(mp->b_rptr + off); 1057269Sericheng if (selp->dl_qos_type != DL_QOS_CL_SEL1) { 1058269Sericheng dl_err = DL_BADQOSTYPE; 1059269Sericheng goto failed; 1060269Sericheng } 1061269Sericheng 1062269Sericheng rw_enter(&dsp->ds_lock, RW_WRITER); 1063269Sericheng 1064269Sericheng if (dsp->ds_vid == VLAN_ID_NONE || 1065269Sericheng selp->dl_priority > (1 << VLAN_PRI_SIZE) - 1 || 1066269Sericheng selp->dl_priority < 0) { 1067269Sericheng dl_err = DL_BADQOSPARAM; 1068269Sericheng goto failed; 1069269Sericheng } 1070269Sericheng 1071269Sericheng dsp->ds_pri = selp->dl_priority; 1072269Sericheng 1073269Sericheng rw_exit(&dsp->ds_lock); 1074269Sericheng dlokack(q, mp, DL_UDQOS_REQ); 1075269Sericheng return (B_TRUE); 1076269Sericheng failed: 1077269Sericheng rw_exit(&dsp->ds_lock); 1078269Sericheng dlerrorack(q, mp, DL_UDQOS_REQ, dl_err, 0); 1079269Sericheng return (B_FALSE); 10800Sstevel@tonic-gate } 10810Sstevel@tonic-gate 1082*1184Skrgopi static boolean_t 1083*1184Skrgopi check_ip_above(queue_t *q) 1084*1184Skrgopi { 1085*1184Skrgopi queue_t *next_q; 1086*1184Skrgopi boolean_t ret = B_TRUE; 1087*1184Skrgopi 1088*1184Skrgopi claimstr(q); 1089*1184Skrgopi next_q = q->q_next; 1090*1184Skrgopi if (strcmp(next_q->q_qinfo->qi_minfo->mi_idname, "ip") != 0) 1091*1184Skrgopi ret = B_FALSE; 1092*1184Skrgopi releasestr(q); 1093*1184Skrgopi return (ret); 1094*1184Skrgopi } 1095*1184Skrgopi 10960Sstevel@tonic-gate /* 1097269Sericheng * DL_CAPABILITY_REQ 10980Sstevel@tonic-gate */ 1099269Sericheng /*ARGSUSED*/ 1100269Sericheng static boolean_t 1101269Sericheng proto_capability_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 11020Sstevel@tonic-gate { 1103269Sericheng dl_capability_req_t *dlp = (dl_capability_req_t *)udlp; 1104269Sericheng dl_capability_sub_t *sp; 1105269Sericheng size_t size, len; 1106269Sericheng offset_t off, end; 1107269Sericheng t_uscalar_t dl_err; 1108269Sericheng queue_t *q = dsp->ds_wq; 1109269Sericheng boolean_t upgraded; 1110269Sericheng 1111269Sericheng rw_enter(&dsp->ds_lock, RW_READER); 1112269Sericheng 1113269Sericheng if (MBLKL(mp) < sizeof (dl_capability_req_t)) { 1114269Sericheng dl_err = DL_BADPRIM; 1115269Sericheng goto failed; 1116269Sericheng } 1117269Sericheng 1118269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 1119269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 1120269Sericheng dl_err = DL_OUTSTATE; 1121269Sericheng goto failed; 1122269Sericheng } 1123269Sericheng 1124269Sericheng /* 1125269Sericheng * This request is overloaded. If there are no requested capabilities 1126269Sericheng * then we just want to acknowledge with all the capabilities we 1127269Sericheng * support. Otherwise we enable the set of capabilities requested. 1128269Sericheng */ 1129269Sericheng if (dlp->dl_sub_length == 0) { 1130269Sericheng /* callee drops lock */ 1131269Sericheng return (proto_capability_advertise(dsp, mp)); 1132269Sericheng } 1133269Sericheng 1134269Sericheng if (!MBLKIN(mp, dlp->dl_sub_offset, dlp->dl_sub_length)) { 1135269Sericheng dl_err = DL_BADPRIM; 1136269Sericheng goto failed; 1137269Sericheng } 1138269Sericheng 1139269Sericheng dlp->dl_primitive = DL_CAPABILITY_ACK; 1140269Sericheng 1141269Sericheng off = dlp->dl_sub_offset; 1142269Sericheng len = dlp->dl_sub_length; 11430Sstevel@tonic-gate 11440Sstevel@tonic-gate /* 1145269Sericheng * Walk the list of capabilities to be enabled. 11460Sstevel@tonic-gate */ 1147269Sericheng upgraded = B_FALSE; 1148269Sericheng for (end = off + len; off < end; ) { 1149269Sericheng sp = (dl_capability_sub_t *)(mp->b_rptr + off); 1150269Sericheng size = sizeof (dl_capability_sub_t) + sp->dl_length; 1151269Sericheng 1152269Sericheng if (off + size > end || 1153269Sericheng !IS_P2ALIGNED(off, sizeof (uint32_t))) { 1154269Sericheng dl_err = DL_BADPRIM; 1155269Sericheng goto failed; 1156269Sericheng } 1157269Sericheng 1158269Sericheng switch (sp->dl_cap) { 1159269Sericheng /* 1160269Sericheng * TCP/IP checksum offload to hardware. 1161269Sericheng */ 1162269Sericheng case DL_CAPAB_HCKSUM: { 1163269Sericheng dl_capab_hcksum_t *hcksump; 1164269Sericheng dl_capab_hcksum_t hcksum; 1165269Sericheng 1166269Sericheng ASSERT(dsp->ds_mip->mi_cksum != 0); 1167269Sericheng 1168269Sericheng hcksump = (dl_capab_hcksum_t *)&sp[1]; 1169269Sericheng /* 1170269Sericheng * Copy for alignment. 1171269Sericheng */ 1172269Sericheng bcopy(hcksump, &hcksum, sizeof (dl_capab_hcksum_t)); 1173269Sericheng dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq); 1174269Sericheng bcopy(&hcksum, hcksump, sizeof (dl_capab_hcksum_t)); 1175269Sericheng break; 1176269Sericheng } 1177269Sericheng 1178269Sericheng /* 1179269Sericheng * IP polling interface. 1180269Sericheng */ 1181269Sericheng case DL_CAPAB_POLL: { 1182*1184Skrgopi dl_capab_dls_t *pollp; 1183*1184Skrgopi dl_capab_dls_t poll; 1184269Sericheng 1185*1184Skrgopi pollp = (dl_capab_dls_t *)&sp[1]; 1186269Sericheng /* 1187269Sericheng * Copy for alignment. 1188269Sericheng */ 1189*1184Skrgopi bcopy(pollp, &poll, sizeof (dl_capab_dls_t)); 1190269Sericheng 1191269Sericheng /* 1192269Sericheng * We need to become writer before enabling and/or 1193269Sericheng * disabling the polling interface. If we couldn' 1194269Sericheng * upgrade, check state again after re-acquiring the 1195269Sericheng * lock to make sure we can proceed. 1196269Sericheng */ 1197269Sericheng if (!upgraded && !rw_tryupgrade(&dsp->ds_lock)) { 1198269Sericheng rw_exit(&dsp->ds_lock); 1199269Sericheng rw_enter(&dsp->ds_lock, RW_WRITER); 1200269Sericheng 1201269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 1202269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 1203269Sericheng dl_err = DL_OUTSTATE; 1204269Sericheng goto failed; 1205269Sericheng } 1206269Sericheng } 1207269Sericheng upgraded = B_TRUE; 1208269Sericheng 1209*1184Skrgopi switch (poll.dls_flags) { 1210269Sericheng default: 1211269Sericheng /*FALLTHRU*/ 1212269Sericheng case POLL_DISABLE: 1213269Sericheng proto_poll_disable(dsp); 1214269Sericheng break; 1215269Sericheng 1216269Sericheng case POLL_ENABLE: 1217269Sericheng ASSERT(!(dld_opt & DLD_OPT_NO_POLL)); 1218269Sericheng 1219269Sericheng /* 1220269Sericheng * Make sure polling is disabled. 1221269Sericheng */ 1222269Sericheng proto_poll_disable(dsp); 1223269Sericheng 1224269Sericheng /* 1225269Sericheng * Now attempt enable it. 1226269Sericheng */ 1227*1184Skrgopi if (check_ip_above(dsp->ds_rq) && 1228*1184Skrgopi proto_poll_enable(dsp, &poll)) { 1229*1184Skrgopi bzero(&poll, sizeof (dl_capab_dls_t)); 1230*1184Skrgopi poll.dls_flags = POLL_ENABLE; 1231*1184Skrgopi } 1232269Sericheng break; 1233269Sericheng } 1234269Sericheng 1235*1184Skrgopi dlcapabsetqid(&(poll.dls_mid), dsp->ds_rq); 1236*1184Skrgopi bcopy(&poll, pollp, sizeof (dl_capab_dls_t)); 1237*1184Skrgopi break; 1238*1184Skrgopi } 1239*1184Skrgopi case DL_CAPAB_SOFT_RING: { 1240*1184Skrgopi dl_capab_dls_t *soft_ringp; 1241*1184Skrgopi dl_capab_dls_t soft_ring; 1242*1184Skrgopi 1243*1184Skrgopi soft_ringp = (dl_capab_dls_t *)&sp[1]; 1244*1184Skrgopi /* 1245*1184Skrgopi * Copy for alignment. 1246*1184Skrgopi */ 1247*1184Skrgopi bcopy(soft_ringp, &soft_ring, 1248*1184Skrgopi sizeof (dl_capab_dls_t)); 1249*1184Skrgopi 1250*1184Skrgopi /* 1251*1184Skrgopi * We need to become writer before enabling and/or 1252*1184Skrgopi * disabling the soft_ring interface. If we couldn' 1253*1184Skrgopi * upgrade, check state again after re-acquiring the 1254*1184Skrgopi * lock to make sure we can proceed. 1255*1184Skrgopi */ 1256*1184Skrgopi if (!upgraded && !rw_tryupgrade(&dsp->ds_lock)) { 1257*1184Skrgopi rw_exit(&dsp->ds_lock); 1258*1184Skrgopi rw_enter(&dsp->ds_lock, RW_WRITER); 1259*1184Skrgopi 1260*1184Skrgopi if (dsp->ds_dlstate == DL_UNATTACHED || 1261*1184Skrgopi DL_ACK_PENDING(dsp->ds_dlstate)) { 1262*1184Skrgopi dl_err = DL_OUTSTATE; 1263*1184Skrgopi goto failed; 1264*1184Skrgopi } 1265*1184Skrgopi } 1266*1184Skrgopi upgraded = B_TRUE; 1267*1184Skrgopi 1268*1184Skrgopi switch (soft_ring.dls_flags) { 1269*1184Skrgopi default: 1270*1184Skrgopi /*FALLTHRU*/ 1271*1184Skrgopi case SOFT_RING_DISABLE: 1272*1184Skrgopi proto_soft_ring_disable(dsp); 1273*1184Skrgopi break; 1274*1184Skrgopi 1275*1184Skrgopi case SOFT_RING_ENABLE: 1276*1184Skrgopi /* 1277*1184Skrgopi * Make sure soft_ring is disabled. 1278*1184Skrgopi */ 1279*1184Skrgopi proto_soft_ring_disable(dsp); 1280*1184Skrgopi 1281*1184Skrgopi /* 1282*1184Skrgopi * Now attempt enable it. 1283*1184Skrgopi */ 1284*1184Skrgopi if (check_ip_above(dsp->ds_rq) && 1285*1184Skrgopi proto_soft_ring_enable(dsp, &soft_ring)) { 1286*1184Skrgopi bzero(&soft_ring, 1287*1184Skrgopi sizeof (dl_capab_dls_t)); 1288*1184Skrgopi soft_ring.dls_flags = 1289*1184Skrgopi SOFT_RING_ENABLE; 1290*1184Skrgopi } else { 1291*1184Skrgopi bzero(&soft_ring, 1292*1184Skrgopi sizeof (dl_capab_dls_t)); 1293*1184Skrgopi soft_ring.dls_flags = 1294*1184Skrgopi SOFT_RING_DISABLE; 1295*1184Skrgopi } 1296*1184Skrgopi break; 1297*1184Skrgopi } 1298*1184Skrgopi 1299*1184Skrgopi dlcapabsetqid(&(soft_ring.dls_mid), dsp->ds_rq); 1300*1184Skrgopi bcopy(&soft_ring, soft_ringp, 1301*1184Skrgopi sizeof (dl_capab_dls_t)); 1302269Sericheng break; 1303269Sericheng } 1304269Sericheng default: 1305269Sericheng break; 1306269Sericheng } 1307269Sericheng 1308269Sericheng off += size; 1309269Sericheng } 1310269Sericheng rw_exit(&dsp->ds_lock); 1311269Sericheng qreply(q, mp); 1312269Sericheng return (B_TRUE); 1313269Sericheng failed: 1314269Sericheng rw_exit(&dsp->ds_lock); 1315269Sericheng dlerrorack(q, mp, DL_CAPABILITY_REQ, dl_err, 0); 1316269Sericheng return (B_FALSE); 13170Sstevel@tonic-gate } 13180Sstevel@tonic-gate 13190Sstevel@tonic-gate /* 1320269Sericheng * DL_NOTIFY_REQ 13210Sstevel@tonic-gate */ 1322269Sericheng static boolean_t 1323269Sericheng proto_notify_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 13240Sstevel@tonic-gate { 1325269Sericheng dl_notify_req_t *dlp = (dl_notify_req_t *)udlp; 1326269Sericheng t_uscalar_t dl_err; 1327269Sericheng queue_t *q = dsp->ds_wq; 1328269Sericheng uint_t note = 1329269Sericheng DL_NOTE_PROMISC_ON_PHYS | 1330269Sericheng DL_NOTE_PROMISC_OFF_PHYS | 1331269Sericheng DL_NOTE_PHYS_ADDR | 1332269Sericheng DL_NOTE_LINK_UP | 1333269Sericheng DL_NOTE_LINK_DOWN | 1334269Sericheng DL_NOTE_CAPAB_RENEG; 13350Sstevel@tonic-gate 1336269Sericheng if (MBLKL(mp) < sizeof (dl_notify_req_t)) { 1337269Sericheng dl_err = DL_BADPRIM; 1338269Sericheng goto failed; 1339269Sericheng } 13400Sstevel@tonic-gate 1341269Sericheng rw_enter(&dsp->ds_lock, RW_WRITER); 1342269Sericheng if (dsp->ds_dlstate == DL_UNATTACHED || 1343269Sericheng DL_ACK_PENDING(dsp->ds_dlstate)) { 1344269Sericheng dl_err = DL_OUTSTATE; 1345269Sericheng goto failed; 13460Sstevel@tonic-gate } 13470Sstevel@tonic-gate 1348269Sericheng if (dsp->ds_mip->mi_stat[MAC_STAT_IFSPEED]) 1349269Sericheng note |= DL_NOTE_SPEED; 1350269Sericheng 1351269Sericheng /* 1352269Sericheng * Cache the notifications that are being enabled. 1353269Sericheng */ 1354269Sericheng dsp->ds_notifications = dlp->dl_notifications & note; 1355269Sericheng rw_exit(&dsp->ds_lock); 1356269Sericheng /* 1357269Sericheng * The ACK carries all notifications regardless of which set is 1358269Sericheng * being enabled. 1359269Sericheng */ 1360269Sericheng dlnotifyack(q, mp, note); 1361269Sericheng 1362269Sericheng /* 1363269Sericheng * Solicit DL_NOTIFY_IND messages for each enabled notification. 1364269Sericheng */ 1365269Sericheng rw_enter(&dsp->ds_lock, RW_READER); 1366269Sericheng if (dsp->ds_notifications != 0) { 1367269Sericheng rw_exit(&dsp->ds_lock); 1368269Sericheng dld_str_notify_ind(dsp); 1369269Sericheng } else { 1370269Sericheng rw_exit(&dsp->ds_lock); 1371269Sericheng } 1372269Sericheng return (B_TRUE); 1373269Sericheng failed: 1374269Sericheng rw_exit(&dsp->ds_lock); 1375269Sericheng dlerrorack(q, mp, DL_NOTIFY_REQ, dl_err, 0); 1376269Sericheng return (B_FALSE); 13770Sstevel@tonic-gate } 13780Sstevel@tonic-gate 13790Sstevel@tonic-gate /* 1380269Sericheng * DL_UINTDATA_REQ 13810Sstevel@tonic-gate */ 1382269Sericheng static boolean_t 1383269Sericheng proto_unitdata_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 13840Sstevel@tonic-gate { 1385269Sericheng queue_t *q = dsp->ds_wq; 1386269Sericheng dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)udlp; 1387269Sericheng off_t off; 1388269Sericheng size_t len, size; 1389269Sericheng const uint8_t *addr; 1390269Sericheng uint16_t sap; 1391269Sericheng uint_t addr_length; 1392269Sericheng mblk_t *bp, *cont; 1393269Sericheng uint32_t start, stuff, end, value, flags; 1394269Sericheng t_uscalar_t dl_err; 1395269Sericheng 1396269Sericheng rw_enter(&dsp->ds_lock, RW_READER); 1397269Sericheng 1398269Sericheng if (MBLKL(mp) < sizeof (dl_unitdata_req_t) || mp->b_cont == NULL) { 1399269Sericheng dl_err = DL_BADPRIM; 1400269Sericheng goto failed; 1401269Sericheng } 1402269Sericheng 1403269Sericheng if (dsp->ds_dlstate != DL_IDLE) { 1404269Sericheng dl_err = DL_OUTSTATE; 1405269Sericheng goto failed; 1406269Sericheng } 1407269Sericheng addr_length = dsp->ds_mip->mi_addr_length; 1408269Sericheng 1409269Sericheng off = dlp->dl_dest_addr_offset; 1410269Sericheng len = dlp->dl_dest_addr_length; 1411269Sericheng 1412269Sericheng if (!MBLKIN(mp, off, len) || !IS_P2ALIGNED(off, sizeof (uint16_t))) { 1413269Sericheng dl_err = DL_BADPRIM; 1414269Sericheng goto failed; 1415269Sericheng } 1416269Sericheng 1417269Sericheng if (len != addr_length + sizeof (uint16_t)) { 1418269Sericheng dl_err = DL_BADADDR; 1419269Sericheng goto failed; 1420269Sericheng } 1421269Sericheng 1422269Sericheng addr = mp->b_rptr + off; 1423269Sericheng sap = *(uint16_t *)(mp->b_rptr + off + addr_length); 1424269Sericheng 1425269Sericheng /* 1426269Sericheng * Check the length of the packet and the block types. 1427269Sericheng */ 1428269Sericheng size = 0; 1429269Sericheng cont = mp->b_cont; 1430269Sericheng for (bp = cont; bp != NULL; bp = bp->b_cont) { 1431269Sericheng if (DB_TYPE(bp) != M_DATA) 1432269Sericheng goto baddata; 1433269Sericheng 1434269Sericheng size += MBLKL(bp); 1435269Sericheng } 1436269Sericheng 1437269Sericheng if (size > dsp->ds_mip->mi_sdu_max) 1438269Sericheng goto baddata; 1439269Sericheng 1440269Sericheng /* 1441269Sericheng * Build a packet header. 1442269Sericheng */ 1443269Sericheng if ((bp = dls_header(dsp->ds_dc, addr, sap, dsp->ds_pri)) == NULL) { 1444269Sericheng dl_err = DL_BADADDR; 1445269Sericheng goto failed; 1446269Sericheng } 1447269Sericheng 1448269Sericheng /* 1449269Sericheng * We no longer need the M_PROTO header, so free it. 1450269Sericheng */ 1451269Sericheng freeb(mp); 1452269Sericheng 1453269Sericheng /* 1454269Sericheng * Transfer the checksum offload information if it is present. 1455269Sericheng */ 1456269Sericheng hcksum_retrieve(cont, NULL, NULL, &start, &stuff, &end, &value, 1457269Sericheng &flags); 1458269Sericheng (void) hcksum_assoc(bp, NULL, NULL, start, stuff, end, value, flags, 1459269Sericheng 0); 1460269Sericheng 1461269Sericheng /* 1462269Sericheng * Link the payload onto the new header. 1463269Sericheng */ 1464269Sericheng ASSERT(bp->b_cont == NULL); 1465269Sericheng bp->b_cont = cont; 1466269Sericheng 1467269Sericheng str_mdata_fastpath_put(dsp, bp); 1468269Sericheng rw_exit(&dsp->ds_lock); 1469269Sericheng return (B_TRUE); 1470269Sericheng failed: 1471269Sericheng rw_exit(&dsp->ds_lock); 1472269Sericheng dlerrorack(q, mp, DL_UNITDATA_REQ, dl_err, 0); 1473269Sericheng return (B_FALSE); 1474269Sericheng 1475269Sericheng baddata: 1476269Sericheng rw_exit(&dsp->ds_lock); 1477269Sericheng dluderrorind(q, mp, (void *)addr, len, DL_BADDATA, 0); 1478269Sericheng return (B_FALSE); 1479269Sericheng } 1480269Sericheng 1481269Sericheng /* 1482269Sericheng * DL_PASSIVE_REQ 1483269Sericheng */ 1484269Sericheng /* ARGSUSED */ 1485269Sericheng static boolean_t 1486269Sericheng proto_passive_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) 1487269Sericheng { 1488269Sericheng t_uscalar_t dl_err; 1489269Sericheng 1490269Sericheng rw_enter(&dsp->ds_lock, RW_WRITER); 1491269Sericheng /* 1492269Sericheng * If we've already become active by issuing an active primitive, 1493269Sericheng * then it's too late to try to become passive. 1494269Sericheng */ 1495269Sericheng if (dsp->ds_passivestate == DLD_ACTIVE) { 1496269Sericheng dl_err = DL_OUTSTATE; 1497269Sericheng goto failed; 1498269Sericheng } 1499269Sericheng 1500269Sericheng if (MBLKL(mp) < sizeof (dl_passive_req_t)) { 1501269Sericheng dl_err = DL_BADPRIM; 1502269Sericheng goto failed; 1503269Sericheng } 1504269Sericheng 1505269Sericheng dsp->ds_passivestate = DLD_PASSIVE; 1506269Sericheng rw_exit(&dsp->ds_lock); 1507269Sericheng dlokack(dsp->ds_wq, mp, DL_PASSIVE_REQ); 1508269Sericheng return (B_TRUE); 1509269Sericheng failed: 1510269Sericheng rw_exit(&dsp->ds_lock); 1511269Sericheng dlerrorack(dsp->ds_wq, mp, DL_PASSIVE_REQ, dl_err, 0); 1512269Sericheng return (B_FALSE); 1513269Sericheng } 1514269Sericheng 1515269Sericheng 1516269Sericheng /* 1517269Sericheng * Catch-all handler. 1518269Sericheng */ 1519269Sericheng static boolean_t 1520269Sericheng proto_req(dld_str_t *dsp, union DL_primitives *dlp, mblk_t *mp) 1521269Sericheng { 1522269Sericheng dlerrorack(dsp->ds_wq, mp, dlp->dl_primitive, DL_UNSUPPORTED, 0); 1523269Sericheng return (B_FALSE); 15240Sstevel@tonic-gate } 15250Sstevel@tonic-gate 15260Sstevel@tonic-gate static void 15270Sstevel@tonic-gate proto_poll_disable(dld_str_t *dsp) 15280Sstevel@tonic-gate { 15290Sstevel@tonic-gate mac_handle_t mh; 15300Sstevel@tonic-gate 1531269Sericheng ASSERT(RW_WRITE_HELD(&dsp->ds_lock)); 1532269Sericheng 15330Sstevel@tonic-gate if (!dsp->ds_polling) 15340Sstevel@tonic-gate return; 15350Sstevel@tonic-gate 15360Sstevel@tonic-gate /* 15370Sstevel@tonic-gate * It should be impossible to enable raw mode if polling is turned on. 15380Sstevel@tonic-gate */ 15390Sstevel@tonic-gate ASSERT(dsp->ds_mode != DLD_RAW); 15400Sstevel@tonic-gate 15410Sstevel@tonic-gate /* 15420Sstevel@tonic-gate * Reset the resource_add callback. 15430Sstevel@tonic-gate */ 15440Sstevel@tonic-gate mh = dls_mac(dsp->ds_dc); 15450Sstevel@tonic-gate mac_resource_set(mh, NULL, NULL); 1546*1184Skrgopi mac_resources(mh); 15470Sstevel@tonic-gate 15480Sstevel@tonic-gate /* 15490Sstevel@tonic-gate * Set receive function back to default. 15500Sstevel@tonic-gate */ 15510Sstevel@tonic-gate dls_rx_set(dsp->ds_dc, (dsp->ds_mode == DLD_FASTPATH) ? 15520Sstevel@tonic-gate dld_str_rx_fastpath : dld_str_rx_unitdata, (void *)dsp); 15530Sstevel@tonic-gate 15540Sstevel@tonic-gate /* 15550Sstevel@tonic-gate * Note that polling is disabled. 15560Sstevel@tonic-gate */ 15570Sstevel@tonic-gate dsp->ds_polling = B_FALSE; 15580Sstevel@tonic-gate } 15590Sstevel@tonic-gate 15600Sstevel@tonic-gate static boolean_t 1561*1184Skrgopi proto_poll_enable(dld_str_t *dsp, dl_capab_dls_t *pollp) 15620Sstevel@tonic-gate { 15630Sstevel@tonic-gate mac_handle_t mh; 15640Sstevel@tonic-gate 1565269Sericheng ASSERT(RW_WRITE_HELD(&dsp->ds_lock)); 15660Sstevel@tonic-gate ASSERT(!dsp->ds_polling); 15670Sstevel@tonic-gate 15680Sstevel@tonic-gate /* 15690Sstevel@tonic-gate * We cannot enable polling if raw mode 15700Sstevel@tonic-gate * has been enabled. 15710Sstevel@tonic-gate */ 15720Sstevel@tonic-gate if (dsp->ds_mode == DLD_RAW) 15730Sstevel@tonic-gate return (B_FALSE); 15740Sstevel@tonic-gate 15750Sstevel@tonic-gate mh = dls_mac(dsp->ds_dc); 15760Sstevel@tonic-gate 15770Sstevel@tonic-gate /* 15780Sstevel@tonic-gate * Register resources. 15790Sstevel@tonic-gate */ 1580*1184Skrgopi mac_resource_set(mh, (mac_resource_add_t)pollp->dls_ring_add, 1581*1184Skrgopi (void *)pollp->dls_rx_handle); 15820Sstevel@tonic-gate mac_resources(mh); 15830Sstevel@tonic-gate 15840Sstevel@tonic-gate /* 15850Sstevel@tonic-gate * Set the receive function. 15860Sstevel@tonic-gate */ 1587*1184Skrgopi dls_rx_set(dsp->ds_dc, (dls_rx_t)pollp->dls_rx, 1588*1184Skrgopi (void *)pollp->dls_rx_handle); 15890Sstevel@tonic-gate 15900Sstevel@tonic-gate /* 15910Sstevel@tonic-gate * Note that polling is enabled. This prevents further DLIOCHDRINFO 15920Sstevel@tonic-gate * ioctls from overwriting the receive function pointer. 15930Sstevel@tonic-gate */ 15940Sstevel@tonic-gate dsp->ds_polling = B_TRUE; 15950Sstevel@tonic-gate return (B_TRUE); 15960Sstevel@tonic-gate } 15970Sstevel@tonic-gate 1598*1184Skrgopi static void 1599*1184Skrgopi proto_soft_ring_disable(dld_str_t *dsp) 1600*1184Skrgopi { 1601*1184Skrgopi ASSERT(RW_WRITE_HELD(&dsp->ds_lock)); 1602*1184Skrgopi 1603*1184Skrgopi if (!dsp->ds_soft_ring) 1604*1184Skrgopi return; 1605*1184Skrgopi 1606*1184Skrgopi /* 1607*1184Skrgopi * It should be impossible to enable raw mode if soft_ring is turned on. 1608*1184Skrgopi */ 1609*1184Skrgopi ASSERT(dsp->ds_mode != DLD_RAW); 1610*1184Skrgopi proto_change_soft_ring_fanout(dsp, SOFT_RING_NONE); 1611*1184Skrgopi /* 1612*1184Skrgopi * Note that fanout is disabled. 1613*1184Skrgopi */ 1614*1184Skrgopi dsp->ds_soft_ring = B_FALSE; 1615*1184Skrgopi } 1616*1184Skrgopi 1617*1184Skrgopi static boolean_t 1618*1184Skrgopi proto_soft_ring_enable(dld_str_t *dsp, dl_capab_dls_t *soft_ringp) 1619*1184Skrgopi { 1620*1184Skrgopi ASSERT(RW_WRITE_HELD(&dsp->ds_lock)); 1621*1184Skrgopi ASSERT(!dsp->ds_soft_ring); 1622*1184Skrgopi 1623*1184Skrgopi /* 1624*1184Skrgopi * We cannot enable soft_ring if raw mode 1625*1184Skrgopi * has been enabled. 1626*1184Skrgopi */ 1627*1184Skrgopi if (dsp->ds_mode == DLD_RAW) 1628*1184Skrgopi return (B_FALSE); 1629*1184Skrgopi 1630*1184Skrgopi if (dls_soft_ring_enable(dsp->ds_dc, soft_ringp) == B_FALSE) 1631*1184Skrgopi return (B_FALSE); 1632*1184Skrgopi 1633*1184Skrgopi dsp->ds_soft_ring = B_TRUE; 1634*1184Skrgopi return (B_TRUE); 1635*1184Skrgopi } 1636*1184Skrgopi 1637*1184Skrgopi static void 1638*1184Skrgopi proto_change_soft_ring_fanout(dld_str_t *dsp, int type) 1639*1184Skrgopi { 1640*1184Skrgopi dls_rx_t rx; 1641*1184Skrgopi 1642*1184Skrgopi if (type == SOFT_RING_NONE) { 1643*1184Skrgopi rx = (dsp->ds_mode == DLD_FASTPATH) ? 1644*1184Skrgopi dld_str_rx_fastpath : dld_str_rx_unitdata; 1645*1184Skrgopi } else { 1646*1184Skrgopi rx = (dls_rx_t)dls_ether_soft_ring_fanout; 1647*1184Skrgopi } 1648*1184Skrgopi dls_soft_ring_rx_set(dsp->ds_dc, rx, dsp, type); 1649*1184Skrgopi } 1650*1184Skrgopi 1651*1184Skrgopi static void 1652*1184Skrgopi proto_stop_soft_ring_threads(void *arg) 1653*1184Skrgopi { 1654*1184Skrgopi dld_str_t *dsp = (dld_str_t *)arg; 1655*1184Skrgopi 1656*1184Skrgopi rw_enter(&dsp->ds_lock, RW_WRITER); 1657*1184Skrgopi dls_soft_ring_disable(dsp->ds_dc); 1658*1184Skrgopi dsp->ds_dlstate = DL_UNBOUND; 1659*1184Skrgopi rw_exit(&dsp->ds_lock); 1660*1184Skrgopi dlokack(dsp->ds_wq, dsp->ds_unbind_req, DL_UNBIND_REQ); 1661*1184Skrgopi rw_enter(&dsp->ds_lock, RW_WRITER); 1662*1184Skrgopi dsp->ds_task_id = NULL; 1663*1184Skrgopi rw_exit(&dsp->ds_lock); 1664*1184Skrgopi } 1665*1184Skrgopi 16660Sstevel@tonic-gate /* 16670Sstevel@tonic-gate * DL_CAPABILITY_ACK/DL_ERROR_ACK 16680Sstevel@tonic-gate */ 1669269Sericheng static boolean_t 1670269Sericheng proto_capability_advertise(dld_str_t *dsp, mblk_t *mp) 16710Sstevel@tonic-gate { 16720Sstevel@tonic-gate dl_capability_ack_t *dlap; 16730Sstevel@tonic-gate dl_capability_sub_t *dlsp; 16740Sstevel@tonic-gate size_t subsize; 1675*1184Skrgopi dl_capab_dls_t poll; 1676*1184Skrgopi dl_capab_dls_t soft_ring; 16770Sstevel@tonic-gate dl_capab_hcksum_t hcksum; 16780Sstevel@tonic-gate dl_capab_zerocopy_t zcopy; 16790Sstevel@tonic-gate uint8_t *ptr; 16800Sstevel@tonic-gate uint32_t cksum; 16810Sstevel@tonic-gate boolean_t poll_cap; 1682269Sericheng queue_t *q = dsp->ds_wq; 1683269Sericheng mblk_t *mp1; 1684269Sericheng 1685269Sericheng ASSERT(RW_READ_HELD(&dsp->ds_lock)); 16860Sstevel@tonic-gate 16870Sstevel@tonic-gate /* 16880Sstevel@tonic-gate * Initially assume no capabilities. 16890Sstevel@tonic-gate */ 16900Sstevel@tonic-gate subsize = 0; 16910Sstevel@tonic-gate 1692*1184Skrgopi /* Always advertize soft ring capability for GLDv3 drivers */ 1693*1184Skrgopi subsize += sizeof (dl_capability_sub_t) + sizeof (dl_capab_dls_t); 1694*1184Skrgopi 16950Sstevel@tonic-gate /* 16960Sstevel@tonic-gate * Check if polling can be enabled on this interface. 16970Sstevel@tonic-gate * If advertising DL_CAPAB_POLL has not been explicitly disabled 16980Sstevel@tonic-gate * then reserve space for that capability. 16990Sstevel@tonic-gate */ 17000Sstevel@tonic-gate poll_cap = ((dsp->ds_mip->mi_poll & DL_CAPAB_POLL) && 17010Sstevel@tonic-gate !(dld_opt & DLD_OPT_NO_POLL) && (dsp->ds_vid == VLAN_ID_NONE)); 17020Sstevel@tonic-gate if (poll_cap) { 17030Sstevel@tonic-gate subsize += sizeof (dl_capability_sub_t) + 1704*1184Skrgopi sizeof (dl_capab_dls_t); 17050Sstevel@tonic-gate } 17060Sstevel@tonic-gate 17070Sstevel@tonic-gate /* 17080Sstevel@tonic-gate * If the MAC interface supports checksum offload then reserve 17090Sstevel@tonic-gate * space for the DL_CAPAB_HCKSUM capability. 17100Sstevel@tonic-gate */ 17110Sstevel@tonic-gate if ((cksum = dsp->ds_mip->mi_cksum) != 0) { 17120Sstevel@tonic-gate subsize += sizeof (dl_capability_sub_t) + 17130Sstevel@tonic-gate sizeof (dl_capab_hcksum_t); 17140Sstevel@tonic-gate } 17150Sstevel@tonic-gate 17160Sstevel@tonic-gate /* 17170Sstevel@tonic-gate * If DL_CAPAB_ZEROCOPY has not be explicitly disabled then 17180Sstevel@tonic-gate * reserve space for it. 17190Sstevel@tonic-gate */ 17200Sstevel@tonic-gate if (!(dld_opt & DLD_OPT_NO_ZEROCOPY)) { 17210Sstevel@tonic-gate subsize += sizeof (dl_capability_sub_t) + 17220Sstevel@tonic-gate sizeof (dl_capab_zerocopy_t); 17230Sstevel@tonic-gate } 17240Sstevel@tonic-gate 17250Sstevel@tonic-gate /* 1726269Sericheng * If there are no capabilities to advertise or if we 1727269Sericheng * can't allocate a response, send a DL_ERROR_ACK. 17280Sstevel@tonic-gate */ 1729*1184Skrgopi if ((mp1 = reallocb(mp, 1730269Sericheng sizeof (dl_capability_ack_t) + subsize, 0)) == NULL) { 1731269Sericheng rw_exit(&dsp->ds_lock); 1732269Sericheng dlerrorack(q, mp, DL_CAPABILITY_REQ, DL_NOTSUPPORTED, 0); 1733269Sericheng return (B_FALSE); 17340Sstevel@tonic-gate } 17350Sstevel@tonic-gate 1736269Sericheng mp = mp1; 1737269Sericheng DB_TYPE(mp) = M_PROTO; 1738269Sericheng mp->b_wptr = mp->b_rptr + sizeof (dl_capability_ack_t) + subsize; 1739269Sericheng bzero(mp->b_rptr, MBLKL(mp)); 17400Sstevel@tonic-gate dlap = (dl_capability_ack_t *)mp->b_rptr; 17410Sstevel@tonic-gate dlap->dl_primitive = DL_CAPABILITY_ACK; 17420Sstevel@tonic-gate dlap->dl_sub_offset = sizeof (dl_capability_ack_t); 17430Sstevel@tonic-gate dlap->dl_sub_length = subsize; 17440Sstevel@tonic-gate ptr = (uint8_t *)&dlap[1]; 17450Sstevel@tonic-gate 17460Sstevel@tonic-gate /* 17470Sstevel@tonic-gate * IP polling interface. 17480Sstevel@tonic-gate */ 17490Sstevel@tonic-gate if (poll_cap) { 17500Sstevel@tonic-gate /* 1751269Sericheng * Attempt to disable just in case this is a re-negotiation; 1752269Sericheng * we need to become writer before doing so. 17530Sstevel@tonic-gate */ 1754269Sericheng if (!rw_tryupgrade(&dsp->ds_lock)) { 1755269Sericheng rw_exit(&dsp->ds_lock); 1756269Sericheng rw_enter(&dsp->ds_lock, RW_WRITER); 1757269Sericheng } 17580Sstevel@tonic-gate 1759269Sericheng /* 1760269Sericheng * Check if polling state has changed after we re-acquired 1761269Sericheng * the lock above, so that we don't mis-advertise it. 1762269Sericheng */ 1763269Sericheng poll_cap = ((dsp->ds_mip->mi_poll & DL_CAPAB_POLL) && 1764269Sericheng !(dld_opt & DLD_OPT_NO_POLL) && 1765269Sericheng (dsp->ds_vid == VLAN_ID_NONE)); 17660Sstevel@tonic-gate 1767269Sericheng if (!poll_cap) { 1768269Sericheng int poll_capab_size; 1769269Sericheng 1770269Sericheng rw_downgrade(&dsp->ds_lock); 1771269Sericheng 1772269Sericheng poll_capab_size = sizeof (dl_capability_sub_t) + 1773*1184Skrgopi sizeof (dl_capab_dls_t); 17740Sstevel@tonic-gate 1775269Sericheng mp->b_wptr -= poll_capab_size; 1776269Sericheng subsize -= poll_capab_size; 1777269Sericheng dlap->dl_sub_length = subsize; 1778269Sericheng } else { 1779269Sericheng proto_poll_disable(dsp); 1780269Sericheng 1781269Sericheng rw_downgrade(&dsp->ds_lock); 1782269Sericheng 1783269Sericheng dlsp = (dl_capability_sub_t *)ptr; 1784269Sericheng 1785269Sericheng dlsp->dl_cap = DL_CAPAB_POLL; 1786*1184Skrgopi dlsp->dl_length = sizeof (dl_capab_dls_t); 1787269Sericheng ptr += sizeof (dl_capability_sub_t); 17880Sstevel@tonic-gate 1789*1184Skrgopi bzero(&poll, sizeof (dl_capab_dls_t)); 1790*1184Skrgopi poll.dls_version = POLL_VERSION_1; 1791*1184Skrgopi poll.dls_flags = POLL_CAPABLE; 1792*1184Skrgopi poll.dls_tx_handle = (uintptr_t)dsp; 1793*1184Skrgopi poll.dls_tx = (uintptr_t)str_mdata_fastpath_put; 1794269Sericheng 1795*1184Skrgopi dlcapabsetqid(&(poll.dls_mid), dsp->ds_rq); 1796*1184Skrgopi bcopy(&poll, ptr, sizeof (dl_capab_dls_t)); 1797*1184Skrgopi ptr += sizeof (dl_capab_dls_t); 1798269Sericheng } 17990Sstevel@tonic-gate } 18000Sstevel@tonic-gate 1801269Sericheng ASSERT(RW_READ_HELD(&dsp->ds_lock)); 1802269Sericheng 1803*1184Skrgopi dlsp = (dl_capability_sub_t *)ptr; 1804*1184Skrgopi 1805*1184Skrgopi dlsp->dl_cap = DL_CAPAB_SOFT_RING; 1806*1184Skrgopi dlsp->dl_length = sizeof (dl_capab_dls_t); 1807*1184Skrgopi ptr += sizeof (dl_capability_sub_t); 1808*1184Skrgopi 1809*1184Skrgopi bzero(&soft_ring, sizeof (dl_capab_dls_t)); 1810*1184Skrgopi soft_ring.dls_version = SOFT_RING_VERSION_1; 1811*1184Skrgopi soft_ring.dls_flags = SOFT_RING_CAPABLE; 1812*1184Skrgopi soft_ring.dls_tx_handle = (uintptr_t)dsp; 1813*1184Skrgopi soft_ring.dls_tx = (uintptr_t)str_mdata_fastpath_put; 1814*1184Skrgopi soft_ring.dls_ring_change_status = 1815*1184Skrgopi (uintptr_t)proto_change_soft_ring_fanout; 1816*1184Skrgopi soft_ring.dls_ring_bind = (uintptr_t)soft_ring_bind; 1817*1184Skrgopi soft_ring.dls_ring_unbind = (uintptr_t)soft_ring_unbind; 1818*1184Skrgopi 1819*1184Skrgopi dlcapabsetqid(&(soft_ring.dls_mid), dsp->ds_rq); 1820*1184Skrgopi bcopy(&soft_ring, ptr, sizeof (dl_capab_dls_t)); 1821*1184Skrgopi ptr += sizeof (dl_capab_dls_t); 1822*1184Skrgopi 18230Sstevel@tonic-gate /* 18240Sstevel@tonic-gate * TCP/IP checksum offload. 18250Sstevel@tonic-gate */ 18260Sstevel@tonic-gate if (cksum != 0) { 18270Sstevel@tonic-gate dlsp = (dl_capability_sub_t *)ptr; 18280Sstevel@tonic-gate 18290Sstevel@tonic-gate dlsp->dl_cap = DL_CAPAB_HCKSUM; 18300Sstevel@tonic-gate dlsp->dl_length = sizeof (dl_capab_hcksum_t); 18310Sstevel@tonic-gate ptr += sizeof (dl_capability_sub_t); 18320Sstevel@tonic-gate 18330Sstevel@tonic-gate bzero(&hcksum, sizeof (dl_capab_hcksum_t)); 18340Sstevel@tonic-gate hcksum.hcksum_version = HCKSUM_VERSION_1; 18350Sstevel@tonic-gate hcksum.hcksum_txflags = cksum; 18360Sstevel@tonic-gate 18370Sstevel@tonic-gate dlcapabsetqid(&(hcksum.hcksum_mid), dsp->ds_rq); 18380Sstevel@tonic-gate bcopy(&hcksum, ptr, sizeof (dl_capab_hcksum_t)); 18390Sstevel@tonic-gate ptr += sizeof (dl_capab_hcksum_t); 18400Sstevel@tonic-gate } 18410Sstevel@tonic-gate 18420Sstevel@tonic-gate /* 18430Sstevel@tonic-gate * Zero copy 18440Sstevel@tonic-gate */ 18450Sstevel@tonic-gate if (!(dld_opt & DLD_OPT_NO_ZEROCOPY)) { 18460Sstevel@tonic-gate dlsp = (dl_capability_sub_t *)ptr; 18470Sstevel@tonic-gate 18480Sstevel@tonic-gate dlsp->dl_cap = DL_CAPAB_ZEROCOPY; 18490Sstevel@tonic-gate dlsp->dl_length = sizeof (dl_capab_zerocopy_t); 18500Sstevel@tonic-gate ptr += sizeof (dl_capability_sub_t); 18510Sstevel@tonic-gate 18520Sstevel@tonic-gate bzero(&zcopy, sizeof (dl_capab_zerocopy_t)); 18530Sstevel@tonic-gate zcopy.zerocopy_version = ZEROCOPY_VERSION_1; 18540Sstevel@tonic-gate zcopy.zerocopy_flags = DL_CAPAB_VMSAFE_MEM; 18550Sstevel@tonic-gate 18560Sstevel@tonic-gate dlcapabsetqid(&(zcopy.zerocopy_mid), dsp->ds_rq); 18570Sstevel@tonic-gate bcopy(&zcopy, ptr, sizeof (dl_capab_zerocopy_t)); 18580Sstevel@tonic-gate ptr += sizeof (dl_capab_zerocopy_t); 18590Sstevel@tonic-gate } 18600Sstevel@tonic-gate 18610Sstevel@tonic-gate ASSERT(ptr == mp->b_rptr + sizeof (dl_capability_ack_t) + subsize); 1862269Sericheng 1863269Sericheng rw_exit(&dsp->ds_lock); 1864269Sericheng qreply(q, mp); 1865269Sericheng return (B_TRUE); 18660Sstevel@tonic-gate } 1867