softmac_pkt.c revision 11878:ac93462db6d7
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 2010 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
30mblk_t *
31softmac_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
60void
61softmac_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		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;
82	}
83
84	mac_rx(slp->sl_softmac->smac_mh, NULL, mp);
85	return;
86
87failed:
88	freemsg(mp);
89}
90
91#define	ACKTIMEOUT	(10 * hz)
92
93static int
94dlpi_get_errno(t_uscalar_t error, t_uscalar_t unix_errno)
95{
96	return (error == DL_SYSERR ? unix_errno : EINVAL);
97}
98
99int
100softmac_output(softmac_lower_t *slp, mblk_t *mp, t_uscalar_t dl_prim,
101    t_uscalar_t ack, mblk_t **mpp)
102{
103	union DL_primitives	*dlp;
104	mac_perim_handle_t	mph;
105	int			err = 0;
106
107	mac_perim_enter_by_mh(slp->sl_softmac->smac_mh, &mph);
108
109	ASSERT(!slp->sl_pending_ioctl);
110	ASSERT(slp->sl_pending_prim == DL_PRIM_INVAL);
111
112	/*
113	 * Record the pending DLPI primitive.
114	 */
115	mutex_enter(&slp->sl_mutex);
116	slp->sl_pending_prim = dl_prim;
117	mutex_exit(&slp->sl_mutex);
118
119	putnext(slp->sl_wq, mp);
120
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;
126	}
127
128	mp = slp->sl_ack_mp;
129	slp->sl_ack_mp = NULL;
130
131	/*
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.
134	 */
135	ASSERT(mp != NULL || slp->sl_pending_prim != DL_PRIM_INVAL);
136
137	slp->sl_pending_prim = DL_PRIM_INVAL;
138	mutex_exit(&slp->sl_mutex);
139
140	if (mp != NULL) {
141		dlp = (union DL_primitives *)mp->b_rptr;
142
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);
148		}
149	} else {
150		err = ENOMSG;
151	}
152
153	if (mpp != NULL)
154		*mpp = mp;
155	else
156		freemsg(mp);
157
158	mac_perim_exit(mph);
159	return (err);
160}
161
162void
163softmac_ioctl_tx(softmac_lower_t *slp, mblk_t *mp, mblk_t **mpp)
164{
165	mac_perim_handle_t	mph;
166
167	mac_perim_enter_by_mh(slp->sl_softmac->smac_mh, &mph);
168
169	/*
170	 * Record that ioctl processing is currently in progress.
171	 */
172	mutex_enter(&slp->sl_mutex);
173	slp->sl_pending_ioctl = B_TRUE;
174	mutex_exit(&slp->sl_mutex);
175
176	putnext(slp->sl_wq, mp);
177
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);
184
185	ASSERT(mpp != NULL && mp != NULL);
186	*mpp = mp;
187
188	mac_perim_exit(mph);
189}
190
191int
192softmac_mexchange_error_ack(mblk_t **mpp, t_uscalar_t error_primitive,
193	t_uscalar_t error, t_uscalar_t unix_errno)
194{
195	union DL_primitives *dlp;
196
197	if ((*mpp = mexchange(NULL, *mpp, sizeof (dl_error_ack_t), M_PCPROTO,
198	    DL_ERROR_ACK)) == NULL)
199		return (ENOMEM);
200
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;
205
206	return (0);
207}
208
209int
210softmac_proto_tx(softmac_lower_t *slp, mblk_t *mp, mblk_t **mpp)
211{
212	int err = 0;
213	t_uscalar_t dl_prim;
214
215	dl_prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive;
216
217	ASSERT(slp->sl_softmac != NULL);
218
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);
246		}
247		break;
248	}
249	return (err);
250}
251