[PATCH] USB: rndis updates (mostly cleanup)

Some bugfixes and lots of cleanup (net code shrink):

  - On reset, force the RNDIS state machine its initial state

  - Hook up the RNDIS (outgoing) filters to the CDC mechanism

  - Lots of cleanup:
     * Eliminate duplicate copy of OID table;
     * Unify handlying of the OID "query" response data pointer;
     * Reduce code duplication for calculating query response lengths;
     * Remove some checks for "can't happen" errors;
     * Get rid of debugging #ifdefs by making the debug flag an integer level

Most of the patch, by volume, relates to those query response cleanups.
It incidentally shaves off a few hundred bytes of object code.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 3f783cb..a766c29 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -94,8 +94,9 @@
 #ifdef	CONFIG_USB_ETH_RNDIS
 #include "rndis.h"
 #else
-#define rndis_init() 0
-#define rndis_exit() do{}while(0)
+#define rndis_init()	0
+#define rndis_uninit(x)	do{}while(0)
+#define rndis_exit()	do{}while(0)
 #endif
 
 /* CDC and RNDIS support the same host-chosen outgoing packet filters. */
@@ -395,7 +396,8 @@
 #define STRING_SUBSET			8
 #define STRING_RNDIS			9
 
-#define USB_BUFSIZ	256		/* holds our biggest descriptor */
+/* holds our biggest descriptor (or RNDIS response) */
+#define USB_BUFSIZ	256
 
 /*
  * This device advertises one configuration, eth_config, unless RNDIS
@@ -1124,6 +1126,7 @@
 
 	netif_stop_queue (dev->net);
 	netif_carrier_off (dev->net);
+	rndis_uninit(dev->rndis_config);
 
 	/* disable endpoints, forcing (synchronous) completion of
 	 * pending i/o.  then free the requests.
@@ -2565,7 +2568,7 @@
 		/* these set up a lot of the OIDs that RNDIS needs */
 		rndis_set_host_mac (dev->rndis_config, dev->host_mac);
 		if (rndis_set_param_dev (dev->rndis_config, dev->net,
-					 &dev->stats))
+					 &dev->stats, &dev->cdc_filter))
 			goto fail0;
 		if (rndis_set_param_vendor (dev->rndis_config, vendorID,
 					    manufacturer))
diff --git a/drivers/usb/gadget/ndis.h b/drivers/usb/gadget/ndis.h
index c553bbf6..09e3ee4 100644
--- a/drivers/usb/gadget/ndis.h
+++ b/drivers/usb/gadget/ndis.h
@@ -47,17 +47,17 @@
 #define NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE   0x00000004
 
 struct NDIS_PNP_CAPABILITIES {
-	u32					Flags;
+	__le32					Flags;
 	struct NDIS_PM_WAKE_UP_CAPABILITIES	WakeUpCapabilities;
 };
 
 struct NDIS_PM_PACKET_PATTERN {
-	u32	Priority;
-	u32	Reserved;
-	u32	MaskSize;
-	u32	PatternOffset;
-	u32	PatternSize;
-	u32	PatternFlags;
+	__le32	Priority;
+	__le32	Reserved;
+	__le32	MaskSize;
+	__le32	PatternOffset;
+	__le32	PatternSize;
+	__le32	PatternFlags;
 };
 
 
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 7457268..c9a0af2 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -41,6 +41,7 @@
 
 
 #undef	RNDIS_PM
+#undef	RNDIS_WAKEUP
 #undef	VERBOSE
 
 #include "rndis.h"
@@ -60,7 +61,7 @@
 	} while (0)
 static int rndis_debug = 0;
 
-module_param (rndis_debug, bool, 0);
+module_param (rndis_debug, int, 0);
 MODULE_PARM_DESC (rndis_debug, "enable debugging");
 
 #else
@@ -78,22 +79,103 @@
 static const __le32 rndis_driver_version = __constant_cpu_to_le32 (1);
 
 /* Function Prototypes */
-static int rndis_init_response (int configNr, rndis_init_msg_type *buf);
-static int rndis_query_response (int configNr, rndis_query_msg_type *buf);
-static int rndis_set_response (int configNr, rndis_set_msg_type *buf);
-static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf);
-static int rndis_keepalive_response (int configNr, 
-				     rndis_keepalive_msg_type *buf);
-
 static rndis_resp_t *rndis_add_response (int configNr, u32 length);
 
 
+/* supported OIDs */
+static const u32 oid_supported_list [] = 
+{
+	/* the general stuff */
+	OID_GEN_SUPPORTED_LIST,
+	OID_GEN_HARDWARE_STATUS,
+	OID_GEN_MEDIA_SUPPORTED,
+	OID_GEN_MEDIA_IN_USE,
+	OID_GEN_MAXIMUM_FRAME_SIZE,
+	OID_GEN_LINK_SPEED,
+	OID_GEN_TRANSMIT_BLOCK_SIZE,
+	OID_GEN_RECEIVE_BLOCK_SIZE,
+	OID_GEN_VENDOR_ID,
+	OID_GEN_VENDOR_DESCRIPTION,
+	OID_GEN_VENDOR_DRIVER_VERSION,
+	OID_GEN_CURRENT_PACKET_FILTER,
+	OID_GEN_MAXIMUM_TOTAL_SIZE,
+	OID_GEN_MEDIA_CONNECT_STATUS,
+	OID_GEN_PHYSICAL_MEDIUM,
+#if 0
+	OID_GEN_RNDIS_CONFIG_PARAMETER,
+#endif
+	
+	/* the statistical stuff */
+	OID_GEN_XMIT_OK,
+	OID_GEN_RCV_OK,
+	OID_GEN_XMIT_ERROR,
+	OID_GEN_RCV_ERROR,
+	OID_GEN_RCV_NO_BUFFER,
+#ifdef	RNDIS_OPTIONAL_STATS
+	OID_GEN_DIRECTED_BYTES_XMIT,
+	OID_GEN_DIRECTED_FRAMES_XMIT,
+	OID_GEN_MULTICAST_BYTES_XMIT,
+	OID_GEN_MULTICAST_FRAMES_XMIT,
+	OID_GEN_BROADCAST_BYTES_XMIT,
+	OID_GEN_BROADCAST_FRAMES_XMIT,
+	OID_GEN_DIRECTED_BYTES_RCV,
+	OID_GEN_DIRECTED_FRAMES_RCV,
+	OID_GEN_MULTICAST_BYTES_RCV,
+	OID_GEN_MULTICAST_FRAMES_RCV,
+	OID_GEN_BROADCAST_BYTES_RCV,
+	OID_GEN_BROADCAST_FRAMES_RCV,
+	OID_GEN_RCV_CRC_ERROR,
+	OID_GEN_TRANSMIT_QUEUE_LENGTH,
+#endif	/* RNDIS_OPTIONAL_STATS */
+
+    	/* mandatory 802.3 */
+	/* the general stuff */
+	OID_802_3_PERMANENT_ADDRESS,
+	OID_802_3_CURRENT_ADDRESS,
+	OID_802_3_MULTICAST_LIST,
+	OID_802_3_MAC_OPTIONS,
+	OID_802_3_MAXIMUM_LIST_SIZE,
+	
+	/* the statistical stuff */
+	OID_802_3_RCV_ERROR_ALIGNMENT,
+	OID_802_3_XMIT_ONE_COLLISION,
+	OID_802_3_XMIT_MORE_COLLISIONS,
+#ifdef	RNDIS_OPTIONAL_STATS
+	OID_802_3_XMIT_DEFERRED,
+	OID_802_3_XMIT_MAX_COLLISIONS,
+	OID_802_3_RCV_OVERRUN,
+	OID_802_3_XMIT_UNDERRUN,
+	OID_802_3_XMIT_HEARTBEAT_FAILURE,
+	OID_802_3_XMIT_TIMES_CRS_LOST,
+	OID_802_3_XMIT_LATE_COLLISIONS,
+#endif	/* RNDIS_OPTIONAL_STATS */
+
+#ifdef	RNDIS_PM
+	/* PM and wakeup are mandatory for USB: */
+
+	/* power management */
+	OID_PNP_CAPABILITIES,
+	OID_PNP_QUERY_POWER,
+	OID_PNP_SET_POWER,
+
+#ifdef	RNDIS_WAKEUP
+	/* wake up host */
+	OID_PNP_ENABLE_WAKE_UP,
+	OID_PNP_ADD_WAKE_UP_PATTERN,
+	OID_PNP_REMOVE_WAKE_UP_PATTERN,
+#endif	/* RNDIS_WAKEUP */
+#endif	/* RNDIS_PM */
+};
+
+
 /* NDIS Functions */
-static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
+static int
+gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
+		rndis_resp_t *r)
 {
 	int 			retval = -ENOTSUPP;
-	u32 			length = 0;
-	__le32			*tmp;
+	u32 			length = 4;	/* usually */
+	__le32			*outbuf;
 	int			i, count;
 	rndis_query_cmplt_type	*resp;
 
@@ -101,7 +183,22 @@
 	resp = (rndis_query_cmplt_type *) r->buf;
 
 	if (!resp) return -ENOMEM;
-	
+
+	if (buf_len && rndis_debug > 1) {
+		DEBUG("query OID %08x value, len %d:\n", OID, buf_len);
+		for (i = 0; i < buf_len; i += 16) {
+			DEBUG ("%03d: %08x %08x %08x %08x\n", i,
+				le32_to_cpup((__le32 *)&buf[i]),
+				le32_to_cpup((__le32 *)&buf[i + 4]),
+				le32_to_cpup((__le32 *)&buf[i + 8]),
+				le32_to_cpup((__le32 *)&buf[i + 12]));
+		}
+	}
+
+	/* response goes here, right after the header */
+	outbuf = (__le32 *) &resp[1];
+	resp->InformationBufferOffset = __constant_cpu_to_le32 (16);
+
 	switch (OID) {
 
 	/* general oids (table 4-1) */
@@ -111,42 +208,36 @@
 		DEBUG ("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__);
 		length = sizeof (oid_supported_list);
 		count  = length / sizeof (u32);
-		tmp = (__le32 *) ((u8 *)resp + 24);
 		for (i = 0; i < count; i++)
-			tmp[i] = cpu_to_le32 (oid_supported_list[i]);
+			outbuf[i] = cpu_to_le32 (oid_supported_list[i]);
 		retval = 0;
 		break;
 		
 	/* mandatory */
 	case OID_GEN_HARDWARE_STATUS:
 		DEBUG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__);
-		length = 4;
 		/* Bogus question! 
 		 * Hardware must be ready to receive high level protocols.
 		 * BTW: 
 		 * reddite ergo quae sunt Caesaris Caesari
 		 * et quae sunt Dei Deo!
 		 */
-		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+		*outbuf = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 		
 	/* mandatory */
 	case OID_GEN_MEDIA_SUPPORTED:
 		DEBUG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__);
-		length = 4;
-		*((__le32 *) resp + 6) = cpu_to_le32 (
-					rndis_per_dev_params [configNr].medium);
+		*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
 		retval = 0;
 		break;
 		
 	/* mandatory */
 	case OID_GEN_MEDIA_IN_USE:
 		DEBUG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__);
