ChangeSet 1.1732, 2004/05/17 15:32:03-07:00, david-b@pacbell.net [PATCH] USB: RNDIS (and CDC) filter flag handling This should fix the problem David Meggy found, where RNDIS was setting the OID_GEN_CURRENT_PACKET_FILTER state incorrectly. It's the same issue Andrew Morton noticed a while back, for that matter, but with more than just a "now compiles on 64 bit" fix. Basically the code needs to interpret 32 bits provided in the request from the (Windows) host, rather than 8 bits of other memory that's got some irrelevant value. The fix is just to save the 32 bits. I did the same thing with the CDC Ethernet filter, which should eventually be used the same way: to limit what packets get sent to the host. Also defined a couple more of the CDC requests. drivers/usb/gadget/ether.c | 29 +++++++++++++++++++--- drivers/usb/gadget/rndis.c | 57 ++++++++++----------------------------------- drivers/usb/gadget/rndis.h | 1 3 files changed, 39 insertions(+), 48 deletions(-) diff -Nru a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c --- a/drivers/usb/gadget/ether.c Mon May 17 16:37:33 2004 +++ b/drivers/usb/gadget/ether.c Mon May 17 16:37:33 2004 @@ -117,6 +117,7 @@ unsigned zlp:1; unsigned cdc:1; unsigned rndis:1; + u16 cdc_filter; unsigned long todo; #define WORK_RX_MEMORY 0 int rndis_config; @@ -1139,6 +1140,9 @@ } eth_reset_config (dev); + /* default: pass all packets, no multicast filtering */ + dev->cdc_filter = 0x000f; + switch (number) { case DEV_CONFIG_VALUE: dev->rndis = 0; @@ -1311,9 +1315,20 @@ * section 3.6.2.1 table 4 has ACM requests; RNDIS requires the * encapsulated command mechanism. */ -#define CDC_SEND_ENCAPSULATED_COMMAND 0x00 /* optional */ -#define CDC_GET_ENCAPSULATED_RESPONSE 0x01 /* optional */ -#define CDC_SET_ETHERNET_PACKET_FILTER 0x43 /* required */ +#define CDC_SEND_ENCAPSULATED_COMMAND 0x00 /* optional */ +#define CDC_GET_ENCAPSULATED_RESPONSE 0x01 /* optional */ +#define CDC_SET_ETHERNET_MULTICAST_FILTERS 0x40 /* optional */ +#define CDC_SET_ETHERNET_PM_PATTERN_FILTER 0x41 /* optional */ +#define CDC_GET_ETHERNET_PM_PATTERN_FILTER 0x42 /* optional */ +#define CDC_SET_ETHERNET_PACKET_FILTER 0x43 /* required */ +#define CDC_GET_ETHERNET_STATISTIC 0x44 /* optional */ + +/* table 62; bits in cdc_filter */ +#define CDC_PACKET_TYPE_PROMISCUOUS (1 << 0) +#define CDC_PACKET_TYPE_ALL_MULTICAST (1 << 1) /* no filter */ +#define CDC_PACKET_TYPE_DIRECTED (1 << 2) +#define CDC_PACKET_TYPE_BROADCAST (1 << 3) +#define CDC_PACKET_TYPE_MULTICAST (1 << 4) /* filtered */ #ifdef CONFIG_USB_ETH_RNDIS @@ -1513,8 +1528,9 @@ DEBUG (dev, "NOP packet filter %04x\n", ctrl->wValue); /* NOTE: table 62 has 5 filter bits to reduce traffic, * and we "must" support multicast and promiscuous. - * this NOP implements a bad filter... + * this NOP implements a bad filter (always promisc) */ + dev->cdc_filter = ctrl->wValue; value = 0; break; #endif /* DEV_CONFIG_CDC */ @@ -1941,6 +1957,11 @@ int retval; struct usb_request *req = 0; unsigned long flags; + + /* FIXME check dev->cdc_filter to decide whether to send this, + * instead of acting as if CDC_PACKET_TYPE_PROMISCUOUS were + * always set. RNDIS has the same kind of outgoing filter. + */ spin_lock_irqsave (&dev->lock, flags); req = container_of (dev->tx_reqs.next, struct usb_request, list); diff -Nru a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c --- a/drivers/usb/gadget/rndis.c Mon May 17 16:37:33 2004 +++ b/drivers/usb/gadget/rndis.c Mon May 17 16:37:33 2004 @@ -78,44 +78,6 @@ static rndis_resp_t *rndis_add_response (int configNr, u32 length); -/* helper functions */ -static u32 devFlags2currentFilter (struct net_device *dev) -{ - u32 filter = 0; - - if (!dev) return 0; - - if (dev->flags & IFF_MULTICAST) - filter |= NDIS_PACKET_TYPE_MULTICAST; - if (dev->flags & IFF_BROADCAST) - filter |= NDIS_PACKET_TYPE_BROADCAST; - if (dev->flags & IFF_ALLMULTI) - filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; - if (dev->flags & IFF_PROMISC) - filter |= NDIS_PACKET_TYPE_PROMISCUOUS; - - return filter; -} - -static void currentFilter2devFlags (u32 currentFilter, struct net_device *dev) -{ - /* FIXME the filter is supposed to control what gets - * forwarded from gadget to host; but dev->flags controls - * reporting from host to gadget ... - */ -#if 0 - if (!dev) return; - if (currentFilter & NDIS_PACKET_TYPE_MULTICAST) - dev->flags |= IFF_MULTICAST; - if (currentFilter & NDIS_PACKET_TYPE_BROADCAST) - dev->flags |= IFF_BROADCAST; - if (currentFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) - dev->flags |= IFF_ALLMULTI; - if (currentFilter & NDIS_PACKET_TYPE_PROMISCUOUS) - dev->flags |= IFF_PROMISC; -#endif -} - /* FIXME OMITTED OIDs, that RNDIS-on-USB "must" support, include * - power management (OID_PNP_CAPABILITIES, ...) * - network wakeup (OID_PNP_ENABLE_WAKE_UP, ...) @@ -252,13 +214,12 @@ rndis_per_dev_params [configNr].vendorDescr, length); retval = 0; break; - + /* mandatory */ case OID_GEN_CURRENT_PACKET_FILTER: DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__); length = 4; - *((u32 *) resp + 6) = devFlags2currentFilter ( - rndis_per_dev_params [configNr].dev); + *((u32 *) resp + 6) = rndis_per_dev_params[configNr].filter; retval = 0; break; @@ -767,16 +728,24 @@ switch (OID) { case OID_GEN_CURRENT_PACKET_FILTER: - DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__); params = &rndis_per_dev_params [configNr]; - currentFilter2devFlags(cp[28], params->dev); retval = 0; + /* FIXME use this NDIS_PACKET_TYPE_* bitflags to + * filter packets in hard_start_xmit() + * NDIS_PACKET_TYPE_x == CDC_PACKET_TYPE_x for x in: + * PROMISCUOUS, DIRECTED, + * MULTICAST, ALL_MULTICAST, BROADCAST + */ + params->filter = *(u32 *)buf; + DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n", + __FUNCTION__, params->filter); + /* this call has a significant side effect: it's * what makes the packet flow start and stop, like * activating the CDC Ethernet altsetting. */ - if (cp[28]) { + if (params->filter) { params->state = RNDIS_DATA_INITIALIZED; netif_carrier_on(params->dev); if (netif_running(params->dev)) diff -Nru a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h --- a/drivers/usb/gadget/rndis.h Mon May 17 16:37:33 2004 +++ b/drivers/usb/gadget/rndis.h Mon May 17 16:37:33 2004 @@ -277,6 +277,7 @@ u8 confignr; int used; enum rndis_state state; + u32 filter; u32 medium; u32 speed; u32 media_state;