Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / io / softmac / softmac_pkt.c
blob6389ec132822d9b4202dbb1787bdfc9ee43e78c8
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/strsubr.h>
27 #include <inet/led.h>
28 #include <sys/softmac_impl.h>
30 mblk_t *
31 softmac_m_tx(void *arg, mblk_t *mp)
33 queue_t *wq = ((softmac_t *)arg)->smac_lower->sl_wq;
36 * Optimize for the most common case.
38 if (mp->b_next == NULL) {
39 if (!SOFTMAC_CANPUTNEXT(wq))
40 return (mp);
42 mp->b_flag |= MSGNOLOOP;
43 putnext(wq, mp);
44 return (NULL);
47 while (mp != NULL) {
48 mblk_t *next = mp->b_next;
50 if (!SOFTMAC_CANPUTNEXT(wq))
51 break;
52 mp->b_next = NULL;
53 mp->b_flag |= MSGNOLOOP;
54 putnext(wq, mp);
55 mp = next;
57 return (mp);
60 void
61 softmac_rput_process_data(softmac_lower_t *slp, mblk_t *mp)
64 * When packets arrive, the softmac might not be fully started.
66 ASSERT((slp->sl_softmac != NULL));
67 ASSERT((mp->b_next == NULL) && (mp->b_prev == NULL));
69 if (DB_REF(mp) > 1) {
70 mblk_t *tmp;
71 uint32_t start, stuff, end, value, flags;
73 if ((tmp = copymsg(mp)) == NULL) {
74 cmn_err(CE_WARN, "softmac_rput_process_data: "
75 "copymsg failed");
76 goto failed;
78 mac_hcksum_get(mp, &start, &stuff, &end, &value, &flags);
79 mac_hcksum_set(tmp, start, stuff, end, value, flags);
80 freemsg(mp);
81 mp = tmp;
84 mac_rx(slp->sl_softmac->smac_mh, NULL, mp);
85 return;
87 failed:
88 freemsg(mp);
91 #define ACKTIMEOUT (10 * hz)
93 static int
94 dlpi_get_errno(t_uscalar_t error, t_uscalar_t unix_errno)
96 return (error == DL_SYSERR ? unix_errno : EINVAL);
99 int
100 softmac_output(softmac_lower_t *slp, mblk_t *mp, t_uscalar_t dl_prim,
101 t_uscalar_t ack, mblk_t **mpp)
103 union DL_primitives *dlp;
104 mac_perim_handle_t mph;
105 int err = 0;
107 mac_perim_enter_by_mh(slp->sl_softmac->smac_mh, &mph);
109 ASSERT(!slp->sl_pending_ioctl);
110 ASSERT(slp->sl_pending_prim == DL_PRIM_INVAL);
113 * Record the pending DLPI primitive.
115 mutex_enter(&slp->sl_mutex);
116 slp->sl_pending_prim = dl_prim;
117 mutex_exit(&slp->sl_mutex);
119 putnext(slp->sl_wq, mp);
121 mutex_enter(&slp->sl_mutex);
122 while (slp->sl_pending_prim != DL_PRIM_INVAL) {
123 if (cv_reltimedwait(&slp->sl_cv, &slp->sl_mutex, ACKTIMEOUT,
124 TR_CLOCK_TICK) == -1)
125 break;
128 mp = slp->sl_ack_mp;
129 slp->sl_ack_mp = NULL;
132 * If we timed out, sl_ack_mp will still be NULL, but sl_pending_prim
133 * won't be set to DL_PRIM_INVAL.
135 ASSERT(mp != NULL || slp->sl_pending_prim != DL_PRIM_INVAL);
137 slp->sl_pending_prim = DL_PRIM_INVAL;
138 mutex_exit(&slp->sl_mutex);
140 if (mp != NULL) {
141 dlp = (union DL_primitives *)mp->b_rptr;
143 if (dlp->dl_primitive == DL_ERROR_ACK) {
144 err = dlpi_get_errno(dlp->error_ack.dl_errno,
145 dlp->error_ack.dl_unix_errno);
146 } else {
147 ASSERT(dlp->dl_primitive == ack);
149 } else {
150 err = ENOMSG;
153 if (mpp != NULL)
154 *mpp = mp;
155 else
156 freemsg(mp);
158 mac_perim_exit(mph);
159 return (err);
162 void
163 softmac_ioctl_tx(softmac_lower_t *slp, mblk_t *mp, mblk_t **mpp)
165 mac_perim_handle_t mph;
167 mac_perim_enter_by_mh(slp->sl_softmac->smac_mh, &mph);
170 * Record that ioctl processing is currently in progress.
172 mutex_enter(&slp->sl_mutex);
173 slp->sl_pending_ioctl = B_TRUE;
174 mutex_exit(&slp->sl_mutex);
176 putnext(slp->sl_wq, mp);
178 mutex_enter(&slp->sl_mutex);
179 while (slp->sl_pending_ioctl)
180 cv_wait(&slp->sl_cv, &slp->sl_mutex);
181 mp = slp->sl_ack_mp;
182 slp->sl_ack_mp = NULL;
183 mutex_exit(&slp->sl_mutex);
185 ASSERT(mpp != NULL && mp != NULL);
186 *mpp = mp;
188 mac_perim_exit(mph);
192 softmac_mexchange_error_ack(mblk_t **mpp, t_uscalar_t error_primitive,
193 t_uscalar_t error, t_uscalar_t unix_errno)
195 union DL_primitives *dlp;
197 if ((*mpp = mexchange(NULL, *mpp, sizeof (dl_error_ack_t), M_PCPROTO,
198 DL_ERROR_ACK)) == NULL)
199 return (ENOMEM);
201 dlp = (union DL_primitives *)(*mpp)->b_rptr;
202 dlp->error_ack.dl_error_primitive = error_primitive;
203 dlp->error_ack.dl_errno = error;
204 dlp->error_ack.dl_unix_errno = unix_errno;
206 return (0);
210 softmac_proto_tx(softmac_lower_t *slp, mblk_t *mp, mblk_t **mpp)
212 int err = 0;
213 t_uscalar_t dl_prim;
215 dl_prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive;
217 ASSERT(slp->sl_softmac != NULL);
219 switch (dl_prim) {
220 case DL_ENABMULTI_REQ:
221 case DL_DISABMULTI_REQ:
222 case DL_SET_PHYS_ADDR_REQ:
223 case DL_UNBIND_REQ:
224 case DL_UDQOS_REQ:
225 case DL_PROMISCON_REQ:
226 case DL_PROMISCOFF_REQ:
227 err = softmac_output(slp, mp, dl_prim, DL_OK_ACK, mpp);
228 break;
229 case DL_BIND_REQ:
230 err = softmac_output(slp, mp, dl_prim, DL_BIND_ACK, mpp);
231 break;
232 case DL_NOTIFY_REQ:
233 err = softmac_output(slp, mp, dl_prim, DL_NOTIFY_ACK, mpp);
234 break;
235 case DL_CONTROL_REQ:
236 err = softmac_output(slp, mp, dl_prim, DL_CONTROL_ACK, mpp);
237 break;
238 case DL_CAPABILITY_REQ:
239 err = softmac_output(slp, mp, dl_prim, DL_CAPABILITY_ACK, mpp);
240 break;
241 default:
242 if (mpp != NULL) {
243 *mpp = mp;
244 err = softmac_mexchange_error_ack(mpp, dl_prim,
245 DL_UNSUPPORTED, 0);
247 break;
249 return (err);