-		length = 4;
 		/* one medium, one transport... (maybe you do it better) */
-		*((__le32 *) resp + 6) = cpu_to_le32 (
-					rndis_per_dev_params [configNr].medium);
+		*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
 		retval = 0;
 		break;
 		
@@ -154,25 +245,21 @@
 	case OID_GEN_MAXIMUM_FRAME_SIZE:
 		DEBUG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].dev) {
-			length = 4;
-			*((__le32 *) resp + 6) = cpu_to_le32 (
+			*outbuf = cpu_to_le32 (
 				rndis_per_dev_params [configNr].dev->mtu);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	/* mandatory */
 	case OID_GEN_LINK_SPEED:
-//		DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
-		length = 4;
+		if (rndis_debug > 1)
+			DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].media_state
-			== NDIS_MEDIA_STATE_DISCONNECTED)
-		    *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+				== NDIS_MEDIA_STATE_DISCONNECTED)
+			*outbuf = __constant_cpu_to_le32 (0);
 		else
-		    *((__le32 *) resp + 6) = cpu_to_le32 (
+			*outbuf = cpu_to_le32 (
 				rndis_per_dev_params [configNr].speed);
 		retval = 0;
 		break;
@@ -181,8 +268,7 @@
 	case OID_GEN_TRANSMIT_BLOCK_SIZE:
 		DEBUG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].dev) {
-			length = 4;
-			*((__le32 *) resp + 6) = cpu_to_le32 (
+			*outbuf = cpu_to_le32 (
 				rndis_per_dev_params [configNr].dev->mtu);
 			retval = 0;
 		}
@@ -192,8 +278,7 @@
 	case OID_GEN_RECEIVE_BLOCK_SIZE:
 		DEBUG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].dev) {
-			length = 4;
-			*((__le32 *) resp + 6) = cpu_to_le32 (
+			*outbuf = cpu_to_le32 (
 				rndis_per_dev_params [configNr].dev->mtu);
 			retval = 0;
 		}
@@ -202,8 +287,7 @@
 	/* mandatory */
 	case OID_GEN_VENDOR_ID:
 		DEBUG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__);
-		length = 4;
-		*((__le32 *) resp + 6) = cpu_to_le32 (
+		*outbuf = cpu_to_le32 (
 			rndis_per_dev_params [configNr].vendorID);
 		retval = 0;
 		break;
@@ -212,51 +296,44 @@
 	case OID_GEN_VENDOR_DESCRIPTION:
 		DEBUG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__);
 		length = strlen (rndis_per_dev_params [configNr].vendorDescr);
-		memcpy ((u8 *) resp + 24, 
+		memcpy (outbuf,
 			rndis_per_dev_params [configNr].vendorDescr, length);
 		retval = 0;
 		break;
 
 	case OID_GEN_VENDOR_DRIVER_VERSION:
 		DEBUG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__);
-		length = 4;
 		/* Created as LE */
-		*((__le32 *) resp + 6) = rndis_driver_version;
+		*outbuf = rndis_driver_version;
 		retval = 0;
 		break;
 
 	/* mandatory */
 	case OID_GEN_CURRENT_PACKET_FILTER:
 		DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__);
-		length = 4;
-		*((__le32 *) resp + 6) = cpu_to_le32 (
-					rndis_per_dev_params[configNr].filter);
+		*outbuf = cpu_to_le32 (*rndis_per_dev_params[configNr].filter);
 		retval = 0;
 		break;
 
 	/* mandatory */
 	case OID_GEN_MAXIMUM_TOTAL_SIZE:
 		DEBUG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__);
-		length = 4;
-		*((__le32 *) resp + 6) = __constant_cpu_to_le32(
-					RNDIS_MAX_TOTAL_SIZE);
+		*outbuf = __constant_cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
 		retval = 0;
 		break;
 
 	/* mandatory */
 	case OID_GEN_MEDIA_CONNECT_STATUS:
-		DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__);
-		length = 4;
-		*((__le32 *) resp + 6) = cpu_to_le32 (
-					rndis_per_dev_params [configNr]
+		if (rndis_debug > 1)
+			DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__);
+		*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 						.media_state);
 		retval = 0;
 		break;
 
 	case OID_GEN_PHYSICAL_MEDIUM:
 		DEBUG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__);
