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