Commit eaab83eb authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[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.
parent 6aecb90d
......@@ -117,6 +117,7 @@ struct eth_dev {
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_set_config (struct eth_dev *dev, unsigned number, int gfp_flags)
}
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 @@ static void eth_setup_complete (struct usb_ep *ep, struct usb_request *req)
* 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 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
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 */
......@@ -1942,6 +1958,11 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
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);
list_del (&req->list);
......
......@@ -78,44 +78,6 @@ static int rndis_keepalive_response (int configNr,
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 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
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 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
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))
......
......@@ -277,6 +277,7 @@ typedef struct rndis_params
u8 confignr;
int used;
enum rndis_state state;
u32 filter;
u32 medium;
u32 speed;
u32 media_state;
......
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