-		length = 4;
-		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+		*outbuf = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 
@@ -266,8 +343,7 @@
 	 */
 	case OID_GEN_MAC_OPTIONS:		/* from WinME */
 		DEBUG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__);
-		length = 4;
-		*((__le32 *) resp + 6) = __constant_cpu_to_le32(
+		*outbuf = __constant_cpu_to_le32(
 			  NDIS_MAC_OPTION_RECEIVE_SERIALIZED
 			| NDIS_MAC_OPTION_FULL_DUPLEX);
 		retval = 0;
@@ -277,62 +353,49 @@
 
 	/* mandatory */
 	case OID_GEN_XMIT_OK:
-		DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__);
+		if (rndis_debug > 1)
+			DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			length = 4;
-			*((__le32 *) resp + 6) = cpu_to_le32 (
+			*outbuf = cpu_to_le32 (
 			    rndis_per_dev_params [configNr].stats->tx_packets - 
 			    rndis_per_dev_params [configNr].stats->tx_errors -
 			    rndis_per_dev_params [configNr].stats->tx_dropped);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 
 	/* mandatory */
 	case OID_GEN_RCV_OK:
-		DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__);
+		if (rndis_debug > 1)
+			DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			length = 4;
-			*((__le32 *) resp + 6) = cpu_to_le32 (
+			*outbuf = cpu_to_le32 (
 			    rndis_per_dev_params [configNr].stats->rx_packets - 
 			    rndis_per_dev_params [configNr].stats->rx_errors -
 			    rndis_per_dev_params [configNr].stats->rx_dropped);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	/* mandatory */
 	case OID_GEN_XMIT_ERROR:
-		DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__);
+		if (rndis_debug > 1)
+			DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			length = 4;
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->tx_errors);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	/* mandatory */
 	case OID_GEN_RCV_ERROR:
-		DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__);
+		if (rndis_debug > 1)
+			DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->rx_errors);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
@@ -340,13 +403,9 @@
 	case OID_GEN_RCV_NO_BUFFER:
 		DEBUG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->rx_dropped);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 
@@ -359,8 +418,7 @@
 		 * divided by weight of Alpha Centauri
 		 */
 		if (rndis_per_dev_params [configNr].stats) {
-			length = 4;
-			*((__le32 *) resp + 6) = cpu_to_le32 (
+			*outbuf = cpu_to_le32 (
 				(rndis_per_dev_params [configNr]
 					.stats->tx_packets - 
 				 rndis_per_dev_params [configNr]
@@ -369,9 +427,6 @@
 					 .stats->tx_dropped)
 				* 123);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
@@ -379,8 +434,7 @@
 		DEBUG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__);
 		/* dito */
 		if (rndis_per_dev_params [configNr].stats) {
-			length = 4;
-			*((__le32 *) resp + 6) = cpu_to_le32 (
+			*outbuf = cpu_to_le32 (
 				(rndis_per_dev_params [configNr]
 					.stats->tx_packets - 
 				 rndis_per_dev_params [configNr]
@@ -389,144 +443,105 @@
 					 .stats->tx_dropped)
 				/ 123);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_MULTICAST_BYTES_XMIT:
 		DEBUG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->multicast*1234);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_MULTICAST_FRAMES_XMIT:
 		DEBUG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->multicast);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_BROADCAST_BYTES_XMIT:
 		DEBUG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->tx_packets/42*255);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_BROADCAST_FRAMES_XMIT:
 		DEBUG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->tx_packets/42);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_DIRECTED_BYTES_RCV:
 		DEBUG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__);
-		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+		*outbuf = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 		
 	case OID_GEN_DIRECTED_FRAMES_RCV:
 		DEBUG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__);
-		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+		*outbuf = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 		
 	case OID_GEN_MULTICAST_BYTES_RCV:
 		DEBUG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->multicast * 1111);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_MULTICAST_FRAMES_RCV:
 		DEBUG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->multicast);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_BROADCAST_BYTES_RCV:
 		DEBUG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->rx_packets/42*255);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_BROADCAST_FRAMES_RCV:
 		DEBUG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->rx_packets/42);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_RCV_CRC_ERROR:
 		DEBUG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->rx_crc_errors);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_TRANSMIT_QUEUE_LENGTH:
 		DEBUG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__);
-		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+		*outbuf = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 #endif	/* RNDIS_OPTIONAL_STATS */
@@ -538,13 +553,10 @@
 		DEBUG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].dev) {
 			length = ETH_ALEN;
-			memcpy ((u8 *) resp + 24,
+			memcpy (outbuf,
 				rndis_per_dev_params [configNr].host_mac,
 				length);
 			retval = 0;
-		} else {
-			*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
-			retval = 0;
 		}
 		break;
 		
@@ -553,7 +565,7 @@
 		DEBUG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].dev) {
 			length = ETH_ALEN;
-			memcpy ((u8 *) resp + 24,
+			memcpy (outbuf,
 				rndis_per_dev_params [configNr].host_mac,
 				length);
 			retval = 0;
@@ -563,18 +575,16 @@
 	/* mandatory */
 	case OID_802_3_MULTICAST_LIST:
 		DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
-		length = 4;
 		/* Multicast base address only */
-		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0xE0000000);
+		*outbuf = __constant_cpu_to_le32 (0xE0000000);
 		retval = 0;
 		break;
 		
 	/* mandatory */
 	case OID_802_3_MAXIMUM_LIST_SIZE:
 		DEBUG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__);
