Commit b45c7f9c authored by HardenedBSD Sync Service's avatar HardenedBSD Sync Service
Browse files

Merge remote-tracking branch 'freebsd/stable/13' into hardened/13-stable/master

parents 22f76ef6 dcd0d08b
......@@ -2168,29 +2168,28 @@ mvneta_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
ifp->if_hwassist = CSUM_IP | CSUM_TCP |
CSUM_UDP;
}
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
/* Stop hardware */
/*
* Reinitialize RX queues.
* We need to update RX descriptor size.
*/
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
mvneta_stop_locked(sc);
/*
* Reinitialize RX queues.
* We need to update RX descriptor size.
*/
for (q = 0; q < MVNETA_RX_QNUM_MAX; q++) {
mvneta_rx_lockq(sc, q);
if (mvneta_rx_queue_init(ifp, q) != 0) {
device_printf(sc->dev,
"initialization failed:"
" cannot initialize queue\n");
mvneta_rx_unlockq(sc, q);
error = ENOBUFS;
break;
}
for (q = 0; q < MVNETA_RX_QNUM_MAX; q++) {
mvneta_rx_lockq(sc, q);
if (mvneta_rx_queue_init(ifp, q) != 0) {
device_printf(sc->dev,
"initialization failed:"
" cannot initialize queue\n");
mvneta_rx_unlockq(sc, q);
error = ENOBUFS;
break;
}
/* Trigger reinitialization */
mvneta_init_locked(sc);
mvneta_rx_unlockq(sc, q);
}
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
mvneta_init_locked(sc);
mvneta_sc_unlock(sc);
}
break;
......
......@@ -111,8 +111,13 @@ static uether_fn_t cdce_stop;
static uether_fn_t cdce_start;
static uether_fn_t cdce_setmulti;
static uether_fn_t cdce_setpromisc;
static int cdce_attach_post_sub(struct usb_ether *);
static int cdce_ioctl(struct ifnet *, u_long, caddr_t);
static int cdce_media_change_cb(struct ifnet *);
static void cdce_media_status_cb(struct ifnet *, struct ifmediareq *);
static uint32_t cdce_m_crc32(struct mbuf *, uint32_t, uint32_t);
static void cdce_set_filter(struct usb_ether *);
#ifdef USB_DEBUG
static int cdce_debug = 0;
......@@ -124,6 +129,8 @@ SYSCTL_INT(_hw_usb_cdce, OID_AUTO, debug, CTLFLAG_RWTUN, &cdce_debug, 0,
"Debug level");
SYSCTL_INT(_hw_usb_cdce, OID_AUTO, interval, CTLFLAG_RWTUN, &cdce_tx_interval, 0,
"NCM transmit interval in ms");
#else
#define cdce_debug 0
#endif
static const struct usb_config cdce_config[CDCE_N_TRANSFER] = {
......@@ -307,6 +314,7 @@ USB_PNP_DUAL_INFO(cdce_dual_devs);
static const struct usb_ether_methods cdce_ue_methods = {
.ue_attach_post = cdce_attach_post,
.ue_attach_post_sub = cdce_attach_post_sub,
.ue_start = cdce_start,
.ue_init = cdce_init,
.ue_stop = cdce_stop,
......@@ -560,6 +568,39 @@ cdce_attach_post(struct usb_ether *ue)
return;
}
static int
cdce_attach_post_sub(struct usb_ether *ue)
{
struct cdce_softc *sc = uether_getsc(ue);
struct ifnet *ifp = uether_getifp(ue);
/* mostly copied from usb_ethernet.c */
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_start = uether_start;
ifp->if_ioctl = cdce_ioctl;
ifp->if_init = uether_init;
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
IFQ_SET_READY(&ifp->if_snd);
if ((sc->sc_flags & CDCE_FLAG_VLAN) == CDCE_FLAG_VLAN)
if_setcapabilitiesbit(ifp, IFCAP_VLAN_MTU, 0);
if_setcapabilitiesbit(ifp, IFCAP_LINKSTATE, 0);
if_setcapenable(ifp, if_getcapabilities(ifp));
ifmedia_init(&sc->sc_media, IFM_IMASK, cdce_media_change_cb,
cdce_media_status_cb);
ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
sc->sc_media.ifm_media = sc->sc_media.ifm_cur->ifm_media;
CDCE_LOCK(sc);
cdce_set_filter(ue);
CDCE_UNLOCK(sc);
return 0;
}
static int
cdce_attach(device_t dev)
{
......@@ -672,6 +713,14 @@ cdce_attach(device_t dev)
if ((ued == NULL) || (ued->bLength < sizeof(*ued))) {
error = USB_ERR_INVAL;
} else {
/*
* ECM 1.2 doesn't say it excludes the CRC, but states that it's
* normally 1514, which excludes the CRC.
*/
DPRINTF("max segsize: %d\n", UGETW(ued->wMaxSegmentSize));
if (UGETW(ued->wMaxSegmentSize) >= (ETHER_MAX_LEN - ETHER_CRC_LEN + ETHER_VLAN_ENCAP_LEN))
sc->sc_flags |= CDCE_FLAG_VLAN;
error = usbd_req_get_string_any(uaa->device, NULL,
eaddr_str, sizeof(eaddr_str), ued->iMacAddress);
}
......@@ -742,6 +791,8 @@ cdce_detach(device_t dev)
uether_ifdetach(ue);
mtx_destroy(&sc->sc_mtx);
ifmedia_removeall(&sc->sc_media);
return (0);
}
......@@ -757,6 +808,29 @@ cdce_start(struct usb_ether *ue)
usbd_transfer_start(sc->sc_xfer[CDCE_BULK_RX]);
}
static int
cdce_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
{
struct usb_ether *ue = ifp->if_softc;
struct cdce_softc *sc = uether_getsc(ue);
struct ifreq *ifr = (struct ifreq *)data;
int error;
error = 0;
switch(command) {
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command);
break;
default:
error = uether_ioctl(ifp, command, data);
break;
}
return (error);
}
static void
cdce_free_queue(struct mbuf **ppm, uint8_t n)
{
......@@ -769,6 +843,26 @@ cdce_free_queue(struct mbuf **ppm, uint8_t n)
}
}
static int
cdce_media_change_cb(struct ifnet *ifp)
{
return (EOPNOTSUPP);
}
static void
cdce_media_status_cb(struct ifnet *ifp, struct ifmediareq *ifmr)
{
if ((if_getflags(ifp) & IFF_UP) == 0)
return;
ifmr->ifm_active = IFM_ETHER;
ifmr->ifm_status = IFM_AVALID;
ifmr->ifm_status |=
ifp->if_link_state == LINK_STATE_UP ? IFM_ACTIVE : 0;
}
static void
cdce_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
{
......@@ -935,15 +1029,44 @@ cdce_stop(struct usb_ether *ue)
static void
cdce_setmulti(struct usb_ether *ue)
{
/* no-op */
return;
cdce_set_filter(ue);
}
static void
cdce_setpromisc(struct usb_ether *ue)
{
/* no-op */
return;
cdce_set_filter(ue);
}
static void
cdce_set_filter(struct usb_ether *ue)
{
struct cdce_softc *sc = uether_getsc(ue);
struct ifnet *ifp = uether_getifp(ue);
struct usb_device_request req;
uint16_t value;
value = CDC_PACKET_TYPE_DIRECTED | CDC_PACKET_TYPE_BROADCAST;
if (if_getflags(ifp) & IFF_PROMISC)
value |= CDC_PACKET_TYPE_PROMISC;
if (if_getflags(ifp) & IFF_ALLMULTI)
value |= CDC_PACKET_TYPE_ALL_MULTICAST;
req.bmRequestType = UT_CLASS | UT_INTERFACE;
req.bRequest = CDC_SET_ETHERNET_PACKET_FILTER;
USETW(req.wValue, value);
req.wIndex[0] = sc->sc_ifaces_index[1];
req.wIndex[1] = 0;
USETW(req.wLength, 0);
/*
* Function below will drop the sc mutex.
* We can do that since we're called from a separate task,
* that simply wraps the setpromisc/setmulti methods.
*/
usbd_do_request(sc->sc_ue.ue_udev, &sc->sc_mtx, &req, NULL);
}
static int
......@@ -1043,17 +1166,69 @@ cdce_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
static void
cdce_intr_read_callback(struct usb_xfer *xfer, usb_error_t error)
{
struct cdce_softc *sc = usbd_xfer_softc(xfer);
int actlen;
u_char buf[CDCE_IND_SIZE_MAX];
struct usb_cdc_notification ucn;
struct cdce_softc *sc;
struct ifnet *ifp;
struct usb_page_cache *pc;
int off, actlen;
uint32_t downrate, uprate;
sc = usbd_xfer_softc(xfer);
ifp = uether_getifp(&sc->sc_ue);
pc = usbd_xfer_get_frame(xfer, 0);
usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
switch (USB_GET_STATE(xfer)) {
case USB_ST_TRANSFERRED:
if (USB_DEBUG_VAR)
usbd_copy_out(pc, 0, buf, MIN(actlen, sizeof buf));
DPRINTF("Received %d bytes: %*D\n", actlen,
(int)MIN(actlen, sizeof buf), buf, "");
off = 0;
while (actlen - off >= UCDC_NOTIFICATION_LENGTH) {
usbd_copy_out(pc, off, &ucn, UCDC_NOTIFICATION_LENGTH);
do {
if (ucn.bmRequestType != 0xa1)
break;
switch (ucn.bNotification) {
case UCDC_N_NETWORK_CONNECTION:
DPRINTF("changing link state: %d\n",
UGETW(ucn.wValue));
if_link_state_change(ifp,
UGETW(ucn.wValue) ? LINK_STATE_UP :
LINK_STATE_DOWN);
break;
case UCDC_N_CONNECTION_SPEED_CHANGE:
if (UGETW(ucn.wLength) != 8)
break;
usbd_copy_out(pc, off +
UCDC_NOTIFICATION_LENGTH,
&ucn.data, UGETW(ucn.wLength));
downrate = UGETDW(ucn.data);
uprate = UGETDW(ucn.data);
if (downrate != uprate)
break;
/* set rate */
DPRINTF("changing baudrate: %u\n",
downrate);
if_setbaudrate(ifp, downrate);
break;
default:
break;
}
} while (0);
DPRINTF("Received %d bytes\n", actlen);
/* TODO: decode some indications */
off += UCDC_NOTIFICATION_LENGTH + UGETW(ucn.wLength);
}
/* FALLTHROUGH */
case USB_ST_SETUP:
......
......@@ -37,6 +37,8 @@
#ifndef _USB_IF_CDCEREG_H_
#define _USB_IF_CDCEREG_H_
#define CDCE_BIT(x) (1 << (x))
#define CDCE_FRAMES_MAX 8 /* units */
#define CDCE_IND_SIZE_MAX 32 /* bytes */
......@@ -88,10 +90,13 @@ struct cdce_softc {
struct mbuf *sc_rx_buf[CDCE_FRAMES_MAX];
struct mbuf *sc_tx_buf[CDCE_FRAMES_MAX];
struct ifmedia sc_media;
int sc_flags;
#define CDCE_FLAG_ZAURUS 0x0001
#define CDCE_FLAG_NO_UNION 0x0002
#define CDCE_FLAG_RX_DATA 0x0010
#define CDCE_FLAG_VLAN 0x0020
uint8_t sc_eaddr_str_index;
uint8_t sc_ifaces_index[2];
......@@ -101,6 +106,19 @@ struct cdce_softc {
#define CDCE_NOTIFY_DONE 2
};
/*
* Taken from USB CDC Subclass Specification for Ethernet Devices v1.2,
* section 6.2.4.
*/
#define CDC_SET_ETHERNET_PACKET_FILTER 0x43 /* Command code. */
#define CDC_PACKET_TYPE_PROMISC CDCE_BIT(0)
#define CDC_PACKET_TYPE_ALL_MULTICAST CDCE_BIT(1) /* Allmulti. */
#define CDC_PACKET_TYPE_DIRECTED CDCE_BIT(2) /* Filter unicast by mac. */
#define CDC_PACKET_TYPE_BROADCAST CDCE_BIT(3)
#define CDC_PACKET_TYPE_MULTICAST CDCE_BIT(4) /* Multicast filtering, not supported. */
#define CDCE_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
#define CDCE_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
#define CDCE_LOCK_ASSERT(_sc, t) mtx_assert(&(_sc)->sc_mtx, t)
......
......@@ -146,6 +146,8 @@ static const STRUCT_USB_HOST_ID umodem_host_devs[] = {
{USB_VENDOR(USB_VENDOR_HUAWEI),USB_IFACE_CLASS(UICLASS_CDC),
USB_IFACE_SUBCLASS(UISUBCLASS_ABSTRACT_CONTROL_MODEL),
USB_IFACE_PROTOCOL(0xFF)},
{USB_VENDOR(USB_VENDOR_HUAWEI), USB_IFACE_CLASS(0xFF),
USB_IFACE_SUBCLASS(0xF), USB_IFACE_PROTOCOL(0xFF)},
/* Kyocera AH-K3001V */
{USB_VPI(USB_VENDOR_KYOCERA, USB_PRODUCT_KYOCERA_AHK3001V, 1)},
{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720, 1)},
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment