xref: /openbsd-src/sys/dev/usb/if_urndis.c (revision 81508fe356eb7772a68118f65f91723ce5261d7d)
1*81508fe3Sjsg /*	$OpenBSD: if_urndis.c,v 1.74 2024/05/23 03:21:09 jsg Exp $ */
2f8bfa4e2Smk 
3f8bfa4e2Smk /*
418b419daSfabien  * Copyright (c) 2010 Jonathan Armani <armani@openbsd.org>
518b419daSfabien  * Copyright (c) 2010 Fabien Romano <fabien@openbsd.org>
6f8bfa4e2Smk  * Copyright (c) 2010 Michael Knudsen <mk@openbsd.org>
7f8bfa4e2Smk  * All rights reserved.
8f8bfa4e2Smk  *
9f8bfa4e2Smk  * Permission to use, copy, modify, and distribute this software for any
10f8bfa4e2Smk  * purpose with or without fee is hereby granted, provided that the above
11f8bfa4e2Smk  * copyright notice and this permission notice appear in all copies.
12f8bfa4e2Smk  *
13f8bfa4e2Smk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14f8bfa4e2Smk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15f8bfa4e2Smk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16f8bfa4e2Smk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17f8bfa4e2Smk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18f8bfa4e2Smk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19f8bfa4e2Smk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20f8bfa4e2Smk  */
21f8bfa4e2Smk 
22f8bfa4e2Smk #include "bpfilter.h"
23f8bfa4e2Smk 
24f8bfa4e2Smk #include <sys/param.h>
25f8bfa4e2Smk #include <sys/systm.h>
26f8bfa4e2Smk #include <sys/sockio.h>
27f8bfa4e2Smk #include <sys/mbuf.h>
28f8bfa4e2Smk 
29f8bfa4e2Smk #include <sys/device.h>
30f8bfa4e2Smk 
31f8bfa4e2Smk #include <machine/bus.h>
32f8bfa4e2Smk 
33f8bfa4e2Smk #include <net/if.h>
34f8bfa4e2Smk 
35f8bfa4e2Smk #if NBPFILTER > 0
36f8bfa4e2Smk #include <net/bpf.h>
37f8bfa4e2Smk #endif
38f8bfa4e2Smk 
39f8bfa4e2Smk #include <netinet/in.h>
40f8bfa4e2Smk #include <netinet/if_ether.h>
41f8bfa4e2Smk 
42f8bfa4e2Smk #include <dev/usb/usb.h>
43f8bfa4e2Smk #include <dev/usb/usbdi.h>
44f8bfa4e2Smk #include <dev/usb/usbdevs.h>
45f8bfa4e2Smk 
467591b6e0Smikeb #include <dev/rndis.h>
477591b6e0Smikeb 
48f8bfa4e2Smk #include <dev/usb/if_urndisreg.h>
49f8bfa4e2Smk 
50cf497616Sfabien #ifdef URNDIS_DEBUG
51f8bfa4e2Smk #define DPRINTF(x)      do { printf x; } while (0)
52f8bfa4e2Smk #else
53f8bfa4e2Smk #define DPRINTF(x)
54f8bfa4e2Smk #endif
55f8bfa4e2Smk 
56f8bfa4e2Smk #define DEVNAME(sc)	((sc)->sc_dev.dv_xname)
57f8bfa4e2Smk 
5854384797Smk int urndis_newbuf(struct urndis_softc *, struct urndis_chain *);
59f8bfa4e2Smk 
60f8bfa4e2Smk int urndis_ioctl(struct ifnet *, u_long, caddr_t);
6161cec935Smk #if 0
62f8bfa4e2Smk void urndis_watchdog(struct ifnet *);
6361cec935Smk #endif
64f8bfa4e2Smk 
65f8bfa4e2Smk void urndis_start(struct ifnet *);
66ab0b1be7Smglocker void urndis_rxeof(struct usbd_xfer *, void *, usbd_status);
67ab0b1be7Smglocker void urndis_txeof(struct usbd_xfer *, void *, usbd_status);
68f8bfa4e2Smk int urndis_rx_list_init(struct urndis_softc *);
69f8bfa4e2Smk int urndis_tx_list_init(struct urndis_softc *);
70f8bfa4e2Smk 
71f8bfa4e2Smk void urndis_init(struct urndis_softc *);
72f8bfa4e2Smk void urndis_stop(struct urndis_softc *);
73f8bfa4e2Smk 
74f8bfa4e2Smk usbd_status urndis_ctrl_msg(struct urndis_softc *, uint8_t, uint8_t,
75f8bfa4e2Smk     uint16_t, uint16_t, void *, size_t);
76f8bfa4e2Smk usbd_status urndis_ctrl_send(struct urndis_softc *, void *, size_t);
777591b6e0Smikeb struct rndis_comp_hdr *urndis_ctrl_recv(struct urndis_softc *);
78f8bfa4e2Smk 
79c951c319Smk u_int32_t urndis_ctrl_handle(struct urndis_softc *,
807591b6e0Smikeb     struct rndis_comp_hdr *, void **, size_t *);
81c951c319Smk u_int32_t urndis_ctrl_handle_init(struct urndis_softc *,
827591b6e0Smikeb     const struct rndis_comp_hdr *);
83c951c319Smk u_int32_t urndis_ctrl_handle_query(struct urndis_softc *,
847591b6e0Smikeb     const struct rndis_comp_hdr *, void **, size_t *);
85c951c319Smk u_int32_t urndis_ctrl_handle_reset(struct urndis_softc *,
867591b6e0Smikeb     const struct rndis_comp_hdr *);
87bc3fdfc9Smikeb u_int32_t urndis_ctrl_handle_status(struct urndis_softc *,
88bc3fdfc9Smikeb     const struct rndis_comp_hdr *);
89f8bfa4e2Smk 
90c951c319Smk u_int32_t urndis_ctrl_init(struct urndis_softc *);
91c951c319Smk u_int32_t urndis_ctrl_halt(struct urndis_softc *);
92c951c319Smk u_int32_t urndis_ctrl_query(struct urndis_softc *, u_int32_t, void *, size_t,
93f8bfa4e2Smk     void **, size_t *);
94c951c319Smk u_int32_t urndis_ctrl_set(struct urndis_softc *, u_int32_t, void *, size_t);
95c951c319Smk u_int32_t urndis_ctrl_set_param(struct urndis_softc *, const char *, u_int32_t,
96f8bfa4e2Smk     void *, size_t);
9761cec935Smk #if 0
98c951c319Smk u_int32_t urndis_ctrl_reset(struct urndis_softc *);
99c951c319Smk u_int32_t urndis_ctrl_keepalive(struct urndis_softc *);
10061cec935Smk #endif
101f8bfa4e2Smk 
102f8bfa4e2Smk int urndis_encap(struct urndis_softc *, struct mbuf *, int);
1031a5c899fSmk void urndis_decap(struct urndis_softc *, struct urndis_chain *, u_int32_t);
104f8bfa4e2Smk 
10596761c40Sfgsch const struct urndis_class *urndis_lookup(usb_interface_descriptor_t *);
10696761c40Sfgsch 
107f8bfa4e2Smk int urndis_match(struct device *, void *, void *);
108f8bfa4e2Smk void urndis_attach(struct device *, struct device *, void *);
109f8bfa4e2Smk int urndis_detach(struct device *, int);
110f8bfa4e2Smk 
111f8bfa4e2Smk struct cfdriver urndis_cd = {
112f8bfa4e2Smk 	NULL, "urndis", DV_IFNET
113f8bfa4e2Smk };
114f8bfa4e2Smk 
115990261acSmpi const struct cfattach urndis_ca = {
11653c6612dSmpi 	sizeof(struct urndis_softc), urndis_match, urndis_attach, urndis_detach
117f8bfa4e2Smk };
118f8bfa4e2Smk 
11996761c40Sfgsch const struct urndis_class {
120003f6321Sfgsch 	u_int8_t class;
121003f6321Sfgsch 	u_int8_t subclass;
122003f6321Sfgsch 	u_int8_t protocol;
12396761c40Sfgsch 	const char *typestr;
124003f6321Sfgsch } urndis_class[] = {
12596761c40Sfgsch 	{ UICLASS_CDC, UISUBCLASS_ABSTRACT_CONTROL_MODEL, 0xff, "Vendor" },
12696761c40Sfgsch 	{ UICLASS_WIRELESS, UISUBCLASS_RF, UIPROTO_RNDIS, "RNDIS" },
12796761c40Sfgsch 	{ UICLASS_MISC, UISUBCLASS_SYNC, UIPROTO_ACTIVESYNC, "Activesync" }
12869858956Smk };
12969858956Smk 
130f8bfa4e2Smk usbd_status
urndis_ctrl_msg(struct urndis_softc * sc,uint8_t rt,uint8_t r,uint16_t index,uint16_t value,void * buf,size_t buflen)131f8bfa4e2Smk urndis_ctrl_msg(struct urndis_softc *sc, uint8_t rt, uint8_t r,
132f8bfa4e2Smk     uint16_t index, uint16_t value, void *buf, size_t buflen)
133f8bfa4e2Smk {
134f8bfa4e2Smk 	usb_device_request_t req;
135f8bfa4e2Smk 
136f8bfa4e2Smk 	req.bmRequestType = rt;
137f8bfa4e2Smk 	req.bRequest = r;
138f8bfa4e2Smk 	USETW(req.wValue, value);
139f8bfa4e2Smk 	USETW(req.wIndex, index);
140f8bfa4e2Smk 	USETW(req.wLength, buflen);
141f8bfa4e2Smk 
142f8bfa4e2Smk 	return usbd_do_request(sc->sc_udev, &req, buf);
143f8bfa4e2Smk }
144f8bfa4e2Smk 
145f8bfa4e2Smk usbd_status
urndis_ctrl_send(struct urndis_softc * sc,void * buf,size_t len)146f8bfa4e2Smk urndis_ctrl_send(struct urndis_softc *sc, void *buf, size_t len)
147f8bfa4e2Smk {
148f8bfa4e2Smk 	usbd_status err;
149f8bfa4e2Smk 
1500a7d4bd2Spirofti 	if (usbd_is_dying(sc->sc_udev))
151f8bfa4e2Smk 		return(0);
152f8bfa4e2Smk 
153f8bfa4e2Smk 	err = urndis_ctrl_msg(sc, UT_WRITE_CLASS_INTERFACE, UR_GET_STATUS,
154f8bfa4e2Smk 	    sc->sc_ifaceno_ctl, 0, buf, len);
155f8bfa4e2Smk 
156f8bfa4e2Smk 	if (err != USBD_NORMAL_COMPLETION)
157f8bfa4e2Smk 		printf("%s: %s\n", DEVNAME(sc), usbd_errstr(err));
158f8bfa4e2Smk 
159f8bfa4e2Smk 	return err;
160f8bfa4e2Smk }
161f8bfa4e2Smk 
1627591b6e0Smikeb struct rndis_comp_hdr *
urndis_ctrl_recv(struct urndis_softc * sc)163f8bfa4e2Smk urndis_ctrl_recv(struct urndis_softc *sc)
164f8bfa4e2Smk {
165e0c375e3Smk #define RNDIS_RESPONSE_LEN 0x400
1667591b6e0Smikeb 	struct rndis_comp_hdr	*hdr;
167f8bfa4e2Smk 	char			*buf;
168f8bfa4e2Smk 	usbd_status		 err;
169f8bfa4e2Smk 
170f8bfa4e2Smk 	buf = malloc(RNDIS_RESPONSE_LEN, M_TEMP, M_WAITOK | M_CANFAIL);
171f8bfa4e2Smk 	if (buf == NULL) {
172f8bfa4e2Smk 		printf("%s: out of memory\n", DEVNAME(sc));
173f8bfa4e2Smk 		return NULL;
174f8bfa4e2Smk 	}
175f8bfa4e2Smk 
176f8bfa4e2Smk 	err = urndis_ctrl_msg(sc, UT_READ_CLASS_INTERFACE, UR_CLEAR_FEATURE,
177f8bfa4e2Smk 	    sc->sc_ifaceno_ctl, 0, buf, RNDIS_RESPONSE_LEN);
178f8bfa4e2Smk 
179f8bfa4e2Smk 	if (err != USBD_NORMAL_COMPLETION && err != USBD_SHORT_XFER) {
180f8bfa4e2Smk 		printf("%s: %s\n", DEVNAME(sc), usbd_errstr(err));
181c9ee9455Sderaadt 		free(buf, M_TEMP, RNDIS_RESPONSE_LEN);
182f8bfa4e2Smk 		return NULL;
183f8bfa4e2Smk 	}
184f8bfa4e2Smk 
1857591b6e0Smikeb 	hdr = (struct rndis_comp_hdr *)buf;
186f8bfa4e2Smk 	DPRINTF(("%s: urndis_ctrl_recv: type 0x%x len %u\n",
187f8bfa4e2Smk 	    DEVNAME(sc),
188f8bfa4e2Smk 	    letoh32(hdr->rm_type),
189f8bfa4e2Smk 	    letoh32(hdr->rm_len)));
190f8bfa4e2Smk 
191f8bfa4e2Smk 	if (letoh32(hdr->rm_len) > RNDIS_RESPONSE_LEN) {
192f8bfa4e2Smk 		printf("%s: ctrl message error: wrong size %u > %u\n",
193f8bfa4e2Smk 		    DEVNAME(sc),
194f8bfa4e2Smk 		    letoh32(hdr->rm_len),
195f8bfa4e2Smk 		    RNDIS_RESPONSE_LEN);
196c9ee9455Sderaadt 		free(buf, M_TEMP, RNDIS_RESPONSE_LEN);
197f8bfa4e2Smk 		return NULL;
198f8bfa4e2Smk 	}
199f8bfa4e2Smk 
200e0c375e3Smk 	return hdr;
201f8bfa4e2Smk }
202f8bfa4e2Smk 
203c951c319Smk u_int32_t
urndis_ctrl_handle(struct urndis_softc * sc,struct rndis_comp_hdr * hdr,void ** buf,size_t * bufsz)2047591b6e0Smikeb urndis_ctrl_handle(struct urndis_softc *sc, struct rndis_comp_hdr *hdr,
205f8bfa4e2Smk     void **buf, size_t *bufsz)
206f8bfa4e2Smk {
207c951c319Smk 	u_int32_t rval;
208f8bfa4e2Smk 
209f8bfa4e2Smk 	DPRINTF(("%s: urndis_ctrl_handle\n", DEVNAME(sc)));
210f8bfa4e2Smk 
211f8bfa4e2Smk 	if (buf && bufsz) {
212f8bfa4e2Smk 		*buf = NULL;
213f8bfa4e2Smk 		*bufsz = 0;
214f8bfa4e2Smk 	}
215f8bfa4e2Smk 
216f8bfa4e2Smk 	switch (letoh32(hdr->rm_type)) {
217f8bfa4e2Smk 		case REMOTE_NDIS_INITIALIZE_CMPLT:
218f8bfa4e2Smk 			rval = urndis_ctrl_handle_init(sc, hdr);
219f8bfa4e2Smk 			break;
220f8bfa4e2Smk 
221f8bfa4e2Smk 		case REMOTE_NDIS_QUERY_CMPLT:
222f8bfa4e2Smk 			rval = urndis_ctrl_handle_query(sc, hdr, buf, bufsz);
223f8bfa4e2Smk 			break;
224f8bfa4e2Smk 
225f8bfa4e2Smk 		case REMOTE_NDIS_RESET_CMPLT:
226f8bfa4e2Smk 			rval = urndis_ctrl_handle_reset(sc, hdr);
227f8bfa4e2Smk 			break;
228f8bfa4e2Smk 
229f8bfa4e2Smk 		case REMOTE_NDIS_KEEPALIVE_CMPLT:
230f8bfa4e2Smk 		case REMOTE_NDIS_SET_CMPLT:
231f8bfa4e2Smk 			rval = letoh32(hdr->rm_status);
232f8bfa4e2Smk 			break;
233f8bfa4e2Smk 
234bc3fdfc9Smikeb 		case REMOTE_NDIS_INDICATE_STATUS_MSG:
235bc3fdfc9Smikeb 			rval = urndis_ctrl_handle_status(sc, hdr);
236bc3fdfc9Smikeb 			break;
237bc3fdfc9Smikeb 
238f8bfa4e2Smk 		default:
239f8bfa4e2Smk 			printf("%s: ctrl message error: unknown event 0x%x\n",
240f8bfa4e2Smk 			    DEVNAME(sc), letoh32(hdr->rm_type));
241f8bfa4e2Smk 			rval = RNDIS_STATUS_FAILURE;
242f8bfa4e2Smk 	}
243f8bfa4e2Smk 
244234dfda1Sderaadt 	free(hdr, M_TEMP, RNDIS_RESPONSE_LEN);
245f8bfa4e2Smk 
246f8bfa4e2Smk 	return rval;
247f8bfa4e2Smk }
248f8bfa4e2Smk 
249c951c319Smk u_int32_t
urndis_ctrl_handle_init(struct urndis_softc * sc,const struct rndis_comp_hdr * hdr)250bb30f7e7Smk urndis_ctrl_handle_init(struct urndis_softc *sc,
2517591b6e0Smikeb     const struct rndis_comp_hdr *hdr)
252f8bfa4e2Smk {
2537591b6e0Smikeb 	const struct rndis_init_comp	*msg;
254f8bfa4e2Smk 
2557591b6e0Smikeb 	msg = (struct rndis_init_comp *) hdr;
256f8bfa4e2Smk 
257f8bfa4e2Smk 	DPRINTF(("%s: urndis_ctrl_handle_init: len %u rid %u status 0x%x "
258f8bfa4e2Smk 	    "ver_major %u ver_minor %u devflags 0x%x medium 0x%x pktmaxcnt %u "
259f8bfa4e2Smk 	    "pktmaxsz %u align %u aflistoffset %u aflistsz %u\n",
260f8bfa4e2Smk 	    DEVNAME(sc),
261f8bfa4e2Smk 	    letoh32(msg->rm_len),
262f8bfa4e2Smk 	    letoh32(msg->rm_rid),
263f8bfa4e2Smk 	    letoh32(msg->rm_status),
264f8bfa4e2Smk 	    letoh32(msg->rm_ver_major),
265f8bfa4e2Smk 	    letoh32(msg->rm_ver_minor),
266f8bfa4e2Smk 	    letoh32(msg->rm_devflags),
267f8bfa4e2Smk 	    letoh32(msg->rm_medium),
268f8bfa4e2Smk 	    letoh32(msg->rm_pktmaxcnt),
269f8bfa4e2Smk 	    letoh32(msg->rm_pktmaxsz),
270f8bfa4e2Smk 	    letoh32(msg->rm_align),
271f8bfa4e2Smk 	    letoh32(msg->rm_aflistoffset),
272f8bfa4e2Smk 	    letoh32(msg->rm_aflistsz)));
273f8bfa4e2Smk 
274f8bfa4e2Smk 	if (letoh32(msg->rm_status) != RNDIS_STATUS_SUCCESS) {
275f8bfa4e2Smk 		printf("%s: init failed 0x%x\n",
276f8bfa4e2Smk 		    DEVNAME(sc),
277f8bfa4e2Smk 		    letoh32(msg->rm_status));
278f8bfa4e2Smk 
279f8bfa4e2Smk 		return letoh32(msg->rm_status);
280f8bfa4e2Smk 	}
281f8bfa4e2Smk 
282f8bfa4e2Smk 	if (letoh32(msg->rm_devflags) != RNDIS_DF_CONNECTIONLESS) {
283f8bfa4e2Smk 		printf("%s: wrong device type (current type: 0x%x)\n",
284f8bfa4e2Smk 		    DEVNAME(sc),
285f8bfa4e2Smk 		    letoh32(msg->rm_devflags));
286f8bfa4e2Smk 
287f8bfa4e2Smk 		return RNDIS_STATUS_FAILURE;
288f8bfa4e2Smk 	}
289f8bfa4e2Smk 
290f8bfa4e2Smk 	if (letoh32(msg->rm_medium) != RNDIS_MEDIUM_802_3) {
291f8bfa4e2Smk 		printf("%s: medium not 802.3 (current medium: 0x%x)\n",
292f8bfa4e2Smk 		    DEVNAME(sc), letoh32(msg->rm_medium));
293f8bfa4e2Smk 
294f8bfa4e2Smk 		return RNDIS_STATUS_FAILURE;
295f8bfa4e2Smk 	}
296f8bfa4e2Smk 
297f8bfa4e2Smk 	sc->sc_lim_pktsz = letoh32(msg->rm_pktmaxsz);
298f8bfa4e2Smk 
299f8bfa4e2Smk 	return letoh32(msg->rm_status);
300f8bfa4e2Smk }
301f8bfa4e2Smk 
302c951c319Smk u_int32_t
urndis_ctrl_handle_query(struct urndis_softc * sc,const struct rndis_comp_hdr * hdr,void ** buf,size_t * bufsz)303f8bfa4e2Smk urndis_ctrl_handle_query(struct urndis_softc *sc,
3047591b6e0Smikeb     const struct rndis_comp_hdr *hdr, void **buf, size_t *bufsz)
305f8bfa4e2Smk {
3067591b6e0Smikeb 	const struct rndis_query_comp	*msg;
307f8bfa4e2Smk 
3087591b6e0Smikeb 	msg = (struct rndis_query_comp *) hdr;
309f8bfa4e2Smk 
310f8bfa4e2Smk 	DPRINTF(("%s: urndis_ctrl_handle_query: len %u rid %u status 0x%x "
311f8bfa4e2Smk 	    "buflen %u bufoff %u\n",
312f8bfa4e2Smk 	    DEVNAME(sc),
313f8bfa4e2Smk 	    letoh32(msg->rm_len),
314f8bfa4e2Smk 	    letoh32(msg->rm_rid),
315f8bfa4e2Smk 	    letoh32(msg->rm_status),
316f8bfa4e2Smk 	    letoh32(msg->rm_infobuflen),
317f8bfa4e2Smk 	    letoh32(msg->rm_infobufoffset)));
318f8bfa4e2Smk 
319f8bfa4e2Smk 	if (buf && bufsz) {
320f8bfa4e2Smk 		*buf = NULL;
321f8bfa4e2Smk 		*bufsz = 0;
322f8bfa4e2Smk 	}
323f8bfa4e2Smk 
324f8bfa4e2Smk 	if (letoh32(msg->rm_status) != RNDIS_STATUS_SUCCESS) {
325f8bfa4e2Smk 		printf("%s: query failed 0x%x\n",
326f8bfa4e2Smk 		    DEVNAME(sc),
327f8bfa4e2Smk 		    letoh32(msg->rm_status));
328f8bfa4e2Smk 
329f8bfa4e2Smk 		return letoh32(msg->rm_status);
330f8bfa4e2Smk 	}
331ef710148Sarmani 
332f8bfa4e2Smk 	if (letoh32(msg->rm_infobuflen) + letoh32(msg->rm_infobufoffset) +
333ef710148Sarmani 	    RNDIS_HEADER_OFFSET > letoh32(msg->rm_len)) {
334f8bfa4e2Smk 		printf("%s: ctrl message error: invalid query info "
3352b2fa8a9Ssf 		    "len/offset/end_position(%u/%u/%zu) -> "
3362b2fa8a9Ssf 		    "go out of buffer limit %u\n",
337f8bfa4e2Smk 		    DEVNAME(sc),
338f8bfa4e2Smk 		    letoh32(msg->rm_infobuflen),
339f8bfa4e2Smk 		    letoh32(msg->rm_infobufoffset),
340f8bfa4e2Smk 		    letoh32(msg->rm_infobuflen) +
341ef710148Sarmani 		    letoh32(msg->rm_infobufoffset) + RNDIS_HEADER_OFFSET,
342f8bfa4e2Smk 		    letoh32(msg->rm_len));
343f8bfa4e2Smk 		return RNDIS_STATUS_FAILURE;
344f8bfa4e2Smk 	}
345f8bfa4e2Smk 
346f8bfa4e2Smk 	if (buf && bufsz) {
347f8bfa4e2Smk 		*buf = malloc(letoh32(msg->rm_infobuflen),
348f8bfa4e2Smk 		    M_TEMP, M_WAITOK | M_CANFAIL);
349f8bfa4e2Smk 		if (*buf == NULL) {
350f8bfa4e2Smk 			printf("%s: out of memory\n", DEVNAME(sc));
351f8bfa4e2Smk 			return RNDIS_STATUS_FAILURE;
352f8bfa4e2Smk 		} else {
353f8bfa4e2Smk 			char *p;
354f8bfa4e2Smk 			*bufsz = letoh32(msg->rm_infobuflen);
355f8bfa4e2Smk 
356f8bfa4e2Smk 			p = (char *)&msg->rm_rid;
357f8bfa4e2Smk 			p += letoh32(msg->rm_infobufoffset);
358f8bfa4e2Smk 			memcpy(*buf, p, letoh32(msg->rm_infobuflen));
359f8bfa4e2Smk 		}
360f8bfa4e2Smk 	}
361f8bfa4e2Smk 
362f8bfa4e2Smk 	return letoh32(msg->rm_status);
363f8bfa4e2Smk }
364f8bfa4e2Smk 
365c951c319Smk u_int32_t
urndis_ctrl_handle_reset(struct urndis_softc * sc,const struct rndis_comp_hdr * hdr)366f8bfa4e2Smk urndis_ctrl_handle_reset(struct urndis_softc *sc,
3677591b6e0Smikeb     const struct rndis_comp_hdr *hdr)
368f8bfa4e2Smk {
3697591b6e0Smikeb 	const struct rndis_reset_comp	*msg;
370c951c319Smk 	u_int32_t			 rval;
371f8bfa4e2Smk 
3727591b6e0Smikeb 	msg = (struct rndis_reset_comp *) hdr;
373f8bfa4e2Smk 
374f8bfa4e2Smk 	rval = letoh32(msg->rm_status);
375f8bfa4e2Smk 
376f8bfa4e2Smk 	DPRINTF(("%s: urndis_ctrl_handle_reset: len %u status 0x%x "
377f8bfa4e2Smk 	    "adrreset %u\n",
378f8bfa4e2Smk 	    DEVNAME(sc),
379f8bfa4e2Smk 	    letoh32(msg->rm_len),
380f8bfa4e2Smk 	    rval,
381f8bfa4e2Smk 	    letoh32(msg->rm_adrreset)));
382f8bfa4e2Smk 
383f8bfa4e2Smk 	if (rval != RNDIS_STATUS_SUCCESS) {
384f8bfa4e2Smk 		printf("%s: reset failed 0x%x\n", DEVNAME(sc), rval);
385f8bfa4e2Smk 		return rval;
386f8bfa4e2Smk 	}
387f8bfa4e2Smk 
388f8bfa4e2Smk 	if (letoh32(msg->rm_adrreset) != 0) {
389f8bfa4e2Smk 		u_int32_t filter;
390f8bfa4e2Smk 
391f8bfa4e2Smk 		filter = htole32(sc->sc_filter);
392f8bfa4e2Smk 		rval = urndis_ctrl_set(sc, OID_GEN_CURRENT_PACKET_FILTER,
393f8bfa4e2Smk 		    &filter, sizeof(filter));
394f8bfa4e2Smk 		if (rval != RNDIS_STATUS_SUCCESS) {
395f8bfa4e2Smk 			printf("%s: unable to reset data filters\n",
396f8bfa4e2Smk 			    DEVNAME(sc));
397f8bfa4e2Smk 			return rval;
398f8bfa4e2Smk 		}
399f8bfa4e2Smk 	}
400f8bfa4e2Smk 
401f8bfa4e2Smk 	return rval;
402f8bfa4e2Smk }
403f8bfa4e2Smk 
404c951c319Smk u_int32_t
urndis_ctrl_handle_status(struct urndis_softc * sc,const struct rndis_comp_hdr * hdr)405bc3fdfc9Smikeb urndis_ctrl_handle_status(struct urndis_softc *sc,
406bc3fdfc9Smikeb     const struct rndis_comp_hdr *hdr)
407bc3fdfc9Smikeb {
408bc3fdfc9Smikeb 	const struct rndis_status_msg	*msg;
409bc3fdfc9Smikeb 	u_int32_t			 rval;
410bc3fdfc9Smikeb 
411bc3fdfc9Smikeb 	msg = (struct rndis_status_msg *)hdr;
412bc3fdfc9Smikeb 
413bc3fdfc9Smikeb 	rval = letoh32(msg->rm_status);
414bc3fdfc9Smikeb 
415bc3fdfc9Smikeb 	DPRINTF(("%s: urndis_ctrl_handle_status: len %u status 0x%x "
416bc3fdfc9Smikeb 	    "stbuflen %u\n",
417bc3fdfc9Smikeb 	    DEVNAME(sc),
418bc3fdfc9Smikeb 	    letoh32(msg->rm_len),
419bc3fdfc9Smikeb 	    rval,
420bc3fdfc9Smikeb 	    letoh32(msg->rm_stbuflen)));
421bc3fdfc9Smikeb 
422bc3fdfc9Smikeb 	switch (rval) {
423bc3fdfc9Smikeb 		case RNDIS_STATUS_MEDIA_CONNECT:
424bc3fdfc9Smikeb 		case RNDIS_STATUS_MEDIA_DISCONNECT:
425bc3fdfc9Smikeb 		case RNDIS_STATUS_OFFLOAD_CURRENT_CONFIG:
426bc3fdfc9Smikeb 			rval = RNDIS_STATUS_SUCCESS;
427bc3fdfc9Smikeb 			break;
428bc3fdfc9Smikeb 
429bc3fdfc9Smikeb 		default:
430bc3fdfc9Smikeb 			printf("%s: status 0x%x\n", DEVNAME(sc), rval);
431bc3fdfc9Smikeb 	}
432bc3fdfc9Smikeb 
433bc3fdfc9Smikeb 	return rval;
434bc3fdfc9Smikeb }
435bc3fdfc9Smikeb 
436bc3fdfc9Smikeb u_int32_t
urndis_ctrl_init(struct urndis_softc * sc)437f8bfa4e2Smk urndis_ctrl_init(struct urndis_softc *sc)
438f8bfa4e2Smk {
4397591b6e0Smikeb 	struct rndis_init_req	*msg;
440c951c319Smk 	u_int32_t		 rval;
4417591b6e0Smikeb 	struct rndis_comp_hdr	*hdr;
442f8bfa4e2Smk 
443d5bd7054Skevlo 	msg = malloc(sizeof(*msg), M_TEMP, M_WAITOK | M_CANFAIL);
444f8bfa4e2Smk 	if (msg == NULL) {
445f8bfa4e2Smk 		printf("%s: out of memory\n", DEVNAME(sc));
446f8bfa4e2Smk 		return RNDIS_STATUS_FAILURE;
447f8bfa4e2Smk 	}
448f8bfa4e2Smk 
449f8bfa4e2Smk 	msg->rm_type = htole32(REMOTE_NDIS_INITIALIZE_MSG);
450f8bfa4e2Smk 	msg->rm_len = htole32(sizeof(*msg));
451f8bfa4e2Smk 	msg->rm_rid = htole32(0);
452f8bfa4e2Smk 	msg->rm_ver_major = htole32(1);
453f8bfa4e2Smk 	msg->rm_ver_minor = htole32(1);
454f8bfa4e2Smk 	msg->rm_max_xfersz = htole32(RNDIS_BUFSZ);
455f8bfa4e2Smk 
456f8bfa4e2Smk 	DPRINTF(("%s: urndis_ctrl_init send: type %u len %u rid %u ver_major %u "
457f8bfa4e2Smk 	    "ver_minor %u max_xfersz %u\n",
458f8bfa4e2Smk 	    DEVNAME(sc),
459f8bfa4e2Smk 	    letoh32(msg->rm_type),
460f8bfa4e2Smk 	    letoh32(msg->rm_len),
461f8bfa4e2Smk 	    letoh32(msg->rm_rid),
462f8bfa4e2Smk 	    letoh32(msg->rm_ver_major),
463f8bfa4e2Smk 	    letoh32(msg->rm_ver_minor),
464f8bfa4e2Smk 	    letoh32(msg->rm_max_xfersz)));
465f8bfa4e2Smk 
466f8bfa4e2Smk 	rval = urndis_ctrl_send(sc, msg, sizeof(*msg));
467c9ee9455Sderaadt 	free(msg, M_TEMP, sizeof *msg);
468f8bfa4e2Smk 
469f8bfa4e2Smk 	if (rval != RNDIS_STATUS_SUCCESS) {
470f8bfa4e2Smk 		printf("%s: init failed\n", DEVNAME(sc));
471f8bfa4e2Smk 		return rval;
472f8bfa4e2Smk 	}
473f8bfa4e2Smk 
474f8bfa4e2Smk 	if ((hdr = urndis_ctrl_recv(sc)) == NULL) {
475f8bfa4e2Smk 		printf("%s: unable to get init response\n", DEVNAME(sc));
476f8bfa4e2Smk 		return RNDIS_STATUS_FAILURE;
477f8bfa4e2Smk 	}
478f8bfa4e2Smk 	rval = urndis_ctrl_handle(sc, hdr, NULL, NULL);
479f8bfa4e2Smk 
480f8bfa4e2Smk 	return rval;
481f8bfa4e2Smk }
482f8bfa4e2Smk 
483c951c319Smk u_int32_t
urndis_ctrl_halt(struct urndis_softc * sc)484f8bfa4e2Smk urndis_ctrl_halt(struct urndis_softc *sc)
485f8bfa4e2Smk {
4867591b6e0Smikeb 	struct rndis_halt_req	*msg;
487c951c319Smk 	u_int32_t		 rval;
488f8bfa4e2Smk 
489d5bd7054Skevlo 	msg = malloc(sizeof(*msg), M_TEMP, M_WAITOK | M_CANFAIL);
490f8bfa4e2Smk 	if (msg == NULL) {
491f8bfa4e2Smk 		printf("%s: out of memory\n", DEVNAME(sc));
492f8bfa4e2Smk 		return RNDIS_STATUS_FAILURE;
493f8bfa4e2Smk 	}
494f8bfa4e2Smk 
495f8bfa4e2Smk 	msg->rm_type = htole32(REMOTE_NDIS_HALT_MSG);
496f8bfa4e2Smk 	msg->rm_len = htole32(sizeof(*msg));
497f8bfa4e2Smk 	msg->rm_rid = 0;
498f8bfa4e2Smk 
499f8bfa4e2Smk 	DPRINTF(("%s: urndis_ctrl_halt send: type %u len %u rid %u\n",
500f8bfa4e2Smk 	    DEVNAME(sc),
501f8bfa4e2Smk 	    letoh32(msg->rm_type),
502f8bfa4e2Smk 	    letoh32(msg->rm_len),
503f8bfa4e2Smk 	    letoh32(msg->rm_rid)));
504f8bfa4e2Smk 
505f8bfa4e2Smk 	rval = urndis_ctrl_send(sc, msg, sizeof(*msg));
506c9ee9455Sderaadt 	free(msg, M_TEMP, sizeof *msg);
507f8bfa4e2Smk 
508f8bfa4e2Smk 	if (rval != RNDIS_STATUS_SUCCESS)
509f8bfa4e2Smk 		printf("%s: halt failed\n", DEVNAME(sc));
510f8bfa4e2Smk 
511f8bfa4e2Smk 	return rval;
512f8bfa4e2Smk }
513f8bfa4e2Smk 
514c951c319Smk u_int32_t
urndis_ctrl_query(struct urndis_softc * sc,u_int32_t oid,void * qbuf,size_t qlen,void ** rbuf,size_t * rbufsz)515c951c319Smk urndis_ctrl_query(struct urndis_softc *sc, u_int32_t oid,
516f8bfa4e2Smk     void *qbuf, size_t qlen,
517f8bfa4e2Smk     void **rbuf, size_t *rbufsz)
518f8bfa4e2Smk {
5197591b6e0Smikeb 	struct rndis_query_req	*msg;
520c951c319Smk 	u_int32_t		 rval;
5217591b6e0Smikeb 	struct rndis_comp_hdr	*hdr;
522f8bfa4e2Smk 
523d5bd7054Skevlo 	msg = malloc(sizeof(*msg) + qlen, M_TEMP, M_WAITOK | M_CANFAIL);
524f8bfa4e2Smk 	if (msg == NULL) {
525f8bfa4e2Smk 		printf("%s: out of memory\n", DEVNAME(sc));
526f8bfa4e2Smk 		return RNDIS_STATUS_FAILURE;
527f8bfa4e2Smk 	}
528f8bfa4e2Smk 
529f8bfa4e2Smk 	msg->rm_type = htole32(REMOTE_NDIS_QUERY_MSG);
530f8bfa4e2Smk 	msg->rm_len = htole32(sizeof(*msg) + qlen);
531f8bfa4e2Smk 	msg->rm_rid = 0; /* XXX */
532f8bfa4e2Smk 	msg->rm_oid = htole32(oid);
533f8bfa4e2Smk 	msg->rm_infobuflen = htole32(qlen);
534f8bfa4e2Smk 	if (qlen != 0) {
535f8bfa4e2Smk 		msg->rm_infobufoffset = htole32(20);
536f8bfa4e2Smk 		memcpy((char*)msg + 20, qbuf, qlen);
537f8bfa4e2Smk 	} else
538f8bfa4e2Smk 		msg->rm_infobufoffset = 0;
539f8bfa4e2Smk 	msg->rm_devicevchdl = 0;
540f8bfa4e2Smk 
541f8bfa4e2Smk 	DPRINTF(("%s: urndis_ctrl_query send: type %u len %u rid %u oid 0x%x "
542f8bfa4e2Smk 	    "infobuflen %u infobufoffset %u devicevchdl %u\n",
543f8bfa4e2Smk 	    DEVNAME(sc),
544f8bfa4e2Smk 	    letoh32(msg->rm_type),
545f8bfa4e2Smk 	    letoh32(msg->rm_len),
546f8bfa4e2Smk 	    letoh32(msg->rm_rid),
547f8bfa4e2Smk 	    letoh32(msg->rm_oid),
548f8bfa4e2Smk 	    letoh32(msg->rm_infobuflen),
549f8bfa4e2Smk 	    letoh32(msg->rm_infobufoffset),
550f8bfa4e2Smk 	    letoh32(msg->rm_devicevchdl)));
551f8bfa4e2Smk 
552f8bfa4e2Smk 	rval = urndis_ctrl_send(sc, msg, sizeof(*msg));
553c9ee9455Sderaadt 	free(msg, M_TEMP, sizeof *msg + qlen);
554f8bfa4e2Smk 
555f8bfa4e2Smk 	if (rval != RNDIS_STATUS_SUCCESS) {
556f8bfa4e2Smk 		printf("%s: query failed\n", DEVNAME(sc));
557f8bfa4e2Smk 		return rval;
558f8bfa4e2Smk 	}
559f8bfa4e2Smk 
560f8bfa4e2Smk 	if ((hdr = urndis_ctrl_recv(sc)) == NULL) {
561f8bfa4e2Smk 		printf("%s: unable to get query response\n", DEVNAME(sc));
562f8bfa4e2Smk 		return RNDIS_STATUS_FAILURE;
563f8bfa4e2Smk 	}
564f8bfa4e2Smk 	rval = urndis_ctrl_handle(sc, hdr, rbuf, rbufsz);
565f8bfa4e2Smk 
566f8bfa4e2Smk 	return rval;
567f8bfa4e2Smk }
568f8bfa4e2Smk 
569c951c319Smk u_int32_t
urndis_ctrl_set(struct urndis_softc * sc,u_int32_t oid,void * buf,size_t len)570c951c319Smk urndis_ctrl_set(struct urndis_softc *sc, u_int32_t oid, void *buf, size_t len)
571f8bfa4e2Smk {
5727591b6e0Smikeb 	struct rndis_set_req	*msg;
573c951c319Smk 	u_int32_t		 rval;
5747591b6e0Smikeb 	struct rndis_comp_hdr	*hdr;
575f8bfa4e2Smk 
576d5bd7054Skevlo 	msg = malloc(sizeof(*msg) + len, M_TEMP, M_WAITOK | M_CANFAIL);
577f8bfa4e2Smk 	if (msg == NULL) {
578f8bfa4e2Smk 		printf("%s: out of memory\n", DEVNAME(sc));
579f8bfa4e2Smk 		return RNDIS_STATUS_FAILURE;
580f8bfa4e2Smk 	}
581f8bfa4e2Smk 
582f8bfa4e2Smk 	msg->rm_type = htole32(REMOTE_NDIS_SET_MSG);
583f8bfa4e2Smk 	msg->rm_len = htole32(sizeof(*msg) + len);
584f8bfa4e2Smk 	msg->rm_rid = 0; /* XXX */
585f8bfa4e2Smk 	msg->rm_oid = htole32(oid);
586f8bfa4e2Smk 	msg->rm_infobuflen = htole32(len);
587f8bfa4e2Smk 	if (len != 0) {
588f8bfa4e2Smk 		msg->rm_infobufoffset = htole32(20);
589f4b3fec4Skettenis 		memcpy((char*)msg + 28, buf, len);
590f8bfa4e2Smk 	} else
591f8bfa4e2Smk 		msg->rm_infobufoffset = 0;
592f8bfa4e2Smk 	msg->rm_devicevchdl = 0;
593f8bfa4e2Smk 
594f8bfa4e2Smk 	DPRINTF(("%s: urndis_ctrl_set send: type %u len %u rid %u oid 0x%x "
595f8bfa4e2Smk 	    "infobuflen %u infobufoffset %u devicevchdl %u\n",
596f8bfa4e2Smk 	    DEVNAME(sc),
597f8bfa4e2Smk 	    letoh32(msg->rm_type),
598f8bfa4e2Smk 	    letoh32(msg->rm_len),
599f8bfa4e2Smk 	    letoh32(msg->rm_rid),
600f8bfa4e2Smk 	    letoh32(msg->rm_oid),
601f8bfa4e2Smk 	    letoh32(msg->rm_infobuflen),
602f8bfa4e2Smk 	    letoh32(msg->rm_infobufoffset),
603f8bfa4e2Smk 	    letoh32(msg->rm_devicevchdl)));
604f8bfa4e2Smk 
605f4b3fec4Skettenis 	rval = urndis_ctrl_send(sc, msg, sizeof(*msg) + len);
606c9ee9455Sderaadt 	free(msg, M_TEMP, sizeof *msg + len);
607f8bfa4e2Smk 
608f8bfa4e2Smk 	if (rval != RNDIS_STATUS_SUCCESS) {
609f8bfa4e2Smk 		printf("%s: set failed\n", DEVNAME(sc));
610f8bfa4e2Smk 		return rval;
611f8bfa4e2Smk 	}
612f8bfa4e2Smk 
613f8bfa4e2Smk 	if ((hdr = urndis_ctrl_recv(sc)) == NULL) {
614f8bfa4e2Smk 		printf("%s: unable to get set response\n", DEVNAME(sc));
615f8bfa4e2Smk 		return RNDIS_STATUS_FAILURE;
616f8bfa4e2Smk 	}
617f8bfa4e2Smk 	rval = urndis_ctrl_handle(sc, hdr, NULL, NULL);
618f8bfa4e2Smk 	if (rval != RNDIS_STATUS_SUCCESS)
619f8bfa4e2Smk 		printf("%s: set failed 0x%x\n", DEVNAME(sc), rval);
620f8bfa4e2Smk 
621f8bfa4e2Smk 	return rval;
622f8bfa4e2Smk }
623f8bfa4e2Smk 
624c951c319Smk u_int32_t
urndis_ctrl_set_param(struct urndis_softc * sc,const char * name,u_int32_t type,void * buf,size_t len)625bb30f7e7Smk urndis_ctrl_set_param(struct urndis_softc *sc,
626bb30f7e7Smk     const char *name,
627bb30f7e7Smk     u_int32_t type,
628bb30f7e7Smk     void *buf,
629bb30f7e7Smk     size_t len)
630f8bfa4e2Smk {
6317591b6e0Smikeb 	struct rndis_set_parameter	*param;
632c951c319Smk 	u_int32_t			 rval;
633f8bfa4e2Smk 	size_t				 namelen, tlen;
634f8bfa4e2Smk 
635f8bfa4e2Smk 	if (name)
636f8bfa4e2Smk 		namelen = strlen(name);
637f8bfa4e2Smk 	else
638f8bfa4e2Smk 		namelen = 0;
639f8bfa4e2Smk 	tlen = sizeof(*param) + len + namelen;
640d5bd7054Skevlo 	param = malloc(tlen, M_TEMP, M_WAITOK | M_CANFAIL);
641f8bfa4e2Smk 	if (param == NULL) {
642f8bfa4e2Smk 		printf("%s: out of memory\n", DEVNAME(sc));
643f8bfa4e2Smk 		return RNDIS_STATUS_FAILURE;
644f8bfa4e2Smk 	}
645f8bfa4e2Smk 
646f8bfa4e2Smk 	param->rm_namelen = htole32(namelen);
647f8bfa4e2Smk 	param->rm_valuelen = htole32(len);
648f8bfa4e2Smk 	param->rm_type = htole32(type);
649f8bfa4e2Smk 	if (namelen != 0) {
650f8bfa4e2Smk 		param->rm_nameoffset = htole32(20);
651f8bfa4e2Smk 		memcpy(param + 20, name, namelen);
652f8bfa4e2Smk 	} else
653f8bfa4e2Smk 		param->rm_nameoffset = 0;
654f8bfa4e2Smk 	if (len != 0) {
655f8bfa4e2Smk 		param->rm_valueoffset = htole32(20 + namelen);
656f8bfa4e2Smk 		memcpy(param + 20 + namelen, buf, len);
657f8bfa4e2Smk 	} else
658f8bfa4e2Smk 		param->rm_valueoffset = 0;
659f8bfa4e2Smk 
660f8bfa4e2Smk 	DPRINTF(("%s: urndis_ctrl_set_param send: nameoffset %u namelen %u "
661f8bfa4e2Smk 	    "type 0x%x valueoffset %u valuelen %u\n",
662f8bfa4e2Smk 	    DEVNAME(sc),
663f8bfa4e2Smk 	    letoh32(param->rm_nameoffset),
664f8bfa4e2Smk 	    letoh32(param->rm_namelen),
665f8bfa4e2Smk 	    letoh32(param->rm_type),
666f8bfa4e2Smk 	    letoh32(param->rm_valueoffset),
667f8bfa4e2Smk 	    letoh32(param->rm_valuelen)));
668f8bfa4e2Smk 
669f8bfa4e2Smk 	rval = urndis_ctrl_set(sc, OID_GEN_RNDIS_CONFIG_PARAMETER, param, tlen);
670c9ee9455Sderaadt 	free(param, M_TEMP, tlen);
671f8bfa4e2Smk 	if (rval != RNDIS_STATUS_SUCCESS)
672f8bfa4e2Smk 		printf("%s: set param failed 0x%x\n", DEVNAME(sc), rval);
673f8bfa4e2Smk 
674f8bfa4e2Smk 	return rval;
675f8bfa4e2Smk }
676f8bfa4e2Smk 
67761cec935Smk #if 0
678f8bfa4e2Smk /* XXX : adrreset, get it from response */
679c951c319Smk u_int32_t
680f8bfa4e2Smk urndis_ctrl_reset(struct urndis_softc *sc)
681f8bfa4e2Smk {
6827591b6e0Smikeb 	struct rndis_reset_req		*reset;
683c951c319Smk 	u_int32_t			 rval;
6847591b6e0Smikeb 	struct rndis_comp_hdr		*hdr;
685f8bfa4e2Smk 
686d5bd7054Skevlo 	reset = malloc(sizeof(*reset), M_TEMP, M_WAITOK | M_CANFAIL);
687f8bfa4e2Smk 	if (reset == NULL) {
688f8bfa4e2Smk 		printf("%s: out of memory\n", DEVNAME(sc));
689f8bfa4e2Smk 		return RNDIS_STATUS_FAILURE;
690f8bfa4e2Smk 	}
691f8bfa4e2Smk 
692f8bfa4e2Smk 	reset->rm_type = htole32(REMOTE_NDIS_RESET_MSG);
693f8bfa4e2Smk 	reset->rm_len = htole32(sizeof(*reset));
694f8bfa4e2Smk 	reset->rm_rid = 0; /* XXX rm_rid == reserved ... remove ? */
695f8bfa4e2Smk 
696f8bfa4e2Smk 	DPRINTF(("%s: urndis_ctrl_reset send: type %u len %u rid %u\n",
697f8bfa4e2Smk 	    DEVNAME(sc),
698f8bfa4e2Smk 	    letoh32(reset->rm_type),
699f8bfa4e2Smk 	    letoh32(reset->rm_len),
700f8bfa4e2Smk 	    letoh32(reset->rm_rid)));
701f8bfa4e2Smk 
702f8bfa4e2Smk 	rval = urndis_ctrl_send(sc, reset, sizeof(*reset));
703c9ee9455Sderaadt 	free(reset, M_TEMP, sizeof *reset);
704f8bfa4e2Smk 
705f8bfa4e2Smk 	if (rval != RNDIS_STATUS_SUCCESS) {
706f8bfa4e2Smk 		printf("%s: reset failed\n", DEVNAME(sc));
707f8bfa4e2Smk 		return rval;
708f8bfa4e2Smk 	}
709f8bfa4e2Smk 
710f8bfa4e2Smk 	if ((hdr = urndis_ctrl_recv(sc)) == NULL) {
711f8bfa4e2Smk 		printf("%s: unable to get reset response\n", DEVNAME(sc));
712f8bfa4e2Smk 		return RNDIS_STATUS_FAILURE;
713f8bfa4e2Smk 	}
714f8bfa4e2Smk 	rval = urndis_ctrl_handle(sc, hdr, NULL, NULL);
715f8bfa4e2Smk 
716f8bfa4e2Smk 	return rval;
717f8bfa4e2Smk }
718f8bfa4e2Smk 
719c951c319Smk u_int32_t
720f8bfa4e2Smk urndis_ctrl_keepalive(struct urndis_softc *sc)
721f8bfa4e2Smk {
7227591b6e0Smikeb 	struct rndis_keepalive_req	*keep;
723c951c319Smk 	u_int32_t			 rval;
7247591b6e0Smikeb 	struct rndis_comp_hdr		*hdr;
725f8bfa4e2Smk 
726d5bd7054Skevlo 	keep = malloc(sizeof(*keep), M_TEMP, M_WAITOK | M_CANFAIL);
727f8bfa4e2Smk 	if (keep == NULL) {
728f8bfa4e2Smk 		printf("%s: out of memory\n", DEVNAME(sc));
729f8bfa4e2Smk 		return RNDIS_STATUS_FAILURE;
730f8bfa4e2Smk 	}
731f8bfa4e2Smk 
732f8bfa4e2Smk 	keep->rm_type = htole32(REMOTE_NDIS_KEEPALIVE_MSG);
733f8bfa4e2Smk 	keep->rm_len = htole32(sizeof(*keep));
734f8bfa4e2Smk 	keep->rm_rid = 0; /* XXX rm_rid == reserved ... remove ? */
735f8bfa4e2Smk 
736bf0fd1bcSarmani 	DPRINTF(("%s: urndis_ctrl_keepalive: type %u len %u rid %u\n",
737f8bfa4e2Smk 	    DEVNAME(sc),
738f8bfa4e2Smk 	    letoh32(keep->rm_type),
739f8bfa4e2Smk 	    letoh32(keep->rm_len),
740f8bfa4e2Smk 	    letoh32(keep->rm_rid)));
741f8bfa4e2Smk 
742f8bfa4e2Smk 	rval = urndis_ctrl_send(sc, keep, sizeof(*keep));
743c9ee9455Sderaadt 	free(keep, M_TEMP, sizeof *keep);
744f8bfa4e2Smk 
745f8bfa4e2Smk 	if (rval != RNDIS_STATUS_SUCCESS) {
746f8bfa4e2Smk 		printf("%s: keepalive failed\n", DEVNAME(sc));
747f8bfa4e2Smk 		return rval;
748f8bfa4e2Smk 	}
749f8bfa4e2Smk 
750f8bfa4e2Smk 	if ((hdr = urndis_ctrl_recv(sc)) == NULL) {
751f8bfa4e2Smk 		printf("%s: unable to get keepalive response\n", DEVNAME(sc));
752f8bfa4e2Smk 		return RNDIS_STATUS_FAILURE;
753f8bfa4e2Smk 	}
754f8bfa4e2Smk 	rval = urndis_ctrl_handle(sc, hdr, NULL, NULL);
755f8bfa4e2Smk 	if (rval != RNDIS_STATUS_SUCCESS) {
756f8bfa4e2Smk 		printf("%s: keepalive failed 0x%x\n", DEVNAME(sc), rval);
757f8bfa4e2Smk 		urndis_ctrl_reset(sc);
758f8bfa4e2Smk 	}
759f8bfa4e2Smk 
760f8bfa4e2Smk 	return rval;
761f8bfa4e2Smk }
76261cec935Smk #endif
763f8bfa4e2Smk 
764f8bfa4e2Smk int
urndis_encap(struct urndis_softc * sc,struct mbuf * m,int idx)765f8bfa4e2Smk urndis_encap(struct urndis_softc *sc, struct mbuf *m, int idx)
766f8bfa4e2Smk {
767f8bfa4e2Smk 	struct urndis_chain		*c;
768f8bfa4e2Smk 	usbd_status			 err;
7697591b6e0Smikeb 	struct rndis_packet_msg		*msg;
770f8bfa4e2Smk 
771f8bfa4e2Smk 	c = &sc->sc_data.sc_tx_chain[idx];
772f8bfa4e2Smk 
7737591b6e0Smikeb 	msg = (struct rndis_packet_msg *)c->sc_buf;
774f8bfa4e2Smk 
775f8bfa4e2Smk 	memset(msg, 0, sizeof(*msg));
776f8bfa4e2Smk 	msg->rm_type = htole32(REMOTE_NDIS_PACKET_MSG);
777f8bfa4e2Smk 	msg->rm_len = htole32(sizeof(*msg) + m->m_pkthdr.len);
778f8bfa4e2Smk 
779ef710148Sarmani 	msg->rm_dataoffset = htole32(RNDIS_DATA_OFFSET);
780f8bfa4e2Smk 	msg->rm_datalen = htole32(m->m_pkthdr.len);
781f8bfa4e2Smk 
782f8bfa4e2Smk 	m_copydata(m, 0, m->m_pkthdr.len,
783ef710148Sarmani 	    ((char*)msg + RNDIS_DATA_OFFSET + RNDIS_HEADER_OFFSET));
784f8bfa4e2Smk 
785f8bfa4e2Smk 	DPRINTF(("%s: urndis_encap type 0x%x len %u data(off %u len %u)\n",
786f8bfa4e2Smk 	    DEVNAME(sc),
787f8bfa4e2Smk 	    letoh32(msg->rm_type),
788f8bfa4e2Smk 	    letoh32(msg->rm_len),
789f8bfa4e2Smk 	    letoh32(msg->rm_dataoffset),
790f8bfa4e2Smk 	    letoh32(msg->rm_datalen)));
791f8bfa4e2Smk 
792f8bfa4e2Smk 	c->sc_mbuf = m;
793f8bfa4e2Smk 
794f8bfa4e2Smk 	usbd_setup_xfer(c->sc_xfer, sc->sc_bulkout_pipe, c, c->sc_buf,
795f8bfa4e2Smk 	    letoh32(msg->rm_len), USBD_FORCE_SHORT_XFER | USBD_NO_COPY, 10000,
796f8bfa4e2Smk 	    urndis_txeof);
797f8bfa4e2Smk 
798f8bfa4e2Smk 	/* Transmit */
799f8bfa4e2Smk 	err = usbd_transfer(c->sc_xfer);
800f8bfa4e2Smk 	if (err != USBD_IN_PROGRESS) {
8014ced949bSgerhard 		c->sc_mbuf = NULL;
802f8bfa4e2Smk 		urndis_stop(sc);
803f8bfa4e2Smk 		return(EIO);
804f8bfa4e2Smk 	}
805f8bfa4e2Smk 
806f8bfa4e2Smk 	sc->sc_data.sc_tx_cnt++;
807f8bfa4e2Smk 
808f8bfa4e2Smk 	return(0);
809f8bfa4e2Smk }
810f8bfa4e2Smk 
811f8bfa4e2Smk void
urndis_decap(struct urndis_softc * sc,struct urndis_chain * c,u_int32_t len)8121a5c899fSmk urndis_decap(struct urndis_softc *sc, struct urndis_chain *c, u_int32_t len)
813f8bfa4e2Smk {
814f8bfa4e2Smk 	struct mbuf		*m;
815c7d77cdcSmpi 	struct mbuf_list	 ml = MBUF_LIST_INITIALIZER();
8167591b6e0Smikeb 	struct rndis_packet_msg	*msg;
817f8bfa4e2Smk 	struct ifnet		*ifp;
818f8bfa4e2Smk 	int			 s;
819f8bfa4e2Smk 	int			 offset;
820f8bfa4e2Smk 
821f8bfa4e2Smk 	ifp = GET_IFP(sc);
822f8bfa4e2Smk 	offset = 0;
823f8bfa4e2Smk 
824e842dab9Smpi 	while (len > 1) {
8257591b6e0Smikeb 		msg = (struct rndis_packet_msg *)((char*)c->sc_buf + offset);
826f8bfa4e2Smk 		m = c->sc_mbuf;
827f8bfa4e2Smk 
828f8bfa4e2Smk 		DPRINTF(("%s: urndis_decap buffer size left %u\n", DEVNAME(sc),
829a87747bfSmk 		    len));
830f8bfa4e2Smk 
831ec8516e5Sarmani 		if (len < sizeof(*msg)) {
832ec8516e5Sarmani 			printf("%s: urndis_decap invalid buffer len %u < "
8332b2fa8a9Ssf 			    "minimum header %zu\n",
834ec8516e5Sarmani 			    DEVNAME(sc),
835ec8516e5Sarmani 			    len,
836ec8516e5Sarmani 			    sizeof(*msg));
837e842dab9Smpi 			break;
838ec8516e5Sarmani 		}
839ec8516e5Sarmani 
840f8bfa4e2Smk 		DPRINTF(("%s: urndis_decap len %u data(off:%u len:%u) "
841f8bfa4e2Smk 		    "oobdata(off:%u len:%u nb:%u) perpacket(off:%u len:%u)\n",
842f8bfa4e2Smk 		    DEVNAME(sc),
843f8bfa4e2Smk 		    letoh32(msg->rm_len),
844f8bfa4e2Smk 		    letoh32(msg->rm_dataoffset),
845f8bfa4e2Smk 		    letoh32(msg->rm_datalen),
846f8bfa4e2Smk 		    letoh32(msg->rm_oobdataoffset),
847f8bfa4e2Smk 		    letoh32(msg->rm_oobdatalen),
848f8bfa4e2Smk 		    letoh32(msg->rm_oobdataelements),
849f8bfa4e2Smk 		    letoh32(msg->rm_pktinfooffset),
850f8bfa4e2Smk 		    letoh32(msg->rm_pktinfooffset)));
851f8bfa4e2Smk 
852f8bfa4e2Smk 		if (letoh32(msg->rm_type) != REMOTE_NDIS_PACKET_MSG) {
853f8bfa4e2Smk 			printf("%s: urndis_decap invalid type 0x%x != 0x%x\n",
854f8bfa4e2Smk 			    DEVNAME(sc),
855f8bfa4e2Smk 			    letoh32(msg->rm_type),
856f8bfa4e2Smk 			    REMOTE_NDIS_PACKET_MSG);
857e842dab9Smpi 			break;
858f8bfa4e2Smk 		}
859f8bfa4e2Smk 		if (letoh32(msg->rm_len) < sizeof(*msg)) {
8602b2fa8a9Ssf 			printf("%s: urndis_decap invalid msg len %u < %zu\n",
861f8bfa4e2Smk 			    DEVNAME(sc),
862f8bfa4e2Smk 			    letoh32(msg->rm_len),
863f8bfa4e2Smk 			    sizeof(*msg));
864e842dab9Smpi 			break;
865f8bfa4e2Smk 		}
866f8bfa4e2Smk 		if (letoh32(msg->rm_len) > len) {
867f8bfa4e2Smk 			printf("%s: urndis_decap invalid msg len %u > buffer "
868f8bfa4e2Smk 			    "len %u\n",
869f8bfa4e2Smk 			    DEVNAME(sc),
870f8bfa4e2Smk 			    letoh32(msg->rm_len),
871f8bfa4e2Smk 			    len);
872e842dab9Smpi 			break;
873f8bfa4e2Smk 		}
874ef710148Sarmani 
875f8bfa4e2Smk 		if (letoh32(msg->rm_dataoffset) +
876ef710148Sarmani 		    letoh32(msg->rm_datalen) + RNDIS_HEADER_OFFSET
877ef710148Sarmani 			> letoh32(msg->rm_len)) {
878f8bfa4e2Smk 			printf("%s: urndis_decap invalid data "
8792b2fa8a9Ssf 			    "len/offset/end_position(%u/%u/%zu) -> "
880f8bfa4e2Smk 			    "go out of receive buffer limit %u\n",
881f8bfa4e2Smk 			    DEVNAME(sc),
882f8bfa4e2Smk 			    letoh32(msg->rm_datalen),
883f8bfa4e2Smk 			    letoh32(msg->rm_dataoffset),
884f8bfa4e2Smk 			    letoh32(msg->rm_dataoffset) +
885ef710148Sarmani 			    letoh32(msg->rm_datalen) + RNDIS_HEADER_OFFSET,
886f8bfa4e2Smk 			    letoh32(msg->rm_len));
887e842dab9Smpi 			break;
888f8bfa4e2Smk 		}
889f8bfa4e2Smk 
8902ebf542fSmk 		if (letoh32(msg->rm_datalen) < sizeof(struct ether_header)) {
8912ebf542fSmk 			ifp->if_ierrors++;
892552902b1Sstsp 			DPRINTF(("%s: urndis_decap invalid ethernet size "
8932b2fa8a9Ssf 			    "%u < %zu\n",
8942ebf542fSmk 			    DEVNAME(sc),
8952ebf542fSmk 			    letoh32(msg->rm_datalen),
896552902b1Sstsp 			    sizeof(struct ether_header)));
897e842dab9Smpi 			break;
8982ebf542fSmk 		}
8992ebf542fSmk 
900f8bfa4e2Smk 		memcpy(mtod(m, char*),
901f8bfa4e2Smk 		    ((char*)&msg->rm_dataoffset + letoh32(msg->rm_dataoffset)),
902f8bfa4e2Smk 		    letoh32(msg->rm_datalen));
903f8bfa4e2Smk 		m->m_pkthdr.len = m->m_len = letoh32(msg->rm_datalen);
904f8bfa4e2Smk 
90554384797Smk 		if (urndis_newbuf(sc, c) == ENOBUFS) {
906f8bfa4e2Smk 			ifp->if_ierrors++;
907f8bfa4e2Smk 		} else {
908c7d77cdcSmpi 			ml_enqueue(&ml, m);
909f8bfa4e2Smk 		}
910f8bfa4e2Smk 
911f8bfa4e2Smk 		offset += letoh32(msg->rm_len);
912f8bfa4e2Smk 		len -= letoh32(msg->rm_len);
913f8bfa4e2Smk 	}
914e842dab9Smpi 	if (ml_empty(&ml))
915e842dab9Smpi 		return;
916c7d77cdcSmpi 
917c7d77cdcSmpi 	s = splnet();
918c7d77cdcSmpi 	if_input(ifp, &ml);
919c7d77cdcSmpi 	splx(s);
920f8bfa4e2Smk }
921f8bfa4e2Smk 
922f8bfa4e2Smk int
urndis_newbuf(struct urndis_softc * sc,struct urndis_chain * c)92354384797Smk urndis_newbuf(struct urndis_softc *sc, struct urndis_chain *c)
924f8bfa4e2Smk {
925f8bfa4e2Smk 	struct mbuf *m_new = NULL;
926f8bfa4e2Smk 
927f8bfa4e2Smk 	MGETHDR(m_new, M_DONTWAIT, MT_DATA);
928f8bfa4e2Smk 	if (m_new == NULL) {
92954384797Smk 		printf("%s: no memory for rx list -- packet dropped!\n",
930f8bfa4e2Smk 		    DEVNAME(sc));
931f8bfa4e2Smk 		return (ENOBUFS);
932f8bfa4e2Smk 	}
933f8bfa4e2Smk 	MCLGET(m_new, M_DONTWAIT);
934f8bfa4e2Smk 	if (!(m_new->m_flags & M_EXT)) {
93554384797Smk 		printf("%s: no memory for rx list -- packet dropped!\n",
936f8bfa4e2Smk 		    DEVNAME(sc));
937f8bfa4e2Smk 		m_freem(m_new);
938f8bfa4e2Smk 		return (ENOBUFS);
939f8bfa4e2Smk 	}
940f8bfa4e2Smk 	m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
941f8bfa4e2Smk 
942f8bfa4e2Smk 	m_adj(m_new, ETHER_ALIGN);
943f8bfa4e2Smk 	c->sc_mbuf = m_new;
944f8bfa4e2Smk 	return (0);
945f8bfa4e2Smk }
946f8bfa4e2Smk 
947f8bfa4e2Smk int
urndis_rx_list_init(struct urndis_softc * sc)948f8bfa4e2Smk urndis_rx_list_init(struct urndis_softc *sc)
949f8bfa4e2Smk {
950f8bfa4e2Smk 	struct urndis_cdata	*cd;
951f8bfa4e2Smk 	struct urndis_chain	*c;
952f8bfa4e2Smk 	int			 i;
953f8bfa4e2Smk 
954f8bfa4e2Smk 	cd = &sc->sc_data;
955f8bfa4e2Smk 	for (i = 0; i < RNDIS_RX_LIST_CNT; i++) {
956f8bfa4e2Smk 		c = &cd->sc_rx_chain[i];
9570497a875Smk 		c->sc_softc = sc;
958f8bfa4e2Smk 		c->sc_idx = i;
959f8bfa4e2Smk 
96054384797Smk 		if (urndis_newbuf(sc, c) == ENOBUFS)
961f8bfa4e2Smk 			return (ENOBUFS);
962f8bfa4e2Smk 
963f8bfa4e2Smk 		if (c->sc_xfer == NULL) {
964f8bfa4e2Smk 			c->sc_xfer = usbd_alloc_xfer(sc->sc_udev);
965f8bfa4e2Smk 			if (c->sc_xfer == NULL)
966f8bfa4e2Smk 				return (ENOBUFS);
967f8bfa4e2Smk 			c->sc_buf = usbd_alloc_buffer(c->sc_xfer,
968f8bfa4e2Smk 			    RNDIS_BUFSZ);
969f8bfa4e2Smk 			if (c->sc_buf == NULL)
970f8bfa4e2Smk 				return (ENOBUFS);
971f8bfa4e2Smk 		}
972f8bfa4e2Smk 	}
973f8bfa4e2Smk 
974f8bfa4e2Smk 	return (0);
975f8bfa4e2Smk }
976f8bfa4e2Smk 
977f8bfa4e2Smk int
urndis_tx_list_init(struct urndis_softc * sc)978f8bfa4e2Smk urndis_tx_list_init(struct urndis_softc *sc)
979f8bfa4e2Smk {
980f8bfa4e2Smk 	struct urndis_cdata	*cd;
981f8bfa4e2Smk 	struct urndis_chain	*c;
982f8bfa4e2Smk 	int			 i;
983f8bfa4e2Smk 
984f8bfa4e2Smk 	cd = &sc->sc_data;
985f8bfa4e2Smk 	for (i = 0; i < RNDIS_TX_LIST_CNT; i++) {
986f8bfa4e2Smk 		c = &cd->sc_tx_chain[i];
9870497a875Smk 		c->sc_softc = sc;
988f8bfa4e2Smk 		c->sc_idx = i;
989f8bfa4e2Smk 		c->sc_mbuf = NULL;
990f8bfa4e2Smk 		if (c->sc_xfer == NULL) {
991f8bfa4e2Smk 			c->sc_xfer = usbd_alloc_xfer(sc->sc_udev);
992f8bfa4e2Smk 			if (c->sc_xfer == NULL)
993f8bfa4e2Smk 				return (ENOBUFS);
994f8bfa4e2Smk 			c->sc_buf = usbd_alloc_buffer(c->sc_xfer,
995f8bfa4e2Smk 			    RNDIS_BUFSZ);
996f8bfa4e2Smk 			if (c->sc_buf == NULL)
997f8bfa4e2Smk 				return (ENOBUFS);
998f8bfa4e2Smk 		}
999f8bfa4e2Smk 	}
1000f8bfa4e2Smk 	return (0);
1001f8bfa4e2Smk }
1002f8bfa4e2Smk 
1003f8bfa4e2Smk int
urndis_ioctl(struct ifnet * ifp,u_long command,caddr_t data)1004f8bfa4e2Smk urndis_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
1005f8bfa4e2Smk {
1006c6ba154eSbrad 	struct urndis_softc	*sc = ifp->if_softc;
1007c6ba154eSbrad 	int			 s, error = 0;
1008f8bfa4e2Smk 
10090a7d4bd2Spirofti 	if (usbd_is_dying(sc->sc_udev))
1010947e4cccSstsp 		return ENXIO;
1011f8bfa4e2Smk 
1012f8bfa4e2Smk 	s = splnet();
1013f8bfa4e2Smk 
1014f8bfa4e2Smk 	switch(command) {
1015f8bfa4e2Smk 	case SIOCSIFADDR:
1016f8bfa4e2Smk 		ifp->if_flags |= IFF_UP;
1017c6ba154eSbrad 		if (!(ifp->if_flags & IFF_RUNNING))
1018f8bfa4e2Smk 			urndis_init(sc);
1019f8bfa4e2Smk 		break;
1020f8bfa4e2Smk 
1021f8bfa4e2Smk 	case SIOCSIFFLAGS:
1022f8bfa4e2Smk 		if (ifp->if_flags & IFF_UP) {
1023c6ba154eSbrad 			if (ifp->if_flags & IFF_RUNNING)
1024c6ba154eSbrad 				error = ENETRESET;
1025c6ba154eSbrad 			else
1026f8bfa4e2Smk 				urndis_init(sc);
1027f8bfa4e2Smk 		} else {
1028f8bfa4e2Smk 			if (ifp->if_flags & IFF_RUNNING)
1029f8bfa4e2Smk 				urndis_stop(sc);
1030f8bfa4e2Smk 		}
1031f8bfa4e2Smk 		break;
1032f8bfa4e2Smk 
1033f8bfa4e2Smk 	default:
1034f8bfa4e2Smk 		error = ether_ioctl(ifp, &sc->sc_arpcom, command, data);
1035f8bfa4e2Smk 		break;
1036f8bfa4e2Smk 	}
1037f8bfa4e2Smk 
1038f8bfa4e2Smk 	if (error == ENETRESET)
1039f8bfa4e2Smk 		error = 0;
1040f8bfa4e2Smk 
1041f8bfa4e2Smk 	splx(s);
1042f8bfa4e2Smk 	return (error);
1043f8bfa4e2Smk }
1044f8bfa4e2Smk 
104561cec935Smk #if 0
1046f8bfa4e2Smk void
1047f8bfa4e2Smk urndis_watchdog(struct ifnet *ifp)
1048f8bfa4e2Smk {
1049f8bfa4e2Smk 	struct urndis_softc *sc;
1050f8bfa4e2Smk 
1051f8bfa4e2Smk 	sc = ifp->if_softc;
1052f8bfa4e2Smk 
10530a7d4bd2Spirofti 	if (usbd_is_dying(sc->sc_udev))
1054f8bfa4e2Smk 		return;
1055f8bfa4e2Smk 
1056f8bfa4e2Smk 	ifp->if_oerrors++;
1057f8bfa4e2Smk 	printf("%s: watchdog timeout\n", DEVNAME(sc));
1058f8bfa4e2Smk 
1059f8bfa4e2Smk 	urndis_ctrl_keepalive(sc);
1060f8bfa4e2Smk }
106161cec935Smk #endif
1062f8bfa4e2Smk 
1063f8bfa4e2Smk void
urndis_init(struct urndis_softc * sc)1064f8bfa4e2Smk urndis_init(struct urndis_softc *sc)
1065f8bfa4e2Smk {
1066c6ba154eSbrad 	struct ifnet		*ifp = GET_IFP(sc);
1067f8bfa4e2Smk 	int			 i, s;
1068f8bfa4e2Smk 	usbd_status		 err;
1069f8bfa4e2Smk 
1070f8bfa4e2Smk 	if (urndis_ctrl_init(sc) != RNDIS_STATUS_SUCCESS)
1071f8bfa4e2Smk 		return;
1072f8bfa4e2Smk 
1073f8bfa4e2Smk 	s = splnet();
1074f8bfa4e2Smk 
1075f8bfa4e2Smk 	if (urndis_tx_list_init(sc) == ENOBUFS) {
1076f8bfa4e2Smk 		printf("%s: tx list init failed\n",
1077f8bfa4e2Smk 		    DEVNAME(sc));
1078f8bfa4e2Smk 		splx(s);
1079f8bfa4e2Smk 		return;
1080f8bfa4e2Smk 	}
1081f8bfa4e2Smk 
1082f8bfa4e2Smk 	if (urndis_rx_list_init(sc) == ENOBUFS) {
1083f8bfa4e2Smk 		printf("%s: rx list init failed\n",
1084f8bfa4e2Smk 		    DEVNAME(sc));
1085f8bfa4e2Smk 		splx(s);
1086f8bfa4e2Smk 		return;
1087f8bfa4e2Smk 	}
1088f8bfa4e2Smk 
1089f8bfa4e2Smk 	err = usbd_open_pipe(sc->sc_iface_data, sc->sc_bulkin_no,
1090f8bfa4e2Smk 	    USBD_EXCLUSIVE_USE, &sc->sc_bulkin_pipe);
1091f8bfa4e2Smk 	if (err) {
1092f8bfa4e2Smk 		printf("%s: open rx pipe failed: %s\n", DEVNAME(sc),
1093f8bfa4e2Smk 		    usbd_errstr(err));
1094f8bfa4e2Smk 		splx(s);
1095f8bfa4e2Smk 		return;
1096f8bfa4e2Smk 	}
1097f8bfa4e2Smk 
1098f8bfa4e2Smk 	err = usbd_open_pipe(sc->sc_iface_data, sc->sc_bulkout_no,
1099f8bfa4e2Smk 	    USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
1100f8bfa4e2Smk 	if (err) {
1101f8bfa4e2Smk 		printf("%s: open tx pipe failed: %s\n", DEVNAME(sc),
1102f8bfa4e2Smk 		    usbd_errstr(err));
1103f8bfa4e2Smk 		splx(s);
1104f8bfa4e2Smk 		return;
1105f8bfa4e2Smk 	}
1106f8bfa4e2Smk 
1107f8bfa4e2Smk 	for (i = 0; i < RNDIS_RX_LIST_CNT; i++) {
1108f8bfa4e2Smk 		struct urndis_chain *c;
1109f8bfa4e2Smk 
1110f8bfa4e2Smk 		c = &sc->sc_data.sc_rx_chain[i];
1111f8bfa4e2Smk 		usbd_setup_xfer(c->sc_xfer, sc->sc_bulkin_pipe, c,
1112f8bfa4e2Smk 		    c->sc_buf, RNDIS_BUFSZ,
1113f8bfa4e2Smk 		    USBD_SHORT_XFER_OK | USBD_NO_COPY,
1114f8bfa4e2Smk 		    USBD_NO_TIMEOUT, urndis_rxeof);
1115f8bfa4e2Smk 		usbd_transfer(c->sc_xfer);
1116f8bfa4e2Smk 	}
1117f8bfa4e2Smk 
1118f8bfa4e2Smk 	ifp->if_flags |= IFF_RUNNING;
1119de6cd8fbSdlg 	ifq_clr_oactive(&ifp->if_snd);
1120f8bfa4e2Smk 
1121f8bfa4e2Smk 	splx(s);
1122f8bfa4e2Smk }
1123f8bfa4e2Smk 
1124f8bfa4e2Smk void
urndis_stop(struct urndis_softc * sc)1125f8bfa4e2Smk urndis_stop(struct urndis_softc *sc)
1126f8bfa4e2Smk {
1127f8bfa4e2Smk 	usbd_status	 err;
1128f8bfa4e2Smk 	struct ifnet	*ifp;
1129f8bfa4e2Smk 	int		 i;
1130f8bfa4e2Smk 
1131f8bfa4e2Smk 	ifp = GET_IFP(sc);
1132f8bfa4e2Smk 	ifp->if_timer = 0;
1133de6cd8fbSdlg 	ifp->if_flags &= ~IFF_RUNNING;
1134de6cd8fbSdlg 	ifq_clr_oactive(&ifp->if_snd);
1135f8bfa4e2Smk 
1136f8bfa4e2Smk 	if (sc->sc_bulkin_pipe != NULL) {
1137f8bfa4e2Smk 		err = usbd_close_pipe(sc->sc_bulkin_pipe);
1138f8bfa4e2Smk 		if (err)
1139f8bfa4e2Smk 			printf("%s: close rx pipe failed: %s\n",
1140f8bfa4e2Smk 			    DEVNAME(sc), usbd_errstr(err));
1141f8bfa4e2Smk 		sc->sc_bulkin_pipe = NULL;
1142f8bfa4e2Smk 	}
1143f8bfa4e2Smk 
1144f8bfa4e2Smk 	if (sc->sc_bulkout_pipe != NULL) {
1145f8bfa4e2Smk 		err = usbd_close_pipe(sc->sc_bulkout_pipe);
1146f8bfa4e2Smk 		if (err)
1147f8bfa4e2Smk 			printf("%s: close tx pipe failed: %s\n",
1148f8bfa4e2Smk 			    DEVNAME(sc), usbd_errstr(err));
1149f8bfa4e2Smk 		sc->sc_bulkout_pipe = NULL;
1150f8bfa4e2Smk 	}
1151f8bfa4e2Smk 
1152f8bfa4e2Smk 	for (i = 0; i < RNDIS_RX_LIST_CNT; i++) {
1153f8bfa4e2Smk 		if (sc->sc_data.sc_rx_chain[i].sc_mbuf != NULL) {
1154f8bfa4e2Smk 			m_freem(sc->sc_data.sc_rx_chain[i].sc_mbuf);
1155f8bfa4e2Smk 			sc->sc_data.sc_rx_chain[i].sc_mbuf = NULL;
1156f8bfa4e2Smk 		}
1157f8bfa4e2Smk 		if (sc->sc_data.sc_rx_chain[i].sc_xfer != NULL) {
1158f8bfa4e2Smk 			usbd_free_xfer(sc->sc_data.sc_rx_chain[i].sc_xfer);
1159f8bfa4e2Smk 			sc->sc_data.sc_rx_chain[i].sc_xfer = NULL;
1160f8bfa4e2Smk 		}
1161f8bfa4e2Smk 	}
1162f8bfa4e2Smk 
1163f8bfa4e2Smk 	for (i = 0; i < RNDIS_TX_LIST_CNT; i++) {
1164f8bfa4e2Smk 		if (sc->sc_data.sc_tx_chain[i].sc_mbuf != NULL) {
1165f8bfa4e2Smk 			m_freem(sc->sc_data.sc_tx_chain[i].sc_mbuf);
1166f8bfa4e2Smk 			sc->sc_data.sc_tx_chain[i].sc_mbuf = NULL;
1167f8bfa4e2Smk 		}
1168f8bfa4e2Smk 		if (sc->sc_data.sc_tx_chain[i].sc_xfer != NULL) {
1169f8bfa4e2Smk 			usbd_free_xfer(sc->sc_data.sc_tx_chain[i].sc_xfer);
1170f8bfa4e2Smk 			sc->sc_data.sc_tx_chain[i].sc_xfer = NULL;
1171f8bfa4e2Smk 		}
1172f8bfa4e2Smk 	}
1173f8bfa4e2Smk }
1174f8bfa4e2Smk 
1175f8bfa4e2Smk void
urndis_start(struct ifnet * ifp)1176f8bfa4e2Smk urndis_start(struct ifnet *ifp)
1177f8bfa4e2Smk {
1178f8bfa4e2Smk 	struct urndis_softc	*sc;
1179f8bfa4e2Smk 	struct mbuf		*m_head = NULL;
1180f8bfa4e2Smk 
1181f8bfa4e2Smk 	sc = ifp->if_softc;
1182f8bfa4e2Smk 
1183de6cd8fbSdlg 	if (usbd_is_dying(sc->sc_udev) || ifq_is_oactive(&ifp->if_snd))
1184f8bfa4e2Smk 		return;
1185f8bfa4e2Smk 
11864ced949bSgerhard 	m_head = ifq_dequeue(&ifp->if_snd);
1187f8bfa4e2Smk 	if (m_head == NULL)
1188f8bfa4e2Smk 		return;
1189f8bfa4e2Smk 
1190f8bfa4e2Smk 	if (urndis_encap(sc, m_head, 0)) {
11914ced949bSgerhard 		m_freem(m_head);
1192de6cd8fbSdlg 		ifq_set_oactive(&ifp->if_snd);
1193f8bfa4e2Smk 		return;
1194f8bfa4e2Smk 	}
1195f8bfa4e2Smk 
1196f8bfa4e2Smk 	/*
1197f8bfa4e2Smk 	 * If there's a BPF listener, bounce a copy of this frame
1198f8bfa4e2Smk 	 * to him.
1199f8bfa4e2Smk 	 */
1200f8bfa4e2Smk #if NBPFILTER > 0
1201f8bfa4e2Smk 	if (ifp->if_bpf)
1202f8bfa4e2Smk 		bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
1203f8bfa4e2Smk #endif
1204f8bfa4e2Smk 
1205de6cd8fbSdlg 	ifq_set_oactive(&ifp->if_snd);
1206f8bfa4e2Smk 
1207f8bfa4e2Smk 	/*
1208f8bfa4e2Smk 	 * Set a timeout in case the chip goes out to lunch.
1209f8bfa4e2Smk 	 */
1210f8bfa4e2Smk 	ifp->if_timer = 5;
1211f8bfa4e2Smk 
1212f8bfa4e2Smk 	return;
1213f8bfa4e2Smk }
1214f8bfa4e2Smk 
1215f8bfa4e2Smk void
urndis_rxeof(struct usbd_xfer * xfer,void * priv,usbd_status status)1216ab0b1be7Smglocker urndis_rxeof(struct usbd_xfer *xfer,
1217ab0b1be7Smglocker     void *priv,
1218bb30f7e7Smk     usbd_status status)
1219f8bfa4e2Smk {
1220f8bfa4e2Smk 	struct urndis_chain	*c;
1221f8bfa4e2Smk 	struct urndis_softc	*sc;
1222f8bfa4e2Smk 	struct ifnet		*ifp;
12231a5c899fSmk 	u_int32_t		 total_len;
1224f8bfa4e2Smk 
1225f8bfa4e2Smk 	c = priv;
12260497a875Smk 	sc = c->sc_softc;
1227f8bfa4e2Smk 	ifp = GET_IFP(sc);
1228f8bfa4e2Smk 	total_len = 0;
1229f8bfa4e2Smk 
12300a7d4bd2Spirofti 	if (usbd_is_dying(sc->sc_udev) || !(ifp->if_flags & IFF_RUNNING))
1231f8bfa4e2Smk 		return;
1232f8bfa4e2Smk 
1233f8bfa4e2Smk 	if (status != USBD_NORMAL_COMPLETION) {
1234f8bfa4e2Smk 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
1235f8bfa4e2Smk 			return;
1236a87747bfSmk 		if (usbd_ratecheck(&sc->sc_rx_notice)) {
1237552902b1Sstsp 			DPRINTF(("%s: usb errors on rx: %s\n",
1238552902b1Sstsp 			    DEVNAME(sc), usbd_errstr(status)));
1239a87747bfSmk 		}
1240f8bfa4e2Smk 		if (status == USBD_STALLED)
1241f8bfa4e2Smk 			usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
1242f8bfa4e2Smk 
1243552902b1Sstsp 		ifp->if_ierrors++;
1244f8bfa4e2Smk 		goto done;
1245f8bfa4e2Smk 	}
1246f8bfa4e2Smk 
12471a5c899fSmk 	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
1248f8bfa4e2Smk 	urndis_decap(sc, c, total_len);
1249f8bfa4e2Smk 
1250f8bfa4e2Smk done:
1251f8bfa4e2Smk 	/* Setup new transfer. */
1252f8bfa4e2Smk 	usbd_setup_xfer(c->sc_xfer, sc->sc_bulkin_pipe, c, c->sc_buf,
1253f8bfa4e2Smk 	    RNDIS_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
1254f8bfa4e2Smk 	    urndis_rxeof);
1255f8bfa4e2Smk 	usbd_transfer(c->sc_xfer);
1256f8bfa4e2Smk }
1257f8bfa4e2Smk 
1258f8bfa4e2Smk void
urndis_txeof(struct usbd_xfer * xfer,void * priv,usbd_status status)1259ab0b1be7Smglocker urndis_txeof(struct usbd_xfer *xfer,
1260ab0b1be7Smglocker     void *priv,
1261bb30f7e7Smk     usbd_status status)
1262f8bfa4e2Smk {
1263f8bfa4e2Smk 	struct urndis_chain	*c;
1264f8bfa4e2Smk 	struct urndis_softc	*sc;
1265f8bfa4e2Smk 	struct ifnet		*ifp;
1266f8bfa4e2Smk 	usbd_status		 err;
1267f8bfa4e2Smk 	int			 s;
1268f8bfa4e2Smk 
1269f8bfa4e2Smk 	c = priv;
12700497a875Smk 	sc = c->sc_softc;
1271f8bfa4e2Smk 	ifp = GET_IFP(sc);
1272f8bfa4e2Smk 
1273f8bfa4e2Smk 	DPRINTF(("%s: urndis_txeof\n", DEVNAME(sc)));
1274f8bfa4e2Smk 
12750a7d4bd2Spirofti 	if (usbd_is_dying(sc->sc_udev))
1276f8bfa4e2Smk 		return;
1277f8bfa4e2Smk 
1278f8bfa4e2Smk 	s = splnet();
1279f8bfa4e2Smk 
1280f8bfa4e2Smk 	ifp->if_timer = 0;
1281de6cd8fbSdlg 	ifq_clr_oactive(&ifp->if_snd);
1282f8bfa4e2Smk 
1283f8bfa4e2Smk 	if (status != USBD_NORMAL_COMPLETION) {
1284f8bfa4e2Smk 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
1285f8bfa4e2Smk 			splx(s);
1286f8bfa4e2Smk 			return;
1287f8bfa4e2Smk 		}
1288f8bfa4e2Smk 		ifp->if_oerrors++;
1289552902b1Sstsp 		DPRINTF(("%s: usb error on tx: %s\n", DEVNAME(sc),
1290552902b1Sstsp 		    usbd_errstr(status)));
1291f8bfa4e2Smk 		if (status == USBD_STALLED)
1292f8bfa4e2Smk 			usbd_clear_endpoint_stall_async(sc->sc_bulkout_pipe);
1293f8bfa4e2Smk 		splx(s);
1294f8bfa4e2Smk 		return;
1295f8bfa4e2Smk 	}
1296f8bfa4e2Smk 
1297f8bfa4e2Smk 	usbd_get_xfer_status(c->sc_xfer, NULL, NULL, NULL, &err);
1298f8bfa4e2Smk 
1299f8bfa4e2Smk 	if (c->sc_mbuf != NULL) {
1300f8bfa4e2Smk 		m_freem(c->sc_mbuf);
1301f8bfa4e2Smk 		c->sc_mbuf = NULL;
1302f8bfa4e2Smk 	}
1303f8bfa4e2Smk 
1304f8bfa4e2Smk 	if (err)
1305f8bfa4e2Smk 		ifp->if_oerrors++;
1306f8bfa4e2Smk 
13070cae21bdSpatrick 	if (ifq_empty(&ifp->if_snd) == 0)
1308f8bfa4e2Smk 		urndis_start(ifp);
1309f8bfa4e2Smk 
1310f8bfa4e2Smk 	splx(s);
1311f8bfa4e2Smk }
1312f8bfa4e2Smk 
131396761c40Sfgsch const struct urndis_class *
urndis_lookup(usb_interface_descriptor_t * id)131496761c40Sfgsch urndis_lookup(usb_interface_descriptor_t *id)
131596761c40Sfgsch {
131696761c40Sfgsch 	const struct urndis_class	*uc;
131796761c40Sfgsch 	int				 i;
131896761c40Sfgsch 
131996761c40Sfgsch 	uc = urndis_class;
132096761c40Sfgsch 	for (i = 0; i < nitems(urndis_class); i++, uc++) {
132196761c40Sfgsch 		if (uc->class == id->bInterfaceClass &&
132296761c40Sfgsch 		    uc->subclass == id->bInterfaceSubClass &&
132396761c40Sfgsch 		    uc->protocol == id->bInterfaceProtocol)
132496761c40Sfgsch 			return (uc);
132596761c40Sfgsch 	}
132696761c40Sfgsch 	return (NULL);
132796761c40Sfgsch }
132896761c40Sfgsch 
1329f8bfa4e2Smk int
urndis_match(struct device * parent,void * match,void * aux)1330f8bfa4e2Smk urndis_match(struct device *parent, void *match, void *aux)
1331f8bfa4e2Smk {
13323cb5b729Skettenis 	struct usb_attach_arg		*uaa = aux;
1333f8bfa4e2Smk 	usb_interface_descriptor_t	*id;
1334f8bfa4e2Smk 
13353cb5b729Skettenis 	/* Advertises both RNDIS and CDC Ethernet, but RNDIS doesn't work. */
13363cb5b729Skettenis 	if (uaa->vendor == USB_VENDOR_FUJITSUCOMP &&
13373cb5b729Skettenis 	    uaa->product == USB_PRODUCT_FUJITSUCOMP_VIRTETH)
13383cb5b729Skettenis 		return (UMATCH_NONE);
1339f8bfa4e2Smk 
1340f8bfa4e2Smk 	if (!uaa->iface)
1341f8bfa4e2Smk 		return (UMATCH_NONE);
1342f8bfa4e2Smk 
1343f8bfa4e2Smk 	id = usbd_get_interface_descriptor(uaa->iface);
1344f8bfa4e2Smk 	if (id == NULL)
1345f8bfa4e2Smk 		return (UMATCH_NONE);
1346f8bfa4e2Smk 
134796761c40Sfgsch 	return (urndis_lookup(id) ?
134896761c40Sfgsch 	    UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO : UMATCH_NONE);
1349f8bfa4e2Smk }
1350f8bfa4e2Smk 
1351f8bfa4e2Smk void
urndis_attach(struct device * parent,struct device * self,void * aux)1352f8bfa4e2Smk urndis_attach(struct device *parent, struct device *self, void *aux)
1353f8bfa4e2Smk {
135496761c40Sfgsch 	const struct urndis_class	*uc;
1355f8bfa4e2Smk 	struct urndis_softc		*sc;
1356f8bfa4e2Smk 	struct usb_attach_arg		*uaa;
1357f8bfa4e2Smk 	struct ifnet			*ifp;
1358f8bfa4e2Smk 	usb_interface_descriptor_t	*id;
1359f8bfa4e2Smk 	usb_endpoint_descriptor_t	*ed;
1360f8bfa4e2Smk 	usb_config_descriptor_t		*cd;
1361f8bfa4e2Smk 	int				 i, j, altcnt;
1362f8bfa4e2Smk 	int				 s;
1363f8bfa4e2Smk 	u_char				 eaddr[ETHER_ADDR_LEN];
1364f8bfa4e2Smk 	void				*buf;
1365f8bfa4e2Smk 	size_t				 bufsz;
1366f8bfa4e2Smk 	u_int32_t			 filter;
1367f8bfa4e2Smk 
1368f8bfa4e2Smk 	sc = (void *)self;
1369f8bfa4e2Smk 	uaa = aux;
1370f8bfa4e2Smk 
13719140db79Spirofti 	sc->sc_attached = 0;
1372f8bfa4e2Smk 	sc->sc_udev = uaa->device;
1373003f6321Sfgsch 	id = usbd_get_interface_descriptor(uaa->iface);
1374003f6321Sfgsch 	sc->sc_ifaceno_ctl = id->bInterfaceNumber;
1375f8bfa4e2Smk 
1376f8bfa4e2Smk 	for (i = 0; i < uaa->nifaces; i++) {
1377438d9437Sjakemsr 		if (usbd_iface_claimed(sc->sc_udev, i))
1378f8bfa4e2Smk 			continue;
1379003f6321Sfgsch 
1380003f6321Sfgsch 		if (uaa->ifaces[i] != uaa->iface) {
1381f8bfa4e2Smk 			sc->sc_iface_data = uaa->ifaces[i];
1382438d9437Sjakemsr 			usbd_claim_iface(sc->sc_udev, i);
1383003f6321Sfgsch 			break;
1384f8bfa4e2Smk 		}
1385f8bfa4e2Smk 	}
1386f8bfa4e2Smk 
1387f8bfa4e2Smk 	if (sc->sc_iface_data == NULL) {
1388f8bfa4e2Smk 		printf("%s: no data interface\n", DEVNAME(sc));
1389f8bfa4e2Smk 		return;
1390f8bfa4e2Smk 	}
1391f8bfa4e2Smk 
139296761c40Sfgsch 	uc = urndis_lookup(id);
139396761c40Sfgsch 	printf("%s: using %s", DEVNAME(sc), uc->typestr);
139496761c40Sfgsch 
1395f8bfa4e2Smk 	id = usbd_get_interface_descriptor(sc->sc_iface_data);
1396f8bfa4e2Smk 	cd = usbd_get_config_descriptor(sc->sc_udev);
1397f8bfa4e2Smk 	altcnt = usbd_get_no_alts(cd, id->bInterfaceNumber);
1398f8bfa4e2Smk 
1399f8bfa4e2Smk 	for (j = 0; j < altcnt; j++) {
1400f8bfa4e2Smk 		if (usbd_set_interface(sc->sc_iface_data, j)) {
140196761c40Sfgsch 			printf(": interface alternate setting %u failed\n", j);
1402f8bfa4e2Smk 			return;
1403f8bfa4e2Smk 		}
1404f8bfa4e2Smk 		/* Find endpoints. */
1405f8bfa4e2Smk 		id = usbd_get_interface_descriptor(sc->sc_iface_data);
1406f8bfa4e2Smk 		sc->sc_bulkin_no = sc->sc_bulkout_no = -1;
1407f8bfa4e2Smk 		for (i = 0; i < id->bNumEndpoints; i++) {
1408f8bfa4e2Smk 			ed = usbd_interface2endpoint_descriptor(
1409f8bfa4e2Smk 			    sc->sc_iface_data, i);
1410f8bfa4e2Smk 			if (!ed) {
141196761c40Sfgsch 				printf(": no descriptor for bulk endpoint "
141296761c40Sfgsch 				    "%u\n", i);
1413f8bfa4e2Smk 				return;
1414f8bfa4e2Smk 			}
1415f8bfa4e2Smk 			if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
1416f8bfa4e2Smk 			    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
1417f8bfa4e2Smk 				sc->sc_bulkin_no = ed->bEndpointAddress;
1418f8bfa4e2Smk 			}
1419f8bfa4e2Smk 			else if (
1420f8bfa4e2Smk 			    UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
1421f8bfa4e2Smk 			    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
1422f8bfa4e2Smk 				sc->sc_bulkout_no = ed->bEndpointAddress;
1423f8bfa4e2Smk 			}
1424f8bfa4e2Smk 		}
1425f8bfa4e2Smk 
1426f8bfa4e2Smk 		if (sc->sc_bulkin_no != -1 && sc->sc_bulkout_no != -1) {
14272e1f0a8fSmk 			DPRINTF(("%s: in=0x%x, out=0x%x\n",
1428f8bfa4e2Smk 			    DEVNAME(sc),
14292e1f0a8fSmk 			    sc->sc_bulkin_no,
1430f8bfa4e2Smk 			    sc->sc_bulkout_no));
1431f8bfa4e2Smk 			goto found;
1432f8bfa4e2Smk 		}
1433f8bfa4e2Smk 	}
1434f8bfa4e2Smk 
1435f8bfa4e2Smk 	if (sc->sc_bulkin_no == -1)
143696761c40Sfgsch 		printf(": could not find data bulk in\n");
1437f8bfa4e2Smk 	if (sc->sc_bulkout_no == -1 )
143896761c40Sfgsch 		printf(": could not find data bulk out\n");
1439f8bfa4e2Smk 	return;
1440f8bfa4e2Smk 
1441f8bfa4e2Smk 	found:
1442f8bfa4e2Smk 
1443a87747bfSmk 	ifp = GET_IFP(sc);
1444a87747bfSmk 	ifp->if_softc = sc;
1445a87747bfSmk 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1446a87747bfSmk 	ifp->if_start = urndis_start;
1447a87747bfSmk 	ifp->if_ioctl = urndis_ioctl;
1448a87747bfSmk #if 0
1449a87747bfSmk 	ifp->if_watchdog = urndis_watchdog;
1450a87747bfSmk #endif
1451a87747bfSmk 
1452a87747bfSmk 	strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
1453a87747bfSmk 
1454f8bfa4e2Smk 	s = splnet();
1455f8bfa4e2Smk 
1456f8bfa4e2Smk 	if (urndis_ctrl_query(sc, OID_802_3_PERMANENT_ADDRESS, NULL, 0,
1457f8bfa4e2Smk 	    &buf, &bufsz) != RNDIS_STATUS_SUCCESS) {
145896761c40Sfgsch 		printf(": unable to get hardware address\n");
1459dd117e2dSfabien 		splx(s);
1460f8bfa4e2Smk 		return;
1461f8bfa4e2Smk 	}
1462f8bfa4e2Smk 
1463f8bfa4e2Smk 	if (bufsz == ETHER_ADDR_LEN) {
1464f8bfa4e2Smk 		memcpy(eaddr, buf, ETHER_ADDR_LEN);
146596761c40Sfgsch 		printf(", address %s\n", ether_sprintf(eaddr));
1466234dfda1Sderaadt 		free(buf, M_TEMP, bufsz);
1467f8bfa4e2Smk 	} else {
146896761c40Sfgsch 		printf(", invalid address\n");
1469234dfda1Sderaadt 		free(buf, M_TEMP, bufsz);
1470dd117e2dSfabien 		splx(s);
1471f8bfa4e2Smk 		return;
1472f8bfa4e2Smk 	}
1473f8bfa4e2Smk 
1474f8bfa4e2Smk 	/* Initialize packet filter */
14757591b6e0Smikeb 	sc->sc_filter = NDIS_PACKET_TYPE_BROADCAST;
14767591b6e0Smikeb 	sc->sc_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
1477f8bfa4e2Smk 	filter = htole32(sc->sc_filter);
1478f8bfa4e2Smk 	if (urndis_ctrl_set(sc, OID_GEN_CURRENT_PACKET_FILTER, &filter,
1479f8bfa4e2Smk 	    sizeof(filter)) != RNDIS_STATUS_SUCCESS) {
1480f8bfa4e2Smk 		printf("%s: unable to set data filters\n", DEVNAME(sc));
1481dd117e2dSfabien 		splx(s);
1482f8bfa4e2Smk 		return;
1483f8bfa4e2Smk 	}
1484f8bfa4e2Smk 
1485f8bfa4e2Smk 	bcopy(eaddr, (char *)&sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
1486f8bfa4e2Smk 
1487f8bfa4e2Smk 	if_attach(ifp);
1488f8bfa4e2Smk 	ether_ifattach(ifp);
1489b896039bSmpi 	sc->sc_attached = 1;
1490f8bfa4e2Smk 
1491f8bfa4e2Smk 	splx(s);
1492f8bfa4e2Smk }
1493f8bfa4e2Smk 
1494f8bfa4e2Smk int
urndis_detach(struct device * self,int flags)1495f8bfa4e2Smk urndis_detach(struct device *self, int flags)
1496f8bfa4e2Smk {
1497f8bfa4e2Smk 	struct urndis_softc	*sc;
1498f8bfa4e2Smk 	struct ifnet		*ifp;
1499f8bfa4e2Smk 	int			 s;
1500f8bfa4e2Smk 
1501f8bfa4e2Smk 	sc = (void*)self;
1502f8bfa4e2Smk 
1503f8bfa4e2Smk 	DPRINTF(("urndis_detach: %s flags %u\n", DEVNAME(sc),
1504f8bfa4e2Smk 	    flags));
1505f8bfa4e2Smk 
1506b896039bSmpi 	if (!sc->sc_attached)
1507b896039bSmpi 		return 0;
1508b896039bSmpi 
150970e15fe7Syuo 	s = splusb();
1510f8bfa4e2Smk 
1511f8bfa4e2Smk 	ifp = GET_IFP(sc);
1512f8bfa4e2Smk 
15135dd621eeSjakemsr 	if (ifp->if_softc != NULL) {
1514f8bfa4e2Smk 		ether_ifdetach(ifp);
1515f8bfa4e2Smk 		if_detach(ifp);
15165dd621eeSjakemsr 	}
1517f8bfa4e2Smk 
1518f8bfa4e2Smk 	urndis_stop(sc);
1519b896039bSmpi 	sc->sc_attached = 0;
1520f8bfa4e2Smk 
1521f8bfa4e2Smk 	splx(s);
1522f8bfa4e2Smk 
1523f8bfa4e2Smk 	return 0;
1524f8bfa4e2Smk }
1525