1/*	$NetBSD: if_urndis.c,v 1.3.2.1 2012/11/24 04:01:21 riz Exp $ */
2/*	$OpenBSD: if_urndis.c,v 1.31 2011/07/03 15:47:17 matthew Exp $ */
3
4/*
5 * Copyright (c) 2010 Jonathan Armani <armani@openbsd.org>
6 * Copyright (c) 2010 Fabien Romano <fabien@openbsd.org>
7 * Copyright (c) 2010 Michael Knudsen <mk@openbsd.org>
8 * All rights reserved.
9 *
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#include <sys/cdefs.h>
24__KERNEL_RCSID(0, "$NetBSD: if_urndis.c,v 1.3.2.1 2012/11/24 04:01:21 riz Exp $");
25
26#include <sys/param.h>
27#include <sys/systm.h>
28#include <sys/sockio.h>
29#include <sys/rwlock.h>
30#include <sys/mbuf.h>
31#include <sys/kmem.h>
32#include <sys/kernel.h>
33#include <sys/proc.h>
34#include <sys/socket.h>
35#include <sys/device.h>
36
37#include <net/if.h>
38#include <net/if_dl.h>
39#include <net/if_media.h>
40#include <net/if_ether.h>
41
42#include <net/bpf.h>
43
44#include <sys/bus.h>
45#include <dev/usb/usb.h>
46#include <dev/usb/usbdi.h>
47#include <dev/usb/usbdi_util.h>
48#include <dev/usb/usbdivar.h>
49#include <dev/usb/usbdevs.h>
50#include <dev/usb/usbcdc.h>
51
52#include <dev/usb/if_urndisreg.h>
53
54#ifdef URNDIS_DEBUG
55#define DPRINTF(x)      do { printf x; } while (0)
56#else
57#define DPRINTF(x)
58#endif
59
60#define DEVNAME(sc)	(device_xname(sc->sc_dev))
61
62#define ETHER_ALIGN 2
63#define URNDIS_RESPONSE_LEN 0x400
64
65
66static int urndis_newbuf(struct urndis_softc *, struct urndis_chain *);
67
68static int urndis_ioctl(struct ifnet *, unsigned long, void *);
69#if 0
70static void urndis_watchdog(struct ifnet *);
71#endif
72
73static void urndis_start(struct ifnet *);
74static void urndis_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
75static void urndis_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
76static int urndis_rx_list_init(struct urndis_softc *);
77static int urndis_tx_list_init(struct urndis_softc *);
78
79static void urndis_init(struct ifnet *);
80static void urndis_stop(struct ifnet *);
81
82static usbd_status urndis_ctrl_msg(struct urndis_softc *, uint8_t, uint8_t,
83    uint16_t, uint16_t, void *, size_t);
84static usbd_status urndis_ctrl_send(struct urndis_softc *, void *, size_t);
85static struct urndis_comp_hdr *urndis_ctrl_recv(struct urndis_softc *);
86
87static uint32_t urndis_ctrl_handle(struct urndis_softc *,
88    struct urndis_comp_hdr *, void **, size_t *);
89static uint32_t urndis_ctrl_handle_init(struct urndis_softc *,
90    const struct urndis_comp_hdr *);
91static uint32_t urndis_ctrl_handle_query(struct urndis_softc *,
92    const struct urndis_comp_hdr *, void **, size_t *);
93static uint32_t urndis_ctrl_handle_reset(struct urndis_softc *,
94    const struct urndis_comp_hdr *);
95
96static uint32_t urndis_ctrl_init(struct urndis_softc *);
97#if 0
98static uint32_t urndis_ctrl_halt(struct urndis_softc *);
99#endif
100static uint32_t urndis_ctrl_query(struct urndis_softc *, uint32_t, void *,
101    size_t, void **, size_t *);
102static uint32_t urndis_ctrl_set(struct urndis_softc *, uint32_t, void *, size_t);
103#if 0
104static uint32_t urndis_ctrl_set_param(struct urndis_softc *, const char *,
105    uint32_t, void *, size_t);
106static uint32_t urndis_ctrl_reset(struct urndis_softc *);
107static uint32_t urndis_ctrl_keepalive(struct urndis_softc *);
108#endif
109
110static int urndis_encap(struct urndis_softc *, struct mbuf *, int);
111static void urndis_decap(struct urndis_softc *, struct urndis_chain *, uint32_t);
112
113static int urndis_match(device_t, cfdata_t, void *);
114static void urndis_attach(device_t, device_t, void *);
115static int urndis_detach(device_t, int);
116static int urndis_activate(device_t, enum devact);
117
118CFATTACH_DECL_NEW(urndis, sizeof(struct urndis_softc),
119    urndis_match, urndis_attach, urndis_detach, urndis_activate);
120
121/*
122 * Supported devices that we can't match by class IDs.
123 */
124static const struct usb_devno urndis_devs[] = {
125	{ USB_VENDOR_HTC,	USB_PRODUCT_HTC_ANDROID },
126	{ USB_VENDOR_SAMSUNG,	USB_PRODUCT_SAMSUNG_ANDROID2 },
127};
128
129static usbd_status
130urndis_ctrl_msg(struct urndis_softc *sc, uint8_t rt, uint8_t r,
131    uint16_t index, uint16_t value, void *buf, size_t buflen)
132{
133	usb_device_request_t req;
134
135	req.bmRequestType = rt;
136	req.bRequest = r;
137	USETW(req.wValue, value);
138	USETW(req.wIndex, index);
139	USETW(req.wLength, buflen);
140
141	return usbd_do_request(sc->sc_udev, &req, buf);
142}
143
144static usbd_status
145urndis_ctrl_send(struct urndis_softc *sc, void *buf, size_t len)
146{
147	usbd_status err;
148
149	if (sc->sc_dying)
150		return(0);
151
152	err = urndis_ctrl_msg(sc, UT_WRITE_CLASS_INTERFACE, UR_GET_STATUS,
153	    sc->sc_ifaceno_ctl, 0, buf, len);
154
155	if (err != USBD_NORMAL_COMPLETION)
156		printf("%s: %s\n", DEVNAME(sc), usbd_errstr(err));
157
158	return err;
159}
160
161static struct urndis_comp_hdr *
162urndis_ctrl_recv(struct urndis_softc *sc)
163{
164	struct urndis_comp_hdr	*hdr;
165	char			*buf;
166	usbd_status		 err;
167
168	buf = kmem_alloc(URNDIS_RESPONSE_LEN, KM_SLEEP);
169	if (buf == NULL) {
170		printf("%s: out of memory\n", DEVNAME(sc));
171		return NULL;
172	}
173
174	err = urndis_ctrl_msg(sc, UT_READ_CLASS_INTERFACE, UR_CLEAR_FEATURE,
175	    sc->sc_ifaceno_ctl, 0, buf, URNDIS_RESPONSE_LEN);
176
177	if (err != USBD_NORMAL_COMPLETION && err != USBD_SHORT_XFER) {
178		printf("%s: %s\n", DEVNAME(sc), usbd_errstr(err));
179		kmem_free(buf, URNDIS_RESPONSE_LEN);
180		return NULL;
181	}
182
183	hdr = (struct urndis_comp_hdr *)buf;
184	DPRINTF(("%s: urndis_ctrl_recv: type 0x%x len %u\n",
185	    DEVNAME(sc),
186	    le32toh(hdr->rm_type),
187	    le32toh(hdr->rm_len)));
188
189	if (le32toh(hdr->rm_len) > URNDIS_RESPONSE_LEN) {
190		printf("%s: ctrl message error: wrong size %u > %u\n",
191		    DEVNAME(sc),
192		    le32toh(hdr->rm_len),
193		    URNDIS_RESPONSE_LEN);
194		kmem_free(buf, URNDIS_RESPONSE_LEN);
195		return NULL;
196	}
197
198	return hdr;
199}
200
201static uint32_t
202urndis_ctrl_handle(struct urndis_softc *sc, struct urndis_comp_hdr *hdr,
203    void **buf, size_t *bufsz)
204{
205	uint32_t rval;
206
207	DPRINTF(("%s: urndis_ctrl_handle\n", DEVNAME(sc)));
208
209	if (buf && bufsz) {
210		*buf = NULL;
211		*bufsz = 0;
212	}
213
214	switch (le32toh(hdr->rm_type)) {
215		case REMOTE_NDIS_INITIALIZE_CMPLT:
216			rval = urndis_ctrl_handle_init(sc, hdr);
217			break;
218
219		case REMOTE_NDIS_QUERY_CMPLT:
220			rval = urndis_ctrl_handle_query(sc, hdr, buf, bufsz);
221			break;
222
223		case REMOTE_NDIS_RESET_CMPLT:
224			rval = urndis_ctrl_handle_reset(sc, hdr);
225			break;
226
227		case REMOTE_NDIS_KEEPALIVE_CMPLT:
228		case REMOTE_NDIS_SET_CMPLT:
229			rval = le32toh(hdr->rm_status);
230			break;
231
232		default:
233			printf("%s: ctrl message error: unknown event 0x%x\n",
234			    DEVNAME(sc), le32toh(hdr->rm_type));
235			rval = RNDIS_STATUS_FAILURE;
236	}
237
238	kmem_free(hdr, URNDIS_RESPONSE_LEN);
239
240	return rval;
241}
242
243static uint32_t
244urndis_ctrl_handle_init(struct urndis_softc *sc,
245    const struct urndis_comp_hdr *hdr)
246{
247	const struct urndis_init_comp	*msg;
248
249	msg = (const struct urndis_init_comp *) hdr;
250
251	DPRINTF(("%s: urndis_ctrl_handle_init: len %u rid %u status 0x%x "
252	    "ver_major %u ver_minor %u devflags 0x%x medium 0x%x pktmaxcnt %u "
253	    "pktmaxsz %u align %u aflistoffset %u aflistsz %u\n",
254	    DEVNAME(sc),
255	    le32toh(msg->rm_len),
256	    le32toh(msg->rm_rid),
257	    le32toh(msg->rm_status),
258	    le32toh(msg->rm_ver_major),
259	    le32toh(msg->rm_ver_minor),
260	    le32toh(msg->rm_devflags),
261	    le32toh(msg->rm_medium),
262	    le32toh(msg->rm_pktmaxcnt),
263	    le32toh(msg->rm_pktmaxsz),
264	    le32toh(msg->rm_align),
265	    le32toh(msg->rm_aflistoffset),
266	    le32toh(msg->rm_aflistsz)));
267
268	if (le32toh(msg->rm_status) != RNDIS_STATUS_SUCCESS) {
269		printf("%s: init failed 0x%x\n",
270		    DEVNAME(sc),
271		    le32toh(msg->rm_status));
272
273		return le32toh(msg->rm_status);
274	}
275
276	if (le32toh(msg->rm_devflags) != RNDIS_DF_CONNECTIONLESS) {
277		printf("%s: wrong device type (current type: 0x%x)\n",
278		    DEVNAME(sc),
279		    le32toh(msg->rm_devflags));
280
281		return RNDIS_STATUS_FAILURE;
282	}
283
284	if (le32toh(msg->rm_medium) != RNDIS_MEDIUM_802_3) {
285		printf("%s: medium not 802.3 (current medium: 0x%x)\n",
286		    DEVNAME(sc), le32toh(msg->rm_medium));
287
288		return RNDIS_STATUS_FAILURE;
289	}
290
291	sc->sc_lim_pktsz = le32toh(msg->rm_pktmaxsz);
292
293	return le32toh(msg->rm_status);
294}
295
296static uint32_t
297urndis_ctrl_handle_query(struct urndis_softc *sc,
298    const struct urndis_comp_hdr *hdr, void **buf, size_t *bufsz)
299{
300	const struct urndis_query_comp	*msg;
301
302	msg = (const struct urndis_query_comp *) hdr;
303
304	DPRINTF(("%s: urndis_ctrl_handle_query: len %u rid %u status 0x%x "
305	    "buflen %u bufoff %u\n",
306	    DEVNAME(sc),
307	    le32toh(msg->rm_len),
308	    le32toh(msg->rm_rid),
309	    le32toh(msg->rm_status),
310	    le32toh(msg->rm_infobuflen),
311	    le32toh(msg->rm_infobufoffset)));
312
313	if (buf && bufsz) {
314		*buf = NULL;
315		*bufsz = 0;
316	}
317
318	if (le32toh(msg->rm_status) != RNDIS_STATUS_SUCCESS) {
319		printf("%s: query failed 0x%x\n",
320		    DEVNAME(sc),
321		    le32toh(msg->rm_status));
322
323		return le32toh(msg->rm_status);
324	}
325
326	if (le32toh(msg->rm_infobuflen) + le32toh(msg->rm_infobufoffset) +
327	    RNDIS_HEADER_OFFSET > le32toh(msg->rm_len)) {
328		printf("%s: ctrl message error: invalid query info "
329		    "len/offset/end_position(%u/%u/%u) -> "
330		    "go out of buffer limit %u\n",
331		    DEVNAME(sc),
332		    le32toh(msg->rm_infobuflen),
333		    le32toh(msg->rm_infobufoffset),
334		    le32toh(msg->rm_infobuflen) +
335		    le32toh(msg->rm_infobufoffset) + (uint32_t)RNDIS_HEADER_OFFSET,
336		    le32toh(msg->rm_len));
337		return RNDIS_STATUS_FAILURE;
338	}
339
340	if (buf && bufsz) {
341		*buf = kmem_alloc(le32toh(msg->rm_infobuflen), KM_SLEEP);
342		if (*buf == NULL) {
343			printf("%s: out of memory\n", DEVNAME(sc));
344			return RNDIS_STATUS_FAILURE;
345		} else {
346			const char *p;
347			*bufsz = le32toh(msg->rm_infobuflen);
348
349			p = (const char *)&msg->rm_rid;
350			p += le32toh(msg->rm_infobufoffset);
351			memcpy(*buf, p, le32toh(msg->rm_infobuflen));
352		}
353	}
354
355	return le32toh(msg->rm_status);
356}
357
358static uint32_t
359urndis_ctrl_handle_reset(struct urndis_softc *sc,
360    const struct urndis_comp_hdr *hdr)
361{
362	const struct urndis_reset_comp	*msg;
363	uint32_t			 rval;
364
365	msg = (const struct urndis_reset_comp *) hdr;
366
367	rval = le32toh(msg->rm_status);
368
369	DPRINTF(("%s: urndis_ctrl_handle_reset: len %u status 0x%x "
370	    "adrreset %u\n",
371	    DEVNAME(sc),
372	    le32toh(msg->rm_len),
373	    rval,
374	    le32toh(msg->rm_adrreset)));
375
376	if (rval != RNDIS_STATUS_SUCCESS) {
377		printf("%s: reset failed 0x%x\n", DEVNAME(sc), rval);
378		return rval;
379	}
380
381	if (le32toh(msg->rm_adrreset) != 0) {
382		uint32_t filter;
383
384		filter = htole32(sc->sc_filter);
385		rval = urndis_ctrl_set(sc, OID_GEN_CURRENT_PACKET_FILTER,
386		    &filter, sizeof(filter));
387		if (rval != RNDIS_STATUS_SUCCESS) {
388			printf("%s: unable to reset data filters\n",
389			    DEVNAME(sc));
390			return rval;
391		}
392	}
393
394	return rval;
395}
396
397static uint32_t
398urndis_ctrl_init(struct urndis_softc *sc)
399{
400	struct urndis_init_req	*msg;
401	uint32_t		 rval;
402	struct urndis_comp_hdr	*hdr;
403
404	msg = kmem_alloc(sizeof(*msg), KM_SLEEP);
405	if (msg == NULL) {
406		printf("%s: out of memory\n", DEVNAME(sc));
407		return RNDIS_STATUS_FAILURE;
408	}
409
410	msg->rm_type = htole32(REMOTE_NDIS_INITIALIZE_MSG);
411	msg->rm_len = htole32(sizeof(*msg));
412	msg->rm_rid = htole32(0);
413	msg->rm_ver_major = htole32(1);
414	msg->rm_ver_minor = htole32(1);
415	msg->rm_max_xfersz = htole32(RNDIS_BUFSZ);
416
417	DPRINTF(("%s: urndis_ctrl_init send: type %u len %u rid %u ver_major %u "
418	    "ver_minor %u max_xfersz %u\n",
419	    DEVNAME(sc),
420	    le32toh(msg->rm_type),
421	    le32toh(msg->rm_len),
422	    le32toh(msg->rm_rid),
423	    le32toh(msg->rm_ver_major),
424	    le32toh(msg->rm_ver_minor),
425	    le32toh(msg->rm_max_xfersz)));
426
427	rval = urndis_ctrl_send(sc, msg, sizeof(*msg));
428	kmem_free(msg, sizeof(*msg));
429
430	if (rval != RNDIS_STATUS_SUCCESS) {
431		printf("%s: init failed\n", DEVNAME(sc));
432		return rval;
433	}
434
435	if ((hdr = urndis_ctrl_recv(sc)) == NULL) {
436		printf("%s: unable to get init response\n", DEVNAME(sc));
437		return RNDIS_STATUS_FAILURE;
438	}
439	rval = urndis_ctrl_handle(sc, hdr, NULL, NULL);
440
441	return rval;
442}
443
444#if 0
445static uint32_t
446urndis_ctrl_halt(struct urndis_softc *sc)
447{
448	struct urndis_halt_req	*msg;
449	uint32_t		 rval;
450
451	msg = kmem_alloc(sizeof(*msg), KM_SLEEP);
452	if (msg == NULL) {
453		printf("%s: out of memory\n", DEVNAME(sc));
454		return RNDIS_STATUS_FAILURE;
455	}
456
457	msg->rm_type = htole32(REMOTE_NDIS_HALT_MSG);
458	msg->rm_len = htole32(sizeof(*msg));
459	msg->rm_rid = 0;
460
461	DPRINTF(("%s: urndis_ctrl_halt send: type %u len %u rid %u\n",
462	    DEVNAME(sc),
463	    le32toh(msg->rm_type),
464	    le32toh(msg->rm_len),
465	    le32toh(msg->rm_rid)));
466
467	rval = urndis_ctrl_send(sc, msg, sizeof(*msg));
468	kmem_free(msg, sizeof(*msg));
469
470	if (rval != RNDIS_STATUS_SUCCESS)
471		printf("%s: halt failed\n", DEVNAME(sc));
472
473	return rval;
474}
475#endif
476
477static uint32_t
478urndis_ctrl_query(struct urndis_softc *sc, uint32_t oid,
479    void *qbuf, size_t qlen,
480    void **rbuf, size_t *rbufsz)
481{
482	struct urndis_query_req	*msg;
483	uint32_t		 rval;
484	struct urndis_comp_hdr	*hdr;
485
486	msg = kmem_alloc(sizeof(*msg) + qlen, KM_SLEEP);
487	if (msg == NULL) {
488		printf("%s: out of memory\n", DEVNAME(sc));
489		return RNDIS_STATUS_FAILURE;
490	}
491
492	msg->rm_type = htole32(REMOTE_NDIS_QUERY_MSG);
493	msg->rm_len = htole32(sizeof(*msg) + qlen);
494	msg->rm_rid = 0; /* XXX */
495	msg->rm_oid = htole32(oid);
496	msg->rm_infobuflen = htole32(qlen);
497	if (qlen != 0) {
498		msg->rm_infobufoffset = htole32(20);
499		memcpy((char*)msg + 20, qbuf, qlen);
500	} else
501		msg->rm_infobufoffset = 0;
502	msg->rm_devicevchdl = 0;
503
504	DPRINTF(("%s: urndis_ctrl_query send: type %u len %u rid %u oid 0x%x "
505	    "infobuflen %u infobufoffset %u devicevchdl %u\n",
506	    DEVNAME(sc),
507	    le32toh(msg->rm_type),
508	    le32toh(msg->rm_len),
509	    le32toh(msg->rm_rid),
510	    le32toh(msg->rm_oid),
511	    le32toh(msg->rm_infobuflen),
512	    le32toh(msg->rm_infobufoffset),
513	    le32toh(msg->rm_devicevchdl)));
514
515	rval = urndis_ctrl_send(sc, msg, sizeof(*msg));
516	kmem_free(msg, sizeof(*msg) + qlen);
517
518	if (rval != RNDIS_STATUS_SUCCESS) {
519		printf("%s: query failed\n", DEVNAME(sc));
520		return rval;
521	}
522
523	if ((hdr = urndis_ctrl_recv(sc)) == NULL) {
524		printf("%s: unable to get query response\n", DEVNAME(sc));
525		return RNDIS_STATUS_FAILURE;
526	}
527	rval = urndis_ctrl_handle(sc, hdr, rbuf, rbufsz);
528
529	return rval;
530}
531
532static uint32_t
533urndis_ctrl_set(struct urndis_softc *sc, uint32_t oid, void *buf, size_t len)
534{
535	struct urndis_set_req	*msg;
536	uint32_t		 rval;
537	struct urndis_comp_hdr	*hdr;
538
539	msg = kmem_alloc(sizeof(*msg) + len, KM_SLEEP);
540	if (msg == NULL) {
541		printf("%s: out of memory\n", DEVNAME(sc));
542		return RNDIS_STATUS_FAILURE;
543	}
544
545	msg->rm_type = htole32(REMOTE_NDIS_SET_MSG);
546	msg->rm_len = htole32(sizeof(*msg) + len);
547	msg->rm_rid = 0; /* XXX */
548	msg->rm_oid = htole32(oid);
549	msg->rm_infobuflen = htole32(len);
550	if (len != 0) {
551		msg->rm_infobufoffset = htole32(20);
552		memcpy((char*)msg + 20, buf, len);
553	} else
554		msg->rm_infobufoffset = 0;
555	msg->rm_devicevchdl = 0;
556
557	DPRINTF(("%s: urndis_ctrl_set send: type %u len %u rid %u oid 0x%x "
558	    "infobuflen %u infobufoffset %u devicevchdl %u\n",
559	    DEVNAME(sc),
560	    le32toh(msg->rm_type),
561	    le32toh(msg->rm_len),
562	    le32toh(msg->rm_rid),
563	    le32toh(msg->rm_oid),
564	    le32toh(msg->rm_infobuflen),
565	    le32toh(msg->rm_infobufoffset),
566	    le32toh(msg->rm_devicevchdl)));
567
568	rval = urndis_ctrl_send(sc, msg, sizeof(*msg));
569	kmem_free(msg, sizeof(*msg) + len);
570
571	if (rval != RNDIS_STATUS_SUCCESS) {
572		printf("%s: set failed\n", DEVNAME(sc));
573		return rval;
574	}
575
576	if ((hdr = urndis_ctrl_recv(sc)) == NULL) {
577		printf("%s: unable to get set response\n", DEVNAME(sc));
578		return RNDIS_STATUS_FAILURE;
579	}
580	rval = urndis_ctrl_handle(sc, hdr, NULL, NULL);
581	if (rval != RNDIS_STATUS_SUCCESS)
582		printf("%s: set failed 0x%x\n", DEVNAME(sc), rval);
583
584	return rval;
585}
586
587#if 0
588static uint32_t
589urndis_ctrl_set_param(struct urndis_softc *sc,
590    const char *name,
591    uint32_t type,
592    void *buf,
593    size_t len)
594{
595	struct urndis_set_parameter	*param;
596	uint32_t			 rval;
597	size_t				 namelen, tlen;
598
599	if (name)
600		namelen = strlen(name);
601	else
602		namelen = 0;
603	tlen = sizeof(*param) + len + namelen;
604	param = kmem_alloc(tlen, KM_SLEEP);
605	if (param == NULL) {
606		printf("%s: out of memory\n", DEVNAME(sc));
607		return RNDIS_STATUS_FAILURE;
608	}
609
610	param->rm_namelen = htole32(namelen);
611	param->rm_valuelen = htole32(len);
612	param->rm_type = htole32(type);
613	if (namelen != 0) {
614		param->rm_nameoffset = htole32(20);
615		memcpy(param + 20, name, namelen);
616	} else
617		param->rm_nameoffset = 0;
618	if (len != 0) {
619		param->rm_valueoffset = htole32(20 + namelen);
620		memcpy(param + 20 + namelen, buf, len);
621	} else
622		param->rm_valueoffset = 0;
623
624	DPRINTF(("%s: urndis_ctrl_set_param send: nameoffset %u namelen %u "
625	    "type 0x%x valueoffset %u valuelen %u\n",
626	    DEVNAME(sc),
627	    le32toh(param->rm_nameoffset),
628	    le32toh(param->rm_namelen),
629	    le32toh(param->rm_type),
630	    le32toh(param->rm_valueoffset),
631	    le32toh(param->rm_valuelen)));
632
633	rval = urndis_ctrl_set(sc, OID_GEN_RNDIS_CONFIG_PARAMETER, param, tlen);
634	kmem_free(param, tlen);
635	if (rval != RNDIS_STATUS_SUCCESS)
636		printf("%s: set param failed 0x%x\n", DEVNAME(sc), rval);
637
638	return rval;
639}
640
641/* XXX : adrreset, get it from response */
642static uint32_t
643urndis_ctrl_reset(struct urndis_softc *sc)
644{
645	struct urndis_reset_req		*reset;
646	uint32_t			 rval;
647	struct urndis_comp_hdr		*hdr;
648
649	reset = kmem_alloc(sizeof(*reset), KM_SLEEP);
650	if (reset == NULL) {
651		printf("%s: out of memory\n", DEVNAME(sc));
652		return RNDIS_STATUS_FAILURE;
653	}
654
655	reset->rm_type = htole32(REMOTE_NDIS_RESET_MSG);
656	reset->rm_len = htole32(sizeof(*reset));
657	reset->rm_rid = 0; /* XXX rm_rid == reserved ... remove ? */
658
659	DPRINTF(("%s: urndis_ctrl_reset send: type %u len %u rid %u\n",
660	    DEVNAME(sc),
661	    le32toh(reset->rm_type),
662	    le32toh(reset->rm_len),
663	    le32toh(reset->rm_rid)));
664
665	rval = urndis_ctrl_send(sc, reset, sizeof(*reset));
666	kmem_free(reset, sizeof(*reset));
667
668	if (rval != RNDIS_STATUS_SUCCESS) {
669		printf("%s: reset failed\n", DEVNAME(sc));
670		return rval;
671	}
672
673	if ((hdr = urndis_ctrl_recv(sc)) == NULL) {
674		printf("%s: unable to get reset response\n", DEVNAME(sc));
675		return RNDIS_STATUS_FAILURE;
676	}
677	rval = urndis_ctrl_handle(sc, hdr, NULL, NULL);
678
679	return rval;
680}
681
682static uint32_t
683urndis_ctrl_keepalive(struct urndis_softc *sc)
684{
685	struct urndis_keepalive_req	*keep;
686	uint32_t			 rval;
687	struct urndis_comp_hdr		*hdr;
688
689	keep = kmem_alloc(sizeof(*keep), KM_SLEEP);
690	if (keep == NULL) {
691		printf("%s: out of memory\n", DEVNAME(sc));
692		return RNDIS_STATUS_FAILURE;
693	}
694
695	keep->rm_type = htole32(REMOTE_NDIS_KEEPALIVE_MSG);
696	keep->rm_len = htole32(sizeof(*keep));
697	keep->rm_rid = 0; /* XXX rm_rid == reserved ... remove ? */
698
699	DPRINTF(("%s: urndis_ctrl_keepalive: type %u len %u rid %u\n",
700	    DEVNAME(sc),
701	    le32toh(keep->rm_type),
702	    le32toh(keep->rm_len),
703	    le32toh(keep->rm_rid)));
704
705	rval = urndis_ctrl_send(sc, keep, sizeof(*keep));
706	kmem_free(keep, sizeof(*keep));
707
708	if (rval != RNDIS_STATUS_SUCCESS) {
709		printf("%s: keepalive failed\n", DEVNAME(sc));
710		return rval;
711	}
712
713	if ((hdr = urndis_ctrl_recv(sc)) == NULL) {
714		printf("%s: unable to get keepalive response\n", DEVNAME(sc));
715		return RNDIS_STATUS_FAILURE;
716	}
717	rval = urndis_ctrl_handle(sc, hdr, NULL, NULL);
718	if (rval != RNDIS_STATUS_SUCCESS) {
719		printf("%s: keepalive failed 0x%x\n", DEVNAME(sc), rval);
720		urndis_ctrl_reset(sc);
721	}
722
723	return rval;
724}
725#endif
726
727static int
728urndis_encap(struct urndis_softc *sc, struct mbuf *m, int idx)
729{
730	struct urndis_chain		*c;
731	usbd_status			 err;
732	struct urndis_packet_msg		*msg;
733
734	c = &sc->sc_data.sc_tx_chain[idx];
735
736	msg = (struct urndis_packet_msg *)c->sc_buf;
737
738	memset(msg, 0, sizeof(*msg));
739	msg->rm_type = htole32(REMOTE_NDIS_PACKET_MSG);
740	msg->rm_len = htole32(sizeof(*msg) + m->m_pkthdr.len);
741
742	msg->rm_dataoffset = htole32(RNDIS_DATA_OFFSET);
743	msg->rm_datalen = htole32(m->m_pkthdr.len);
744
745	m_copydata(m, 0, m->m_pkthdr.len,
746	    ((char*)msg + RNDIS_DATA_OFFSET + RNDIS_HEADER_OFFSET));
747
748	DPRINTF(("%s: urndis_encap type 0x%x len %u data(off %u len %u)\n",
749	    DEVNAME(sc),
750	    le32toh(msg->rm_type),
751	    le32toh(msg->rm_len),
752	    le32toh(msg->rm_dataoffset),
753	    le32toh(msg->rm_datalen)));
754
755	c->sc_mbuf = m;
756
757	usbd_setup_xfer(c->sc_xfer, sc->sc_bulkout_pipe, c, c->sc_buf,
758	    le32toh(msg->rm_len), USBD_FORCE_SHORT_XFER | USBD_NO_COPY, 10000,
759	    urndis_txeof);
760
761	/* Transmit */
762	err = usbd_transfer(c->sc_xfer);
763	if (err != USBD_IN_PROGRESS) {
764		urndis_stop(GET_IFP(sc));
765		return(EIO);
766	}
767
768	sc->sc_data.sc_tx_cnt++;
769
770	return(0);
771}
772
773static void
774urndis_decap(struct urndis_softc *sc, struct urndis_chain *c, uint32_t len)
775{
776	struct mbuf		*m;
777	struct urndis_packet_msg	*msg;
778	struct ifnet		*ifp;
779	int			 s;
780	int			 offset;
781
782	ifp = GET_IFP(sc);
783	offset = 0;
784
785	while (len > 0) {
786		msg = (struct urndis_packet_msg *)((char*)c->sc_buf + offset);
787		m = c->sc_mbuf;
788
789		DPRINTF(("%s: urndis_decap buffer size left %u\n", DEVNAME(sc),
790		    len));
791
792		if (len < sizeof(*msg)) {
793			printf("%s: urndis_decap invalid buffer len %u < "
794			    "minimum header %zu\n",
795			    DEVNAME(sc),
796			    len,
797			    sizeof(*msg));
798			return;
799		}
800
801		DPRINTF(("%s: urndis_decap len %u data(off:%u len:%u) "
802		    "oobdata(off:%u len:%u nb:%u) perpacket(off:%u len:%u)\n",
803		    DEVNAME(sc),
804		    le32toh(msg->rm_len),
805		    le32toh(msg->rm_dataoffset),
806		    le32toh(msg->rm_datalen),
807		    le32toh(msg->rm_oobdataoffset),
808		    le32toh(msg->rm_oobdatalen),
809		    le32toh(msg->rm_oobdataelements),
810		    le32toh(msg->rm_pktinfooffset),
811		    le32toh(msg->rm_pktinfooffset)));
812
813		if (le32toh(msg->rm_type) != REMOTE_NDIS_PACKET_MSG) {
814			printf("%s: urndis_decap invalid type 0x%x != 0x%x\n",
815			    DEVNAME(sc),
816			    le32toh(msg->rm_type),
817			    REMOTE_NDIS_PACKET_MSG);
818			return;
819		}
820		if (le32toh(msg->rm_len) < sizeof(*msg)) {
821			printf("%s: urndis_decap invalid msg len %u < %zu\n",
822			    DEVNAME(sc),
823			    le32toh(msg->rm_len),
824			    sizeof(*msg));
825			return;
826		}
827		if (le32toh(msg->rm_len) > len) {
828			printf("%s: urndis_decap invalid msg len %u > buffer "
829			    "len %u\n",
830			    DEVNAME(sc),
831			    le32toh(msg->rm_len),
832			    len);
833			return;
834		}
835
836		if (le32toh(msg->rm_dataoffset) +
837		    le32toh(msg->rm_datalen) + RNDIS_HEADER_OFFSET
838		        > le32toh(msg->rm_len)) {
839			printf("%s: urndis_decap invalid data "
840			    "len/offset/end_position(%u/%u/%u) -> "
841			    "go out of receive buffer limit %u\n",
842			    DEVNAME(sc),
843			    le32toh(msg->rm_datalen),
844			    le32toh(msg->rm_dataoffset),
845			    le32toh(msg->rm_dataoffset) +
846			    le32toh(msg->rm_datalen) + (uint32_t)RNDIS_HEADER_OFFSET,
847			    le32toh(msg->rm_len));
848			return;
849		}
850
851		if (le32toh(msg->rm_datalen) < sizeof(struct ether_header)) {
852			ifp->if_ierrors++;
853			printf("%s: urndis_decap invalid ethernet size "
854			    "%d < %zu\n",
855			    DEVNAME(sc),
856			    le32toh(msg->rm_datalen),
857			    sizeof(struct ether_header));
858			return;
859		}
860
861		memcpy(mtod(m, char*),
862		    ((char*)&msg->rm_dataoffset + le32toh(msg->rm_dataoffset)),
863		    le32toh(msg->rm_datalen));
864		m->m_pkthdr.len = m->m_len = le32toh(msg->rm_datalen);
865
866		ifp->if_ipackets++;
867		m->m_pkthdr.rcvif = ifp;
868
869		s = splnet();
870
871		if (urndis_newbuf(sc, c) == ENOBUFS) {
872			ifp->if_ierrors++;
873		} else {
874
875			bpf_mtap(ifp, m);
876
877			(*(ifp)->if_input)((ifp), (m));
878		}
879		splx(s);
880
881		offset += le32toh(msg->rm_len);
882		len -= le32toh(msg->rm_len);
883	}
884}
885
886static int
887urndis_newbuf(struct urndis_softc *sc, struct urndis_chain *c)
888{
889	struct mbuf *m_new = NULL;
890
891	MGETHDR(m_new, M_DONTWAIT, MT_DATA);
892	if (m_new == NULL) {
893		printf("%s: no memory for rx list -- packet dropped!\n",
894		    DEVNAME(sc));
895		return (ENOBUFS);
896	}
897	MCLGET(m_new, M_DONTWAIT);
898	if (!(m_new->m_flags & M_EXT)) {
899		printf("%s: no memory for rx list -- packet dropped!\n",
900		    DEVNAME(sc));
901		m_freem(m_new);
902		return (ENOBUFS);
903	}
904	m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
905
906	m_adj(m_new, ETHER_ALIGN);
907	c->sc_mbuf = m_new;
908	return (0);
909}
910
911static int
912urndis_rx_list_init(struct urndis_softc *sc)
913{
914	struct urndis_cdata	*cd;
915	struct urndis_chain	*c;
916	int			 i;
917
918	cd = &sc->sc_data;
919	for (i = 0; i < RNDIS_RX_LIST_CNT; i++) {
920		c = &cd->sc_rx_chain[i];
921		c->sc_softc = sc;
922		c->sc_idx = i;
923
924		if (urndis_newbuf(sc, c) == ENOBUFS)
925			return (ENOBUFS);
926
927		if (c->sc_xfer == NULL) {
928			c->sc_xfer = usbd_alloc_xfer(sc->sc_udev);
929			if (c->sc_xfer == NULL)
930				return (ENOBUFS);
931			c->sc_buf = usbd_alloc_buffer(c->sc_xfer,
932			    RNDIS_BUFSZ);
933			if (c->sc_buf == NULL)
934				return (ENOBUFS);
935		}
936	}
937
938	return (0);
939}
940
941static int
942urndis_tx_list_init(struct urndis_softc *sc)
943{
944	struct urndis_cdata	*cd;
945	struct urndis_chain	*c;
946	int			 i;
947
948	cd = &sc->sc_data;
949	for (i = 0; i < RNDIS_TX_LIST_CNT; i++) {
950		c = &cd->sc_tx_chain[i];
951		c->sc_softc = sc;
952		c->sc_idx = i;
953		c->sc_mbuf = NULL;
954		if (c->sc_xfer == NULL) {
955			c->sc_xfer = usbd_alloc_xfer(sc->sc_udev);
956			if (c->sc_xfer == NULL)
957				return (ENOBUFS);
958			c->sc_buf = usbd_alloc_buffer(c->sc_xfer,
959			    RNDIS_BUFSZ);
960			if (c->sc_buf == NULL)
961				return (ENOBUFS);
962		}
963	}
964	return (0);
965}
966
967static int
968urndis_ioctl(struct ifnet *ifp, unsigned long command, void *data)
969{
970	struct urndis_softc	*sc;
971	struct ifaddr		*ifa;
972	int			 s, error;
973
974	sc = ifp->if_softc;
975	ifa = (struct ifaddr *)data;
976	error = 0;
977
978	if (sc->sc_dying)
979		return (EIO);
980
981	s = splnet();
982
983	switch(command) {
984	case SIOCSIFFLAGS:
985		if ((error = ifioctl_common(ifp, command, data)) != 0)
986			break;
987		if (ifp->if_flags & IFF_UP) {
988			if (!(ifp->if_flags & IFF_RUNNING))
989				urndis_init(ifp);
990		} else {
991			if (ifp->if_flags & IFF_RUNNING)
992				urndis_stop(ifp);
993		}
994		error = 0;
995		break;
996
997	default:
998		error = ether_ioctl(ifp, command, data);
999		break;
1000	}
1001
1002	if (error == ENETRESET)
1003		error = 0;
1004
1005	splx(s);
1006	return (error);
1007}
1008
1009#if 0
1010static void
1011urndis_watchdog(struct ifnet *ifp)
1012{
1013	struct urndis_softc *sc;
1014
1015	sc = ifp->if_softc;
1016
1017	if (sc->sc_dying)
1018		return;
1019
1020	ifp->if_oerrors++;
1021	printf("%s: watchdog timeout\n", DEVNAME(sc));
1022
1023	urndis_ctrl_keepalive(sc);
1024}
1025#endif
1026
1027static void
1028urndis_init(struct ifnet *ifp)
1029{
1030	struct urndis_softc	*sc;
1031	int			 i, s;
1032	usbd_status		 err;
1033
1034	sc = ifp->if_softc;
1035
1036	if (ifp->if_flags & IFF_RUNNING)
1037		return;
1038
1039	if (urndis_ctrl_init(sc) != RNDIS_STATUS_SUCCESS)
1040		return;
1041
1042	s = splnet();
1043
1044	if (urndis_tx_list_init(sc) == ENOBUFS) {
1045		printf("%s: tx list init failed\n",
1046		    DEVNAME(sc));
1047		splx(s);
1048		return;
1049	}
1050
1051	if (urndis_rx_list_init(sc) == ENOBUFS) {
1052		printf("%s: rx list init failed\n",
1053		    DEVNAME(sc));
1054		splx(s);
1055		return;
1056	}
1057
1058	err = usbd_open_pipe(sc->sc_iface_data, sc->sc_bulkin_no,
1059	    USBD_EXCLUSIVE_USE, &sc->sc_bulkin_pipe);
1060	if (err) {
1061		printf("%s: open rx pipe failed: %s\n", DEVNAME(sc),
1062		    usbd_errstr(err));
1063		splx(s);
1064		return;
1065	}
1066
1067	err = usbd_open_pipe(sc->sc_iface_data, sc->sc_bulkout_no,
1068	    USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
1069	if (err) {
1070		printf("%s: open tx pipe failed: %s\n", DEVNAME(sc),
1071		    usbd_errstr(err));
1072		splx(s);
1073		return;
1074	}
1075
1076	for (i = 0; i < RNDIS_RX_LIST_CNT; i++) {
1077		struct urndis_chain *c;
1078
1079		c = &sc->sc_data.sc_rx_chain[i];
1080		usbd_setup_xfer(c->sc_xfer, sc->sc_bulkin_pipe, c,
1081		    c->sc_buf, RNDIS_BUFSZ,
1082		    USBD_SHORT_XFER_OK | USBD_NO_COPY,
1083		    USBD_NO_TIMEOUT, urndis_rxeof);
1084		usbd_transfer(c->sc_xfer);
1085	}
1086
1087	ifp->if_flags |= IFF_RUNNING;
1088	ifp->if_flags &= ~IFF_OACTIVE;
1089
1090	splx(s);
1091}
1092
1093static void
1094urndis_stop(struct ifnet *ifp)
1095{
1096	struct urndis_softc	*sc;
1097	usbd_status	 err;
1098	int		 i;
1099
1100	sc = ifp->if_softc;
1101
1102	ifp->if_timer = 0;
1103	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
1104
1105	if (sc->sc_bulkin_pipe != NULL) {
1106		err = usbd_abort_pipe(sc->sc_bulkin_pipe);
1107		if (err)
1108			printf("%s: abort rx pipe failed: %s\n",
1109			    DEVNAME(sc), usbd_errstr(err));
1110		err = usbd_close_pipe(sc->sc_bulkin_pipe);
1111		if (err)
1112			printf("%s: close rx pipe failed: %s\n",
1113			    DEVNAME(sc), usbd_errstr(err));
1114		sc->sc_bulkin_pipe = NULL;
1115	}
1116
1117	if (sc->sc_bulkout_pipe != NULL) {
1118		err = usbd_abort_pipe(sc->sc_bulkout_pipe);
1119		if (err)
1120			printf("%s: abort tx pipe failed: %s\n",
1121			    DEVNAME(sc), usbd_errstr(err));
1122		err = usbd_close_pipe(sc->sc_bulkout_pipe);
1123		if (err)
1124			printf("%s: close tx pipe failed: %s\n",
1125			    DEVNAME(sc), usbd_errstr(err));
1126		sc->sc_bulkout_pipe = NULL;
1127	}
1128
1129	for (i = 0; i < RNDIS_RX_LIST_CNT; i++) {
1130		if (sc->sc_data.sc_rx_chain[i].sc_mbuf != NULL) {
1131			m_freem(sc->sc_data.sc_rx_chain[i].sc_mbuf);
1132			sc->sc_data.sc_rx_chain[i].sc_mbuf = NULL;
1133		}
1134		if (sc->sc_data.sc_rx_chain[i].sc_xfer != NULL) {
1135			usbd_free_xfer(sc->sc_data.sc_rx_chain[i].sc_xfer);
1136			sc->sc_data.sc_rx_chain[i].sc_xfer = NULL;
1137		}
1138	}
1139
1140	for (i = 0; i < RNDIS_TX_LIST_CNT; i++) {
1141		if (sc->sc_data.sc_tx_chain[i].sc_mbuf != NULL) {
1142			m_freem(sc->sc_data.sc_tx_chain[i].sc_mbuf);
1143			sc->sc_data.sc_tx_chain[i].sc_mbuf = NULL;
1144		}
1145		if (sc->sc_data.sc_tx_chain[i].sc_xfer != NULL) {
1146			usbd_free_xfer(sc->sc_data.sc_tx_chain[i].sc_xfer);
1147			sc->sc_data.sc_tx_chain[i].sc_xfer = NULL;
1148		}
1149	}
1150}
1151
1152static void
1153urndis_start(struct ifnet *ifp)
1154{
1155	struct urndis_softc	*sc;
1156	struct mbuf		*m_head = NULL;
1157
1158	sc = ifp->if_softc;
1159
1160	if (sc->sc_dying || (ifp->if_flags & IFF_OACTIVE))
1161		return;
1162
1163	IFQ_POLL(&ifp->if_snd, m_head);
1164	if (m_head == NULL)
1165		return;
1166
1167	if (urndis_encap(sc, m_head, 0)) {
1168		ifp->if_flags |= IFF_OACTIVE;
1169		return;
1170	}
1171	IFQ_DEQUEUE(&ifp->if_snd, m_head);
1172
1173	/*
1174	 * If there's a BPF listener, bounce a copy of this frame
1175	 * to him.
1176	 */
1177	bpf_mtap(ifp, m_head);
1178
1179	ifp->if_flags |= IFF_OACTIVE;
1180
1181	/*
1182	 * Set a timeout in case the chip goes out to lunch.
1183	 */
1184	ifp->if_timer = 5;
1185
1186	return;
1187}
1188
1189static void
1190urndis_rxeof(usbd_xfer_handle xfer,
1191    usbd_private_handle priv,
1192    usbd_status status)
1193{
1194	struct urndis_chain	*c;
1195	struct urndis_softc	*sc;
1196	struct ifnet		*ifp;
1197	uint32_t		 total_len;
1198
1199	c = priv;
1200	sc = c->sc_softc;
1201	ifp = GET_IFP(sc);
1202	total_len = 0;
1203
1204	if (sc->sc_dying || !(ifp->if_flags & IFF_RUNNING))
1205		return;
1206
1207	if (status != USBD_NORMAL_COMPLETION) {
1208		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
1209			return;
1210		if (usbd_ratecheck(&sc->sc_rx_notice)) {
1211			printf("%s: usb errors on rx: %s\n",
1212			    DEVNAME(sc), usbd_errstr(status));
1213		}
1214		if (status == USBD_STALLED)
1215			usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
1216
1217		goto done;
1218	}
1219
1220	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
1221	urndis_decap(sc, c, total_len);
1222
1223done:
1224	/* Setup new transfer. */
1225	usbd_setup_xfer(c->sc_xfer, sc->sc_bulkin_pipe, c, c->sc_buf,
1226	    RNDIS_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
1227	    urndis_rxeof);
1228	usbd_transfer(c->sc_xfer);
1229}
1230
1231static void
1232urndis_txeof(usbd_xfer_handle xfer,
1233    usbd_private_handle priv,
1234    usbd_status status)
1235{
1236	struct urndis_chain	*c;
1237	struct urndis_softc	*sc;
1238	struct ifnet		*ifp;
1239	usbd_status		 err;
1240	int			 s;
1241
1242	c = priv;
1243	sc = c->sc_softc;
1244	ifp = GET_IFP(sc);
1245
1246	DPRINTF(("%s: urndis_txeof\n", DEVNAME(sc)));
1247
1248	if (sc->sc_dying)
1249		return;
1250
1251	s = splnet();
1252
1253	ifp->if_timer = 0;
1254	ifp->if_flags &= ~IFF_OACTIVE;
1255
1256	if (status != USBD_NORMAL_COMPLETION) {
1257		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
1258			splx(s);
1259			return;
1260		}
1261		ifp->if_oerrors++;
1262		printf("%s: usb error on tx: %s\n", DEVNAME(sc),
1263		    usbd_errstr(status));
1264		if (status == USBD_STALLED)
1265			usbd_clear_endpoint_stall_async(sc->sc_bulkout_pipe);
1266		splx(s);
1267		return;
1268	}
1269
1270	usbd_get_xfer_status(c->sc_xfer, NULL, NULL, NULL, &err);
1271
1272	if (c->sc_mbuf != NULL) {
1273		m_freem(c->sc_mbuf);
1274		c->sc_mbuf = NULL;
1275	}
1276
1277	if (err)
1278		ifp->if_oerrors++;
1279	else
1280		ifp->if_opackets++;
1281
1282	if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
1283		urndis_start(ifp);
1284
1285	splx(s);
1286}
1287
1288static int
1289urndis_match(device_t parent, cfdata_t match, void *aux)
1290{
1291	struct usbif_attach_arg		*uaa;
1292	usb_interface_descriptor_t	*id;
1293
1294	uaa = aux;
1295
1296	if (!uaa->iface)
1297		return (UMATCH_NONE);
1298
1299	id = usbd_get_interface_descriptor(uaa->iface);
1300	if (id == NULL)
1301		return (UMATCH_NONE);
1302
1303	if (id->bInterfaceClass == UICLASS_WIRELESS &&
1304	    id->bInterfaceSubClass == UISUBCLASS_RF &&
1305	    id->bInterfaceProtocol == UIPROTO_RNDIS)
1306		return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO);
1307
1308	return (usb_lookup(urndis_devs, uaa->vendor, uaa->product) != NULL) ?
1309	    UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
1310}
1311
1312static void
1313urndis_attach(device_t parent, device_t self, void *aux)
1314{
1315	struct urndis_softc		*sc;
1316	struct usbif_attach_arg		*uaa;
1317	struct ifnet			*ifp;
1318	usb_interface_descriptor_t	*id;
1319	usb_endpoint_descriptor_t	*ed;
1320	usb_config_descriptor_t		*cd;
1321	const usb_cdc_union_descriptor_t *ud;
1322	const usb_cdc_header_descriptor_t *desc;
1323	usbd_desc_iter_t		 iter;
1324	int				 if_ctl, if_data;
1325	int				 i, j, altcnt;
1326	int				 s;
1327	u_char				 eaddr[ETHER_ADDR_LEN];
1328	void				*buf;
1329	size_t				 bufsz;
1330	uint32_t			 filter;
1331	char				*devinfop;
1332
1333	sc = device_private(self);
1334	uaa = aux;
1335	sc->sc_dev = self;
1336	sc->sc_udev = uaa->device;
1337
1338	aprint_naive("\n");
1339	aprint_normal("\n");
1340
1341	devinfop = usbd_devinfo_alloc(uaa->device, 0);
1342	aprint_normal_dev(self, "%s\n", devinfop);
1343	usbd_devinfo_free(devinfop);
1344
1345	sc->sc_iface_ctl = uaa->iface;
1346	id = usbd_get_interface_descriptor(sc->sc_iface_ctl);
1347	if_ctl = id->bInterfaceNumber;
1348	sc->sc_ifaceno_ctl = if_ctl;
1349	if_data = -1;
1350
1351	usb_desc_iter_init(sc->sc_udev, &iter);
1352	while ((desc = (const void *)usb_desc_iter_next(&iter)) != NULL) {
1353
1354		if (desc->bDescriptorType != UDESC_CS_INTERFACE) {
1355			continue;
1356		}
1357		switch (desc->bDescriptorSubtype) {
1358		case UDESCSUB_CDC_UNION:
1359			/* XXX bail out when found first? */
1360			ud = (const usb_cdc_union_descriptor_t *)desc;
1361			if (if_data == -1)
1362				if_data = ud->bSlaveInterface[0];
1363			break;
1364		}
1365	}
1366
1367	if (if_data == -1) {
1368		DPRINTF(("urndis_attach: no union interface\n"));
1369		sc->sc_iface_data = sc->sc_iface_ctl;
1370	} else {
1371		DPRINTF(("urndis_attach: union interface: ctl %u, data %u\n",
1372		    if_ctl, if_data));
1373		for (i = 0; i < uaa->nifaces; i++) {
1374			if (uaa->ifaces[i] != NULL) {
1375				id = usbd_get_interface_descriptor(
1376				    uaa->ifaces[i]);
1377				if (id != NULL && id->bInterfaceNumber ==
1378				    if_data) {
1379					sc->sc_iface_data = uaa->ifaces[i];
1380					uaa->ifaces[i] = NULL;
1381				}
1382			}
1383		}
1384	}
1385
1386	if (sc->sc_iface_data == NULL) {
1387		printf("%s: no data interface\n", DEVNAME(sc));
1388		return;
1389	}
1390
1391	id = usbd_get_interface_descriptor(sc->sc_iface_data);
1392	cd = usbd_get_config_descriptor(sc->sc_udev);
1393	altcnt = usbd_get_no_alts(cd, id->bInterfaceNumber);
1394
1395	for (j = 0; j < altcnt; j++) {
1396		if (usbd_set_interface(sc->sc_iface_data, j)) {
1397			printf("%s: interface alternate setting %u failed\n",
1398			    DEVNAME(sc), j);
1399			return;
1400		}
1401		/* Find endpoints. */
1402		id = usbd_get_interface_descriptor(sc->sc_iface_data);
1403		sc->sc_bulkin_no = sc->sc_bulkout_no = -1;
1404		for (i = 0; i < id->bNumEndpoints; i++) {
1405			ed = usbd_interface2endpoint_descriptor(
1406			    sc->sc_iface_data, i);
1407			if (!ed) {
1408				printf("%s: no descriptor for bulk endpoint "
1409				    "%u\n", DEVNAME(sc), i);
1410				return;
1411			}
1412			if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
1413			    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
1414				sc->sc_bulkin_no = ed->bEndpointAddress;
1415			}
1416			else if (
1417			    UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
1418			    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
1419				sc->sc_bulkout_no = ed->bEndpointAddress;
1420			}
1421		}
1422
1423		if (sc->sc_bulkin_no != -1 && sc->sc_bulkout_no != -1) {
1424			DPRINTF(("%s: in=0x%x, out=0x%x\n",
1425			    DEVNAME(sc),
1426			    sc->sc_bulkin_no,
1427			    sc->sc_bulkout_no));
1428			goto found;
1429		}
1430	}
1431
1432	if (sc->sc_bulkin_no == -1)
1433		printf("%s: could not find data bulk in\n", DEVNAME(sc));
1434	if (sc->sc_bulkout_no == -1 )
1435		printf("%s: could not find data bulk out\n", DEVNAME(sc));
1436	return;
1437
1438	found:
1439
1440	ifp = GET_IFP(sc);
1441	ifp->if_softc = sc;
1442	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1443	ifp->if_start = urndis_start;
1444	ifp->if_ioctl = urndis_ioctl;
1445#if 0
1446	ifp->if_watchdog = urndis_watchdog;
1447#endif
1448
1449	strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
1450
1451	IFQ_SET_READY(&ifp->if_snd);
1452
1453	urndis_init(ifp);
1454
1455	s = splnet();
1456
1457	if (urndis_ctrl_query(sc, OID_802_3_PERMANENT_ADDRESS, NULL, 0,
1458	    &buf, &bufsz) != RNDIS_STATUS_SUCCESS) {
1459		printf("%s: unable to get hardware address\n", DEVNAME(sc));
1460		urndis_stop(ifp);
1461		splx(s);
1462		return;
1463	}
1464
1465	if (bufsz == ETHER_ADDR_LEN) {
1466		memcpy(eaddr, buf, ETHER_ADDR_LEN);
1467		printf("%s: address %s\n", DEVNAME(sc), ether_sprintf(eaddr));
1468		kmem_free(buf, bufsz);
1469	} else {
1470		printf("%s: invalid address\n", DEVNAME(sc));
1471		kmem_free(buf, bufsz);
1472		urndis_stop(ifp);
1473		splx(s);
1474		return;
1475	}
1476
1477	/* Initialize packet filter */
1478	sc->sc_filter = RNDIS_PACKET_TYPE_BROADCAST;
1479	sc->sc_filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST;
1480	filter = htole32(sc->sc_filter);
1481	if (urndis_ctrl_set(sc, OID_GEN_CURRENT_PACKET_FILTER, &filter,
1482	    sizeof(filter)) != RNDIS_STATUS_SUCCESS) {
1483		printf("%s: unable to set data filters\n", DEVNAME(sc));
1484		urndis_stop(ifp);
1485		splx(s);
1486		return;
1487	}
1488
1489	if_attach(ifp);
1490	ether_ifattach(ifp, eaddr);
1491	sc->sc_attached = 1;
1492
1493	splx(s);
1494}
1495
1496static int
1497urndis_detach(device_t self, int flags)
1498{
1499	struct urndis_softc	*sc;
1500	struct ifnet		*ifp;
1501	int			 s;
1502
1503	sc = device_private(self);
1504
1505	DPRINTF(("urndis_detach: %s flags %u\n", DEVNAME(sc),
1506	    flags));
1507
1508	if (!sc->sc_attached)
1509		return 0;
1510
1511	s = splusb();
1512
1513	ifp = GET_IFP(sc);
1514
1515	if (ifp->if_softc != NULL) {
1516		ether_ifdetach(ifp);
1517		if_detach(ifp);
1518	}
1519
1520	urndis_stop(ifp);
1521	sc->sc_attached = 0;
1522
1523	splx(s);
1524
1525	return 0;
1526}
1527
1528static int
1529urndis_activate(device_t self, enum devact act)
1530{
1531	struct urndis_softc *sc;
1532
1533	sc = device_private(self);
1534
1535	switch (act) {
1536	case DVACT_DEACTIVATE:
1537		sc->sc_dying = 1;
1538		return 0;
1539	}
1540
1541	return EOPNOTSUPP;
1542}
1543
1544