xref: /onnv-gate/usr/src/uts/common/io/softmac/softmac_pkt.c (revision 9682:6573382ca7cc)
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