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