-		 length = 4;
 		/* Multicast base address only */
-		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (1);
+		*outbuf = __constant_cpu_to_le32 (1);
 		retval = 0;
 		break;
 		
@@ -587,11 +597,8 @@
 	/* mandatory */
 	case OID_802_3_RCV_ERROR_ALIGNMENT:
 		DEBUG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__);
-		if (rndis_per_dev_params [configNr].stats)
-		{
-			length = 4;
-			*((__le32 *) resp + 6) = cpu_to_le32 (
-				rndis_per_dev_params [configNr]
+		if (rndis_per_dev_params [configNr].stats) {
+			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->rx_frame_errors);
 			retval = 0;
 		}
@@ -600,16 +607,14 @@
 	/* mandatory */
 	case OID_802_3_XMIT_ONE_COLLISION:
 		DEBUG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__);
-		length = 4;
-		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+		*outbuf = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 		
 	/* mandatory */
 	case OID_802_3_XMIT_MORE_COLLISIONS:
 		DEBUG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__);
-		length = 4;
-		*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+		*outbuf = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 		
@@ -655,27 +660,18 @@
 	case OID_PNP_CAPABILITIES:
 		DEBUG("%s: OID_PNP_CAPABILITIES\n", __FUNCTION__);
 
-		/* just PM, and remote wakeup on link status change
-		 * (not magic packet or pattern match)
-		 */
+		/* for now, no wakeup capabilities */
 		length = sizeof (struct NDIS_PNP_CAPABILITIES);
-		memset (resp, 0, length);
-		{
-			struct NDIS_PNP_CAPABILITIES *caps = (void *) resp;
-
-			caps->Flags = NDIS_DEVICE_WAKE_UP_ENABLE;
-			caps->WakeUpCapabilities.MinLinkChangeWakeUp 
-				 = NdisDeviceStateD3;
-
-			/* FIXME then use usb_gadget_wakeup(), and
-			 * set USB_CONFIG_ATT_WAKEUP in config desc
-			 */
-		}
+		memset(outbuf, 0, length);
 		retval = 0;
 		break;
 	case OID_PNP_QUERY_POWER:
-		DEBUG("%s: OID_PNP_QUERY_POWER\n", __FUNCTION__);
-		/* sure, handle any power state that maps to USB suspend */
+		DEBUG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__,
+				le32_to_cpup((__le32 *) buf) - 1);
+		/* only suspend is a real power state, and
+		 * it can't be entered by OID_PNP_SET_POWER...
+		 */
+		length = 0;
 		retval = 0;
 		break;
 #endif
@@ -684,11 +680,12 @@
 		printk (KERN_WARNING "%s: query unknown OID 0x%08X\n", 
 			 __FUNCTION__, OID);
 	}
+	if (retval < 0)
+		length = 0;
 	
-	resp->InformationBufferOffset = __constant_cpu_to_le32 (16);
 	resp->InformationBufferLength = cpu_to_le32 (length);
-	resp->MessageLength = cpu_to_le32 (24 + length);
-	r->length = 24 + length;
+	r->length = length + sizeof *resp;
+	resp->MessageLength = cpu_to_le32 (r->length);
 	return retval;
 }
 
@@ -705,45 +702,40 @@
 	if (!resp)
 		return -ENOMEM;
 
