15d460eafSCathy Zhou /* 25d460eafSCathy Zhou * CDDL HEADER START 35d460eafSCathy Zhou * 45d460eafSCathy Zhou * The contents of this file are subject to the terms of the 55d460eafSCathy Zhou * Common Development and Distribution License (the "License"). 65d460eafSCathy Zhou * You may not use this file except in compliance with the License. 75d460eafSCathy Zhou * 85d460eafSCathy Zhou * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95d460eafSCathy Zhou * or http://www.opensolaris.org/os/licensing. 105d460eafSCathy Zhou * See the License for the specific language governing permissions 115d460eafSCathy Zhou * and limitations under the License. 125d460eafSCathy Zhou * 135d460eafSCathy Zhou * When distributing Covered Code, include this CDDL HEADER in each 145d460eafSCathy Zhou * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155d460eafSCathy Zhou * If applicable, add the following below this CDDL HEADER, with the 165d460eafSCathy Zhou * fields enclosed by brackets "[]" replaced with your own identifying 175d460eafSCathy Zhou * information: Portions Copyright [yyyy] [name of copyright owner] 185d460eafSCathy Zhou * 195d460eafSCathy Zhou * CDDL HEADER END 205d460eafSCathy Zhou */ 215d460eafSCathy Zhou /* 225d460eafSCathy Zhou * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 235d460eafSCathy Zhou * Use is subject to license terms. 245d460eafSCathy Zhou */ 255d460eafSCathy Zhou 265d460eafSCathy Zhou /* 275d460eafSCathy Zhou * Softmac data-path switching: 285d460eafSCathy Zhou * 295d460eafSCathy Zhou * - Fast-path model 305d460eafSCathy Zhou * 315d460eafSCathy Zhou * When the softmac fast-path is used, a dedicated lower-stream 325d460eafSCathy Zhou * will be opened over the legacy device for each IP/ARP (upper-)stream 335d460eafSCathy Zhou * over the softMAC, and all DLPI messages (including control messages 345d460eafSCathy Zhou * and data messages) will be exchanged between the upper-stream and 355d460eafSCathy Zhou * the corresponding lower-stream directly. Therefore, the data 365d460eafSCathy Zhou * demultiplexing, filtering and classification processing will be done 375d460eafSCathy Zhou * by the lower-stream, and the GLDv3 DLS/MAC layer processing will be 385d460eafSCathy Zhou * no longer needed. 395d460eafSCathy Zhou * 405d460eafSCathy Zhou * - Slow-path model 415d460eafSCathy Zhou * 425d460eafSCathy Zhou * Some GLDv3 features requires the GLDv3 DLS/MAC layer processing to 435d460eafSCathy Zhou * not be bypassed to assure its function correctness. For example, 445d460eafSCathy Zhou * softmac fast-path must be disabled to support GLDv3 VNIC functionality. 455d460eafSCathy Zhou * In this case, a shared lower-stream will be opened over the legacy 465d460eafSCathy Zhou * device, which is responsible for implementing the GLDv3 callbacks 475d460eafSCathy Zhou * and passing RAW data messages between the legacy devices and the GLDv3 485d460eafSCathy Zhou * framework. 495d460eafSCathy Zhou * 505d460eafSCathy Zhou * By default, the softmac fast-path mode will be used to assure the 515d460eafSCathy Zhou * performance; MAC clients will be able to request to disable the softmac 525d460eafSCathy Zhou * fast-path mode to support certain features, and if that succeeds, 535d460eafSCathy Zhou * the system will fallback to the slow-path softmac data-path model. 545d460eafSCathy Zhou * 555d460eafSCathy Zhou * 565d460eafSCathy Zhou * The details of the softmac data fast-path model is stated as below 575d460eafSCathy Zhou * 585d460eafSCathy Zhou * 1. When a stream is opened on a softMAC, the softmac module will takes 595d460eafSCathy Zhou * over the DLPI processing on this stream; 605d460eafSCathy Zhou * 615d460eafSCathy Zhou * 2. For IP/ARP streams over a softMAC, softmac data fast-path will be 625d460eafSCathy Zhou * used by default, unless fast-path is disabled by any MAC client 635d460eafSCathy Zhou * explicitly. The softmac module first identifies an IP/ARP stream 645d460eafSCathy Zhou * by seeing whether there is a SIOCSLIFNAME ioctl sent from upstream, 655d460eafSCathy Zhou * if there is one, this stream is either an IP or an ARP stream 665d460eafSCathy Zhou * and will use fast-path potentially; 675d460eafSCathy Zhou * 685d460eafSCathy Zhou * 3. When the softmac fast-path is used, an dedicated lower-stream will 695d460eafSCathy Zhou * be setup for each IP/ARP stream (1-1 mapping). From that point on, 705d460eafSCathy Zhou * all control and data messages will be exchanged between the IP/ARP 715d460eafSCathy Zhou * upper-stream and the legacy device through this dedicated 725d460eafSCathy Zhou * lower-stream. As a result, the DLS/MAC layer processing in GLDv3 735d460eafSCathy Zhou * will be skipped, and this greatly improves the performance; 745d460eafSCathy Zhou * 755d460eafSCathy Zhou * 4. When the softmac data fast-path is disabled by a MAC client (e.g., 765d460eafSCathy Zhou * by a VNIC), all the IP/ARP upper streams will try to switch from 775d460eafSCathy Zhou * the fast-path to the slow-path. The dedicated lower-stream will be 785d460eafSCathy Zhou * destroyed, and all the control and data-messages will go through the 795d460eafSCathy Zhou * existing GLDv3 code path and (in the end) the shared lower-stream; 805d460eafSCathy Zhou * 815d460eafSCathy Zhou * 5. On the other hand, when the last MAC client cancels its fast-path 825d460eafSCathy Zhou * disable request, all the IP/ARP streams will try to switch back to 835d460eafSCathy Zhou * the fast-path mode; 845d460eafSCathy Zhou * 855d460eafSCathy Zhou * Step 5 and 6 both rely on the data-path mode switching process 865d460eafSCathy Zhou * described below: 875d460eafSCathy Zhou * 885d460eafSCathy Zhou * 1) To switch the softmac data-path mode (between fast-path and slow-path), 895d460eafSCathy Zhou * softmac will first send a DL_NOTE_REPLUMB DL_NOTIFY_IND message 905d460eafSCathy Zhou * upstream over each IP/ARP streams that needs data-path mode switching; 915d460eafSCathy Zhou * 925d460eafSCathy Zhou * 2) When IP receives this DL_NOTE_REPLUMB message, it will bring down 935d460eafSCathy Zhou * all the IP interfaces on the corresponding ill (IP Lower level 945d460eafSCathy Zhou * structure), and bring up those interfaces over again; this will in 955d460eafSCathy Zhou * turn cause the ARP to "replumb" the interface. 965d460eafSCathy Zhou * 975d460eafSCathy Zhou * During the replumb process, both IP and ARP will send downstream the 985d460eafSCathy Zhou * necessary DL_DISABMULTI_REQ and DL_UNBIND_REQ messages and cleanup 995d460eafSCathy Zhou * the old state of the underlying softMAC, following with the necessary 1005d460eafSCathy Zhou * DL_BIND_REQ and DL_ENABMULTI_REQ messages to setup the new state. 1015d460eafSCathy Zhou * Between the cleanup and re-setup process, IP/ARP will also send down 1025d460eafSCathy Zhou * a DL_NOTE_REPLUMB_DONE DL_NOTIFY_CONF messages to the softMAC to 1035d460eafSCathy Zhou * indicate the *switching point*; 1045d460eafSCathy Zhou * 1055d460eafSCathy Zhou * 3) When softmac receives the DL_NOTE_REPLUMB_DONE message, it either 1065d460eafSCathy Zhou * creates or destroys the dedicated lower-stream (depending on which 1075d460eafSCathy Zhou * data-path mode the softMAC switches to), and change the softmac 1085d460eafSCathy Zhou * data-path mode. From then on, softmac will process all the succeeding 1095d460eafSCathy Zhou * control messages (including the DL_BIND_REQ and DL_ENABMULTI_REQ 1105d460eafSCathy Zhou * messages) and data messages based on new data-path mode. 1115d460eafSCathy Zhou */ 1125d460eafSCathy Zhou 1135d460eafSCathy Zhou #include <sys/types.h> 1145d460eafSCathy Zhou #include <sys/disp.h> 1155d460eafSCathy Zhou #include <sys/callb.h> 1165d460eafSCathy Zhou #include <sys/sysmacros.h> 1175d460eafSCathy Zhou #include <sys/file.h> 1185d460eafSCathy Zhou #include <sys/vlan.h> 1195d460eafSCathy Zhou #include <sys/dld.h> 1205d460eafSCathy Zhou #include <sys/sockio.h> 1215d460eafSCathy Zhou #include <sys/softmac_impl.h> 12282a2fc47SJames Carlson #include <net/if.h> 1235d460eafSCathy Zhou 1245d460eafSCathy Zhou static kmutex_t softmac_taskq_lock; 1255d460eafSCathy Zhou static kcondvar_t softmac_taskq_cv; 1265d460eafSCathy Zhou static list_t softmac_taskq_list; /* List of softmac_upper_t */ 1275d460eafSCathy Zhou boolean_t softmac_taskq_quit; 1285d460eafSCathy Zhou boolean_t softmac_taskq_done; 1295d460eafSCathy Zhou 1305d460eafSCathy Zhou static void softmac_taskq_dispatch(); 1315d460eafSCathy Zhou static int softmac_fastpath_setup(softmac_upper_t *); 1325d460eafSCathy Zhou static mac_tx_cookie_t softmac_fastpath_wput_data(softmac_upper_t *, mblk_t *, 1335d460eafSCathy Zhou uintptr_t, uint16_t); 1345d460eafSCathy Zhou static void softmac_datapath_switch_done(softmac_upper_t *); 1355d460eafSCathy Zhou 1365d460eafSCathy Zhou void 1375d460eafSCathy Zhou softmac_fp_init() 1385d460eafSCathy Zhou { 1395d460eafSCathy Zhou mutex_init(&softmac_taskq_lock, NULL, MUTEX_DRIVER, NULL); 1405d460eafSCathy Zhou cv_init(&softmac_taskq_cv, NULL, CV_DRIVER, NULL); 1415d460eafSCathy Zhou 1425d460eafSCathy Zhou softmac_taskq_quit = B_FALSE; 1435d460eafSCathy Zhou softmac_taskq_done = B_FALSE; 1445d460eafSCathy Zhou list_create(&softmac_taskq_list, sizeof (softmac_upper_t), 1455d460eafSCathy Zhou offsetof(softmac_upper_t, su_taskq_list_node)); 1465d460eafSCathy Zhou (void) thread_create(NULL, 0, softmac_taskq_dispatch, NULL, 0, 1475d460eafSCathy Zhou &p0, TS_RUN, minclsyspri); 1485d460eafSCathy Zhou } 1495d460eafSCathy Zhou 1505d460eafSCathy Zhou void 1515d460eafSCathy Zhou softmac_fp_fini() 1525d460eafSCathy Zhou { 1535d460eafSCathy Zhou /* 1545d460eafSCathy Zhou * Request the softmac_taskq thread to quit and wait for it to be done. 1555d460eafSCathy Zhou */ 1565d460eafSCathy Zhou mutex_enter(&softmac_taskq_lock); 1575d460eafSCathy Zhou softmac_taskq_quit = B_TRUE; 1585d460eafSCathy Zhou cv_signal(&softmac_taskq_cv); 1595d460eafSCathy Zhou while (!softmac_taskq_done) 1605d460eafSCathy Zhou cv_wait(&softmac_taskq_cv, &softmac_taskq_lock); 1615d460eafSCathy Zhou mutex_exit(&softmac_taskq_lock); 1625d460eafSCathy Zhou list_destroy(&softmac_taskq_list); 1635d460eafSCathy Zhou 1645d460eafSCathy Zhou mutex_destroy(&softmac_taskq_lock); 1655d460eafSCathy Zhou cv_destroy(&softmac_taskq_cv); 1665d460eafSCathy Zhou } 1675d460eafSCathy Zhou 1685d460eafSCathy Zhou static boolean_t 1695d460eafSCathy Zhou check_ip_above(queue_t *q) 1705d460eafSCathy Zhou { 1715d460eafSCathy Zhou queue_t *next_q; 1725d460eafSCathy Zhou boolean_t ret = B_TRUE; 1735d460eafSCathy Zhou 1745d460eafSCathy Zhou claimstr(q); 1755d460eafSCathy Zhou next_q = q->q_next; 1765d460eafSCathy Zhou if (strcmp(next_q->q_qinfo->qi_minfo->mi_idname, "ip") != 0) 1775d460eafSCathy Zhou ret = B_FALSE; 1785d460eafSCathy Zhou releasestr(q); 1795d460eafSCathy Zhou return (ret); 1805d460eafSCathy Zhou } 1815d460eafSCathy Zhou 1825d460eafSCathy Zhou /* ARGSUSED */ 1835d460eafSCathy Zhou static int 1845d460eafSCathy Zhou softmac_capab_perim(softmac_upper_t *sup, void *data, uint_t flags) 1855d460eafSCathy Zhou { 1865d460eafSCathy Zhou switch (flags) { 1875d460eafSCathy Zhou case DLD_ENABLE: 1885d460eafSCathy Zhou mutex_enter(&sup->su_mutex); 1895d460eafSCathy Zhou break; 1905d460eafSCathy Zhou case DLD_DISABLE: 1915d460eafSCathy Zhou mutex_exit(&sup->su_mutex); 1925d460eafSCathy Zhou break; 1935d460eafSCathy Zhou case DLD_QUERY: 1945d460eafSCathy Zhou return (MUTEX_HELD(&sup->su_mutex)); 1955d460eafSCathy Zhou } 1965d460eafSCathy Zhou return (0); 1975d460eafSCathy Zhou } 1985d460eafSCathy Zhou 1995d460eafSCathy Zhou static mac_tx_notify_handle_t 20079eeb645SCathy Zhou softmac_client_tx_notify(softmac_upper_t *sup, mac_tx_notify_t func, void *arg) 2015d460eafSCathy Zhou { 20279eeb645SCathy Zhou ASSERT(MUTEX_HELD(&sup->su_mutex)); 20379eeb645SCathy Zhou 20479eeb645SCathy Zhou if (func != NULL) { 20579eeb645SCathy Zhou sup->su_tx_notify_func = func; 20679eeb645SCathy Zhou sup->su_tx_notify_arg = arg; 20779eeb645SCathy Zhou } else { 20879eeb645SCathy Zhou /* 20979eeb645SCathy Zhou * Wait for all tx_notify_func call to be done. 21079eeb645SCathy Zhou */ 21179eeb645SCathy Zhou while (sup->su_tx_inprocess != 0) 21279eeb645SCathy Zhou cv_wait(&sup->su_cv, &sup->su_mutex); 21379eeb645SCathy Zhou 21479eeb645SCathy Zhou sup->su_tx_notify_func = NULL; 21579eeb645SCathy Zhou sup->su_tx_notify_arg = NULL; 21679eeb645SCathy Zhou } 21779eeb645SCathy Zhou return ((mac_tx_notify_handle_t)sup); 21879eeb645SCathy Zhou } 21979eeb645SCathy Zhou 22079eeb645SCathy Zhou static boolean_t 22179eeb645SCathy Zhou softmac_tx_is_flow_blocked(softmac_upper_t *sup, mac_tx_cookie_t cookie) 22279eeb645SCathy Zhou { 22379eeb645SCathy Zhou ASSERT(cookie == (mac_tx_cookie_t)sup); 22479eeb645SCathy Zhou return (sup->su_tx_busy); 2255d460eafSCathy Zhou } 2265d460eafSCathy Zhou 2275d460eafSCathy Zhou static int 2285d460eafSCathy Zhou softmac_capab_direct(softmac_upper_t *sup, void *data, uint_t flags) 2295d460eafSCathy Zhou { 2305d460eafSCathy Zhou dld_capab_direct_t *direct = data; 2315d460eafSCathy Zhou softmac_lower_t *slp = sup->su_slp; 2325d460eafSCathy Zhou 2335d460eafSCathy Zhou ASSERT(MUTEX_HELD(&sup->su_mutex)); 2345d460eafSCathy Zhou 2355d460eafSCathy Zhou ASSERT(sup->su_mode == SOFTMAC_FASTPATH); 2365d460eafSCathy Zhou 2375d460eafSCathy Zhou switch (flags) { 2385d460eafSCathy Zhou case DLD_ENABLE: 2395d460eafSCathy Zhou if (sup->su_direct) 2405d460eafSCathy Zhou return (0); 2415d460eafSCathy Zhou 2425d460eafSCathy Zhou sup->su_direct_rxinfo.slr_rx = (softmac_rx_t)direct->di_rx_cf; 2435d460eafSCathy Zhou sup->su_direct_rxinfo.slr_arg = direct->di_rx_ch; 2445d460eafSCathy Zhou slp->sl_rxinfo = &sup->su_direct_rxinfo; 2455d460eafSCathy Zhou direct->di_tx_df = (uintptr_t)softmac_fastpath_wput_data; 2465d460eafSCathy Zhou direct->di_tx_dh = sup; 24779eeb645SCathy Zhou direct->di_tx_fctl_df = (uintptr_t)softmac_tx_is_flow_blocked; 24879eeb645SCathy Zhou direct->di_tx_fctl_dh = sup; 2495d460eafSCathy Zhou direct->di_tx_cb_df = (uintptr_t)softmac_client_tx_notify; 25079eeb645SCathy Zhou direct->di_tx_cb_dh = sup; 2515d460eafSCathy Zhou sup->su_direct = B_TRUE; 2525d460eafSCathy Zhou return (0); 2535d460eafSCathy Zhou 2545d460eafSCathy Zhou case DLD_DISABLE: 2555d460eafSCathy Zhou if (!sup->su_direct) 2565d460eafSCathy Zhou return (0); 2575d460eafSCathy Zhou 2585d460eafSCathy Zhou slp->sl_rxinfo = &sup->su_rxinfo; 2595d460eafSCathy Zhou sup->su_direct = B_FALSE; 2605d460eafSCathy Zhou return (0); 2615d460eafSCathy Zhou } 2625d460eafSCathy Zhou return (ENOTSUP); 2635d460eafSCathy Zhou } 2645d460eafSCathy Zhou 2655d460eafSCathy Zhou static int 2665d460eafSCathy Zhou softmac_dld_capab(softmac_upper_t *sup, uint_t type, void *data, uint_t flags) 2675d460eafSCathy Zhou { 2685d460eafSCathy Zhou int err; 2695d460eafSCathy Zhou 2705d460eafSCathy Zhou /* 2715d460eafSCathy Zhou * Don't enable direct callback capabilities unless the caller is 2725d460eafSCathy Zhou * the IP client. When a module is inserted in a stream (_I_INSERT) 2735d460eafSCathy Zhou * the stack initiates capability disable, but due to races, the 2745d460eafSCathy Zhou * module insertion may complete before the capability disable 2755d460eafSCathy Zhou * completes. So we limit the check to DLD_ENABLE case. 2765d460eafSCathy Zhou */ 2775d460eafSCathy Zhou if ((flags == DLD_ENABLE && type != DLD_CAPAB_PERIM) && 2785d460eafSCathy Zhou !check_ip_above(sup->su_rq)) { 2795d460eafSCathy Zhou return (ENOTSUP); 2805d460eafSCathy Zhou } 2815d460eafSCathy Zhou 2825d460eafSCathy Zhou switch (type) { 2835d460eafSCathy Zhou case DLD_CAPAB_DIRECT: 2845d460eafSCathy Zhou err = softmac_capab_direct(sup, data, flags); 2855d460eafSCathy Zhou break; 2865d460eafSCathy Zhou 2875d460eafSCathy Zhou case DLD_CAPAB_PERIM: 2885d460eafSCathy Zhou err = softmac_capab_perim(sup, data, flags); 2895d460eafSCathy Zhou break; 2905d460eafSCathy Zhou 2915d460eafSCathy Zhou default: 2925d460eafSCathy Zhou err = ENOTSUP; 2935d460eafSCathy Zhou break; 2945d460eafSCathy Zhou } 2955d460eafSCathy Zhou return (err); 2965d460eafSCathy Zhou } 2975d460eafSCathy Zhou 2985d460eafSCathy Zhou static void 2995d460eafSCathy Zhou softmac_capability_advertise(softmac_upper_t *sup, mblk_t *mp) 3005d460eafSCathy Zhou { 3015d460eafSCathy Zhou dl_capability_ack_t *dlap; 3025d460eafSCathy Zhou dl_capability_sub_t *dlsp; 3035d460eafSCathy Zhou t_uscalar_t subsize; 3045d460eafSCathy Zhou uint8_t *ptr; 3055d460eafSCathy Zhou queue_t *q = sup->su_wq; 3065d460eafSCathy Zhou mblk_t *mp1; 3075d460eafSCathy Zhou softmac_t *softmac = sup->su_softmac; 3085d460eafSCathy Zhou boolean_t dld_capable = B_FALSE; 3095d460eafSCathy Zhou boolean_t hcksum_capable = B_FALSE; 3105d460eafSCathy Zhou boolean_t zcopy_capable = B_FALSE; 3115d460eafSCathy Zhou boolean_t mdt_capable = B_FALSE; 3125d460eafSCathy Zhou 3135d460eafSCathy Zhou ASSERT(sup->su_mode == SOFTMAC_FASTPATH); 3145d460eafSCathy Zhou 3155d460eafSCathy Zhou /* 3165d460eafSCathy Zhou * Initially assume no capabilities. 3175d460eafSCathy Zhou */ 3185d460eafSCathy Zhou subsize = 0; 3195d460eafSCathy Zhou 3205d460eafSCathy Zhou /* 3215d460eafSCathy Zhou * Direct capability negotiation interface between IP and softmac 3225d460eafSCathy Zhou */ 3235d460eafSCathy Zhou if (check_ip_above(sup->su_rq)) { 3245d460eafSCathy Zhou dld_capable = B_TRUE; 3255d460eafSCathy Zhou subsize += sizeof (dl_capability_sub_t) + 3265d460eafSCathy Zhou sizeof (dl_capab_dld_t); 3275d460eafSCathy Zhou } 3285d460eafSCathy Zhou 3295d460eafSCathy Zhou /* 3305d460eafSCathy Zhou * Check if checksum offload is supported on this MAC. 3315d460eafSCathy Zhou */ 3325d460eafSCathy Zhou if (softmac->smac_capab_flags & MAC_CAPAB_HCKSUM) { 3335d460eafSCathy Zhou hcksum_capable = B_TRUE; 3345d460eafSCathy Zhou subsize += sizeof (dl_capability_sub_t) + 3355d460eafSCathy Zhou sizeof (dl_capab_hcksum_t); 3365d460eafSCathy Zhou } 3375d460eafSCathy Zhou 3385d460eafSCathy Zhou /* 3395d460eafSCathy Zhou * Check if zerocopy is supported on this interface. 3405d460eafSCathy Zhou */ 3415d460eafSCathy Zhou if (!(softmac->smac_capab_flags & MAC_CAPAB_NO_ZCOPY)) { 3425d460eafSCathy Zhou zcopy_capable = B_TRUE; 3435d460eafSCathy Zhou subsize += sizeof (dl_capability_sub_t) + 3445d460eafSCathy Zhou sizeof (dl_capab_zerocopy_t); 3455d460eafSCathy Zhou } 3465d460eafSCathy Zhou 3475d460eafSCathy Zhou if (softmac->smac_mdt) { 3485d460eafSCathy Zhou mdt_capable = B_TRUE; 3495d460eafSCathy Zhou subsize += sizeof (dl_capability_sub_t) + 3505d460eafSCathy Zhou sizeof (dl_capab_mdt_t); 3515d460eafSCathy Zhou } 3525d460eafSCathy Zhou 3535d460eafSCathy Zhou /* 3545d460eafSCathy Zhou * If there are no capabilities to advertise or if we 3555d460eafSCathy Zhou * can't allocate a response, send a DL_ERROR_ACK. 3565d460eafSCathy Zhou */ 3575d460eafSCathy Zhou if ((subsize == 0) || (mp1 = reallocb(mp, 3585d460eafSCathy Zhou sizeof (dl_capability_ack_t) + subsize, 0)) == NULL) { 3595d460eafSCathy Zhou dlerrorack(q, mp, DL_CAPABILITY_REQ, DL_NOTSUPPORTED, 0); 3605d460eafSCathy Zhou return; 3615d460eafSCathy Zhou } 3625d460eafSCathy Zhou 3635d460eafSCathy Zhou mp = mp1; 3645d460eafSCathy Zhou DB_TYPE(mp) = M_PROTO; 3655d460eafSCathy Zhou mp->b_wptr = mp->b_rptr + sizeof (dl_capability_ack_t) + subsize; 3665d460eafSCathy Zhou bzero(mp->b_rptr, MBLKL(mp)); 3675d460eafSCathy Zhou dlap = (dl_capability_ack_t *)mp->b_rptr; 3685d460eafSCathy Zhou dlap->dl_primitive = DL_CAPABILITY_ACK; 3695d460eafSCathy Zhou dlap->dl_sub_offset = sizeof (dl_capability_ack_t); 3705d460eafSCathy Zhou dlap->dl_sub_length = subsize; 3715d460eafSCathy Zhou ptr = (uint8_t *)&dlap[1]; 3725d460eafSCathy Zhou 3735d460eafSCathy Zhou /* 3745d460eafSCathy Zhou * IP polling interface. 3755d460eafSCathy Zhou */ 3765d460eafSCathy Zhou if (dld_capable) { 3775d460eafSCathy Zhou dl_capab_dld_t dld; 3785d460eafSCathy Zhou 3795d460eafSCathy Zhou dlsp = (dl_capability_sub_t *)ptr; 3805d460eafSCathy Zhou dlsp->dl_cap = DL_CAPAB_DLD; 3815d460eafSCathy Zhou dlsp->dl_length = sizeof (dl_capab_dld_t); 3825d460eafSCathy Zhou ptr += sizeof (dl_capability_sub_t); 3835d460eafSCathy Zhou 3845d460eafSCathy Zhou bzero(&dld, sizeof (dl_capab_dld_t)); 3855d460eafSCathy Zhou dld.dld_version = DLD_CURRENT_VERSION; 3865d460eafSCathy Zhou dld.dld_capab = (uintptr_t)softmac_dld_capab; 3875d460eafSCathy Zhou dld.dld_capab_handle = (uintptr_t)sup; 3885d460eafSCathy Zhou 3895d460eafSCathy Zhou dlcapabsetqid(&(dld.dld_mid), sup->su_rq); 3905d460eafSCathy Zhou bcopy(&dld, ptr, sizeof (dl_capab_dld_t)); 3915d460eafSCathy Zhou ptr += sizeof (dl_capab_dld_t); 3925d460eafSCathy Zhou } 3935d460eafSCathy Zhou 3945d460eafSCathy Zhou /* 3955d460eafSCathy Zhou * TCP/IP checksum offload. 3965d460eafSCathy Zhou */ 3975d460eafSCathy Zhou if (hcksum_capable) { 3985d460eafSCathy Zhou dl_capab_hcksum_t hcksum; 3995d460eafSCathy Zhou 4005d460eafSCathy Zhou dlsp = (dl_capability_sub_t *)ptr; 4015d460eafSCathy Zhou 4025d460eafSCathy Zhou dlsp->dl_cap = DL_CAPAB_HCKSUM; 4035d460eafSCathy Zhou dlsp->dl_length = sizeof (dl_capab_hcksum_t); 4045d460eafSCathy Zhou ptr += sizeof (dl_capability_sub_t); 4055d460eafSCathy Zhou 4065d460eafSCathy Zhou bzero(&hcksum, sizeof (dl_capab_hcksum_t)); 4075d460eafSCathy Zhou hcksum.hcksum_version = HCKSUM_VERSION_1; 4085d460eafSCathy Zhou hcksum.hcksum_txflags = softmac->smac_hcksum_txflags; 4095d460eafSCathy Zhou dlcapabsetqid(&(hcksum.hcksum_mid), sup->su_rq); 4105d460eafSCathy Zhou bcopy(&hcksum, ptr, sizeof (dl_capab_hcksum_t)); 4115d460eafSCathy Zhou ptr += sizeof (dl_capab_hcksum_t); 4125d460eafSCathy Zhou } 4135d460eafSCathy Zhou 4145d460eafSCathy Zhou /* 4155d460eafSCathy Zhou * Zero copy 4165d460eafSCathy Zhou */ 4175d460eafSCathy Zhou if (zcopy_capable) { 4185d460eafSCathy Zhou dl_capab_zerocopy_t zcopy; 4195d460eafSCathy Zhou 4205d460eafSCathy Zhou dlsp = (dl_capability_sub_t *)ptr; 4215d460eafSCathy Zhou 4225d460eafSCathy Zhou dlsp->dl_cap = DL_CAPAB_ZEROCOPY; 4235d460eafSCathy Zhou dlsp->dl_length = sizeof (dl_capab_zerocopy_t); 4245d460eafSCathy Zhou ptr += sizeof (dl_capability_sub_t); 4255d460eafSCathy Zhou 4265d460eafSCathy Zhou bzero(&zcopy, sizeof (dl_capab_zerocopy_t)); 4275d460eafSCathy Zhou zcopy.zerocopy_version = ZEROCOPY_VERSION_1; 4285d460eafSCathy Zhou zcopy.zerocopy_flags = DL_CAPAB_VMSAFE_MEM; 4295d460eafSCathy Zhou dlcapabsetqid(&(zcopy.zerocopy_mid), sup->su_rq); 4305d460eafSCathy Zhou bcopy(&zcopy, ptr, sizeof (dl_capab_zerocopy_t)); 4315d460eafSCathy Zhou ptr += sizeof (dl_capab_zerocopy_t); 4325d460eafSCathy Zhou } 4335d460eafSCathy Zhou 4345d460eafSCathy Zhou /* 4355d460eafSCathy Zhou * MDT 4365d460eafSCathy Zhou */ 4375d460eafSCathy Zhou if (mdt_capable) { 4385d460eafSCathy Zhou dl_capab_mdt_t mdt; 4395d460eafSCathy Zhou 4405d460eafSCathy Zhou dlsp = (dl_capability_sub_t *)ptr; 4415d460eafSCathy Zhou 4425d460eafSCathy Zhou dlsp->dl_cap = DL_CAPAB_MDT; 4435d460eafSCathy Zhou dlsp->dl_length = sizeof (dl_capab_mdt_t); 4445d460eafSCathy Zhou ptr += sizeof (dl_capability_sub_t); 4455d460eafSCathy Zhou 4465d460eafSCathy Zhou bzero(&mdt, sizeof (dl_capab_mdt_t)); 4475d460eafSCathy Zhou mdt.mdt_version = MDT_VERSION_2; 4485d460eafSCathy Zhou mdt.mdt_flags = DL_CAPAB_MDT_ENABLE; 4495d460eafSCathy Zhou mdt.mdt_hdr_head = softmac->smac_mdt_capab.mdt_hdr_head; 4505d460eafSCathy Zhou mdt.mdt_hdr_tail = softmac->smac_mdt_capab.mdt_hdr_tail; 4515d460eafSCathy Zhou mdt.mdt_max_pld = softmac->smac_mdt_capab.mdt_max_pld; 4525d460eafSCathy Zhou mdt.mdt_span_limit = softmac->smac_mdt_capab.mdt_span_limit; 4535d460eafSCathy Zhou dlcapabsetqid(&(mdt.mdt_mid), sup->su_rq); 4545d460eafSCathy Zhou bcopy(&mdt, ptr, sizeof (dl_capab_mdt_t)); 4555d460eafSCathy Zhou ptr += sizeof (dl_capab_mdt_t); 4565d460eafSCathy Zhou } 4575d460eafSCathy Zhou 4585d460eafSCathy Zhou ASSERT(ptr == mp->b_rptr + sizeof (dl_capability_ack_t) + subsize); 4595d460eafSCathy Zhou qreply(q, mp); 4605d460eafSCathy Zhou } 4615d460eafSCathy Zhou 4625d460eafSCathy Zhou static void 4635d460eafSCathy Zhou softmac_capability_req(softmac_upper_t *sup, mblk_t *mp) 4645d460eafSCathy Zhou { 4655d460eafSCathy Zhou dl_capability_req_t *dlp = (dl_capability_req_t *)mp->b_rptr; 4665d460eafSCathy Zhou dl_capability_sub_t *sp; 4675d460eafSCathy Zhou size_t size, len; 4685d460eafSCathy Zhou offset_t off, end; 4695d460eafSCathy Zhou t_uscalar_t dl_err; 4705d460eafSCathy Zhou queue_t *q = sup->su_wq; 4715d460eafSCathy Zhou 4725d460eafSCathy Zhou ASSERT(sup->su_mode == SOFTMAC_FASTPATH); 4735d460eafSCathy Zhou if (MBLKL(mp) < sizeof (dl_capability_req_t)) { 4745d460eafSCathy Zhou dl_err = DL_BADPRIM; 4755d460eafSCathy Zhou goto failed; 4765d460eafSCathy Zhou } 4775d460eafSCathy Zhou 4785d460eafSCathy Zhou if (!sup->su_bound) { 4795d460eafSCathy Zhou dl_err = DL_OUTSTATE; 4805d460eafSCathy Zhou goto failed; 4815d460eafSCathy Zhou } 4825d460eafSCathy Zhou 4835d460eafSCathy Zhou /* 4845d460eafSCathy Zhou * This request is overloaded. If there are no requested capabilities 4855d460eafSCathy Zhou * then we just want to acknowledge with all the capabilities we 4865d460eafSCathy Zhou * support. Otherwise we enable the set of capabilities requested. 4875d460eafSCathy Zhou */ 4885d460eafSCathy Zhou if (dlp->dl_sub_length == 0) { 4895d460eafSCathy Zhou softmac_capability_advertise(sup, mp); 4905d460eafSCathy Zhou return; 4915d460eafSCathy Zhou } 4925d460eafSCathy Zhou 4935d460eafSCathy Zhou if (!MBLKIN(mp, dlp->dl_sub_offset, dlp->dl_sub_length)) { 4945d460eafSCathy Zhou dl_err = DL_BADPRIM; 4955d460eafSCathy Zhou goto failed; 4965d460eafSCathy Zhou } 4975d460eafSCathy Zhou 4985d460eafSCathy Zhou dlp->dl_primitive = DL_CAPABILITY_ACK; 4995d460eafSCathy Zhou 5005d460eafSCathy Zhou off = dlp->dl_sub_offset; 5015d460eafSCathy Zhou len = dlp->dl_sub_length; 5025d460eafSCathy Zhou 5035d460eafSCathy Zhou /* 5045d460eafSCathy Zhou * Walk the list of capabilities to be enabled. 5055d460eafSCathy Zhou */ 5065d460eafSCathy Zhou for (end = off + len; off < end; ) { 5075d460eafSCathy Zhou sp = (dl_capability_sub_t *)(mp->b_rptr + off); 5085d460eafSCathy Zhou size = sizeof (dl_capability_sub_t) + sp->dl_length; 5095d460eafSCathy Zhou 5105d460eafSCathy Zhou if (off + size > end || 5115d460eafSCathy Zhou !IS_P2ALIGNED(off, sizeof (uint32_t))) { 5125d460eafSCathy Zhou dl_err = DL_BADPRIM; 5135d460eafSCathy Zhou goto failed; 5145d460eafSCathy Zhou } 5155d460eafSCathy Zhou 5165d460eafSCathy Zhou switch (sp->dl_cap) { 5175d460eafSCathy Zhou /* 5185d460eafSCathy Zhou * TCP/IP checksum offload to hardware. 5195d460eafSCathy Zhou */ 5205d460eafSCathy Zhou case DL_CAPAB_HCKSUM: { 5215d460eafSCathy Zhou dl_capab_hcksum_t *hcksump; 5225d460eafSCathy Zhou dl_capab_hcksum_t hcksum; 5235d460eafSCathy Zhou 5245d460eafSCathy Zhou hcksump = (dl_capab_hcksum_t *)&sp[1]; 5255d460eafSCathy Zhou /* 5265d460eafSCathy Zhou * Copy for alignment. 5275d460eafSCathy Zhou */ 5285d460eafSCathy Zhou bcopy(hcksump, &hcksum, sizeof (dl_capab_hcksum_t)); 5295d460eafSCathy Zhou dlcapabsetqid(&(hcksum.hcksum_mid), sup->su_rq); 5305d460eafSCathy Zhou bcopy(&hcksum, hcksump, sizeof (dl_capab_hcksum_t)); 5315d460eafSCathy Zhou break; 5325d460eafSCathy Zhou } 5335d460eafSCathy Zhou 5345d460eafSCathy Zhou default: 5355d460eafSCathy Zhou break; 5365d460eafSCathy Zhou } 5375d460eafSCathy Zhou 5385d460eafSCathy Zhou off += size; 5395d460eafSCathy Zhou } 5405d460eafSCathy Zhou qreply(q, mp); 5415d460eafSCathy Zhou return; 5425d460eafSCathy Zhou failed: 5435d460eafSCathy Zhou dlerrorack(q, mp, DL_CAPABILITY_REQ, dl_err, 0); 5445d460eafSCathy Zhou } 5455d460eafSCathy Zhou 5465d460eafSCathy Zhou static void 5475d460eafSCathy Zhou softmac_bind_req(softmac_upper_t *sup, mblk_t *mp) 5485d460eafSCathy Zhou { 5495d460eafSCathy Zhou softmac_lower_t *slp = sup->su_slp; 5505d460eafSCathy Zhou softmac_t *softmac = sup->su_softmac; 5515d460eafSCathy Zhou mblk_t *ackmp, *mp1; 5525d460eafSCathy Zhou int err; 5535d460eafSCathy Zhou 5545d460eafSCathy Zhou if (MBLKL(mp) < DL_BIND_REQ_SIZE) { 5555d460eafSCathy Zhou freemsg(mp); 5565d460eafSCathy Zhou return; 5575d460eafSCathy Zhou } 5585d460eafSCathy Zhou 5595d460eafSCathy Zhou /* 5605d460eafSCathy Zhou * Allocate ackmp incase the underlying driver does not ack timely. 5615d460eafSCathy Zhou */ 5625d460eafSCathy Zhou if ((mp1 = allocb(sizeof (dl_error_ack_t), BPRI_HI)) == NULL) { 5635d460eafSCathy Zhou dlerrorack(sup->su_wq, mp, DL_BIND_REQ, DL_SYSERR, ENOMEM); 5645d460eafSCathy Zhou return; 5655d460eafSCathy Zhou } 5665d460eafSCathy Zhou 5675d460eafSCathy Zhou err = softmac_output(slp, mp, DL_BIND_REQ, DL_BIND_ACK, &ackmp); 5685d460eafSCathy Zhou if (ackmp != NULL) { 5695d460eafSCathy Zhou freemsg(mp1); 5705d460eafSCathy Zhou } else { 5715d460eafSCathy Zhou /* 5725d460eafSCathy Zhou * The driver does not ack timely. 5735d460eafSCathy Zhou */ 5745d460eafSCathy Zhou ASSERT(err == ENOMSG); 5755d460eafSCathy Zhou ackmp = mp1; 5765d460eafSCathy Zhou } 5775d460eafSCathy Zhou if (err != 0) 5785d460eafSCathy Zhou goto failed; 5795d460eafSCathy Zhou 5805d460eafSCathy Zhou /* 5815d460eafSCathy Zhou * Enable capabilities the underlying driver claims to support. 5825d460eafSCathy Zhou */ 5835d460eafSCathy Zhou if ((err = softmac_capab_enable(slp)) != 0) 5845d460eafSCathy Zhou goto failed; 5855d460eafSCathy Zhou 5865d460eafSCathy Zhou /* 5875d460eafSCathy Zhou * Check whether this softmac is already marked as exclusively used, 5885d460eafSCathy Zhou * e.g., an aggregation is created over it. Fail the BIND_REQ if so. 5895d460eafSCathy Zhou */ 5905d460eafSCathy Zhou mutex_enter(&softmac->smac_active_mutex); 5915d460eafSCathy Zhou if (softmac->smac_active) { 5925d460eafSCathy Zhou mutex_exit(&softmac->smac_active_mutex); 5935d460eafSCathy Zhou err = EBUSY; 5945d460eafSCathy Zhou goto failed; 5955d460eafSCathy Zhou } 5965d460eafSCathy Zhou softmac->smac_nactive++; 5975d460eafSCathy Zhou sup->su_active = B_TRUE; 5985d460eafSCathy Zhou mutex_exit(&softmac->smac_active_mutex); 5995d460eafSCathy Zhou sup->su_bound = B_TRUE; 6005d460eafSCathy Zhou 6015d460eafSCathy Zhou qreply(sup->su_wq, ackmp); 6025d460eafSCathy Zhou return; 6035d460eafSCathy Zhou failed: 6045d460eafSCathy Zhou if (err != 0) { 6055d460eafSCathy Zhou dlerrorack(sup->su_wq, ackmp, DL_BIND_REQ, DL_SYSERR, err); 6065d460eafSCathy Zhou return; 6075d460eafSCathy Zhou } 6085d460eafSCathy Zhou } 6095d460eafSCathy Zhou 6105d460eafSCathy Zhou static void 6115d460eafSCathy Zhou softmac_unbind_req(softmac_upper_t *sup, mblk_t *mp) 6125d460eafSCathy Zhou { 6135d460eafSCathy Zhou softmac_lower_t *slp = sup->su_slp; 6145d460eafSCathy Zhou softmac_t *softmac = sup->su_softmac; 6155d460eafSCathy Zhou mblk_t *ackmp, *mp1; 6165d460eafSCathy Zhou int err; 6175d460eafSCathy Zhou 6185d460eafSCathy Zhou if (MBLKL(mp) < DL_UNBIND_REQ_SIZE) { 6195d460eafSCathy Zhou freemsg(mp); 6205d460eafSCathy Zhou return; 6215d460eafSCathy Zhou } 6225d460eafSCathy Zhou 6235d460eafSCathy Zhou if (!sup->su_bound) { 6245d460eafSCathy Zhou dlerrorack(sup->su_wq, mp, DL_UNBIND_REQ, DL_OUTSTATE, 0); 6255d460eafSCathy Zhou return; 6265d460eafSCathy Zhou } 6275d460eafSCathy Zhou 6285d460eafSCathy Zhou /* 6295d460eafSCathy Zhou * Allocate ackmp incase the underlying driver does not ack timely. 6305d460eafSCathy Zhou */ 6315d460eafSCathy Zhou if ((mp1 = allocb(sizeof (dl_error_ack_t), BPRI_HI)) == NULL) { 6325d460eafSCathy Zhou dlerrorack(sup->su_wq, mp, DL_UNBIND_REQ, DL_SYSERR, ENOMEM); 6335d460eafSCathy Zhou return; 6345d460eafSCathy Zhou } 6355d460eafSCathy Zhou 6365d460eafSCathy Zhou err = softmac_output(slp, mp, DL_UNBIND_REQ, DL_OK_ACK, &ackmp); 6375d460eafSCathy Zhou if (ackmp != NULL) { 6385d460eafSCathy Zhou freemsg(mp1); 6395d460eafSCathy Zhou } else { 6405d460eafSCathy Zhou /* 6415d460eafSCathy Zhou * The driver does not ack timely. 6425d460eafSCathy Zhou */ 6435d460eafSCathy Zhou ASSERT(err == ENOMSG); 6445d460eafSCathy Zhou ackmp = mp1; 6455d460eafSCathy Zhou } 6465d460eafSCathy Zhou if (err != 0) { 6475d460eafSCathy Zhou dlerrorack(sup->su_wq, ackmp, DL_UNBIND_REQ, DL_SYSERR, err); 6485d460eafSCathy Zhou return; 6495d460eafSCathy Zhou } 6505d460eafSCathy Zhou 6515d460eafSCathy Zhou sup->su_bound = B_FALSE; 6525d460eafSCathy Zhou 6535d460eafSCathy Zhou mutex_enter(&softmac->smac_active_mutex); 6545d460eafSCathy Zhou if (sup->su_active) { 6555d460eafSCathy Zhou ASSERT(!softmac->smac_active); 6565d460eafSCathy Zhou softmac->smac_nactive--; 6575d460eafSCathy Zhou sup->su_active = B_FALSE; 6585d460eafSCathy Zhou } 6595d460eafSCathy Zhou mutex_exit(&softmac->smac_active_mutex); 6605d460eafSCathy Zhou 6615d460eafSCathy Zhou done: 6625d460eafSCathy Zhou qreply(sup->su_wq, ackmp); 6635d460eafSCathy Zhou } 6645d460eafSCathy Zhou 6655d460eafSCathy Zhou /* 6665d460eafSCathy Zhou * Process the non-data mblk. 6675d460eafSCathy Zhou */ 6685d460eafSCathy Zhou static void 6695d460eafSCathy Zhou softmac_wput_single_nondata(softmac_upper_t *sup, mblk_t *mp) 6705d460eafSCathy Zhou { 6715d460eafSCathy Zhou softmac_t *softmac = sup->su_softmac; 6725d460eafSCathy Zhou softmac_lower_t *slp = sup->su_slp; 6735d460eafSCathy Zhou unsigned char dbtype; 6745d460eafSCathy Zhou t_uscalar_t prim; 6755d460eafSCathy Zhou 6765d460eafSCathy Zhou dbtype = DB_TYPE(mp); 677*bd670b35SErik Nordmark sup->su_is_arp = 0; 6785d460eafSCathy Zhou switch (dbtype) { 679*bd670b35SErik Nordmark case M_CTL: 680*bd670b35SErik Nordmark sup->su_is_arp = 1; 681*bd670b35SErik Nordmark /* FALLTHROUGH */ 682*bd670b35SErik Nordmark case M_IOCTL: { 6835d460eafSCathy Zhou uint32_t expected_mode; 6845d460eafSCathy Zhou 6855d460eafSCathy Zhou if (((struct iocblk *)(mp->b_rptr))->ioc_cmd != SIOCSLIFNAME) 6865d460eafSCathy Zhou break; 6875d460eafSCathy Zhou 6885d460eafSCathy Zhou /* 6895d460eafSCathy Zhou * Nak the M_IOCTL based on the STREAMS specification. 6905d460eafSCathy Zhou */ 6915d460eafSCathy Zhou if (dbtype == M_IOCTL) 6925d460eafSCathy Zhou miocnak(sup->su_wq, mp, 0, EINVAL); 693f1956ffeSCathy Zhou else 694f1956ffeSCathy Zhou freemsg(mp); 6955d460eafSCathy Zhou 6965d460eafSCathy Zhou /* 6975d460eafSCathy Zhou * This stream is either IP or ARP. See whether 6985d460eafSCathy Zhou * we need to setup a dedicated-lower-stream for it. 6995d460eafSCathy Zhou */ 7005d460eafSCathy Zhou mutex_enter(&softmac->smac_fp_mutex); 7015d460eafSCathy Zhou 7025d460eafSCathy Zhou expected_mode = DATAPATH_MODE(softmac); 7035d460eafSCathy Zhou if (expected_mode == SOFTMAC_SLOWPATH) 7045d460eafSCathy Zhou sup->su_mode = SOFTMAC_SLOWPATH; 7055d460eafSCathy Zhou list_insert_head(&softmac->smac_sup_list, sup); 7065d460eafSCathy Zhou mutex_exit(&softmac->smac_fp_mutex); 7075d460eafSCathy Zhou 7085d460eafSCathy Zhou /* 7095d460eafSCathy Zhou * Setup the fast-path dedicated lower stream if fast-path 7105d460eafSCathy Zhou * is expected. Note that no lock is held here, and if 7115d460eafSCathy Zhou * smac_expected_mode is changed from SOFTMAC_FASTPATH to 7125d460eafSCathy Zhou * SOFTMAC_SLOWPATH, the DL_NOTE_REPLUMB message used for 7135d460eafSCathy Zhou * data-path switching would already be queued and will 7145d460eafSCathy Zhou * be processed by softmac_wput_single_nondata() later. 7155d460eafSCathy Zhou */ 7165d460eafSCathy Zhou if (expected_mode == SOFTMAC_FASTPATH) 7175d460eafSCathy Zhou (void) softmac_fastpath_setup(sup); 7185d460eafSCathy Zhou return; 7195d460eafSCathy Zhou } 7205d460eafSCathy Zhou case M_PROTO: 7215d460eafSCathy Zhou case M_PCPROTO: 7225d460eafSCathy Zhou if (MBLKL(mp) < sizeof (t_uscalar_t)) { 7235d460eafSCathy Zhou freemsg(mp); 7245d460eafSCathy Zhou return; 7255d460eafSCathy Zhou } 7265d460eafSCathy Zhou prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive; 7275d460eafSCathy Zhou switch (prim) { 7285d460eafSCathy Zhou case DL_NOTIFY_IND: 7295d460eafSCathy Zhou if (MBLKL(mp) < sizeof (dl_notify_ind_t) || 7305d460eafSCathy Zhou ((dl_notify_ind_t *)mp->b_rptr)->dl_notification != 7315d460eafSCathy Zhou DL_NOTE_REPLUMB) { 7325d460eafSCathy Zhou freemsg(mp); 7335d460eafSCathy Zhou return; 7345d460eafSCathy Zhou } 7355d460eafSCathy Zhou /* 7365d460eafSCathy Zhou * This DL_NOTE_REPLUMB message is initiated 7375d460eafSCathy Zhou * and queued by the softmac itself, when the 7385d460eafSCathy Zhou * sup is trying to switching its datapath mode 7395d460eafSCathy Zhou * between SOFTMAC_SLOWPATH and SOFTMAC_FASTPATH. 7405d460eafSCathy Zhou * Send this message upstream. 7415d460eafSCathy Zhou */ 7425d460eafSCathy Zhou qreply(sup->su_wq, mp); 7435d460eafSCathy Zhou return; 7445d460eafSCathy Zhou case DL_NOTIFY_CONF: 7455d460eafSCathy Zhou if (MBLKL(mp) < sizeof (dl_notify_conf_t) || 7465d460eafSCathy Zhou ((dl_notify_conf_t *)mp->b_rptr)->dl_notification != 7475d460eafSCathy Zhou DL_NOTE_REPLUMB_DONE) { 7485d460eafSCathy Zhou freemsg(mp); 7495d460eafSCathy Zhou return; 7505d460eafSCathy Zhou } 7515d460eafSCathy Zhou /* 7525d460eafSCathy Zhou * This is an indication from IP/ARP that the 7535d460eafSCathy Zhou * fastpath->slowpath switch is done. 7545d460eafSCathy Zhou */ 7555d460eafSCathy Zhou freemsg(mp); 7565d460eafSCathy Zhou softmac_datapath_switch_done(sup); 7575d460eafSCathy Zhou return; 7585d460eafSCathy Zhou } 7595d460eafSCathy Zhou break; 7605d460eafSCathy Zhou } 7615d460eafSCathy Zhou 7625d460eafSCathy Zhou /* 7635d460eafSCathy Zhou * No need to hold lock to check su_mode, since su_mode updating only 7645d460eafSCathy Zhou * operation is is serialized by softmac_wput_nondata_task(). 7655d460eafSCathy Zhou */ 7665d460eafSCathy Zhou if (sup->su_mode != SOFTMAC_FASTPATH) { 7675d460eafSCathy Zhou dld_wput(sup->su_wq, mp); 7685d460eafSCathy Zhou return; 7695d460eafSCathy Zhou } 7705d460eafSCathy Zhou 7715d460eafSCathy Zhou /* 7725d460eafSCathy Zhou * Fastpath non-data message processing. Most of non-data messages 7735d460eafSCathy Zhou * can be directly passed down to the dedicated-lower-stream, aside 7745d460eafSCathy Zhou * from the following M_PROTO/M_PCPROTO messages. 7755d460eafSCathy Zhou */ 7765d460eafSCathy Zhou switch (dbtype) { 7775d460eafSCathy Zhou case M_PROTO: 7785d460eafSCathy Zhou case M_PCPROTO: 7795d460eafSCathy Zhou switch (prim) { 7805d460eafSCathy Zhou case DL_BIND_REQ: 7815d460eafSCathy Zhou softmac_bind_req(sup, mp); 7825d460eafSCathy Zhou break; 7835d460eafSCathy Zhou case DL_UNBIND_REQ: 7845d460eafSCathy Zhou softmac_unbind_req(sup, mp); 7855d460eafSCathy Zhou break; 7865d460eafSCathy Zhou case DL_CAPABILITY_REQ: 7875d460eafSCathy Zhou softmac_capability_req(sup, mp); 7885d460eafSCathy Zhou break; 7895d460eafSCathy Zhou default: 7905d460eafSCathy Zhou putnext(slp->sl_wq, mp); 7915d460eafSCathy Zhou break; 7925d460eafSCathy Zhou } 7935d460eafSCathy Zhou break; 7945d460eafSCathy Zhou default: 7955d460eafSCathy Zhou putnext(slp->sl_wq, mp); 7965d460eafSCathy Zhou break; 7975d460eafSCathy Zhou } 7985d460eafSCathy Zhou } 7995d460eafSCathy Zhou 8005d460eafSCathy Zhou /* 8015d460eafSCathy Zhou * The worker thread which processes non-data messages. Note we only process 8025d460eafSCathy Zhou * one message at one time in order to be able to "flush" the queued message 8035d460eafSCathy Zhou * and serialize the processing. 8045d460eafSCathy Zhou */ 8055d460eafSCathy Zhou static void 8065d460eafSCathy Zhou softmac_wput_nondata_task(void *arg) 8075d460eafSCathy Zhou { 8085d460eafSCathy Zhou softmac_upper_t *sup = arg; 8095d460eafSCathy Zhou mblk_t *mp; 8105d460eafSCathy Zhou 8115d460eafSCathy Zhou mutex_enter(&sup->su_disp_mutex); 8125d460eafSCathy Zhou 8135d460eafSCathy Zhou while (sup->su_pending_head != NULL) { 8145d460eafSCathy Zhou if (sup->su_closing) 8155d460eafSCathy Zhou break; 8165d460eafSCathy Zhou 8175d460eafSCathy Zhou SOFTMAC_DQ_PENDING(sup, &mp); 8185d460eafSCathy Zhou mutex_exit(&sup->su_disp_mutex); 8195d460eafSCathy Zhou softmac_wput_single_nondata(sup, mp); 8205d460eafSCathy Zhou mutex_enter(&sup->su_disp_mutex); 8215d460eafSCathy Zhou } 8225d460eafSCathy Zhou 8235d460eafSCathy Zhou /* 8245d460eafSCathy Zhou * If the stream is closing, flush all queued messages and inform 8255d460eafSCathy Zhou * the stream to be closed. 8265d460eafSCathy Zhou */ 8275d460eafSCathy Zhou freemsgchain(sup->su_pending_head); 8285d460eafSCathy Zhou sup->su_pending_head = sup->su_pending_tail = NULL; 8295d460eafSCathy Zhou sup->su_dlpi_pending = B_FALSE; 8305d460eafSCathy Zhou cv_signal(&sup->su_disp_cv); 8315d460eafSCathy Zhou mutex_exit(&sup->su_disp_mutex); 8325d460eafSCathy Zhou } 8335d460eafSCathy Zhou 8345d460eafSCathy Zhou /* 8355d460eafSCathy Zhou * Kernel thread to handle taskq dispatch failures in softmac_wput_nondata(). 8365d460eafSCathy Zhou * This thread is started when the softmac module is first loaded. 8375d460eafSCathy Zhou */ 8385d460eafSCathy Zhou static void 8395d460eafSCathy Zhou softmac_taskq_dispatch(void) 8405d460eafSCathy Zhou { 8415d460eafSCathy Zhou callb_cpr_t cprinfo; 8425d460eafSCathy Zhou softmac_upper_t *sup; 8435d460eafSCathy Zhou 8445d460eafSCathy Zhou CALLB_CPR_INIT(&cprinfo, &softmac_taskq_lock, callb_generic_cpr, 8455d460eafSCathy Zhou "softmac_taskq_dispatch"); 8465d460eafSCathy Zhou mutex_enter(&softmac_taskq_lock); 8475d460eafSCathy Zhou 8485d460eafSCathy Zhou while (!softmac_taskq_quit) { 8495d460eafSCathy Zhou sup = list_head(&softmac_taskq_list); 8505d460eafSCathy Zhou while (sup != NULL) { 8515d460eafSCathy Zhou list_remove(&softmac_taskq_list, sup); 8525d460eafSCathy Zhou sup->su_taskq_scheduled = B_FALSE; 8535d460eafSCathy Zhou mutex_exit(&softmac_taskq_lock); 8545d460eafSCathy Zhou VERIFY(taskq_dispatch(system_taskq, 8555d460eafSCathy Zhou softmac_wput_nondata_task, sup, TQ_SLEEP) != NULL); 8565d460eafSCathy Zhou mutex_enter(&softmac_taskq_lock); 8575d460eafSCathy Zhou sup = list_head(&softmac_taskq_list); 8585d460eafSCathy Zhou } 8595d460eafSCathy Zhou 8605d460eafSCathy Zhou CALLB_CPR_SAFE_BEGIN(&cprinfo); 8615d460eafSCathy Zhou cv_wait(&softmac_taskq_cv, &softmac_taskq_lock); 8625d460eafSCathy Zhou CALLB_CPR_SAFE_END(&cprinfo, &softmac_taskq_lock); 8635d460eafSCathy Zhou } 8645d460eafSCathy Zhou 8655d460eafSCathy Zhou softmac_taskq_done = B_TRUE; 8665d460eafSCathy Zhou cv_signal(&softmac_taskq_cv); 8675d460eafSCathy Zhou CALLB_CPR_EXIT(&cprinfo); 8685d460eafSCathy Zhou thread_exit(); 8695d460eafSCathy Zhou } 8705d460eafSCathy Zhou 8715d460eafSCathy Zhou void 8725d460eafSCathy Zhou softmac_wput_nondata(softmac_upper_t *sup, mblk_t *mp) 8735d460eafSCathy Zhou { 8745d460eafSCathy Zhou /* 8755d460eafSCathy Zhou * The processing of the message might block. Enqueue the 8765d460eafSCathy Zhou * message for later processing. 8775d460eafSCathy Zhou */ 8785d460eafSCathy Zhou mutex_enter(&sup->su_disp_mutex); 8795d460eafSCathy Zhou 8805d460eafSCathy Zhou if (sup->su_closing) { 8815d460eafSCathy Zhou mutex_exit(&sup->su_disp_mutex); 8825d460eafSCathy Zhou freemsg(mp); 8835d460eafSCathy Zhou return; 8845d460eafSCathy Zhou } 8855d460eafSCathy Zhou 8865d460eafSCathy Zhou SOFTMAC_EQ_PENDING(sup, mp); 8875d460eafSCathy Zhou 8885d460eafSCathy Zhou if (sup->su_dlpi_pending) { 8895d460eafSCathy Zhou mutex_exit(&sup->su_disp_mutex); 8905d460eafSCathy Zhou return; 8915d460eafSCathy Zhou } 8925d460eafSCathy Zhou sup->su_dlpi_pending = B_TRUE; 8935d460eafSCathy Zhou mutex_exit(&sup->su_disp_mutex); 8945d460eafSCathy Zhou 8955d460eafSCathy Zhou if (taskq_dispatch(system_taskq, softmac_wput_nondata_task, 8965d460eafSCathy Zhou sup, TQ_NOSLEEP) != NULL) { 8975d460eafSCathy Zhou return; 8985d460eafSCathy Zhou } 8995d460eafSCathy Zhou 9005d460eafSCathy Zhou mutex_enter(&softmac_taskq_lock); 9015d460eafSCathy Zhou if (!sup->su_taskq_scheduled) { 9025d460eafSCathy Zhou list_insert_tail(&softmac_taskq_list, sup); 9035d460eafSCathy Zhou cv_signal(&softmac_taskq_cv); 9045d460eafSCathy Zhou } 9055d460eafSCathy Zhou sup->su_taskq_scheduled = B_TRUE; 9065d460eafSCathy Zhou mutex_exit(&softmac_taskq_lock); 9075d460eafSCathy Zhou } 9085d460eafSCathy Zhou 9095d460eafSCathy Zhou /* 9105d460eafSCathy Zhou * Setup the dedicated-lower-stream (fast-path) for the IP/ARP upperstream. 9115d460eafSCathy Zhou */ 9125d460eafSCathy Zhou static int 9135d460eafSCathy Zhou softmac_fastpath_setup(softmac_upper_t *sup) 9145d460eafSCathy Zhou { 9155d460eafSCathy Zhou softmac_t *softmac = sup->su_softmac; 9165d460eafSCathy Zhou softmac_lower_t *slp; 9175d460eafSCathy Zhou int err; 9185d460eafSCathy Zhou 9195d460eafSCathy Zhou err = softmac_lower_setup(softmac, sup, &slp); 9205d460eafSCathy Zhou 9215d460eafSCathy Zhou mutex_enter(&sup->su_mutex); 9225d460eafSCathy Zhou /* 9235d460eafSCathy Zhou * Wait for all data messages to be processed so that we can change 9245d460eafSCathy Zhou * the su_mode. 9255d460eafSCathy Zhou */ 9265d460eafSCathy Zhou while (sup->su_tx_inprocess != 0) 9275d460eafSCathy Zhou cv_wait(&sup->su_cv, &sup->su_mutex); 9285d460eafSCathy Zhou 9295d460eafSCathy Zhou ASSERT(sup->su_mode != SOFTMAC_FASTPATH); 9305d460eafSCathy Zhou ASSERT(sup->su_slp == NULL); 9315d460eafSCathy Zhou if (err != 0) { 9325d460eafSCathy Zhou sup->su_mode = SOFTMAC_SLOWPATH; 9335d460eafSCathy Zhou } else { 9345d460eafSCathy Zhou sup->su_slp = slp; 9355d460eafSCathy Zhou sup->su_mode = SOFTMAC_FASTPATH; 9365d460eafSCathy Zhou } 9375d460eafSCathy Zhou mutex_exit(&sup->su_mutex); 9385d460eafSCathy Zhou return (err); 9395d460eafSCathy Zhou } 9405d460eafSCathy Zhou 9415d460eafSCathy Zhou /* 9425d460eafSCathy Zhou * Tear down the dedicated-lower-stream (fast-path) for the IP/ARP upperstream. 9435d460eafSCathy Zhou */ 9445d460eafSCathy Zhou static void 9455d460eafSCathy Zhou softmac_fastpath_tear(softmac_upper_t *sup) 9465d460eafSCathy Zhou { 9475d460eafSCathy Zhou mutex_enter(&sup->su_mutex); 9485d460eafSCathy Zhou /* 9495d460eafSCathy Zhou * Wait for all data messages in the dedicated-lower-stream 9505d460eafSCathy Zhou * to be processed. 9515d460eafSCathy Zhou */ 9525d460eafSCathy Zhou while (sup->su_tx_inprocess != 0) 9535d460eafSCathy Zhou cv_wait(&sup->su_cv, &sup->su_mutex); 9545d460eafSCathy Zhou 95579eeb645SCathy Zhou /* 95679eeb645SCathy Zhou * Note that this function is called either when the stream is closed, 95779eeb645SCathy Zhou * or the stream is unbound (fastpath-slowpath-switch). Therefore, 95879eeb645SCathy Zhou * No need to call the tx_notify callback. 95979eeb645SCathy Zhou */ 96079eeb645SCathy Zhou sup->su_tx_notify_func = NULL; 96179eeb645SCathy Zhou sup->su_tx_notify_arg = NULL; 9625d460eafSCathy Zhou if (sup->su_tx_busy) { 9635d460eafSCathy Zhou ASSERT(sup->su_tx_flow_mp == NULL); 96479eeb645SCathy Zhou VERIFY((sup->su_tx_flow_mp = getq(sup->su_wq)) != NULL); 9655d460eafSCathy Zhou sup->su_tx_busy = B_FALSE; 9665d460eafSCathy Zhou } 9675d460eafSCathy Zhou 9685d460eafSCathy Zhou sup->su_mode = SOFTMAC_SLOWPATH; 9695d460eafSCathy Zhou 9705d460eafSCathy Zhou /* 9715d460eafSCathy Zhou * Destroy the dedicated-lower-stream. Note that slp is destroyed 9725d460eafSCathy Zhou * when lh is closed. 9735d460eafSCathy Zhou */ 9745d460eafSCathy Zhou (void) ldi_close(sup->su_slp->sl_lh, FREAD|FWRITE, kcred); 9755d460eafSCathy Zhou sup->su_slp = NULL; 9765d460eafSCathy Zhou mutex_exit(&sup->su_mutex); 9775d460eafSCathy Zhou } 9785d460eafSCathy Zhou 9795d460eafSCathy Zhou void 9805d460eafSCathy Zhou softmac_wput_data(softmac_upper_t *sup, mblk_t *mp) 9815d460eafSCathy Zhou { 9825d460eafSCathy Zhou /* 9835d460eafSCathy Zhou * No lock is required to access the su_mode field since the data 9845d460eafSCathy Zhou * traffic is quiesce by IP when the data-path mode is in the 9855d460eafSCathy Zhou * process of switching. 9865d460eafSCathy Zhou */ 9875d460eafSCathy Zhou if (sup->su_mode != SOFTMAC_FASTPATH) 9885d460eafSCathy Zhou dld_wput(sup->su_wq, mp); 9895d460eafSCathy Zhou else 9905d460eafSCathy Zhou (void) softmac_fastpath_wput_data(sup, mp, NULL, 0); 9915d460eafSCathy Zhou } 9925d460eafSCathy Zhou 9935d460eafSCathy Zhou /*ARGSUSED*/ 9945d460eafSCathy Zhou static mac_tx_cookie_t 9955d460eafSCathy Zhou softmac_fastpath_wput_data(softmac_upper_t *sup, mblk_t *mp, uintptr_t f_hint, 9965d460eafSCathy Zhou uint16_t flag) 9975d460eafSCathy Zhou { 9985d460eafSCathy Zhou queue_t *wq = sup->su_slp->sl_wq; 9995d460eafSCathy Zhou 10005d460eafSCathy Zhou /* 10015d460eafSCathy Zhou * This function is called from IP, only the MAC_DROP_ON_NO_DESC 10025d460eafSCathy Zhou * flag can be specified. 10035d460eafSCathy Zhou */ 10045d460eafSCathy Zhou ASSERT((flag & ~MAC_DROP_ON_NO_DESC) == 0); 10055d460eafSCathy Zhou ASSERT(mp->b_next == NULL); 10065d460eafSCathy Zhou 10075d460eafSCathy Zhou /* 10085d460eafSCathy Zhou * Check wether the dedicated-lower-stream is able to handle more 10095d460eafSCathy Zhou * messages, and enable the flow-control if it is not. 10105d460eafSCathy Zhou * 10115d460eafSCathy Zhou * Note that in order not to introduce any packet reordering, we 10125d460eafSCathy Zhou * always send the message down to the dedicated-lower-stream: 10135d460eafSCathy Zhou * 10145d460eafSCathy Zhou * If the flow-control is already enabled, but we still get 10155d460eafSCathy Zhou * the messages from the upper-stream, it means that the upper 10165d460eafSCathy Zhou * stream does not respect STREAMS flow-control (e.g., TCP). Simply 10175d460eafSCathy Zhou * pass the message down to the lower-stream in that case. 10185d460eafSCathy Zhou */ 10195d460eafSCathy Zhou if (SOFTMAC_CANPUTNEXT(wq)) { 10205d460eafSCathy Zhou putnext(wq, mp); 10215d460eafSCathy Zhou return (NULL); 10225d460eafSCathy Zhou } 10235d460eafSCathy Zhou 10245d460eafSCathy Zhou if (sup->su_tx_busy) { 102579eeb645SCathy Zhou if ((flag & MAC_DROP_ON_NO_DESC) != 0) 102679eeb645SCathy Zhou freemsg(mp); 102779eeb645SCathy Zhou else 10285d460eafSCathy Zhou putnext(wq, mp); 102979eeb645SCathy Zhou return ((mac_tx_cookie_t)sup); 10305d460eafSCathy Zhou } 10315d460eafSCathy Zhou 10325d460eafSCathy Zhou mutex_enter(&sup->su_mutex); 10335d460eafSCathy Zhou if (!sup->su_tx_busy) { 103479eeb645SCathy Zhou /* 103579eeb645SCathy Zhou * If DLD_CAPAB_DIRECT is enabled, the notify callback will be 103679eeb645SCathy Zhou * called when the flow control can be disabled. Otherwise, 103779eeb645SCathy Zhou * put the tx_flow_mp into the wq to make use of the old 103879eeb645SCathy Zhou * streams flow control. 103979eeb645SCathy Zhou */ 10405d460eafSCathy Zhou ASSERT(sup->su_tx_flow_mp != NULL); 10415d460eafSCathy Zhou (void) putq(sup->su_wq, sup->su_tx_flow_mp); 10425d460eafSCathy Zhou sup->su_tx_flow_mp = NULL; 10435d460eafSCathy Zhou sup->su_tx_busy = B_TRUE; 10445d460eafSCathy Zhou qenable(wq); 10455d460eafSCathy Zhou } 10465d460eafSCathy Zhou mutex_exit(&sup->su_mutex); 104779eeb645SCathy Zhou 104879eeb645SCathy Zhou if ((flag & MAC_DROP_ON_NO_DESC) != 0) 104979eeb645SCathy Zhou freemsg(mp); 105079eeb645SCathy Zhou else 10515d460eafSCathy Zhou putnext(wq, mp); 105279eeb645SCathy Zhou return ((mac_tx_cookie_t)sup); 10535d460eafSCathy Zhou } 10545d460eafSCathy Zhou 10555d460eafSCathy Zhou boolean_t 10565d460eafSCathy Zhou softmac_active_set(void *arg) 10575d460eafSCathy Zhou { 10585d460eafSCathy Zhou softmac_t *softmac = arg; 10595d460eafSCathy Zhou 10605d460eafSCathy Zhou mutex_enter(&softmac->smac_active_mutex); 10615d460eafSCathy Zhou if (softmac->smac_nactive != 0) { 10625d460eafSCathy Zhou mutex_exit(&softmac->smac_active_mutex); 10635d460eafSCathy Zhou return (B_FALSE); 10645d460eafSCathy Zhou } 10655d460eafSCathy Zhou softmac->smac_active = B_TRUE; 10665d460eafSCathy Zhou mutex_exit(&softmac->smac_active_mutex); 10675d460eafSCathy Zhou return (B_TRUE); 10685d460eafSCathy Zhou } 10695d460eafSCathy Zhou 10705d460eafSCathy Zhou void 10715d460eafSCathy Zhou softmac_active_clear(void *arg) 10725d460eafSCathy Zhou { 10735d460eafSCathy Zhou softmac_t *softmac = arg; 10745d460eafSCathy Zhou 10755d460eafSCathy Zhou mutex_enter(&softmac->smac_active_mutex); 10765d460eafSCathy Zhou ASSERT(softmac->smac_active && (softmac->smac_nactive == 0)); 10775d460eafSCathy Zhou softmac->smac_active = B_FALSE; 10785d460eafSCathy Zhou mutex_exit(&softmac->smac_active_mutex); 10795d460eafSCathy Zhou } 10805d460eafSCathy Zhou 10815d460eafSCathy Zhou /* 10825d460eafSCathy Zhou * Disable/reenable fastpath on given softmac. This request could come from a 10835d460eafSCathy Zhou * MAC client or directly from administrators. 10845d460eafSCathy Zhou */ 10855d460eafSCathy Zhou int 10865d460eafSCathy Zhou softmac_datapath_switch(softmac_t *softmac, boolean_t disable, boolean_t admin) 10875d460eafSCathy Zhou { 10885d460eafSCathy Zhou softmac_upper_t *sup; 10895d460eafSCathy Zhou mblk_t *head = NULL, *tail = NULL, *mp; 10905d460eafSCathy Zhou list_t reqlist; 10915d460eafSCathy Zhou softmac_switch_req_t *req; 10925d460eafSCathy Zhou uint32_t current_mode, expected_mode; 10935d460eafSCathy Zhou int err = 0; 10945d460eafSCathy Zhou 10955d460eafSCathy Zhou mutex_enter(&softmac->smac_fp_mutex); 10965d460eafSCathy Zhou 10975d460eafSCathy Zhou current_mode = DATAPATH_MODE(softmac); 10985d460eafSCathy Zhou if (admin) { 10995d460eafSCathy Zhou if (softmac->smac_fastpath_admin_disabled == disable) { 11005d460eafSCathy Zhou mutex_exit(&softmac->smac_fp_mutex); 11015d460eafSCathy Zhou return (0); 11025d460eafSCathy Zhou } 11035d460eafSCathy Zhou softmac->smac_fastpath_admin_disabled = disable; 11045d460eafSCathy Zhou } else if (disable) { 11055d460eafSCathy Zhou softmac->smac_fp_disable_clients++; 11065d460eafSCathy Zhou } else { 11075d460eafSCathy Zhou ASSERT(softmac->smac_fp_disable_clients != 0); 11085d460eafSCathy Zhou softmac->smac_fp_disable_clients--; 11095d460eafSCathy Zhou } 11105d460eafSCathy Zhou 11115d460eafSCathy Zhou expected_mode = DATAPATH_MODE(softmac); 11125d460eafSCathy Zhou if (current_mode == expected_mode) { 11135d460eafSCathy Zhou mutex_exit(&softmac->smac_fp_mutex); 11145d460eafSCathy Zhou return (0); 11155d460eafSCathy Zhou } 11165d460eafSCathy Zhou 11175d460eafSCathy Zhou /* 11185d460eafSCathy Zhou * The expected mode is different from whatever datapath mode 11195d460eafSCathy Zhou * this softmac is expected from last request, enqueue the data-path 11205d460eafSCathy Zhou * switch request. 11215d460eafSCathy Zhou */ 11225d460eafSCathy Zhou list_create(&reqlist, sizeof (softmac_switch_req_t), 11235d460eafSCathy Zhou offsetof(softmac_switch_req_t, ssq_req_list_node)); 11245d460eafSCathy Zhou 11255d460eafSCathy Zhou /* 11265d460eafSCathy Zhou * Allocate all DL_NOTIFY_IND messages and request structures that 11275d460eafSCathy Zhou * are required to switch each IP/ARP stream to the expected mode. 11285d460eafSCathy Zhou */ 11295d460eafSCathy Zhou for (sup = list_head(&softmac->smac_sup_list); sup != NULL; 11305d460eafSCathy Zhou sup = list_next(&softmac->smac_sup_list, sup)) { 11315d460eafSCathy Zhou dl_notify_ind_t *dlip; 11325d460eafSCathy Zhou 11335d460eafSCathy Zhou req = kmem_alloc(sizeof (softmac_switch_req_t), KM_NOSLEEP); 11345d460eafSCathy Zhou if (req == NULL) 11355d460eafSCathy Zhou break; 11365d460eafSCathy Zhou 11375d460eafSCathy Zhou req->ssq_expected_mode = expected_mode; 1138*bd670b35SErik Nordmark if (sup->su_is_arp) { 1139*bd670b35SErik Nordmark list_insert_tail(&reqlist, req); 1140*bd670b35SErik Nordmark continue; 1141*bd670b35SErik Nordmark } 11425d460eafSCathy Zhou /* 11435d460eafSCathy Zhou * Allocate the DL_NOTE_REPLUMB message. 11445d460eafSCathy Zhou */ 11455d460eafSCathy Zhou if ((mp = allocb(sizeof (dl_notify_ind_t), BPRI_LO)) == NULL) { 11465d460eafSCathy Zhou kmem_free(req, sizeof (softmac_switch_req_t)); 11475d460eafSCathy Zhou break; 11485d460eafSCathy Zhou } 11495d460eafSCathy Zhou 11505d460eafSCathy Zhou list_insert_tail(&reqlist, req); 11515d460eafSCathy Zhou 11525d460eafSCathy Zhou mp->b_wptr = mp->b_rptr + sizeof (dl_notify_ind_t); 11535d460eafSCathy Zhou mp->b_datap->db_type = M_PROTO; 11545d460eafSCathy Zhou bzero(mp->b_rptr, sizeof (dl_notify_ind_t)); 11555d460eafSCathy Zhou dlip = (dl_notify_ind_t *)mp->b_rptr; 11565d460eafSCathy Zhou dlip->dl_primitive = DL_NOTIFY_IND; 11575d460eafSCathy Zhou dlip->dl_notification = DL_NOTE_REPLUMB; 11585d460eafSCathy Zhou if (head == NULL) { 11595d460eafSCathy Zhou head = tail = mp; 11605d460eafSCathy Zhou } else { 11615d460eafSCathy Zhou tail->b_next = mp; 11625d460eafSCathy Zhou tail = mp; 11635d460eafSCathy Zhou } 11645d460eafSCathy Zhou } 11655d460eafSCathy Zhou 11665d460eafSCathy Zhou /* 11675d460eafSCathy Zhou * Note that it is fine if the expected data-path mode is fast-path 11685d460eafSCathy Zhou * and some of streams fails to switch. Only return failure if we 11695d460eafSCathy Zhou * are expected to switch to the slow-path. 11705d460eafSCathy Zhou */ 11715d460eafSCathy Zhou if (sup != NULL && expected_mode == SOFTMAC_SLOWPATH) { 11725d460eafSCathy Zhou err = ENOMEM; 11735d460eafSCathy Zhou goto fail; 11745d460eafSCathy Zhou } 11755d460eafSCathy Zhou 11765d460eafSCathy Zhou /* 11775d460eafSCathy Zhou * Start switching for each IP/ARP stream. The switching operation 11785d460eafSCathy Zhou * will eventually succeed and there is no need to wait for it 11795d460eafSCathy Zhou * to finish. 11805d460eafSCathy Zhou */ 11815d460eafSCathy Zhou for (sup = list_head(&softmac->smac_sup_list); sup != NULL; 11825d460eafSCathy Zhou sup = list_next(&softmac->smac_sup_list, sup)) { 1183*bd670b35SErik Nordmark if (!sup->su_is_arp) { 11845d460eafSCathy Zhou mp = head->b_next; 11855d460eafSCathy Zhou head->b_next = NULL; 1186*bd670b35SErik Nordmark softmac_wput_nondata(sup, head); 1187*bd670b35SErik Nordmark head = mp; 1188*bd670b35SErik Nordmark } 11895d460eafSCathy Zhou /* 1190*bd670b35SErik Nordmark * Add the switch request to the requests list of the stream. 11915d460eafSCathy Zhou */ 11925d460eafSCathy Zhou req = list_head(&reqlist); 11935d460eafSCathy Zhou ASSERT(req != NULL); 11945d460eafSCathy Zhou list_remove(&reqlist, req); 11955d460eafSCathy Zhou list_insert_tail(&sup->su_req_list, req); 11965d460eafSCathy Zhou } 11975d460eafSCathy Zhou 11985d460eafSCathy Zhou mutex_exit(&softmac->smac_fp_mutex); 11995d460eafSCathy Zhou ASSERT(list_is_empty(&reqlist)); 12005d460eafSCathy Zhou list_destroy(&reqlist); 12015d460eafSCathy Zhou return (0); 12025d460eafSCathy Zhou fail: 12035d460eafSCathy Zhou if (admin) { 12045d460eafSCathy Zhou softmac->smac_fastpath_admin_disabled = !disable; 12055d460eafSCathy Zhou } else if (disable) { 12065d460eafSCathy Zhou softmac->smac_fp_disable_clients--; 12075d460eafSCathy Zhou } else { 12085d460eafSCathy Zhou softmac->smac_fp_disable_clients++; 12095d460eafSCathy Zhou } 12105d460eafSCathy Zhou 12115d460eafSCathy Zhou mutex_exit(&softmac->smac_fp_mutex); 12125d460eafSCathy Zhou while ((req = list_head(&reqlist)) != NULL) { 12135d460eafSCathy Zhou list_remove(&reqlist, req); 12145d460eafSCathy Zhou kmem_free(req, sizeof (softmac_switch_req_t)); 12155d460eafSCathy Zhou } 12165d460eafSCathy Zhou freemsgchain(head); 12175d460eafSCathy Zhou list_destroy(&reqlist); 12185d460eafSCathy Zhou return (err); 12195d460eafSCathy Zhou } 12205d460eafSCathy Zhou 12215d460eafSCathy Zhou int 12225d460eafSCathy Zhou softmac_fastpath_disable(void *arg) 12235d460eafSCathy Zhou { 12245d460eafSCathy Zhou return (softmac_datapath_switch((softmac_t *)arg, B_TRUE, B_FALSE)); 12255d460eafSCathy Zhou } 12265d460eafSCathy Zhou 12275d460eafSCathy Zhou void 12285d460eafSCathy Zhou softmac_fastpath_enable(void *arg) 12295d460eafSCathy Zhou { 12305d460eafSCathy Zhou VERIFY(softmac_datapath_switch((softmac_t *)arg, B_FALSE, 12315d460eafSCathy Zhou B_FALSE) == 0); 12325d460eafSCathy Zhou } 12335d460eafSCathy Zhou 12345d460eafSCathy Zhou void 12355d460eafSCathy Zhou softmac_upperstream_close(softmac_upper_t *sup) 12365d460eafSCathy Zhou { 12375d460eafSCathy Zhou softmac_t *softmac = sup->su_softmac; 12385d460eafSCathy Zhou softmac_switch_req_t *req; 12395d460eafSCathy Zhou 12405d460eafSCathy Zhou mutex_enter(&softmac->smac_fp_mutex); 12415d460eafSCathy Zhou 12425d460eafSCathy Zhou if (sup->su_mode == SOFTMAC_FASTPATH) 12435d460eafSCathy Zhou softmac_fastpath_tear(sup); 12445d460eafSCathy Zhou 12455d460eafSCathy Zhou if (sup->su_mode != SOFTMAC_UNKNOWN) { 12465d460eafSCathy Zhou list_remove(&softmac->smac_sup_list, sup); 12475d460eafSCathy Zhou sup->su_mode = SOFTMAC_UNKNOWN; 12485d460eafSCathy Zhou } 12495d460eafSCathy Zhou 12505d460eafSCathy Zhou /* 12515d460eafSCathy Zhou * Cleanup all the switch requests queueed on this stream. 12525d460eafSCathy Zhou */ 12535d460eafSCathy Zhou while ((req = list_head(&sup->su_req_list)) != NULL) { 12545d460eafSCathy Zhou list_remove(&sup->su_req_list, req); 12555d460eafSCathy Zhou kmem_free(req, sizeof (softmac_switch_req_t)); 12565d460eafSCathy Zhou } 12575d460eafSCathy Zhou mutex_exit(&softmac->smac_fp_mutex); 12585d460eafSCathy Zhou } 12595d460eafSCathy Zhou 12605d460eafSCathy Zhou /* 12615d460eafSCathy Zhou * Handle the DL_NOTE_REPLUMB_DONE indication from IP/ARP. Change the upper 12625d460eafSCathy Zhou * stream from the fastpath mode to the slowpath mode. 12635d460eafSCathy Zhou */ 12645d460eafSCathy Zhou static void 12655d460eafSCathy Zhou softmac_datapath_switch_done(softmac_upper_t *sup) 12665d460eafSCathy Zhou { 12675d460eafSCathy Zhou softmac_t *softmac = sup->su_softmac; 12685d460eafSCathy Zhou softmac_switch_req_t *req; 12695d460eafSCathy Zhou uint32_t expected_mode; 12705d460eafSCathy Zhou 12715d460eafSCathy Zhou mutex_enter(&softmac->smac_fp_mutex); 12725d460eafSCathy Zhou req = list_head(&sup->su_req_list); 12735d460eafSCathy Zhou list_remove(&sup->su_req_list, req); 12745d460eafSCathy Zhou expected_mode = req->ssq_expected_mode; 12755d460eafSCathy Zhou kmem_free(req, sizeof (softmac_switch_req_t)); 12765d460eafSCathy Zhou 12775d460eafSCathy Zhou if (expected_mode == sup->su_mode) { 12785d460eafSCathy Zhou mutex_exit(&softmac->smac_fp_mutex); 12795d460eafSCathy Zhou return; 12805d460eafSCathy Zhou } 12815d460eafSCathy Zhou 12825d460eafSCathy Zhou ASSERT(!sup->su_bound); 12835d460eafSCathy Zhou mutex_exit(&softmac->smac_fp_mutex); 12845d460eafSCathy Zhou 12855d460eafSCathy Zhou /* 12865d460eafSCathy Zhou * It is fine if the expected mode is fast-path and we fail 12875d460eafSCathy Zhou * to enable fastpath on this stream. 12885d460eafSCathy Zhou */ 12895d460eafSCathy Zhou if (expected_mode == SOFTMAC_SLOWPATH) 12905d460eafSCathy Zhou softmac_fastpath_tear(sup); 12915d460eafSCathy Zhou else 12925d460eafSCathy Zhou (void) softmac_fastpath_setup(sup); 12935d460eafSCathy Zhou } 1294