xref: /freebsd/sys/dev/usb/net/if_ipheth.c (revision ca48e43ba9ee73a07cdbad8365117793b01273bb)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2010 Hans Petter Selasky. All rights reserved.
5  * Copyright (c) 2009 Diego Giagio. All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 /*
30  * Thanks to Diego Giagio for figuring out the programming details for
31  * the Apple iPhone Ethernet driver.
32  */
33 
34 #include <sys/stdint.h>
35 #include <sys/stddef.h>
36 #include <sys/param.h>
37 #include <sys/queue.h>
38 #include <sys/types.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/bus.h>
42 #include <sys/module.h>
43 #include <sys/lock.h>
44 #include <sys/mutex.h>
45 #include <sys/condvar.h>
46 #include <sys/socket.h>
47 #include <sys/sysctl.h>
48 #include <sys/sx.h>
49 #include <sys/unistd.h>
50 #include <sys/callout.h>
51 #include <sys/malloc.h>
52 #include <sys/priv.h>
53 
54 #include <net/if.h>
55 #include <net/if_var.h>
56 
57 #include <dev/usb/usb.h>
58 #include <dev/usb/usbdi.h>
59 #include <dev/usb/usbdi_util.h>
60 #include "usbdevs.h"
61 
62 #define	USB_DEBUG_VAR ipheth_debug
63 #include <dev/usb/usb_debug.h>
64 #include <dev/usb/usb_process.h>
65 
66 #include <dev/usb/net/usb_ethernet.h>
67 #include <dev/usb/net/if_iphethvar.h>
68 
69 static device_probe_t ipheth_probe;
70 static device_attach_t ipheth_attach;
71 static device_detach_t ipheth_detach;
72 
73 static usb_callback_t ipheth_bulk_write_callback;
74 static usb_callback_t ipheth_bulk_read_callback;
75 
76 static uether_fn_t ipheth_attach_post;
77 static uether_fn_t ipheth_tick;
78 static uether_fn_t ipheth_init;
79 static uether_fn_t ipheth_stop;
80 static uether_fn_t ipheth_start;
81 static uether_fn_t ipheth_setmulti;
82 static uether_fn_t ipheth_setpromisc;
83 
84 #ifdef USB_DEBUG
85 static int ipheth_debug = 0;
86 
87 static SYSCTL_NODE(_hw_usb, OID_AUTO, ipheth, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
88     "USB iPhone ethernet");
89 SYSCTL_INT(_hw_usb_ipheth, OID_AUTO, debug, CTLFLAG_RWTUN, &ipheth_debug, 0, "Debug level");
90 #endif
91 
92 static const struct usb_config ipheth_config[IPHETH_N_TRANSFER] = {
93 	[IPHETH_BULK_RX] = {
94 		.type = UE_BULK,
95 		.endpoint = UE_ADDR_ANY,
96 		.direction = UE_DIR_RX,
97 		.frames = IPHETH_RX_FRAMES_MAX,
98 		.bufsize = (IPHETH_RX_FRAMES_MAX * MCLBYTES),
99 		.flags = {.short_frames_ok = 1,.short_xfer_ok = 1,.ext_buffer = 1,},
100 		.callback = ipheth_bulk_read_callback,
101 		.timeout = 0,		/* no timeout */
102 	},
103 
104 	[IPHETH_BULK_TX] = {
105 		.type = UE_BULK,
106 		.endpoint = UE_ADDR_ANY,
107 		.direction = UE_DIR_TX,
108 		.frames = IPHETH_TX_FRAMES_MAX,
109 		.bufsize = (IPHETH_TX_FRAMES_MAX * IPHETH_BUF_SIZE),
110 		.flags = {.force_short_xfer = 1,},
111 		.callback = ipheth_bulk_write_callback,
112 		.timeout = IPHETH_TX_TIMEOUT,
113 	},
114 };
115 
116 static device_method_t ipheth_methods[] = {
117 	/* Device interface */
118 	DEVMETHOD(device_probe, ipheth_probe),
119 	DEVMETHOD(device_attach, ipheth_attach),
120 	DEVMETHOD(device_detach, ipheth_detach),
121 
122 	DEVMETHOD_END
123 };
124 
125 static driver_t ipheth_driver = {
126 	.name = "ipheth",
127 	.methods = ipheth_methods,
128 	.size = sizeof(struct ipheth_softc),
129 };
130 
131 static const STRUCT_USB_HOST_ID ipheth_devs[] = {
132 #if 0
133 	{IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE,
134 	    IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
135 	    IPHETH_USBINTF_PROTO)},
136 	{IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_3G,
137 	    IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
138 	    IPHETH_USBINTF_PROTO)},
139 	{IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_3GS,
140 	    IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
141 	    IPHETH_USBINTF_PROTO)},
142 	{IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_4,
143 	    IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
144 	    IPHETH_USBINTF_PROTO)},
145 	{IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_4S,
146 	    IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
147 	    IPHETH_USBINTF_PROTO)},
148 	{IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_5,
149 	    IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
150 	    IPHETH_USBINTF_PROTO)},
151 #else
152 	/* product agnostic interface match */
153 	{USB_VENDOR(USB_VENDOR_APPLE),
154 	 USB_IFACE_CLASS(IPHETH_USBINTF_CLASS),
155 	 USB_IFACE_SUBCLASS(IPHETH_USBINTF_SUBCLASS),
156 	 USB_IFACE_PROTOCOL(IPHETH_USBINTF_PROTO)},
157 #endif
158 };
159 
160 DRIVER_MODULE(ipheth, uhub, ipheth_driver, NULL, NULL);
161 MODULE_VERSION(ipheth, 1);
162 MODULE_DEPEND(ipheth, uether, 1, 1, 1);
163 MODULE_DEPEND(ipheth, usb, 1, 1, 1);
164 MODULE_DEPEND(ipheth, ether, 1, 1, 1);
165 USB_PNP_HOST_INFO(ipheth_devs);
166 
167 static const struct usb_ether_methods ipheth_ue_methods = {
168 	.ue_attach_post = ipheth_attach_post,
169 	.ue_start = ipheth_start,
170 	.ue_init = ipheth_init,
171 	.ue_tick = ipheth_tick,
172 	.ue_stop = ipheth_stop,
173 	.ue_setmulti = ipheth_setmulti,
174 	.ue_setpromisc = ipheth_setpromisc,
175 };
176 
177 #define	IPHETH_ID(v,p,c,sc,pt) \
178     USB_VENDOR(v), USB_PRODUCT(p), \
179     USB_IFACE_CLASS(c), USB_IFACE_SUBCLASS(sc), \
180     USB_IFACE_PROTOCOL(pt)
181 
182 static int
ipheth_get_mac_addr(struct ipheth_softc * sc)183 ipheth_get_mac_addr(struct ipheth_softc *sc)
184 {
185 	struct usb_device_request req;
186 	int error;
187 
188 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
189 	req.bRequest = IPHETH_CMD_GET_MACADDR;
190 	req.wValue[0] = 0;
191 	req.wValue[1] = 0;
192 	req.wIndex[0] = sc->sc_iface_no;
193 	req.wIndex[1] = 0;
194 	req.wLength[0] = ETHER_ADDR_LEN;
195 	req.wLength[1] = 0;
196 
197 	error = usbd_do_request(sc->sc_ue.ue_udev, NULL, &req, sc->sc_data);
198 
199 	if (error)
200 		return (error);
201 
202 	memcpy(sc->sc_ue.ue_eaddr, sc->sc_data, ETHER_ADDR_LEN);
203 
204 	return (0);
205 }
206 
207 static int
ipheth_probe(device_t dev)208 ipheth_probe(device_t dev)
209 {
210 	struct usb_attach_arg *uaa = device_get_ivars(dev);
211 
212 	if (uaa->usb_mode != USB_MODE_HOST)
213 		return (ENXIO);
214 
215 	return (usbd_lookup_id_by_uaa(ipheth_devs, sizeof(ipheth_devs), uaa));
216 }
217 
218 static int
ipheth_attach(device_t dev)219 ipheth_attach(device_t dev)
220 {
221 	struct ipheth_softc *sc = device_get_softc(dev);
222 	struct usb_ether *ue = &sc->sc_ue;
223 	struct usb_attach_arg *uaa = device_get_ivars(dev);
224 	int error;
225 
226 	sc->sc_iface_no = uaa->info.bIfaceIndex;
227 
228 	device_set_usb_desc(dev);
229 
230 	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
231 
232 	error = usbd_set_alt_interface_index(uaa->device,
233 	    uaa->info.bIfaceIndex, IPHETH_ALT_INTFNUM);
234 	if (error) {
235 		device_printf(dev, "Cannot set alternate setting\n");
236 		goto detach;
237 	}
238 	error = usbd_transfer_setup(uaa->device, &sc->sc_iface_no,
239 	    sc->sc_xfer, ipheth_config, IPHETH_N_TRANSFER, sc, &sc->sc_mtx);
240 	if (error) {
241 		device_printf(dev, "Cannot setup USB transfers\n");
242 		goto detach;
243 	}
244 	ue->ue_sc = sc;
245 	ue->ue_dev = dev;
246 	ue->ue_udev = uaa->device;
247 	ue->ue_mtx = &sc->sc_mtx;
248 	ue->ue_methods = &ipheth_ue_methods;
249 
250 	error = ipheth_get_mac_addr(sc);
251 	if (error) {
252 		device_printf(dev, "Cannot get MAC address\n");
253 		goto detach;
254 	}
255 
256 	error = uether_ifattach(ue);
257 	if (error) {
258 		device_printf(dev, "could not attach interface\n");
259 		goto detach;
260 	}
261 	return (0);			/* success */
262 
263 detach:
264 	ipheth_detach(dev);
265 	return (ENXIO);			/* failure */
266 }
267 
268 static int
ipheth_detach(device_t dev)269 ipheth_detach(device_t dev)
270 {
271 	struct ipheth_softc *sc = device_get_softc(dev);
272 	struct usb_ether *ue = &sc->sc_ue;
273 
274 	/* stop all USB transfers first */
275 	usbd_transfer_unsetup(sc->sc_xfer, IPHETH_N_TRANSFER);
276 
277 	uether_ifdetach(ue);
278 
279 	mtx_destroy(&sc->sc_mtx);
280 
281 	return (0);
282 }
283 
284 static void
ipheth_start(struct usb_ether * ue)285 ipheth_start(struct usb_ether *ue)
286 {
287 	struct ipheth_softc *sc = uether_getsc(ue);
288 
289 	/*
290 	 * Start the USB transfers, if not already started:
291 	 */
292 	usbd_transfer_start(sc->sc_xfer[IPHETH_BULK_TX]);
293 	usbd_transfer_start(sc->sc_xfer[IPHETH_BULK_RX]);
294 }
295 
296 static void
ipheth_stop(struct usb_ether * ue)297 ipheth_stop(struct usb_ether *ue)
298 {
299 	struct ipheth_softc *sc = uether_getsc(ue);
300 
301 	/*
302 	 * Stop the USB transfers, if not already stopped:
303 	 */
304 	usbd_transfer_stop(sc->sc_xfer[IPHETH_BULK_TX]);
305 	usbd_transfer_stop(sc->sc_xfer[IPHETH_BULK_RX]);
306 }
307 
308 static void
ipheth_tick(struct usb_ether * ue)309 ipheth_tick(struct usb_ether *ue)
310 {
311 	struct ipheth_softc *sc = uether_getsc(ue);
312 	struct usb_device_request req;
313 	int error;
314 
315 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
316 	req.bRequest = IPHETH_CMD_CARRIER_CHECK;
317 	req.wValue[0] = 0;
318 	req.wValue[1] = 0;
319 	req.wIndex[0] = sc->sc_iface_no;
320 	req.wIndex[1] = 0;
321 	req.wLength[0] = IPHETH_CTRL_BUF_SIZE;
322 	req.wLength[1] = 0;
323 
324 	error = uether_do_request(ue, &req, sc->sc_data, IPHETH_CTRL_TIMEOUT);
325 
326 	if (error)
327 		return;
328 
329 	sc->sc_carrier_on =
330 	    (sc->sc_data[0] == IPHETH_CARRIER_ON);
331 }
332 
333 static void
ipheth_attach_post(struct usb_ether * ue)334 ipheth_attach_post(struct usb_ether *ue)
335 {
336 
337 }
338 
339 static void
ipheth_init(struct usb_ether * ue)340 ipheth_init(struct usb_ether *ue)
341 {
342 	struct ipheth_softc *sc = uether_getsc(ue);
343 	if_t ifp = uether_getifp(ue);
344 
345 	IPHETH_LOCK_ASSERT(sc, MA_OWNED);
346 
347 	if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
348 
349 	/* stall data write direction, which depends on USB mode */
350 	usbd_xfer_set_stall(sc->sc_xfer[IPHETH_BULK_TX]);
351 
352 	/* start data transfers */
353 	ipheth_start(ue);
354 }
355 
356 static void
ipheth_setmulti(struct usb_ether * ue)357 ipheth_setmulti(struct usb_ether *ue)
358 {
359 
360 }
361 
362 static void
ipheth_setpromisc(struct usb_ether * ue)363 ipheth_setpromisc(struct usb_ether *ue)
364 {
365 
366 }
367 
368 static void
ipheth_free_queue(struct mbuf ** ppm,uint8_t n)369 ipheth_free_queue(struct mbuf **ppm, uint8_t n)
370 {
371 	uint8_t x;
372 
373 	for (x = 0; x != n; x++) {
374 		if (ppm[x] != NULL) {
375 			m_freem(ppm[x]);
376 			ppm[x] = NULL;
377 		}
378 	}
379 }
380 
381 static void
ipheth_bulk_write_callback(struct usb_xfer * xfer,usb_error_t error)382 ipheth_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
383 {
384 	struct ipheth_softc *sc = usbd_xfer_softc(xfer);
385 	if_t ifp = uether_getifp(&sc->sc_ue);
386 	struct usb_page_cache *pc;
387 	struct mbuf *m;
388 	uint8_t x;
389 	int actlen;
390 	int aframes;
391 
392 	usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
393 
394 	DPRINTFN(1, "\n");
395 
396 	switch (USB_GET_STATE(xfer)) {
397 	case USB_ST_TRANSFERRED:
398 		DPRINTFN(11, "transfer complete: %u bytes in %u frames\n",
399 		    actlen, aframes);
400 
401 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
402 
403 		/* free all previous TX buffers */
404 		ipheth_free_queue(sc->sc_tx_buf, IPHETH_TX_FRAMES_MAX);
405 
406 		/* FALLTHROUGH */
407 	case USB_ST_SETUP:
408 tr_setup:
409 		for (x = 0; x != IPHETH_TX_FRAMES_MAX; x++) {
410 			m = if_dequeue(ifp);
411 
412 			if (m == NULL)
413 				break;
414 
415 			usbd_xfer_set_frame_offset(xfer,
416 			    x * IPHETH_BUF_SIZE, x);
417 
418 			pc = usbd_xfer_get_frame(xfer, x);
419 
420 			sc->sc_tx_buf[x] = m;
421 
422 			if (m->m_pkthdr.len > IPHETH_BUF_SIZE)
423 				m->m_pkthdr.len = IPHETH_BUF_SIZE;
424 
425 			usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);
426 
427 			usbd_xfer_set_frame_len(xfer, x, IPHETH_BUF_SIZE);
428 
429 			if (IPHETH_BUF_SIZE != m->m_pkthdr.len) {
430 				usbd_frame_zero(pc, m->m_pkthdr.len,
431 					IPHETH_BUF_SIZE - m->m_pkthdr.len);
432 			}
433 
434 			/*
435 			 * If there's a BPF listener, bounce a copy of
436 			 * this frame to him:
437 			 */
438 			BPF_MTAP(ifp, m);
439 		}
440 		if (x != 0) {
441 			usbd_xfer_set_frames(xfer, x);
442 
443 			usbd_transfer_submit(xfer);
444 		}
445 		break;
446 
447 	default:			/* Error */
448 		DPRINTFN(11, "transfer error, %s\n",
449 		    usbd_errstr(error));
450 
451 		/* free all previous TX buffers */
452 		ipheth_free_queue(sc->sc_tx_buf, IPHETH_TX_FRAMES_MAX);
453 
454 		/* count output errors */
455 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
456 
457 		if (error != USB_ERR_CANCELLED) {
458 			/* try to clear stall first */
459 			usbd_xfer_set_stall(xfer);
460 			goto tr_setup;
461 		}
462 		break;
463 	}
464 }
465 
466 static void
ipheth_bulk_read_callback(struct usb_xfer * xfer,usb_error_t error)467 ipheth_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
468 {
469 	struct ipheth_softc *sc = usbd_xfer_softc(xfer);
470 	struct mbuf *m;
471 	uint8_t x;
472 	int actlen;
473 	int aframes;
474 	int len;
475 
476 	usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
477 
478 	switch (USB_GET_STATE(xfer)) {
479 	case USB_ST_TRANSFERRED:
480 
481 		DPRINTF("received %u bytes in %u frames\n", actlen, aframes);
482 
483 		for (x = 0; x != aframes; x++) {
484 			m = sc->sc_rx_buf[x];
485 			sc->sc_rx_buf[x] = NULL;
486 			len = usbd_xfer_frame_len(xfer, x);
487 
488 			if (len < (int)(sizeof(struct ether_header) +
489 			    IPHETH_RX_ADJ)) {
490 				m_freem(m);
491 				continue;
492 			}
493 
494 			m_adj(m, IPHETH_RX_ADJ);
495 
496 			/* queue up mbuf */
497 			uether_rxmbuf(&sc->sc_ue, m, len - IPHETH_RX_ADJ);
498 		}
499 
500 		/* FALLTHROUGH */
501 	case USB_ST_SETUP:
502 
503 		for (x = 0; x != IPHETH_RX_FRAMES_MAX; x++) {
504 			if (sc->sc_rx_buf[x] == NULL) {
505 				m = uether_newbuf();
506 				if (m == NULL)
507 					goto tr_stall;
508 
509 				/* cancel alignment for ethernet */
510 				m_adj(m, ETHER_ALIGN);
511 
512 				sc->sc_rx_buf[x] = m;
513 			} else {
514 				m = sc->sc_rx_buf[x];
515 			}
516 
517 			usbd_xfer_set_frame_data(xfer, x, m->m_data, m->m_len);
518 		}
519 		/* set number of frames and start hardware */
520 		usbd_xfer_set_frames(xfer, x);
521 		usbd_transfer_submit(xfer);
522 		/* flush any received frames */
523 		uether_rxflush(&sc->sc_ue);
524 		break;
525 
526 	default:			/* Error */
527 		DPRINTF("error = %s\n", usbd_errstr(error));
528 
529 		if (error != USB_ERR_CANCELLED) {
530 	tr_stall:
531 			/* try to clear stall first */
532 			usbd_xfer_set_stall(xfer);
533 			usbd_xfer_set_frames(xfer, 0);
534 			usbd_transfer_submit(xfer);
535 			break;
536 		}
537 		/* need to free the RX-mbufs when we are cancelled */
538 		ipheth_free_queue(sc->sc_rx_buf, IPHETH_RX_FRAMES_MAX);
539 		break;
540 	}
541 }
542