-	DEBUG("set OID %08x value, len %d:\n", OID, buf_len);
-	for (i = 0; i < buf_len; i += 16) {
-		DEBUG ("%03d: "
-			" %02x %02x %02x %02x"
-			" %02x %02x %02x %02x"
-			" %02x %02x %02x %02x"
-			" %02x %02x %02x %02x"
-			"\n",
-			i,
-			buf[i], buf [i+1],
-				buf[i+2], buf[i+3],
-			buf[i+4], buf [i+5],
-				buf[i+6], buf[i+7],
-			buf[i+8], buf [i+9],
-				buf[i+10], buf[i+11],
-			buf[i+12], buf [i+13],
-				buf[i+14], buf[i+15]);
+	if (buf_len && rndis_debug > 1) {
+		DEBUG("set OID %08x value, len %d:\n", OID, buf_len);
+		for (i = 0; i < buf_len; i += 16) {
+			DEBUG ("%03d: %08x %08x %08x %08x\n", i,
+				le32_to_cpup((__le32 *)&buf[i]),
+				le32_to_cpup((__le32 *)&buf[i + 4]),
+				le32_to_cpup((__le32 *)&buf[i + 8]),
+				le32_to_cpup((__le32 *)&buf[i + 12]));
+		}
 	}
 
+	params = &rndis_per_dev_params [configNr];
 	switch (OID) {
 	case OID_GEN_CURRENT_PACKET_FILTER:
-		params = &rndis_per_dev_params [configNr];
-		retval = 0;
 
-		/* FIXME use these NDIS_PACKET_TYPE_* bitflags to
-		 * set the cdc_filter; it's not RNDIS-specific
+		/* these NDIS_PACKET_TYPE_* bitflags are shared with
+		 * cdc_filter; it's not RNDIS-specific
 		 * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in:
 		 *	PROMISCUOUS, DIRECTED,
 		 *	MULTICAST, ALL_MULTICAST, BROADCAST
 		 */
-		params->filter = le32_to_cpup((__le32 *)buf);
+		*params->filter = (u16) le32_to_cpup((__le32 *)buf);
 		DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
-			__FUNCTION__, params->filter);
+			__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 (params->filter) {
+#ifdef	RNDIS_PM
+update_linkstate:
+#endif
+		retval = 0;
+		if (*params->filter) {
 			params->state = RNDIS_DATA_INITIALIZED;
 			netif_carrier_on(params->dev);
 			if (netif_running(params->dev))
@@ -776,21 +768,34 @@
 
 #ifdef	RNDIS_PM
 	case OID_PNP_SET_POWER:
-		DEBUG ("OID_PNP_SET_POWER\n");
-		/* sure, handle any power state that maps to USB suspend */
-		retval = 0;
+		/* The only real power state is USB suspend, and RNDIS requests
+		 * can't enter it; this one isn't really about power.  After
+		 * resuming, Windows forces a reset, and then SET_POWER D0.
+		 * FIXME ... then things go batty; Windows wedges itself.
+		 */
+		i = le32_to_cpup((__force __le32 *)buf);
+		DEBUG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1);
+		switch (i) {
+		case NdisDeviceStateD0:
+			*params->filter = params->saved_filter;
+			goto update_linkstate;
+		case NdisDeviceStateD3:
+		case NdisDeviceStateD2:
+		case NdisDeviceStateD1:
+			params->saved_filter = *params->filter;
+			retval = 0;
+			break;
+		}
 		break;
 
-	case OID_PNP_ENABLE_WAKE_UP:
-		/* always-connected ... */
-		DEBUG ("OID_PNP_ENABLE_WAKE_UP\n");
-		retval = 0;
-		break;
-
-	// no PM resume patterns supported (specified where?)
-	// so OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN always fails
+#ifdef	RNDIS_WAKEUP
+	// no wakeup support advertised, so wakeup OIDs always fail:
+	//  - OID_PNP_ENABLE_WAKE_UP
+	//  - OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN
 #endif
 
+#endif	/* RNDIS_PM */
+
 	default:
 		printk (KERN_WARNING "%s: set unknown OID 0x%08X, size %d\n", 
 			 __FUNCTION__, OID, buf_len);
@@ -811,13 +816,10 @@
 	if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP;
 	
 	r = rndis_add_response (configNr, sizeof (rndis_init_cmplt_type));
-	
-	if (!r) return -ENOMEM;
-	
+	if (!r)
+		return -ENOMEM;
 	resp = (rndis_init_cmplt_type *) r->buf;
 	
-	if (!resp) return -ENOMEM;
-	
 	resp->MessageType = __constant_cpu_to_le32 (
 			REMOTE_NDIS_INITIALIZE_CMPLT);
 	resp->MessageLength = __constant_cpu_to_le32 (52);
@@ -857,20 +859,22 @@
 	 * oid_supported_list is the largest answer 
 	 */
 	r = rndis_add_response (configNr, sizeof (oid_supported_list));
-	
-	if (!r) return -ENOMEM;
+	if (!r)
+		return -ENOMEM;
 	resp = (rndis_query_cmplt_type *) r->buf;
 	
-	if (!resp) return -ENOMEM;
-	
 	resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_QUERY_CMPLT);
-	resp->MessageLength = __constant_cpu_to_le32 (24);
 	resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
-	
-	if (gen_ndis_query_resp (configNr, le32_to_cpu (buf->OID), r)) {
+  	
+	if (gen_ndis_query_resp (configNr, le32_to_cpu (buf->OID),
+			le32_to_cpu(buf->InformationBufferOffset)
+					+ 8 + (u8 *) buf,
+			le32_to_cpu(buf->InformationBufferLength),
+			r)) {
 		/* OID not supported */
 		resp->Status = __constant_cpu_to_le32 (
 				RNDIS_STATUS_NOT_SUPPORTED);
+		resp->MessageLength = __constant_cpu_to_le32 (sizeof *resp);
 		resp->InformationBufferLength = __constant_cpu_to_le32 (0);
 		resp->InformationBufferOffset = __constant_cpu_to_le32 (0);
 	} else
@@ -889,10 +893,9 @@
 	rndis_resp_t		*r;
 	
 	r = rndis_add_response (configNr, sizeof (rndis_set_cmplt_type));
-	
-	if (!r) return -ENOMEM;
+	if (!r)
+		return -ENOMEM;
 	resp = (rndis_set_cmplt_type *) r->buf;
-	if (!resp) return -ENOMEM;
 
 	BufLength = le32_to_cpu (buf->InformationBufferLength);
 	BufOffset = le32_to_cpu (buf->InformationBufferOffset);
@@ -930,10 +933,9 @@
 	rndis_resp_t		*r;
 	
 	r = rndis_add_response (configNr, sizeof (rndis_reset_cmplt_type));
-	
-	if (!r) return -ENOMEM;
+	if (!r)
+		return -ENOMEM;
 	resp = (rndis_reset_cmplt_type *) r->buf;
-	if (!resp) return -ENOMEM;
 	
 	resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_RESET_CMPLT);
 	resp->MessageLength = __constant_cpu_to_le32 (16);
@@ -957,8 +959,9 @@
 	/* host "should" check only in RNDIS_DATA_INITIALIZED state */
 
 	r = rndis_add_response (configNr, sizeof (rndis_keepalive_cmplt_type));
+	if (!r)
+		return -ENOMEM;
 	resp = (rndis_keepalive_cmplt_type *) r->buf;
-	if (!resp) return -ENOMEM;
 		
 	resp->MessageType = __constant_cpu_to_le32 (
 			REMOTE_NDIS_KEEPALIVE_CMPLT);
@@ -987,10 +990,9 @@
 	
 	r = rndis_add_response (configNr, 
 				sizeof (rndis_indicate_status_msg_type));
-	if (!r) return -ENOMEM;
-	
+	if (!r)
+		return -ENOMEM;
 	resp = (rndis_indicate_status_msg_type *) r->buf;
-	if (!resp) return -ENOMEM;
 	
 	resp->MessageType = __constant_cpu_to_le32 (
 			REMOTE_NDIS_INDICATE_STATUS_MSG);
@@ -1021,6 +1023,15 @@
 					  RNDIS_STATUS_MEDIA_DISCONNECT);
 }
 
