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 /*
22*11878SVenu.Iyer@Sun.COM * Copyright 2010 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 *
softmac_m_tx(void * arg,mblk_t * mp)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
softmac_rput_process_data(softmac_lower_t * slp,mblk_t * mp)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 }
78*11878SVenu.Iyer@Sun.COM mac_hcksum_get(mp, &start, &stuff, &end, &value, &flags);
79*11878SVenu.Iyer@Sun.COM mac_hcksum_set(tmp, start, stuff, end, value, flags);
805895Syz147064 freemsg(mp);
815895Syz147064 mp = tmp;
825895Syz147064 }
835895Syz147064
848275SEric Cheng mac_rx(slp->sl_softmac->smac_mh, NULL, mp);
855895Syz147064 return;
865895Syz147064
875895Syz147064 failed:
885895Syz147064 freemsg(mp);
895895Syz147064 }
905895Syz147064
915895Syz147064 #define ACKTIMEOUT (10 * hz)
925895Syz147064
935895Syz147064 static int
dlpi_get_errno(t_uscalar_t error,t_uscalar_t unix_errno)945895Syz147064 dlpi_get_errno(t_uscalar_t error, t_uscalar_t unix_errno)
955895Syz147064 {
965895Syz147064 return (error == DL_SYSERR ? unix_errno : EINVAL);
975895Syz147064 }
985895Syz147064
999073SCathy.Zhou@Sun.COM int
softmac_output(softmac_lower_t * slp,mblk_t * mp,t_uscalar_t dl_prim,t_uscalar_t ack,mblk_t ** mpp)1005895Syz147064 softmac_output(softmac_lower_t *slp, mblk_t *mp, t_uscalar_t dl_prim,
1015895Syz147064 t_uscalar_t ack, mblk_t **mpp)
1025895Syz147064 {
1035895Syz147064 union DL_primitives *dlp;
1049682SCathy.Zhou@Sun.COM mac_perim_handle_t mph;
1055895Syz147064 int err = 0;
1065895Syz147064
1079682SCathy.Zhou@Sun.COM mac_perim_enter_by_mh(slp->sl_softmac->smac_mh, &mph);
1089682SCathy.Zhou@Sun.COM
1099682SCathy.Zhou@Sun.COM ASSERT(!slp->sl_pending_ioctl);
1109682SCathy.Zhou@Sun.COM ASSERT(slp->sl_pending_prim == DL_PRIM_INVAL);
1115895Syz147064
1125895Syz147064 /*
1135895Syz147064 * Record the pending DLPI primitive.
1145895Syz147064 */
1155895Syz147064 mutex_enter(&slp->sl_mutex);
1165895Syz147064 slp->sl_pending_prim = dl_prim;
1175895Syz147064 mutex_exit(&slp->sl_mutex);
1185895Syz147064
1195895Syz147064 putnext(slp->sl_wq, mp);
1205895Syz147064
1215895Syz147064 mutex_enter(&slp->sl_mutex);
1225895Syz147064 while (slp->sl_pending_prim != DL_PRIM_INVAL) {
12311066Srafael.vanoni@sun.com if (cv_reltimedwait(&slp->sl_cv, &slp->sl_mutex, ACKTIMEOUT,
12411066Srafael.vanoni@sun.com TR_CLOCK_TICK) == -1)
1255895Syz147064 break;
1265895Syz147064 }
1275895Syz147064
1285895Syz147064 mp = slp->sl_ack_mp;
1295895Syz147064 slp->sl_ack_mp = NULL;
1305895Syz147064
1315895Syz147064 /*
1325895Syz147064 * If we timed out, sl_ack_mp will still be NULL, but sl_pending_prim
1335895Syz147064 * won't be set to DL_PRIM_INVAL.
1345895Syz147064 */
1355895Syz147064 ASSERT(mp != NULL || slp->sl_pending_prim != DL_PRIM_INVAL);
1365895Syz147064
1375895Syz147064 slp->sl_pending_prim = DL_PRIM_INVAL;
1385895Syz147064 mutex_exit(&slp->sl_mutex);
1395895Syz147064
1405895Syz147064 if (mp != NULL) {
1415895Syz147064 dlp = (union DL_primitives *)mp->b_rptr;
1425895Syz147064
1435895Syz147064 if (dlp->dl_primitive == DL_ERROR_ACK) {
1445895Syz147064 err = dlpi_get_errno(dlp->error_ack.dl_errno,
1455895Syz147064 dlp->error_ack.dl_unix_errno);
1465895Syz147064 } else {
1475895Syz147064 ASSERT(dlp->dl_primitive == ack);
1485895Syz147064 }
1495895Syz147064 } else {
1505895Syz147064 err = ENOMSG;
1515895Syz147064 }
1525895Syz147064
1535895Syz147064 if (mpp != NULL)
1545895Syz147064 *mpp = mp;
1555895Syz147064 else
1565895Syz147064 freemsg(mp);
1575895Syz147064
1589682SCathy.Zhou@Sun.COM mac_perim_exit(mph);
1595895Syz147064 return (err);
1605895Syz147064 }
1615895Syz147064
1625895Syz147064 void
softmac_ioctl_tx(softmac_lower_t * slp,mblk_t * mp,mblk_t ** mpp)1635895Syz147064 softmac_ioctl_tx(softmac_lower_t *slp, mblk_t *mp, mblk_t **mpp)
1645895Syz147064 {
1659682SCathy.Zhou@Sun.COM mac_perim_handle_t mph;
1669682SCathy.Zhou@Sun.COM
1679682SCathy.Zhou@Sun.COM mac_perim_enter_by_mh(slp->sl_softmac->smac_mh, &mph);
1685895Syz147064
1695895Syz147064 /*
1705895Syz147064 * Record that ioctl processing is currently in progress.
1715895Syz147064 */
1725895Syz147064 mutex_enter(&slp->sl_mutex);
1735895Syz147064 slp->sl_pending_ioctl = B_TRUE;
1745895Syz147064 mutex_exit(&slp->sl_mutex);
1755895Syz147064
1765895Syz147064 putnext(slp->sl_wq, mp);
1775895Syz147064
1785895Syz147064 mutex_enter(&slp->sl_mutex);
1795895Syz147064 while (slp->sl_pending_ioctl)
1805895Syz147064 cv_wait(&slp->sl_cv, &slp->sl_mutex);
1815895Syz147064 mp = slp->sl_ack_mp;
1825895Syz147064 slp->sl_ack_mp = NULL;
1835895Syz147064 mutex_exit(&slp->sl_mutex);
1845895Syz147064
1855895Syz147064 ASSERT(mpp != NULL && mp != NULL);
1865895Syz147064 *mpp = mp;
1875895Syz147064
1889682SCathy.Zhou@Sun.COM mac_perim_exit(mph);
1895895Syz147064 }
1905895Syz147064
1919073SCathy.Zhou@Sun.COM int
softmac_mexchange_error_ack(mblk_t ** mpp,t_uscalar_t error_primitive,t_uscalar_t error,t_uscalar_t unix_errno)1925895Syz147064 softmac_mexchange_error_ack(mblk_t **mpp, t_uscalar_t error_primitive,
1935895Syz147064 t_uscalar_t error, t_uscalar_t unix_errno)
1945895Syz147064 {
1955895Syz147064 union DL_primitives *dlp;
1965895Syz147064
1975895Syz147064 if ((*mpp = mexchange(NULL, *mpp, sizeof (dl_error_ack_t), M_PCPROTO,
1985895Syz147064 DL_ERROR_ACK)) == NULL)
1995895Syz147064 return (ENOMEM);
2005895Syz147064
2015895Syz147064 dlp = (union DL_primitives *)(*mpp)->b_rptr;
2025895Syz147064 dlp->error_ack.dl_error_primitive = error_primitive;
2035895Syz147064 dlp->error_ack.dl_errno = error;
2045895Syz147064 dlp->error_ack.dl_unix_errno = unix_errno;
2055895Syz147064
2065895Syz147064 return (0);
2075895Syz147064 }
2085895Syz147064
2095895Syz147064 int
softmac_proto_tx(softmac_lower_t * slp,mblk_t * mp,mblk_t ** mpp)2105895Syz147064 softmac_proto_tx(softmac_lower_t *slp, mblk_t *mp, mblk_t **mpp)
2115895Syz147064 {
2125895Syz147064 int err = 0;
2135895Syz147064 t_uscalar_t dl_prim;
2145895Syz147064
2155895Syz147064 dl_prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive;
2165895Syz147064
2175895Syz147064 ASSERT(slp->sl_softmac != NULL);
2185895Syz147064
2195895Syz147064 switch (dl_prim) {
2205895Syz147064 case DL_ENABMULTI_REQ:
2215895Syz147064 case DL_DISABMULTI_REQ:
2225895Syz147064 case DL_SET_PHYS_ADDR_REQ:
2235895Syz147064 case DL_UNBIND_REQ:
2245895Syz147064 case DL_UDQOS_REQ:
2255895Syz147064 case DL_PROMISCON_REQ:
2265895Syz147064 case DL_PROMISCOFF_REQ:
2275895Syz147064 err = softmac_output(slp, mp, dl_prim, DL_OK_ACK, mpp);
2285895Syz147064 break;
2295895Syz147064 case DL_BIND_REQ:
2305895Syz147064 err = softmac_output(slp, mp, dl_prim, DL_BIND_ACK, mpp);
2315895Syz147064 break;
2325895Syz147064 case DL_NOTIFY_REQ:
2335895Syz147064 err = softmac_output(slp, mp, dl_prim, DL_NOTIFY_ACK, mpp);
2345895Syz147064 break;
2355895Syz147064 case DL_CONTROL_REQ:
2365895Syz147064 err = softmac_output(slp, mp, dl_prim, DL_CONTROL_ACK, mpp);
2375895Syz147064 break;
2385895Syz147064 case DL_CAPABILITY_REQ:
2395895Syz147064 err = softmac_output(slp, mp, dl_prim, DL_CAPABILITY_ACK, mpp);
2405895Syz147064 break;
2415895Syz147064 default:
2425895Syz147064 if (mpp != NULL) {
2435895Syz147064 *mpp = mp;
2445895Syz147064 err = softmac_mexchange_error_ack(mpp, dl_prim,
2455895Syz147064 DL_UNSUPPORTED, 0);
2465895Syz147064 }
2475895Syz147064 break;
2485895Syz147064 }
2495895Syz147064 return (err);
2505895Syz147064 }
251