summaryrefslogtreecommitdiff
path: root/sys/dev/usb/usbnet.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb/usbnet.c')
-rw-r--r--sys/dev/usb/usbnet.c69
1 files changed, 61 insertions, 8 deletions
diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 147bda6aed5..3dfda001c9a 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -1,4 +1,4 @@
-/* $NetBSD: usbnet.c,v 1.4 2019/08/04 08:59:13 mrg Exp $ */
+/* $NetBSD: usbnet.c,v 1.5 2019/08/06 00:19:57 mrg Exp $ */
/*
* Copyright (c) 2019 Matthew R. Green
@@ -33,7 +33,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: usbnet.c,v 1.4 2019/08/04 08:59:13 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: usbnet.c,v 1.5 2019/08/06 00:19:57 mrg Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@@ -115,11 +115,12 @@ usbnet_newbuf(void)
* usbnet_rxeof() is designed to be the done callback for rx completion.
* it provides generic setup and finalisation, calls a different usbnet
* rx_loop callback in the middle, which can use usbnet_enqueue() to
- * enqueue a packet for higher levels.
+ * enqueue a packet for higher levels (or usbnet_input() if previously
+ * using if_input() path.)
*/
void
usbnet_enqueue(struct usbnet * const un, uint8_t *buf, size_t buflen,
- int flags)
+ int csum_flags, uint32_t csum_data, int mbuf_flags)
{
USBNETHIST_FUNC(); USBNETHIST_CALLED();
struct ifnet *ifp = &un->un_ec.ec_if;
@@ -135,13 +136,38 @@ usbnet_enqueue(struct usbnet * const un, uint8_t *buf, size_t buflen,
m_set_rcvif(m, ifp);
m->m_pkthdr.len = m->m_len = buflen;
- m->m_pkthdr.csum_flags = flags;
+ m->m_pkthdr.csum_flags = csum_flags;
+ m->m_pkthdr.csum_data = csum_data;
+ m->m_flags |= mbuf_flags;
memcpy(mtod(m, char *), buf, buflen);
/* push the packet up */
if_percpuq_enqueue(ifp->if_percpuq, m);
}
+void
+usbnet_input(struct usbnet * const un, uint8_t *buf, size_t buflen)
+{
+ USBNETHIST_FUNC(); USBNETHIST_CALLED();
+ struct ifnet * const ifp = usbnet_ifp(un);
+ struct mbuf *m;
+
+ KASSERT(mutex_owned(&un->un_rxlock));
+
+ m = usbnet_newbuf();
+ if (m == NULL) {
+ ifp->if_ierrors++;
+ return;
+ }
+
+ m_set_rcvif(m, ifp);
+ m->m_pkthdr.len = m->m_len = buflen;
+ memcpy(mtod(m, char *), buf, buflen);
+
+ /* push the packet up */
+ if_input(ifp, m);
+}
+
/*
* A frame has been uploaded: pass the resulting mbuf chain up to
* the higher level protocols.
@@ -152,7 +178,7 @@ usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
USBNETHIST_FUNC(); USBNETHIST_CALLED();
struct usbnet_chain *c = priv;
struct usbnet * const un = c->unc_un;
- struct ifnet *ifp = &un->un_ec.ec_if;
+ struct ifnet * const ifp = usbnet_ifp(un);
uint32_t total_len;
mutex_enter(&un->un_rxlock);
@@ -787,6 +813,9 @@ usbnet_ioctl(struct ifnet *ifp, u_long cmd, void *data)
struct usbnet * const un = ifp->if_softc;
int error;
+ if (un->un_override_ioctl_cb)
+ return (*un->un_override_ioctl_cb)(ifp, cmd, data);
+
error = ether_ioctl(ifp, cmd, data);
if (error == ENETRESET && un->un_ioctl_cb)
error = (*un->un_ioctl_cb)(ifp, cmd, data);
@@ -946,6 +975,14 @@ usbnet_init(struct ifnet *ifp)
/* Autoconf management. */
+static bool
+usbnet_empty_eaddr(struct usbnet *un)
+{
+ return (un->un_eaddr[0] == 0 && un->un_eaddr[1] == 0 &&
+ un->un_eaddr[2] == 0 && un->un_eaddr[3] == 0 &&
+ un->un_eaddr[4] == 0 && un->un_eaddr[5] == 0);
+}
+
/*
* usbnet_attach() and usbnet_attach_ifp() perform setup of the relevant
* 'usbnet'. The first is enough to enable device access (eg, endpoints
@@ -954,6 +991,9 @@ usbnet_init(struct ifnet *ifp)
*
* Always call usbnet_detach(), even if usbnet_attach_ifp() is skippped.
* Also usable as driver detach directly.
+ *
+ * To skip ethernet configuration (eg, point-to-point), make sure that
+ * the un_eaddr[] is fully zero.
*/
void
usbnet_attach(struct usbnet *un,
@@ -1054,7 +1094,17 @@ usbnet_attach_ifp(struct usbnet *un,
/* Attach the interface. */
if_attach(ifp);
- ether_ifattach(ifp, un->un_eaddr);
+
+ /*
+ * If ethernet address is all zero, skip ether_ifattach() and
+ * instead attach bpf here..
+ */
+ if (!usbnet_empty_eaddr(un)) {
+ ether_ifattach(ifp, un->un_eaddr);
+ } else {
+ if_alloc_sadl(ifp);
+ bpf_attach(ifp, DLT_RAW, 0);
+ }
}
int
@@ -1101,7 +1151,10 @@ usbnet_detach(device_t self, int flags)
ifmedia_delete_instance(&mii->mii_media, IFM_INST_ANY);
}
if (ifp->if_softc) {
- ether_ifdetach(ifp);
+ if (!usbnet_empty_eaddr(un))
+ ether_ifdetach(ifp);
+ else
+ bpf_detach(ifp);
if_detach(ifp);
}