+void rndis_uninit (int configNr)
+{
+	if (configNr >= RNDIS_MAX_CONFIGS)
+		return;
+	rndis_per_dev_params [configNr].used = 0;
+	rndis_per_dev_params [configNr].state = RNDIS_UNINITIALIZED;
+	return;
+}
+
 void rndis_set_host_mac (int configNr, const u8 *addr)
 {
 	rndis_per_dev_params [configNr].host_mac = addr;
@@ -1046,9 +1057,13 @@
 		return -ENOTSUPP;
 	params = &rndis_per_dev_params [configNr];
 	
+	/* NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for
+	 * rx/tx statistics and link status, in addition to KEEPALIVE traffic
+	 * and normal HC level polling to see if there's any IN traffic.
+	 */
+
 	/* For USB: responses may take up to 10 seconds */
-	switch (MsgType)
-	{
+	switch (MsgType) {
 	case REMOTE_NDIS_INITIALIZE_MSG:
 		DEBUG("%s: REMOTE_NDIS_INITIALIZE_MSG\n", 
 			__FUNCTION__ );
@@ -1082,10 +1097,9 @@
 
 	case REMOTE_NDIS_KEEPALIVE_MSG:
 		/* For USB: host does this every 5 seconds */
-#ifdef	VERBOSE
-		DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", 
-			__FUNCTION__ );
-#endif
+		if (rndis_debug > 1)
+			DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", 
+				__FUNCTION__ );
 		return rndis_keepalive_response (configNr,
 						 (rndis_keepalive_msg_type *) 
 						 buf);
@@ -1152,7 +1166,8 @@
 }
 
 int rndis_set_param_dev (u8 configNr, struct net_device *dev, 
-			 struct net_device_stats *stats)
+			 struct net_device_stats *stats,
+			 u16 *cdc_filter)
 {
 	DEBUG("%s:\n", __FUNCTION__ );
 	if (!dev || !stats) return -1;
@@ -1160,6 +1175,7 @@
 	
 	rndis_per_dev_params [configNr].dev = dev;
 	rndis_per_dev_params [configNr].stats = stats;
+	rndis_per_dev_params [configNr].filter = cdc_filter;
 	
 	return 0;
 }
