15895Syz147064 /* 25895Syz147064 * CDDL HEADER START 35895Syz147064 * 45895Syz147064 * The contents of this file are subject to the terms of the 55895Syz147064 * Common Development and Distribution License (the "License"). 65895Syz147064 * You may not use this file except in compliance with the License. 75895Syz147064 * 85895Syz147064 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95895Syz147064 * or http://www.opensolaris.org/os/licensing. 105895Syz147064 * See the License for the specific language governing permissions 115895Syz147064 * and limitations under the License. 125895Syz147064 * 135895Syz147064 * When distributing Covered Code, include this CDDL HEADER in each 145895Syz147064 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155895Syz147064 * If applicable, add the following below this CDDL HEADER, with the 165895Syz147064 * fields enclosed by brackets "[]" replaced with your own identifying 175895Syz147064 * information: Portions Copyright [yyyy] [name of copyright owner] 185895Syz147064 * 195895Syz147064 * CDDL HEADER END 205895Syz147064 */ 215895Syz147064 /* 229002SCathy.Zhou@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 235895Syz147064 * Use is subject to license terms. 245895Syz147064 */ 255895Syz147064 265895Syz147064 #include <sys/strsubr.h> 275895Syz147064 #include <inet/led.h> 285895Syz147064 #include <sys/softmac_impl.h> 295895Syz147064 305895Syz147064 mblk_t * 315895Syz147064 softmac_m_tx(void *arg, mblk_t *mp) 325895Syz147064 { 335895Syz147064 queue_t *wq = ((softmac_t *)arg)->smac_lower->sl_wq; 345895Syz147064 355895Syz147064 /* 365895Syz147064 * Optimize for the most common case. 375895Syz147064 */ 386915Syz147064 if (mp->b_next == NULL) { 399073SCathy.Zhou@Sun.COM if (!SOFTMAC_CANPUTNEXT(wq)) 405895Syz147064 return (mp); 415895Syz147064 425895Syz147064 mp->b_flag |= MSGNOLOOP; 435895Syz147064 putnext(wq, mp); 445895Syz147064 return (NULL); 455895Syz147064 } 465895Syz147064 475895Syz147064 while (mp != NULL) { 485895Syz147064 mblk_t *next = mp->b_next; 495895Syz147064 509073SCathy.Zhou@Sun.COM if (!SOFTMAC_CANPUTNEXT(wq)) 515895Syz147064 break; 525895Syz147064 mp->b_next = NULL; 535895Syz147064 mp->b_flag |= MSGNOLOOP; 545895Syz147064 putnext(wq, mp); 555895Syz147064 mp = next; 565895Syz147064 } 575895Syz147064 return (mp); 585895Syz147064 } 595895Syz147064 605895Syz147064 void 615895Syz147064 softmac_rput_process_data(softmac_lower_t *slp, mblk_t *mp) 625895Syz147064 { 635895Syz147064 /* 645895Syz147064 * When packets arrive, the softmac might not be fully started. 655895Syz147064 */ 665895Syz147064 ASSERT((slp->sl_softmac != NULL)); 675895Syz147064 ASSERT((mp->b_next == NULL) && (mp->b_prev == NULL)); 685895Syz147064 695895Syz147064 if (DB_REF(mp) > 1) { 705895Syz147064 mblk_t *tmp; 719002SCathy.Zhou@Sun.COM uint32_t start, stuff, end, value, flags; 725895Syz147064 735895Syz147064 if ((tmp = copymsg(mp)) == NULL) { 745895Syz147064 cmn_err(CE_WARN, "softmac_rput_process_data: " 755895Syz147064 "copymsg failed"); 765895Syz147064 goto failed; 775895Syz147064 } 789002SCathy.Zhou@Sun.COM hcksum_retrieve(mp, NULL, NULL, &start, &stuff, &end, 799002SCathy.Zhou@Sun.COM &value, &flags); 809002SCathy.Zhou@Sun.COM VERIFY(hcksum_assoc(tmp, NULL, NULL, start, stuff, end, 819002SCathy.Zhou@Sun.COM value, flags, KM_NOSLEEP) == 0); 825895Syz147064 freemsg(mp); 835895Syz147064 mp = tmp; 845895Syz147064 } 855895Syz147064 868275SEric Cheng mac_rx(slp->sl_softmac->smac_mh, NULL, mp); 875895Syz147064 return; 885895Syz147064 895895Syz147064 failed: 905895Syz147064 freemsg(mp); 915895Syz147064 } 925895Syz147064 935895Syz147064 #define ACKTIMEOUT (10 * hz) 945895Syz147064 955895Syz147064 static int 965895Syz147064 dlpi_get_errno(t_uscalar_t error, t_uscalar_t unix_errno) 975895Syz147064 { 985895Syz147064 return (error == DL_SYSERR ? unix_errno : EINVAL); 995895Syz147064 } 1005895Syz147064 1019073SCathy.Zhou@Sun.COM int 1025895Syz147064 softmac_output(softmac_lower_t *slp, mblk_t *mp, t_uscalar_t dl_prim, 1035895Syz147064 t_uscalar_t ack, mblk_t **mpp) 1045895Syz147064 { 1055895Syz147064 union DL_primitives *dlp; 106*9682SCathy.Zhou@Sun.COM mac_perim_handle_t mph; 1075895Syz147064 int err = 0; 1085895Syz147064 109*9682SCathy.Zhou@Sun.COM mac_perim_enter_by_mh(slp->sl_softmac->smac_mh, &mph); 110*9682SCathy.Zhou@Sun.COM 111*9682SCathy.Zhou@Sun.COM ASSERT(!slp->sl_pending_ioctl); 112*9682SCathy.Zhou@Sun.COM ASSERT(slp->sl_pending_prim == DL_PRIM_INVAL); 1135895Syz147064 1145895Syz147064 /* 1155895Syz147064 * Record the pending DLPI primitive. 1165895Syz147064 */ 1175895Syz147064 mutex_enter(&slp->sl_mutex); 1185895Syz147064 slp->sl_pending_prim = dl_prim; 1195895Syz147064 mutex_exit(&slp->sl_mutex); 1205895Syz147064 1215895Syz147064 putnext(slp->sl_wq, mp); 1225895Syz147064 1235895Syz147064 mutex_enter(&slp->sl_mutex); 1245895Syz147064 while (slp->sl_pending_prim != DL_PRIM_INVAL) { 1255895Syz147064 if (cv_timedwait(&slp->sl_cv, &slp->sl_mutex, 1265895Syz147064 lbolt + ACKTIMEOUT) == -1) 1275895Syz147064 break; 1285895Syz147064 } 1295895Syz147064 1305895Syz147064 mp = slp->sl_ack_mp; 1315895Syz147064 slp->sl_ack_mp = NULL; 1325895Syz147064 1335895Syz147064 /* 1345895Syz147064 * If we timed out, sl_ack_mp will still be NULL, but sl_pending_prim 1355895Syz147064 * won't be set to DL_PRIM_INVAL. 1365895Syz147064 */ 1375895Syz147064 ASSERT(mp != NULL || slp->sl_pending_prim != DL_PRIM_INVAL); 1385895Syz147064 1395895Syz147064 slp->sl_pending_prim = DL_PRIM_INVAL; 1405895Syz147064 mutex_exit(&slp->sl_mutex); 1415895Syz147064 1425895Syz147064 if (mp != NULL) { 1435895Syz147064 dlp = (union DL_primitives *)mp->b_rptr; 1445895Syz147064 1455895Syz147064 if (dlp->dl_primitive == DL_ERROR_ACK) { 1465895Syz147064 err = dlpi_get_errno(dlp->error_ack.dl_errno, 1475895Syz147064 dlp->error_ack.dl_unix_errno); 1485895Syz147064 } else { 1495895Syz147064 ASSERT(dlp->dl_primitive == ack); 1505895Syz147064 } 1515895Syz147064 } else { 1525895Syz147064 err = ENOMSG; 1535895Syz147064 } 1545895Syz147064 1555895Syz147064 if (mpp != NULL) 1565895Syz147064 *mpp = mp; 1575895Syz147064 else 1585895Syz147064 freemsg(mp); 1595895Syz147064 160*9682SCathy.Zhou@Sun.COM mac_perim_exit(mph); 1615895Syz147064 return (err); 1625895Syz147064 } 1635895Syz147064 1645895Syz147064 void 1655895Syz147064 softmac_ioctl_tx(softmac_lower_t *slp, mblk_t *mp, mblk_t **mpp) 1665895Syz147064 { 167*9682SCathy.Zhou@Sun.COM mac_perim_handle_t mph; 168*9682SCathy.Zhou@Sun.COM 169*9682SCathy.Zhou@Sun.COM mac_perim_enter_by_mh(slp->sl_softmac->smac_mh, &mph); 1705895Syz147064 1715895Syz147064 /* 1725895Syz147064 * Record that ioctl processing is currently in progress. 1735895Syz147064 */ 1745895Syz147064 mutex_enter(&slp->sl_mutex); 1755895Syz147064 slp->sl_pending_ioctl = B_TRUE; 1765895Syz147064 mutex_exit(&slp->sl_mutex); 1775895Syz147064 1785895Syz147064 putnext(slp->sl_wq, mp); 1795895Syz147064 1805895Syz147064 mutex_enter(&slp->sl_mutex); 1815895Syz147064 while (slp->sl_pending_ioctl) 1825895Syz147064 cv_wait(&slp->sl_cv, &slp->sl_mutex); 1835895Syz147064 mp = slp->sl_ack_mp; 1845895Syz147064 slp->sl_ack_mp = NULL; 1855895Syz147064 mutex_exit(&slp->sl_mutex); 1865895Syz147064 1875895Syz147064 ASSERT(mpp != NULL && mp != NULL); 1885895Syz147064 *mpp = mp; 1895895Syz147064 190*9682SCathy.Zhou@Sun.COM mac_perim_exit(mph); 1915895Syz147064 } 1925895Syz147064 1939073SCathy.Zhou@Sun.COM int 1945895Syz147064 softmac_mexchange_error_ack(mblk_t **mpp, t_uscalar_t error_primitive, 1955895Syz147064 t_uscalar_t error, t_uscalar_t unix_errno) 1965895Syz147064 { 1975895Syz147064 union DL_primitives *dlp; 1985895Syz147064 1995895Syz147064 if ((*mpp = mexchange(NULL, *mpp, sizeof (dl_error_ack_t), M_PCPROTO, 2005895Syz147064 DL_ERROR_ACK)) == NULL) 2015895Syz147064 return (ENOMEM); 2025895Syz147064 2035895Syz147064 dlp = (union DL_primitives *)(*mpp)->b_rptr; 2045895Syz147064 dlp->error_ack.dl_error_primitive = error_primitive; 2055895Syz147064 dlp->error_ack.dl_errno = error; 2065895Syz147064 dlp->error_ack.dl_unix_errno = unix_errno; 2075895Syz147064 2085895Syz147064 return (0); 2095895Syz147064 } 2105895Syz147064 2115895Syz147064 int 2125895Syz147064 softmac_proto_tx(softmac_lower_t *slp, mblk_t *mp, mblk_t **mpp) 2135895Syz147064 { 2145895Syz147064 int err = 0; 2155895Syz147064 t_uscalar_t dl_prim; 2165895Syz147064 2175895Syz147064 dl_prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive; 2185895Syz147064 2195895Syz147064 ASSERT(slp->sl_softmac != NULL); 2205895Syz147064 2215895Syz147064 switch (dl_prim) { 2225895Syz147064 case DL_ENABMULTI_REQ: 2235895Syz147064 case DL_DISABMULTI_REQ: 2245895Syz147064 case DL_SET_PHYS_ADDR_REQ: 2255895Syz147064 case DL_UNBIND_REQ: 2265895Syz147064 case DL_UDQOS_REQ: 2275895Syz147064 case DL_PROMISCON_REQ: 2285895Syz147064 case DL_PROMISCOFF_REQ: 2295895Syz147064 err = softmac_output(slp, mp, dl_prim, DL_OK_ACK, mpp); 2305895Syz147064 break; 2315895Syz147064 case DL_BIND_REQ: 2325895Syz147064 err = softmac_output(slp, mp, dl_prim, DL_BIND_ACK, mpp); 2335895Syz147064 break; 2345895Syz147064 case DL_NOTIFY_REQ: 2355895Syz147064 err = softmac_output(slp, mp, dl_prim, DL_NOTIFY_ACK, mpp); 2365895Syz147064 break; 2375895Syz147064 case DL_CONTROL_REQ: 2385895Syz147064 err = softmac_output(slp, mp, dl_prim, DL_CONTROL_ACK, mpp); 2395895Syz147064 break; 2405895Syz147064 case DL_CAPABILITY_REQ: 2415895Syz147064 err = softmac_output(slp, mp, dl_prim, DL_CAPABILITY_ACK, mpp); 2425895Syz147064 break; 2435895Syz147064 default: 2445895Syz147064 if (mpp != NULL) { 2455895Syz147064 *mpp = mp; 2465895Syz147064 err = softmac_mexchange_error_ack(mpp, dl_prim, 2475895Syz147064 DL_UNSUPPORTED, 0); 2485895Syz147064 } 2495895Syz147064 break; 2505895Syz147064 } 2515895Syz147064 return (err); 2525895Syz147064 } 253