xref: /netbsd-src/sys/dev/usb/if_urndis.c (revision 2718af68c3efc72c9769069b5c7f9ed36f6b9def)
1 /*	$NetBSD: if_urndis.c,v 1.47 2022/03/03 05:56:58 riastradh 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.47 2022/03/03 05:56:58 riastradh Exp $");
25 
26 #ifdef _KERNEL_OPT
27 #include "opt_usb.h"
28 #endif
29 
30 #include <sys/param.h>
31 #include <sys/kmem.h>
32 
33 #include <dev/usb/usbnet.h>
34 #include <dev/usb/usbdevs.h>
35 #include <dev/usb/usbcdc.h>
36 
37 #include <dev/ic/rndisreg.h>
38 
39 #define RNDIS_RX_LIST_CNT	1
40 #define RNDIS_TX_LIST_CNT	1
41 #define RNDIS_BUFSZ		1562
42 
43 struct urndis_softc {
44 	struct usbnet			sc_un;
45 
46 	int				sc_ifaceno_ctl;
47 
48 	/* RNDIS device info */
49 	uint32_t			sc_filter;
50 	uint32_t			sc_maxppt;
51 	uint32_t			sc_maxtsz;
52 	uint32_t			sc_palign;
53 };
54 
55 #ifdef URNDIS_DEBUG
56 #define DPRINTF(x)      do { printf x; } while (0)
57 #else
58 #define DPRINTF(x)
59 #endif
60 
61 #define DEVNAME(un)	(device_xname(un->un_dev))
62 
63 #define URNDIS_RESPONSE_LEN 0x400
64 
65 #if 0
66 static void urndis_watchdog(struct ifnet *);
67 #endif
68 
69 static int urndis_uno_init(struct ifnet *);
70 static void urndis_uno_rx_loop(struct usbnet *, struct usbnet_chain *,
71 			       uint32_t);
72 static unsigned urndis_uno_tx_prepare(struct usbnet *, struct mbuf *,
73 				      struct usbnet_chain *);
74 
75 static uint32_t urndis_ctrl_handle_init(struct usbnet *,
76     const struct rndis_comp_hdr *);
77 static uint32_t urndis_ctrl_handle_query(struct usbnet *,
78     const struct rndis_comp_hdr *, void **, size_t *);
79 static uint32_t urndis_ctrl_handle_reset(struct usbnet *,
80     const struct rndis_comp_hdr *);
81 static uint32_t urndis_ctrl_handle_status(struct usbnet *,
82     const struct rndis_comp_hdr *);
83 
84 static uint32_t urndis_ctrl_set(struct usbnet *, uint32_t, void *,
85     size_t);
86 
87 static int urndis_match(device_t, cfdata_t, void *);
88 static void urndis_attach(device_t, device_t, void *);
89 
90 static const struct usbnet_ops urndis_ops = {
91 	.uno_init = urndis_uno_init,
92 	.uno_tx_prepare = urndis_uno_tx_prepare,
93 	.uno_rx_loop = urndis_uno_rx_loop,
94 };
95 
96 CFATTACH_DECL_NEW(urndis, sizeof(struct urndis_softc),
97     urndis_match, urndis_attach, usbnet_detach, usbnet_activate);
98 
99 /*
100  * Supported devices that we can't match by class IDs.
101  */
102 static const struct usb_devno urndis_devs[] = {
103 	{ USB_VENDOR_HTC,	USB_PRODUCT_HTC_ANDROID },
104 	{ USB_VENDOR_SAMSUNG,	USB_PRODUCT_SAMSUNG_ANDROID2 },
105 	{ USB_VENDOR_SAMSUNG,	USB_PRODUCT_SAMSUNG_ANDROID },
106 };
107 
108 static usbd_status
109 urndis_ctrl_msg(struct usbnet *un, uint8_t rt, uint8_t r,
110     uint16_t index, uint16_t value, void *buf, size_t buflen)
111 {
112 	usb_device_request_t req;
113 
114 	req.bmRequestType = rt;
115 	req.bRequest = r;
116 	USETW(req.wValue, value);
117 	USETW(req.wIndex, index);
118 	USETW(req.wLength, buflen);
119 
120 	return usbd_do_request(un->un_udev, &req, buf);
121 }
122 
123 static usbd_status
124 urndis_ctrl_send(struct usbnet *un, void *buf, size_t len)
125 {
126 	struct urndis_softc	*sc = usbnet_softc(un);
127 	usbd_status err;
128 
129 	if (usbnet_isdying(un))
130 		return(0);
131 
132 	err = urndis_ctrl_msg(un, UT_WRITE_CLASS_INTERFACE, UR_GET_STATUS,
133 	    sc->sc_ifaceno_ctl, 0, buf, len);
134 
135 	if (err != USBD_NORMAL_COMPLETION)
136 		printf("%s: %s\n", DEVNAME(un), usbd_errstr(err));
137 
138 	return err;
139 }
140 
141 static struct rndis_comp_hdr *
142 urndis_ctrl_recv(struct usbnet *un)
143 {
144 	struct urndis_softc	*sc = usbnet_softc(un);
145 	struct rndis_comp_hdr	*hdr;
146 	char			*buf;
147 	usbd_status		 err;
148 
149 	if (usbnet_isdying(un))
150 		return(0);
151 
152 	buf = kmem_alloc(URNDIS_RESPONSE_LEN, KM_SLEEP);
153 	err = urndis_ctrl_msg(un, UT_READ_CLASS_INTERFACE, UR_CLEAR_FEATURE,
154 	    sc->sc_ifaceno_ctl, 0, buf, URNDIS_RESPONSE_LEN);
155 
156 	if (err != USBD_NORMAL_COMPLETION && err != USBD_SHORT_XFER) {
157 		printf("%s: %s\n", DEVNAME(un), usbd_errstr(err));
158 		kmem_free(buf, URNDIS_RESPONSE_LEN);
159 		return NULL;
160 	}
161 
162 	hdr = (struct rndis_comp_hdr *)buf;
163 	DPRINTF(("%s: urndis_ctrl_recv: type %#x len %u\n",
164 	    DEVNAME(un),
165 	    le32toh(hdr->rm_type),
166 	    le32toh(hdr->rm_len)));
167 
168 	if (le32toh(hdr->rm_len) > URNDIS_RESPONSE_LEN) {
169 		printf("%s: ctrl message error: wrong size %u > %u\n",
170 		    DEVNAME(un),
171 		    le32toh(hdr->rm_len),
172 		    URNDIS_RESPONSE_LEN);
173 		kmem_free(buf, URNDIS_RESPONSE_LEN);
174 		return NULL;
175 	}
176 
177 	return hdr;
178 }
179 
180 static uint32_t
181 urndis_ctrl_handle(struct usbnet *un, struct rndis_comp_hdr *hdr,
182     void **buf, size_t *bufsz)
183 {
184 	uint32_t rval;
185 
186 	DPRINTF(("%s: urndis_ctrl_handle\n", DEVNAME(un)));
187 
188 	if (buf && bufsz) {
189 		*buf = NULL;
190 		*bufsz = 0;
191 	}
192 
193 	switch (le32toh(hdr->rm_type)) {
194 		case REMOTE_NDIS_INITIALIZE_CMPLT:
195 			rval = urndis_ctrl_handle_init(un, hdr);
196 			break;
197 
198 		case REMOTE_NDIS_QUERY_CMPLT:
199 			rval = urndis_ctrl_handle_query(un, hdr, buf, bufsz);
200 			break;
201 
202 		case REMOTE_NDIS_RESET_CMPLT:
203 			rval = urndis_ctrl_handle_reset(un, hdr);
204 			break;
205 
206 		case REMOTE_NDIS_KEEPALIVE_CMPLT:
207 		case REMOTE_NDIS_SET_CMPLT:
208 			rval = le32toh(hdr->rm_status);
209 			break;
210 
211 		case REMOTE_NDIS_INDICATE_STATUS_MSG:
212 			rval = urndis_ctrl_handle_status(un, hdr);
213 			break;
214 
215 		default:
216 			printf("%s: ctrl message error: unknown event %#x\n",
217 			    DEVNAME(un), le32toh(hdr->rm_type));
218 			rval = RNDIS_STATUS_FAILURE;
219 	}
220 
221 	kmem_free(hdr, URNDIS_RESPONSE_LEN);
222 
223 	return rval;
224 }
225 
226 static uint32_t
227 urndis_ctrl_handle_init(struct usbnet *un, const struct rndis_comp_hdr *hdr)
228 {
229 	struct urndis_softc		*sc = usbnet_softc(un);
230 	const struct rndis_init_comp	*msg;
231 
232 	msg = (const struct rndis_init_comp *) hdr;
233 
234 	DPRINTF(("%s: urndis_ctrl_handle_init: len %u rid %u status %#x "
235 	    "ver_major %u ver_minor %u devflags %#x medium %#x pktmaxcnt %u "
236 	    "pktmaxsz %u align %u aflistoffset %u aflistsz %u\n",
237 	    DEVNAME(un),
238 	    le32toh(msg->rm_len),
239 	    le32toh(msg->rm_rid),
240 	    le32toh(msg->rm_status),
241 	    le32toh(msg->rm_ver_major),
242 	    le32toh(msg->rm_ver_minor),
243 	    le32toh(msg->rm_devflags),
244 	    le32toh(msg->rm_medium),
245 	    le32toh(msg->rm_pktmaxcnt),
246 	    le32toh(msg->rm_pktmaxsz),
247 	    le32toh(msg->rm_align),
248 	    le32toh(msg->rm_aflistoffset),
249 	    le32toh(msg->rm_aflistsz)));
250 
251 	if (le32toh(msg->rm_status) != RNDIS_STATUS_SUCCESS) {
252 		printf("%s: init failed %#x\n",
253 		    DEVNAME(un),
254 		    le32toh(msg->rm_status));
255 
256 		return le32toh(msg->rm_status);
257 	}
258 
259 	if (le32toh(msg->rm_devflags) != RNDIS_DF_CONNECTIONLESS) {
260 		printf("%s: wrong device type (current type: %#x)\n",
261 		    DEVNAME(un),
262 		    le32toh(msg->rm_devflags));
263 
264 		return RNDIS_STATUS_FAILURE;
265 	}
266 
267 	if (le32toh(msg->rm_medium) != RNDIS_MEDIUM_802_3) {
268 		printf("%s: medium not 802.3 (current medium: %#x)\n",
269 		    DEVNAME(un), le32toh(msg->rm_medium));
270 
271 		return RNDIS_STATUS_FAILURE;
272 	}
273 
274 	if (le32toh(msg->rm_ver_major) != RNDIS_MAJOR_VERSION ||
275 	    le32toh(msg->rm_ver_minor) != RNDIS_MINOR_VERSION) {
276 		printf("%s: version not %u.%u (current version: %u.%u)\n",
277 		    DEVNAME(un), RNDIS_MAJOR_VERSION, RNDIS_MINOR_VERSION,
278 		    le32toh(msg->rm_ver_major), le32toh(msg->rm_ver_minor));
279 
280 		return RNDIS_STATUS_FAILURE;
281 	}
282 
283 	sc->sc_maxppt = le32toh(msg->rm_pktmaxcnt);
284 	sc->sc_maxtsz = le32toh(msg->rm_pktmaxsz);
285 	sc->sc_palign = 1U << le32toh(msg->rm_align);
286 
287 	return le32toh(msg->rm_status);
288 }
289 
290 static uint32_t
291 urndis_ctrl_handle_query(struct usbnet *un,
292     const struct rndis_comp_hdr *hdr, void **buf, size_t *bufsz)
293 {
294 	const struct rndis_query_comp	*msg;
295 
296 	msg = (const struct rndis_query_comp *) hdr;
297 
298 	DPRINTF(("%s: urndis_ctrl_handle_query: len %u rid %u status %#x "
299 	    "buflen %u bufoff %u\n",
300 	    DEVNAME(un),
301 	    le32toh(msg->rm_len),
302 	    le32toh(msg->rm_rid),
303 	    le32toh(msg->rm_status),
304 	    le32toh(msg->rm_infobuflen),
305 	    le32toh(msg->rm_infobufoffset)));
306 
307 	if (buf && bufsz) {
308 		*buf = NULL;
309 		*bufsz = 0;
310 	}
311 
312 	if (le32toh(msg->rm_status) != RNDIS_STATUS_SUCCESS) {
313 		printf("%s: query failed %#x\n",
314 		    DEVNAME(un),
315 		    le32toh(msg->rm_status));
316 
317 		return le32toh(msg->rm_status);
318 	}
319 
320 	if (le32toh(msg->rm_infobuflen) + le32toh(msg->rm_infobufoffset) +
321 	    RNDIS_HEADER_OFFSET > le32toh(msg->rm_len)) {
322 		printf("%s: ctrl message error: invalid query info "
323 		    "len/offset/end_position(%u/%u/%u) -> "
324 		    "go out of buffer limit %u\n",
325 		    DEVNAME(un),
326 		    le32toh(msg->rm_infobuflen),
327 		    le32toh(msg->rm_infobufoffset),
328 		    le32toh(msg->rm_infobuflen) +
329 		    le32toh(msg->rm_infobufoffset) + (uint32_t)RNDIS_HEADER_OFFSET,
330 		    le32toh(msg->rm_len));
331 		return RNDIS_STATUS_FAILURE;
332 	}
333 
334 	if (buf && bufsz) {
335 		const char *p;
336 
337 		*buf = kmem_alloc(le32toh(msg->rm_infobuflen), KM_SLEEP);
338 		*bufsz = le32toh(msg->rm_infobuflen);
339 
340 		p = (const char *)&msg->rm_rid;
341 		p += le32toh(msg->rm_infobufoffset);
342 		memcpy(*buf, p, le32toh(msg->rm_infobuflen));
343 	}
344 
345 	return le32toh(msg->rm_status);
346 }
347 
348 static uint32_t
349 urndis_ctrl_handle_reset(struct usbnet *un, const struct rndis_comp_hdr *hdr)
350 {
351 	struct urndis_softc		*sc = usbnet_softc(un);
352 	const struct rndis_reset_comp	*msg;
353 	uint32_t			 rval;
354 
355 	msg = (const struct rndis_reset_comp *) hdr;
356 
357 	rval = le32toh(msg->rm_status);
358 
359 	DPRINTF(("%s: urndis_ctrl_handle_reset: len %u status %#x "
360 	    "adrreset %u\n",
361 	    DEVNAME(un),
362 	    le32toh(msg->rm_len),
363 	    rval,
364 	    le32toh(msg->rm_adrreset)));
365 
366 	if (rval != RNDIS_STATUS_SUCCESS) {
367 		printf("%s: reset failed %#x\n", DEVNAME(un), rval);
368 		return rval;
369 	}
370 
371 	if (le32toh(msg->rm_adrreset) != 0) {
372 		uint32_t filter;
373 
374 		filter = htole32(sc->sc_filter);
375 		rval = urndis_ctrl_set(un, OID_GEN_CURRENT_PACKET_FILTER,
376 		    &filter, sizeof(filter));
377 		if (rval != RNDIS_STATUS_SUCCESS) {
378 			printf("%s: unable to reset data filters\n",
379 			    DEVNAME(un));
380 			return rval;
381 		}
382 	}
383 
384 	return rval;
385 }
386 
387 static uint32_t
388 urndis_ctrl_handle_status(struct usbnet *un,
389     const struct rndis_comp_hdr *hdr)
390 {
391 	const struct rndis_status_msg	*msg;
392 	uint32_t			rval;
393 
394 	msg = (const struct rndis_status_msg *)hdr;
395 
396 	rval = le32toh(msg->rm_status);
397 
398 	DPRINTF(("%s: urndis_ctrl_handle_status: len %u status %#x "
399 	    "stbuflen %u\n",
400 	    DEVNAME(un),
401 	    le32toh(msg->rm_len),
402 	    rval,
403 	    le32toh(msg->rm_stbuflen)));
404 
405 	switch (rval) {
406 		case RNDIS_STATUS_MEDIA_CONNECT:
407 		case RNDIS_STATUS_MEDIA_DISCONNECT:
408 		case RNDIS_STATUS_OFFLOAD_CURRENT_CONFIG:
409 			rval = RNDIS_STATUS_SUCCESS;
410 			break;
411 
412 		default:
413 		        printf("%s: status %#x\n", DEVNAME(un), rval);
414 	}
415 
416 	return rval;
417 }
418 
419 static uint32_t
420 urndis_ctrl_init(struct usbnet *un)
421 {
422 	struct rndis_init_req	*msg;
423 	uint32_t		 rval;
424 	struct rndis_comp_hdr	*hdr;
425 
426 	msg = kmem_alloc(sizeof(*msg), KM_SLEEP);
427 	msg->rm_type = htole32(REMOTE_NDIS_INITIALIZE_MSG);
428 	msg->rm_len = htole32(sizeof(*msg));
429 	msg->rm_rid = htole32(0);
430 	msg->rm_ver_major = htole32(RNDIS_MAJOR_VERSION);
431 	msg->rm_ver_minor = htole32(RNDIS_MINOR_VERSION);
432 	msg->rm_max_xfersz = htole32(RNDIS_BUFSZ);
433 
434 	DPRINTF(("%s: urndis_ctrl_init send: type %u len %u rid %u ver_major %u "
435 	    "ver_minor %u max_xfersz %u\n",
436 	    DEVNAME(un),
437 	    le32toh(msg->rm_type),
438 	    le32toh(msg->rm_len),
439 	    le32toh(msg->rm_rid),
440 	    le32toh(msg->rm_ver_major),
441 	    le32toh(msg->rm_ver_minor),
442 	    le32toh(msg->rm_max_xfersz)));
443 
444 	rval = urndis_ctrl_send(un, msg, sizeof(*msg));
445 	kmem_free(msg, sizeof(*msg));
446 
447 	if (rval != RNDIS_STATUS_SUCCESS) {
448 		printf("%s: init failed\n", DEVNAME(un));
449 		return rval;
450 	}
451 
452 	if ((hdr = urndis_ctrl_recv(un)) == NULL) {
453 		printf("%s: unable to get init response\n", DEVNAME(un));
454 		return RNDIS_STATUS_FAILURE;
455 	}
456 	rval = urndis_ctrl_handle(un, hdr, NULL, NULL);
457 
458 	return rval;
459 }
460 
461 #if 0
462 static uint32_t
463 urndis_ctrl_halt(struct usbnet *un)
464 {
465 	struct rndis_halt_req	*msg;
466 	uint32_t		 rval;
467 
468 	msg = kmem_alloc(sizeof(*msg), KM_SLEEP);
469 	msg->rm_type = htole32(REMOTE_NDIS_HALT_MSG);
470 	msg->rm_len = htole32(sizeof(*msg));
471 	msg->rm_rid = 0;
472 
473 	DPRINTF(("%s: urndis_ctrl_halt send: type %u len %u rid %u\n",
474 	    DEVNAME(un),
475 	    le32toh(msg->rm_type),
476 	    le32toh(msg->rm_len),
477 	    le32toh(msg->rm_rid)));
478 
479 	rval = urndis_ctrl_send(un, msg, sizeof(*msg));
480 	kmem_free(msg, sizeof(*msg));
481 
482 	if (rval != RNDIS_STATUS_SUCCESS)
483 		printf("%s: halt failed\n", DEVNAME(un));
484 
485 	return rval;
486 }
487 #endif
488 
489 static uint32_t
490 urndis_ctrl_query(struct usbnet *un, uint32_t oid,
491     void *qbuf, size_t qlen,
492     void **rbuf, size_t *rbufsz)
493 {
494 	struct rndis_query_req	*msg;
495 	uint32_t		 rval;
496 	struct rndis_comp_hdr	*hdr;
497 
498 	msg = kmem_alloc(sizeof(*msg) + qlen, KM_SLEEP);
499 	msg->rm_type = htole32(REMOTE_NDIS_QUERY_MSG);
500 	msg->rm_len = htole32(sizeof(*msg) + qlen);
501 	msg->rm_rid = 0; /* XXX */
502 	msg->rm_oid = htole32(oid);
503 	msg->rm_infobuflen = htole32(qlen);
504 	if (qlen != 0) {
505 		msg->rm_infobufoffset = htole32(20);
506 		memcpy((char*)msg + 20, qbuf, qlen);
507 	} else
508 		msg->rm_infobufoffset = 0;
509 	msg->rm_devicevchdl = 0;
510 
511 	DPRINTF(("%s: urndis_ctrl_query send: type %u len %u rid %u oid %#x "
512 	    "infobuflen %u infobufoffset %u devicevchdl %u\n",
513 	    DEVNAME(un),
514 	    le32toh(msg->rm_type),
515 	    le32toh(msg->rm_len),
516 	    le32toh(msg->rm_rid),
517 	    le32toh(msg->rm_oid),
518 	    le32toh(msg->rm_infobuflen),
519 	    le32toh(msg->rm_infobufoffset),
520 	    le32toh(msg->rm_devicevchdl)));
521 
522 	rval = urndis_ctrl_send(un, msg, sizeof(*msg));
523 	kmem_free(msg, sizeof(*msg) + qlen);
524 
525 	if (rval != RNDIS_STATUS_SUCCESS) {
526 		printf("%s: query failed\n", DEVNAME(un));
527 		return rval;
528 	}
529 
530 	if ((hdr = urndis_ctrl_recv(un)) == NULL) {
531 		printf("%s: unable to get query response\n", DEVNAME(un));
532 		return RNDIS_STATUS_FAILURE;
533 	}
534 	rval = urndis_ctrl_handle(un, hdr, rbuf, rbufsz);
535 
536 	return rval;
537 }
538 
539 static uint32_t
540 urndis_ctrl_set(struct usbnet *un, uint32_t oid, void *buf, size_t len)
541 {
542 	struct rndis_set_req	*msg;
543 	uint32_t		 rval;
544 	struct rndis_comp_hdr	*hdr;
545 
546 	msg = kmem_alloc(sizeof(*msg) + len, KM_SLEEP);
547 	msg->rm_type = htole32(REMOTE_NDIS_SET_MSG);
548 	msg->rm_len = htole32(sizeof(*msg) + len);
549 	msg->rm_rid = 0; /* XXX */
550 	msg->rm_oid = htole32(oid);
551 	msg->rm_infobuflen = htole32(len);
552 	if (len != 0) {
553 		msg->rm_infobufoffset = htole32(20);
554 		memcpy((char*)msg + 20, buf, len);
555 	} else
556 		msg->rm_infobufoffset = 0;
557 	msg->rm_devicevchdl = 0;
558 
559 	DPRINTF(("%s: urndis_ctrl_set send: type %u len %u rid %u oid %#x "
560 	    "infobuflen %u infobufoffset %u devicevchdl %u\n",
561 	    DEVNAME(un),
562 	    le32toh(msg->rm_type),
563 	    le32toh(msg->rm_len),
564 	    le32toh(msg->rm_rid),
565 	    le32toh(msg->rm_oid),
566 	    le32toh(msg->rm_infobuflen),
567 	    le32toh(msg->rm_infobufoffset),
568 	    le32toh(msg->rm_devicevchdl)));
569 
570 	rval = urndis_ctrl_send(un, msg, sizeof(*msg));
571 	kmem_free(msg, sizeof(*msg) + len);
572 
573 	if (rval != RNDIS_STATUS_SUCCESS) {
574 		printf("%s: set failed\n", DEVNAME(un));
575 		return rval;
576 	}
577 
578 	if ((hdr = urndis_ctrl_recv(un)) == NULL) {
579 		printf("%s: unable to get set response\n", DEVNAME(un));
580 		return RNDIS_STATUS_FAILURE;
581 	}
582 	rval = urndis_ctrl_handle(un, hdr, NULL, NULL);
583 	if (rval != RNDIS_STATUS_SUCCESS)
584 		printf("%s: set failed %#x\n", DEVNAME(un), rval);
585 
586 	return rval;
587 }
588 
589 #if 0
590 static uint32_t
591 urndis_ctrl_set_param(struct urndis_softc *un,
592     const char *name,
593     uint32_t type,
594     void *buf,
595     size_t len)
596 {
597 	struct rndis_set_parameter	*param;
598 	uint32_t			 rval;
599 	size_t				 namelen, tlen;
600 
601 	if (name)
602 		namelen = strlen(name);
603 	else
604 		namelen = 0;
605 	tlen = sizeof(*param) + len + namelen;
606 	param = kmem_alloc(tlen, KM_SLEEP);
607 	param->rm_namelen = htole32(namelen);
608 	param->rm_valuelen = htole32(len);
609 	param->rm_type = htole32(type);
610 	if (namelen != 0) {
611 		param->rm_nameoffset = htole32(20);
612 		memcpy(param + 20, name, namelen);
613 	} else
614 		param->rm_nameoffset = 0;
615 	if (len != 0) {
616 		param->rm_valueoffset = htole32(20 + namelen);
617 		memcpy(param + 20 + namelen, buf, len);
618 	} else
619 		param->rm_valueoffset = 0;
620 
621 	DPRINTF(("%s: urndis_ctrl_set_param send: nameoffset %u namelen %u "
622 	    "type %#x valueoffset %u valuelen %u\n",
623 	    DEVNAME(un),
624 	    le32toh(param->rm_nameoffset),
625 	    le32toh(param->rm_namelen),
626 	    le32toh(param->rm_type),
627 	    le32toh(param->rm_valueoffset),
628 	    le32toh(param->rm_valuelen)));
629 
630 	rval = urndis_ctrl_set(un, OID_GEN_RNDIS_CONFIG_PARAMETER, param, tlen);
631 	kmem_free(param, tlen);
632 	if (rval != RNDIS_STATUS_SUCCESS)
633 		printf("%s: set param failed %#x\n", DEVNAME(un), rval);
634 
635 	return rval;
636 }
637 
638 /* XXX : adrreset, get it from response */
639 static uint32_t
640 urndis_ctrl_reset(struct usbnet *un)
641 {
642 	struct rndis_reset_req		*reset;
643 	uint32_t			 rval;
644 	struct rndis_comp_hdr		*hdr;
645 
646 	reset = kmem_alloc(sizeof(*reset), KM_SLEEP);
647 	reset->rm_type = htole32(REMOTE_NDIS_RESET_MSG);
648 	reset->rm_len = htole32(sizeof(*reset));
649 	reset->rm_rid = 0; /* XXX rm_rid == reserved ... remove ? */
650 
651 	DPRINTF(("%s: urndis_ctrl_reset send: type %u len %u rid %u\n",
652 	    DEVNAME(un),
653 	    le32toh(reset->rm_type),
654 	    le32toh(reset->rm_len),
655 	    le32toh(reset->rm_rid)));
656 
657 	rval = urndis_ctrl_send(un, reset, sizeof(*reset));
658 	kmem_free(reset, sizeof(*reset));
659 
660 	if (rval != RNDIS_STATUS_SUCCESS) {
661 		printf("%s: reset failed\n", DEVNAME(un));
662 		return rval;
663 	}
664 
665 	if ((hdr = urndis_ctrl_recv(un)) == NULL) {
666 		printf("%s: unable to get reset response\n", DEVNAME(un));
667 		return RNDIS_STATUS_FAILURE;
668 	}
669 	rval = urndis_ctrl_handle(un, hdr, NULL, NULL);
670 
671 	return rval;
672 }
673 
674 static uint32_t
675 urndis_ctrl_keepalive(struct usbnet *un)
676 {
677 	struct rndis_keepalive_req	*keep;
678 	uint32_t			 rval;
679 	struct rndis_comp_hdr		*hdr;
680 
681 	keep = kmem_alloc(sizeof(*keep), KM_SLEEP);
682 	keep->rm_type = htole32(REMOTE_NDIS_KEEPALIVE_MSG);
683 	keep->rm_len = htole32(sizeof(*keep));
684 	keep->rm_rid = 0; /* XXX rm_rid == reserved ... remove ? */
685 
686 	DPRINTF(("%s: urndis_ctrl_keepalive: type %u len %u rid %u\n",
687 	    DEVNAME(un),
688 	    le32toh(keep->rm_type),
689 	    le32toh(keep->rm_len),
690 	    le32toh(keep->rm_rid)));
691 
692 	rval = urndis_ctrl_send(un, keep, sizeof(*keep));
693 	kmem_free(keep, sizeof(*keep));
694 
695 	if (rval != RNDIS_STATUS_SUCCESS) {
696 		printf("%s: keepalive failed\n", DEVNAME(un));
697 		return rval;
698 	}
699 
700 	if ((hdr = urndis_ctrl_recv(un)) == NULL) {
701 		printf("%s: unable to get keepalive response\n", DEVNAME(un));
702 		return RNDIS_STATUS_FAILURE;
703 	}
704 	rval = urndis_ctrl_handle(un, hdr, NULL, NULL);
705 	if (rval != RNDIS_STATUS_SUCCESS) {
706 		printf("%s: keepalive failed %#x\n", DEVNAME(un), rval);
707 		urndis_ctrl_reset(un);
708 	}
709 
710 	return rval;
711 }
712 #endif
713 
714 static unsigned
715 urndis_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c)
716 {
717 	struct rndis_packet_msg		*msg;
718 
719 	if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(*msg))
720 		return 0;
721 
722 	msg = (struct rndis_packet_msg *)c->unc_buf;
723 
724 	memset(msg, 0, sizeof(*msg));
725 	msg->rm_type = htole32(REMOTE_NDIS_PACKET_MSG);
726 	msg->rm_len = htole32(sizeof(*msg) + m->m_pkthdr.len);
727 
728 	msg->rm_dataoffset = htole32(RNDIS_DATA_OFFSET);
729 	msg->rm_datalen = htole32(m->m_pkthdr.len);
730 
731 	m_copydata(m, 0, m->m_pkthdr.len,
732 	    ((char*)msg + RNDIS_DATA_OFFSET + RNDIS_HEADER_OFFSET));
733 
734 	DPRINTF(("%s: %s type %#x len %u data(off %u len %u)\n",
735 	    __func__,
736 	    DEVNAME(un),
737 	    le32toh(msg->rm_type),
738 	    le32toh(msg->rm_len),
739 	    le32toh(msg->rm_dataoffset),
740 	    le32toh(msg->rm_datalen)));
741 
742 	return le32toh(msg->rm_len);
743 }
744 
745 static void
746 urndis_uno_rx_loop(struct usbnet * un, struct usbnet_chain *c,
747 		   uint32_t total_len)
748 {
749 	struct rndis_packet_msg	*msg;
750 	struct ifnet		*ifp = usbnet_ifp(un);
751 	int			 offset;
752 
753 	offset = 0;
754 
755 	while (total_len > 1) {
756 		msg = (struct rndis_packet_msg *)((char*)c->unc_buf + offset);
757 
758 		DPRINTF(("%s: %s buffer size left %u\n", DEVNAME(un), __func__,
759 		    total_len));
760 
761 		if (total_len < sizeof(*msg)) {
762 			printf("%s: urndis_decap invalid buffer total_len %u < "
763 			    "minimum header %zu\n",
764 			    DEVNAME(un),
765 			    total_len,
766 			    sizeof(*msg));
767 			return;
768 		}
769 
770 		DPRINTF(("%s: urndis_decap total_len %u data(off:%u len:%u) "
771 		    "oobdata(off:%u len:%u nb:%u) perpacket(off:%u len:%u)\n",
772 		    DEVNAME(un),
773 		    le32toh(msg->rm_len),
774 		    le32toh(msg->rm_dataoffset),
775 		    le32toh(msg->rm_datalen),
776 		    le32toh(msg->rm_oobdataoffset),
777 		    le32toh(msg->rm_oobdatalen),
778 		    le32toh(msg->rm_oobdataelements),
779 		    le32toh(msg->rm_pktinfooffset),
780 		    le32toh(msg->rm_pktinfooffset)));
781 
782 		if (le32toh(msg->rm_type) != REMOTE_NDIS_PACKET_MSG) {
783 			printf("%s: urndis_decap invalid type %#x != %#x\n",
784 			    DEVNAME(un),
785 			    le32toh(msg->rm_type),
786 			    REMOTE_NDIS_PACKET_MSG);
787 			return;
788 		}
789 		if (le32toh(msg->rm_len) < sizeof(*msg)) {
790 			printf("%s: urndis_decap invalid msg len %u < %zu\n",
791 			    DEVNAME(un),
792 			    le32toh(msg->rm_len),
793 			    sizeof(*msg));
794 			return;
795 		}
796 		if (le32toh(msg->rm_len) > total_len) {
797 			printf("%s: urndis_decap invalid msg len %u > buffer "
798 			    "total_len %u\n",
799 			    DEVNAME(un),
800 			    le32toh(msg->rm_len),
801 			    total_len);
802 			return;
803 		}
804 
805 		if (le32toh(msg->rm_dataoffset) +
806 		    le32toh(msg->rm_datalen) + RNDIS_HEADER_OFFSET
807 		        > le32toh(msg->rm_len)) {
808 			printf("%s: urndis_decap invalid data "
809 			    "len/offset/end_position(%u/%u/%u) -> "
810 			    "go out of receive buffer limit %u\n",
811 			    DEVNAME(un),
812 			    le32toh(msg->rm_datalen),
813 			    le32toh(msg->rm_dataoffset),
814 			    le32toh(msg->rm_dataoffset) +
815 			    le32toh(msg->rm_datalen) + (uint32_t)RNDIS_HEADER_OFFSET,
816 			    le32toh(msg->rm_len));
817 			return;
818 		}
819 
820 		if (le32toh(msg->rm_datalen) < sizeof(struct ether_header)) {
821 			if_statinc(ifp, if_ierrors);
822 			printf("%s: urndis_decap invalid ethernet size "
823 			    "%d < %zu\n",
824 			    DEVNAME(un),
825 			    le32toh(msg->rm_datalen),
826 			    sizeof(struct ether_header));
827 			return;
828 		}
829 
830 		usbnet_enqueue(un,
831 		    ((char*)&msg->rm_dataoffset + le32toh(msg->rm_dataoffset)),
832 		    le32toh(msg->rm_datalen), 0, 0, 0);
833 
834 		offset += le32toh(msg->rm_len);
835 		total_len -= le32toh(msg->rm_len);
836 	}
837 }
838 
839 #if 0
840 static void
841 urndis_watchdog(struct ifnet *ifp)
842 {
843 	struct urndis_softc	*sc = usbnet_softc(un);
844 
845 	if (un->un_dying)
846 		return;
847 
848 	if_statinc(ifp, if_oerrors);
849 	printf("%s: watchdog timeout\n", DEVNAME(un));
850 
851 	urndis_ctrl_keepalive(un);
852 }
853 #endif
854 
855 static int
856 urndis_uno_init(struct ifnet *ifp)
857 {
858 	struct usbnet *un = ifp->if_softc;
859 
860 	KASSERT(IFNET_LOCKED(ifp));
861 
862 	if (urndis_ctrl_init(un) != RNDIS_STATUS_SUCCESS)
863 		return EIO;
864 
865 	return 0;
866 }
867 
868 static int
869 urndis_match(device_t parent, cfdata_t match, void *aux)
870 {
871 	struct usbif_attach_arg		*uiaa = aux;
872 	usb_interface_descriptor_t	*id;
873 
874 	if (!uiaa->uiaa_iface)
875 		return UMATCH_NONE;
876 
877 	id = usbd_get_interface_descriptor(uiaa->uiaa_iface);
878 	if (id == NULL)
879 		return UMATCH_NONE;
880 
881 	if (id->bInterfaceClass == UICLASS_WIRELESS &&
882 	    id->bInterfaceSubClass == UISUBCLASS_RF &&
883 	    id->bInterfaceProtocol == UIPROTO_RNDIS)
884 		return UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO;
885 
886 	return usb_lookup(urndis_devs, uiaa->uiaa_vendor, uiaa->uiaa_product) != NULL ?
887 	    UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
888 }
889 
890 static void
891 urndis_attach(device_t parent, device_t self, void *aux)
892 {
893 	struct urndis_softc		*sc = device_private(self);
894 	struct usbnet * const		 un = &sc->sc_un;
895 	struct usbif_attach_arg		*uiaa = aux;
896 	struct usbd_device	        *dev = uiaa->uiaa_device;
897 	usb_interface_descriptor_t	*id;
898 	usb_endpoint_descriptor_t	*ed;
899 	usb_config_descriptor_t		*cd;
900 	struct usbd_interface		*iface_ctl;
901 	const usb_cdc_union_descriptor_t *ud;
902 	const usb_cdc_header_descriptor_t *desc;
903 	usbd_desc_iter_t		 iter;
904 	int				 if_ctl, if_data;
905 	int				 i, j, altcnt;
906 	void				*buf;
907 	size_t				 bufsz;
908 	uint32_t			 filter;
909 	char				*devinfop;
910 
911 	KASSERT((void *)sc == un);
912 
913 	aprint_naive("\n");
914 	aprint_normal("\n");
915 	devinfop = usbd_devinfo_alloc(dev, 0);
916 	aprint_normal_dev(self, "%s\n", devinfop);
917 	usbd_devinfo_free(devinfop);
918 
919 	un->un_dev = self;
920 	un->un_udev = dev;
921 	un->un_sc = sc;
922 	un->un_ops = &urndis_ops;
923 	un->un_rx_xfer_flags = USBD_SHORT_XFER_OK;
924 	un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER;
925 	un->un_rx_list_cnt = RNDIS_RX_LIST_CNT;
926 	un->un_tx_list_cnt = RNDIS_TX_LIST_CNT;
927 	un->un_rx_bufsz = RNDIS_BUFSZ;
928 	un->un_tx_bufsz = RNDIS_BUFSZ;
929 
930 	iface_ctl = uiaa->uiaa_iface;
931 	un->un_iface = uiaa->uiaa_iface;
932 	id = usbd_get_interface_descriptor(iface_ctl);
933 	if_ctl = id->bInterfaceNumber;
934 	sc->sc_ifaceno_ctl = if_ctl;
935 	if_data = -1;
936 
937 	usb_desc_iter_init(un->un_udev, &iter);
938 	while ((desc = (const void *)usb_desc_iter_next(&iter)) != NULL) {
939 
940 		if (desc->bDescriptorType != UDESC_CS_INTERFACE) {
941 			continue;
942 		}
943 		switch (desc->bDescriptorSubtype) {
944 		case UDESCSUB_CDC_UNION:
945 			/* XXX bail out when found first? */
946 			ud = (const usb_cdc_union_descriptor_t *)desc;
947 			if (if_data == -1)
948 				if_data = ud->bSlaveInterface[0];
949 			break;
950 		}
951 	}
952 
953 	if (if_data == -1) {
954 		DPRINTF(("urndis_attach: no union interface\n"));
955 		un->un_iface = iface_ctl;
956 	} else {
957 		DPRINTF(("urndis_attach: union interface: ctl %u, data %u\n",
958 		    if_ctl, if_data));
959 		for (i = 0; i < uiaa->uiaa_nifaces; i++) {
960 			if (uiaa->uiaa_ifaces[i] != NULL) {
961 				id = usbd_get_interface_descriptor(
962 				    uiaa->uiaa_ifaces[i]);
963 				if (id != NULL && id->bInterfaceNumber ==
964 				    if_data) {
965 					un->un_iface = uiaa->uiaa_ifaces[i];
966 					uiaa->uiaa_ifaces[i] = NULL;
967 				}
968 			}
969 		}
970 	}
971 
972 	if (un->un_iface == NULL) {
973 		aprint_error("%s: no data interface\n", DEVNAME(un));
974 		return;
975 	}
976 
977 	id = usbd_get_interface_descriptor(un->un_iface);
978 	cd = usbd_get_config_descriptor(un->un_udev);
979 	altcnt = usbd_get_no_alts(cd, id->bInterfaceNumber);
980 
981 	for (j = 0; j < altcnt; j++) {
982 		if (usbd_set_interface(un->un_iface, j)) {
983 			aprint_error("%s: interface alternate setting %u "
984 			    "failed\n", DEVNAME(un), j);
985 			return;
986 		}
987 		/* Find endpoints. */
988 		id = usbd_get_interface_descriptor(un->un_iface);
989 		un->un_ed[USBNET_ENDPT_RX] = un->un_ed[USBNET_ENDPT_TX] = 0;
990 		for (i = 0; i < id->bNumEndpoints; i++) {
991 			ed = usbd_interface2endpoint_descriptor(
992 			    un->un_iface, i);
993 			if (!ed) {
994 				aprint_error("%s: no descriptor for bulk "
995 				    "endpoint %u\n", DEVNAME(un), i);
996 				return;
997 			}
998 			if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
999 			    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
1000 				un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress;
1001 			}
1002 			else if (
1003 			    UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
1004 			    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
1005 				un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress;
1006 			}
1007 		}
1008 
1009 		if (un->un_ed[USBNET_ENDPT_RX] != 0 && un->un_ed[USBNET_ENDPT_TX] != 0) {
1010 			DPRINTF(("%s: in=%#x, out=%#x\n",
1011 			    DEVNAME(un),
1012 			    un->un_ed[USBNET_ENDPT_RX],
1013 			    un->un_ed[USBNET_ENDPT_TX]));
1014 			break;
1015 		}
1016 	}
1017 
1018 	if (un->un_ed[USBNET_ENDPT_RX] == 0)
1019 		aprint_error("%s: could not find data bulk in\n", DEVNAME(un));
1020 	if (un->un_ed[USBNET_ENDPT_TX] == 0)
1021 		aprint_error("%s: could not find data bulk out\n",DEVNAME(un));
1022 	if (un->un_ed[USBNET_ENDPT_RX] == 0 || un->un_ed[USBNET_ENDPT_TX] == 0)
1023 		return;
1024 
1025 #if 0
1026 	ifp->if_watchdog = urndis_watchdog;
1027 #endif
1028 
1029 	usbnet_attach(un);
1030 
1031 	if (urndis_ctrl_init(un) != RNDIS_STATUS_SUCCESS) {
1032 		aprint_error("%s: unable to initialize hardware\n",
1033 		    DEVNAME(un));
1034 		return;
1035 	}
1036 
1037 	if (urndis_ctrl_query(un, OID_802_3_PERMANENT_ADDRESS, NULL, 0,
1038 	    &buf, &bufsz) != RNDIS_STATUS_SUCCESS) {
1039 		aprint_error("%s: unable to get hardware address\n",
1040 		    DEVNAME(un));
1041 		return;
1042 	}
1043 
1044 	if (bufsz == ETHER_ADDR_LEN) {
1045 		memcpy(un->un_eaddr, buf, ETHER_ADDR_LEN);
1046 		kmem_free(buf, bufsz);
1047 	} else {
1048 		aprint_error("%s: invalid address\n", DEVNAME(un));
1049 		if (buf && bufsz)
1050 			kmem_free(buf, bufsz);
1051 		return;
1052 	}
1053 
1054 	/* Initialize packet filter */
1055 	sc->sc_filter = RNDIS_PACKET_TYPE_BROADCAST;
1056 	sc->sc_filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST;
1057 	filter = htole32(sc->sc_filter);
1058 	if (urndis_ctrl_set(un, OID_GEN_CURRENT_PACKET_FILTER, &filter,
1059 	    sizeof(filter)) != RNDIS_STATUS_SUCCESS) {
1060 		aprint_error("%s: unable to set data filters\n", DEVNAME(un));
1061 		return;
1062 	}
1063 
1064 	usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST,
1065             0, NULL);
1066 }
1067 
1068 #ifdef _MODULE
1069 #include "ioconf.c"
1070 #endif
1071 
1072 USBNET_MODULE(urndis)
1073