@@ -1178,7 +1194,7 @@
 
 int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed)
 {
-	DEBUG("%s:\n", __FUNCTION__ );
+	DEBUG("%s: %u %u\n", __FUNCTION__, medium, speed);
 	if (configNr >= RNDIS_MAX_CONFIGS) return -1;
 	
 	rndis_per_dev_params [configNr].medium = medium;
@@ -1242,6 +1258,7 @@
 {
 	rndis_resp_t	*r;
 	
+	/* NOTE:  this gets copied into ether.c USB_BUFSIZ bytes ... */
 	r = kmalloc (sizeof (rndis_resp_t) + length, GFP_ATOMIC);
 	if (!r) return NULL;
 	
diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h
index 2b5b55d..95b4c63 100644
--- a/drivers/usb/gadget/rndis.h
+++ b/drivers/usb/gadget/rndis.h
@@ -69,90 +69,6 @@
 #define OID_PNP_ENABLE_WAKE_UP			0xFD010106
 
 
-/* supported OIDs */
-static const u32 oid_supported_list [] = 
-{
-	/* the general stuff */
-	OID_GEN_SUPPORTED_LIST,
-	OID_GEN_HARDWARE_STATUS,
-	OID_GEN_MEDIA_SUPPORTED,
-	OID_GEN_MEDIA_IN_USE,
-	OID_GEN_MAXIMUM_FRAME_SIZE,
-	OID_GEN_LINK_SPEED,
-	OID_GEN_TRANSMIT_BLOCK_SIZE,
-	OID_GEN_RECEIVE_BLOCK_SIZE,
-	OID_GEN_VENDOR_ID,
-	OID_GEN_VENDOR_DESCRIPTION,
-	OID_GEN_VENDOR_DRIVER_VERSION,
-	OID_GEN_CURRENT_PACKET_FILTER,
-	OID_GEN_MAXIMUM_TOTAL_SIZE,
-	OID_GEN_MEDIA_CONNECT_STATUS,
-	OID_GEN_PHYSICAL_MEDIUM,
-#if 0
-	OID_GEN_RNDIS_CONFIG_PARAMETER,
-#endif
-	
-	/* the statistical stuff */
-	OID_GEN_XMIT_OK,
-	OID_GEN_RCV_OK,
-	OID_GEN_XMIT_ERROR,
-	OID_GEN_RCV_ERROR,
-	OID_GEN_RCV_NO_BUFFER,
-#ifdef	RNDIS_OPTIONAL_STATS
-	OID_GEN_DIRECTED_BYTES_XMIT,
-	OID_GEN_DIRECTED_FRAMES_XMIT,
-	OID_GEN_MULTICAST_BYTES_XMIT,
-	OID_GEN_MULTICAST_FRAMES_XMIT,
-	OID_GEN_BROADCAST_BYTES_XMIT,
-	OID_GEN_BROADCAST_FRAMES_XMIT,
-	OID_GEN_DIRECTED_BYTES_RCV,
-	OID_GEN_DIRECTED_FRAMES_RCV,
-	OID_GEN_MULTICAST_BYTES_RCV,
-	OID_GEN_MULTICAST_FRAMES_RCV,
-	OID_GEN_BROADCAST_BYTES_RCV,
-	OID_GEN_BROADCAST_FRAMES_RCV,
-	OID_GEN_RCV_CRC_ERROR,
-	OID_GEN_TRANSMIT_QUEUE_LENGTH,
-#endif	/* RNDIS_OPTIONAL_STATS */
-
-    	/* mandatory 802.3 */
-	/* the general stuff */
-	OID_802_3_PERMANENT_ADDRESS,
-	OID_802_3_CURRENT_ADDRESS,
-	OID_802_3_MULTICAST_LIST,
-	OID_802_3_MAC_OPTIONS,
-	OID_802_3_MAXIMUM_LIST_SIZE,
-	
-	/* the statistical stuff */
-	OID_802_3_RCV_ERROR_ALIGNMENT,
-	OID_802_3_XMIT_ONE_COLLISION,
-	OID_802_3_XMIT_MORE_COLLISIONS,
-#ifdef	RNDIS_OPTIONAL_STATS
-	OID_802_3_XMIT_DEFERRED,
-	OID_802_3_XMIT_MAX_COLLISIONS,
-	OID_802_3_RCV_OVERRUN,
-	OID_802_3_XMIT_UNDERRUN,
-	OID_802_3_XMIT_HEARTBEAT_FAILURE,
-	OID_802_3_XMIT_TIMES_CRS_LOST,
-	OID_802_3_XMIT_LATE_COLLISIONS,
-#endif	/* RNDIS_OPTIONAL_STATS */
-
-#ifdef	RNDIS_PM
-	/* PM and wakeup are mandatory for USB: */
-
-	/* power management */
-	OID_PNP_CAPABILITIES,
-	OID_PNP_QUERY_POWER,
-	OID_PNP_SET_POWER,
-
-	/* wake up host */
-	OID_PNP_ENABLE_WAKE_UP,
-	OID_PNP_ADD_WAKE_UP_PATTERN,
-	OID_PNP_REMOVE_WAKE_UP_PATTERN,
-#endif
-};
-
-
 typedef struct rndis_init_msg_type 
 {
 	__le32	MessageType;
@@ -309,15 +225,18 @@
 typedef struct rndis_params
 {
 	u8			confignr;
-	int			used;
+	u8			used;
+	u16			saved_filter;
 	enum rndis_state	state;
-	u32			filter;
 	u32			medium;
 	u32			speed;
 	u32			media_state;
+
 	const u8		*host_mac;
+	u16			*filter;
 	struct net_device 	*dev;
 	struct net_device_stats *stats;
+
 	u32			vendorID;
 	const char		*vendorDescr;
 	int 			(*ack) (struct net_device *);
@@ -329,7 +248,8 @@
 int  rndis_register (int (*rndis_control_ack) (struct net_device *));
 void rndis_deregister (int configNr);
 int  rndis_set_param_dev (u8 configNr, struct net_device *dev,
-			 struct net_device_stats *stats);
+			 struct net_device_stats *stats,
+			 u16 *cdc_filter);
 int  rndis_set_param_vendor (u8 configNr, u32 vendorID, 
 			    const char *vendorDescr);
 int  rndis_set_param_medium (u8 configNr, u32 medium, u32 speed);
@@ -338,6 +258,7 @@
 u8   *rndis_get_next_response (int configNr, u32 *length);
 void rndis_free_response (int configNr, u8 *buf);
 
+void rndis_uninit (int configNr);
 int  rndis_signal_connect (int configNr);
 int  rndis_signal_disconnect (int configNr);
 int  rndis_state (int configNr);