Home | History | Annotate | Download | only in softmac
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <sys/strsubr.h>
     27 #include <inet/led.h>
     28 #include <sys/softmac_impl.h>
     29 
     30 mblk_t *
     31 softmac_m_tx(void *arg, mblk_t *mp)
     32 {
     33 	queue_t *wq = ((softmac_t *)arg)->smac_lower->sl_wq;
     34 
     35 	/*
     36 	 * Optimize for the most common case.
     37 	 */
     38 	if (mp->b_next == NULL) {
     39 		if (!SOFTMAC_CANPUTNEXT(wq))
     40 			return (mp);
     41 
     42 		mp->b_flag |= MSGNOLOOP;
     43 		putnext(wq, mp);
     44 		return (NULL);
     45 	}
     46 
     47 	while (mp != NULL) {
     48 		mblk_t *next = mp->b_next;
     49 
     50 		if (!SOFTMAC_CANPUTNEXT(wq))
     51 			break;
     52 		mp->b_next = NULL;
     53 		mp->b_flag |= MSGNOLOOP;
     54 		putnext(wq, mp);
     55 		mp = next;
     56 	}
     57 	return (mp);
     58 }
     59 
     60 void
     61 softmac_rput_process_data(softmac_lower_t *slp, mblk_t *mp)
     62 {
     63 	/*
     64 	 * When packets arrive, the softmac might not be fully started.
     65 	 */
     66 	ASSERT((slp->sl_softmac != NULL));
     67 	ASSERT((mp->b_next == NULL) && (mp->b_prev == NULL));
     68 
     69 	if (DB_REF(mp) > 1) {
     70 		mblk_t *tmp;
     71 		uint32_t start, stuff, end, value, flags;
     72 
     73 		if ((tmp = copymsg(mp)) == NULL) {
     74 			cmn_err(CE_WARN, "softmac_rput_process_data: "
     75 			    "copymsg failed");
     76 			goto failed;
     77 		}
     78 		hcksum_retrieve(mp, NULL, NULL, &start, &stuff, &end,
     79 		    &value, &flags);
     80 		VERIFY(hcksum_assoc(tmp, NULL, NULL, start, stuff, end,
     81 		    value, flags, KM_NOSLEEP) == 0);
     82 		freemsg(mp);
     83 		mp = tmp;
     84 	}
     85 
     86 	mac_rx(slp->sl_softmac->smac_mh, NULL, mp);
     87 	return;
     88 
     89 failed:
     90 	freemsg(mp);
     91 }
     92 
     93 #define	ACKTIMEOUT	(10 * hz)
     94 
     95 static int
     96 dlpi_get_errno(t_uscalar_t error, t_uscalar_t unix_errno)
     97 {
     98 	return (error == DL_SYSERR ? unix_errno : EINVAL);
     99 }
    100 
    101 int
    102 softmac_output(softmac_lower_t *slp, mblk_t *mp, t_uscalar_t dl_prim,
    103     t_uscalar_t ack, mblk_t **mpp)
    104 {
    105 	union DL_primitives	*dlp;
    106 	mac_perim_handle_t	mph;
    107 	int			err = 0;
    108 
    109 	mac_perim_enter_by_mh(slp->sl_softmac->smac_mh, &mph);
    110 
    111 	ASSERT(!slp->sl_pending_ioctl);
    112 	ASSERT(slp->sl_pending_prim == DL_PRIM_INVAL);
    113 
    114 	/*
    115 	 * Record the pending DLPI primitive.
    116 	 */
    117 	mutex_enter(&slp->sl_mutex);
    118 	slp->sl_pending_prim = dl_prim;
    119 	mutex_exit(&slp->sl_mutex);
    120 
    121 	putnext(slp->sl_wq, mp);
    122 
    123 	mutex_enter(&slp->sl_mutex);
    124 	while (slp->sl_pending_prim != DL_PRIM_INVAL) {
    125 		if (cv_reltimedwait(&slp->sl_cv, &slp->sl_mutex, ACKTIMEOUT,
    126 		    TR_CLOCK_TICK) == -1)
    127 			break;
    128 	}
    129 
    130 	mp = slp->sl_ack_mp;
    131 	slp->sl_ack_mp = NULL;
    132 
    133 	/*
    134 	 * If we timed out, sl_ack_mp will still be NULL, but sl_pending_prim
    135 	 * won't be set to DL_PRIM_INVAL.
    136 	 */
    137 	ASSERT(mp != NULL || slp->sl_pending_prim != DL_PRIM_INVAL);
    138 
    139 	slp->sl_pending_prim = DL_PRIM_INVAL;
    140 	mutex_exit(&slp->sl_mutex);
    141 
    142 	if (mp != NULL) {
    143 		dlp = (union DL_primitives *)mp->b_rptr;
    144 
    145 		if (dlp->dl_primitive == DL_ERROR_ACK) {
    146 			err = dlpi_get_errno(dlp->error_ack.dl_errno,
    147 			    dlp->error_ack.dl_unix_errno);
    148 		} else {
    149 			ASSERT(dlp->dl_primitive == ack);
    150 		}
    151 	} else {
    152 		err = ENOMSG;
    153 	}
    154 
    155 	if (mpp != NULL)
    156 		*mpp = mp;
    157 	else
    158 		freemsg(mp);
    159 
    160 	mac_perim_exit(mph);
    161 	return (err);
    162 }
    163 
    164 void
    165 softmac_ioctl_tx(softmac_lower_t *slp, mblk_t *mp, mblk_t **mpp)
    166 {
    167 	mac_perim_handle_t	mph;
    168 
    169 	mac_perim_enter_by_mh(slp->sl_softmac->smac_mh, &mph);
    170 
    171 	/*
    172 	 * Record that ioctl processing is currently in progress.
    173 	 */
    174 	mutex_enter(&slp->sl_mutex);
    175 	slp->sl_pending_ioctl = B_TRUE;
    176 	mutex_exit(&slp->sl_mutex);
    177 
    178 	putnext(slp->sl_wq, mp);
    179 
    180 	mutex_enter(&slp->sl_mutex);
    181 	while (slp->sl_pending_ioctl)
    182 		cv_wait(&slp->sl_cv, &slp->sl_mutex);
    183 	mp = slp->sl_ack_mp;
    184 	slp->sl_ack_mp = NULL;
    185 	mutex_exit(&slp->sl_mutex);
    186 
    187 	ASSERT(mpp != NULL && mp != NULL);
    188 	*mpp = mp;
    189 
    190 	mac_perim_exit(mph);
    191 }
    192 
    193 int
    194 softmac_mexchange_error_ack(mblk_t **mpp, t_uscalar_t error_primitive,
    195 	t_uscalar_t error, t_uscalar_t unix_errno)
    196 {
    197 	union DL_primitives *dlp;
    198 
    199 	if ((*mpp = mexchange(NULL, *mpp, sizeof (dl_error_ack_t), M_PCPROTO,
    200 	    DL_ERROR_ACK)) == NULL)
    201 		return (ENOMEM);
    202 
    203 	dlp = (union DL_primitives *)(*mpp)->b_rptr;
    204 	dlp->error_ack.dl_error_primitive = error_primitive;
    205 	dlp->error_ack.dl_errno = error;
    206 	dlp->error_ack.dl_unix_errno = unix_errno;
    207 
    208 	return (0);
    209 }
    210 
    211 int
    212 softmac_proto_tx(softmac_lower_t *slp, mblk_t *mp, mblk_t **mpp)
    213 {
    214 	int err = 0;
    215 	t_uscalar_t dl_prim;
    216 
    217 	dl_prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive;
    218 
    219 	ASSERT(slp->sl_softmac != NULL);
    220 
    221 	switch (dl_prim) {
    222 	case DL_ENABMULTI_REQ:
    223 	case DL_DISABMULTI_REQ:
    224 	case DL_SET_PHYS_ADDR_REQ:
    225 	case DL_UNBIND_REQ:
    226 	case DL_UDQOS_REQ:
    227 	case DL_PROMISCON_REQ:
    228 	case DL_PROMISCOFF_REQ:
    229 		err = softmac_output(slp, mp, dl_prim, DL_OK_ACK, mpp);
    230 		break;
    231 	case DL_BIND_REQ:
    232 		err = softmac_output(slp, mp, dl_prim, DL_BIND_ACK, mpp);
    233 		break;
    234 	case DL_NOTIFY_REQ:
    235 		err = softmac_output(slp, mp, dl_prim, DL_NOTIFY_ACK, mpp);
    236 		break;
    237 	case DL_CONTROL_REQ:
    238 		err = softmac_output(slp, mp, dl_prim, DL_CONTROL_ACK, mpp);
    239 		break;
    240 	case DL_CAPABILITY_REQ:
    241 		err = softmac_output(slp, mp, dl_prim, DL_CAPABILITY_ACK, mpp);
    242 		break;
    243 	default:
    244 		if (mpp != NULL) {
    245 			*mpp = mp;
    246 			err = softmac_mexchange_error_ack(mpp, dl_prim,
    247 			    DL_UNSUPPORTED, 0);
    248 		}
    249 		break;
    250 	}
    251 	return (err);
    252 }
    253