xref: /rk3399_rockchip-uboot/drivers/usb/gadget/rndis.c (revision 04770e6e917b0f766a9496e3f37bcdf2ebb1beb4)
17612a43dSVitaly Kuzmichev /*
27612a43dSVitaly Kuzmichev  * RNDIS MSG parser
37612a43dSVitaly Kuzmichev  *
47612a43dSVitaly Kuzmichev  * Authors:	Benedikt Spranger, Pengutronix
57612a43dSVitaly Kuzmichev  *		Robert Schwebel, Pengutronix
67612a43dSVitaly Kuzmichev  *
77612a43dSVitaly Kuzmichev  *		This software was originally developed in conformance with
87612a43dSVitaly Kuzmichev  *		Microsoft's Remote NDIS Specification License Agreement.
97612a43dSVitaly Kuzmichev  *
107612a43dSVitaly Kuzmichev  * 03/12/2004 Kai-Uwe Bloem <linux-development@auerswald.de>
117612a43dSVitaly Kuzmichev  *		Fixed message length bug in init_response
127612a43dSVitaly Kuzmichev  *
137612a43dSVitaly Kuzmichev  * 03/25/2004 Kai-Uwe Bloem <linux-development@auerswald.de>
147612a43dSVitaly Kuzmichev  *		Fixed rndis_rm_hdr length bug.
157612a43dSVitaly Kuzmichev  *
167612a43dSVitaly Kuzmichev  * Copyright (C) 2004 by David Brownell
177612a43dSVitaly Kuzmichev  *		updates to merge with Linux 2.6, better match RNDIS spec
185b8031ccSTom Rini  *
195b8031ccSTom Rini  * SPDX-License-Identifier:	GPL-2.0
207612a43dSVitaly Kuzmichev  */
217612a43dSVitaly Kuzmichev 
227612a43dSVitaly Kuzmichev #include <common.h>
237612a43dSVitaly Kuzmichev #include <net.h>
247612a43dSVitaly Kuzmichev #include <malloc.h>
257612a43dSVitaly Kuzmichev #include <linux/types.h>
267612a43dSVitaly Kuzmichev #include <linux/list.h>
277612a43dSVitaly Kuzmichev #include <linux/netdevice.h>
287612a43dSVitaly Kuzmichev 
297612a43dSVitaly Kuzmichev #include <asm/byteorder.h>
307612a43dSVitaly Kuzmichev #include <asm/unaligned.h>
311221ce45SMasahiro Yamada #include <linux/errno.h>
327612a43dSVitaly Kuzmichev 
337612a43dSVitaly Kuzmichev #undef	RNDIS_PM
347612a43dSVitaly Kuzmichev #undef	RNDIS_WAKEUP
357612a43dSVitaly Kuzmichev #undef	VERBOSE
367612a43dSVitaly Kuzmichev 
377612a43dSVitaly Kuzmichev #include "rndis.h"
387612a43dSVitaly Kuzmichev 
397612a43dSVitaly Kuzmichev #define ETH_ALEN	6		/* Octets in one ethernet addr	 */
407612a43dSVitaly Kuzmichev #define ETH_HLEN	14		/* Total octets in header.	 */
417612a43dSVitaly Kuzmichev #define ETH_ZLEN	60		/* Min. octets in frame sans FCS */
427612a43dSVitaly Kuzmichev #define ETH_DATA_LEN	1500		/* Max. octets in payload	 */
437612a43dSVitaly Kuzmichev #define ETH_FRAME_LEN	PKTSIZE_ALIGN	/* Max. octets in frame sans FCS */
447612a43dSVitaly Kuzmichev 
457612a43dSVitaly Kuzmichev /*
467612a43dSVitaly Kuzmichev  * The driver for your USB chip needs to support ep0 OUT to work with
477612a43dSVitaly Kuzmichev  * RNDIS, plus all three CDC Ethernet endpoints (interrupt not optional).
487612a43dSVitaly Kuzmichev  *
497612a43dSVitaly Kuzmichev  * Windows hosts need an INF file like Documentation/usb/linux.inf
507612a43dSVitaly Kuzmichev  * and will be happier if you provide the host_addr module parameter.
517612a43dSVitaly Kuzmichev  */
527612a43dSVitaly Kuzmichev 
537612a43dSVitaly Kuzmichev #define RNDIS_MAX_CONFIGS	1
547612a43dSVitaly Kuzmichev 
557612a43dSVitaly Kuzmichev static rndis_params rndis_per_dev_params[RNDIS_MAX_CONFIGS];
567612a43dSVitaly Kuzmichev 
577612a43dSVitaly Kuzmichev /* Driver Version */
587612a43dSVitaly Kuzmichev static const __le32 rndis_driver_version = __constant_cpu_to_le32(1);
597612a43dSVitaly Kuzmichev 
607612a43dSVitaly Kuzmichev /* Function Prototypes */
617612a43dSVitaly Kuzmichev static rndis_resp_t *rndis_add_response(int configNr, u32 length);
627612a43dSVitaly Kuzmichev 
637612a43dSVitaly Kuzmichev 
647612a43dSVitaly Kuzmichev /* supported OIDs */
657612a43dSVitaly Kuzmichev static const u32 oid_supported_list[] = {
667612a43dSVitaly Kuzmichev 	/* the general stuff */
677612a43dSVitaly Kuzmichev 	OID_GEN_SUPPORTED_LIST,
687612a43dSVitaly Kuzmichev 	OID_GEN_HARDWARE_STATUS,
697612a43dSVitaly Kuzmichev 	OID_GEN_MEDIA_SUPPORTED,
707612a43dSVitaly Kuzmichev 	OID_GEN_MEDIA_IN_USE,
717612a43dSVitaly Kuzmichev 	OID_GEN_MAXIMUM_FRAME_SIZE,
727612a43dSVitaly Kuzmichev 	OID_GEN_LINK_SPEED,
737612a43dSVitaly Kuzmichev 	OID_GEN_TRANSMIT_BLOCK_SIZE,
747612a43dSVitaly Kuzmichev 	OID_GEN_RECEIVE_BLOCK_SIZE,
757612a43dSVitaly Kuzmichev 	OID_GEN_VENDOR_ID,
767612a43dSVitaly Kuzmichev 	OID_GEN_VENDOR_DESCRIPTION,
777612a43dSVitaly Kuzmichev 	OID_GEN_VENDOR_DRIVER_VERSION,
787612a43dSVitaly Kuzmichev 	OID_GEN_CURRENT_PACKET_FILTER,
797612a43dSVitaly Kuzmichev 	OID_GEN_MAXIMUM_TOTAL_SIZE,
807612a43dSVitaly Kuzmichev 	OID_GEN_MEDIA_CONNECT_STATUS,
817612a43dSVitaly Kuzmichev 	OID_GEN_PHYSICAL_MEDIUM,
827612a43dSVitaly Kuzmichev #if 0
837612a43dSVitaly Kuzmichev 	OID_GEN_RNDIS_CONFIG_PARAMETER,
847612a43dSVitaly Kuzmichev #endif
857612a43dSVitaly Kuzmichev 
867612a43dSVitaly Kuzmichev 	/* the statistical stuff */
877612a43dSVitaly Kuzmichev 	OID_GEN_XMIT_OK,
887612a43dSVitaly Kuzmichev 	OID_GEN_RCV_OK,
897612a43dSVitaly Kuzmichev 	OID_GEN_XMIT_ERROR,
907612a43dSVitaly Kuzmichev 	OID_GEN_RCV_ERROR,
917612a43dSVitaly Kuzmichev 	OID_GEN_RCV_NO_BUFFER,
927612a43dSVitaly Kuzmichev #ifdef	RNDIS_OPTIONAL_STATS
937612a43dSVitaly Kuzmichev 	OID_GEN_DIRECTED_BYTES_XMIT,
947612a43dSVitaly Kuzmichev 	OID_GEN_DIRECTED_FRAMES_XMIT,
957612a43dSVitaly Kuzmichev 	OID_GEN_MULTICAST_BYTES_XMIT,
967612a43dSVitaly Kuzmichev 	OID_GEN_MULTICAST_FRAMES_XMIT,
977612a43dSVitaly Kuzmichev 	OID_GEN_BROADCAST_BYTES_XMIT,
987612a43dSVitaly Kuzmichev 	OID_GEN_BROADCAST_FRAMES_XMIT,
997612a43dSVitaly Kuzmichev 	OID_GEN_DIRECTED_BYTES_RCV,
1007612a43dSVitaly Kuzmichev 	OID_GEN_DIRECTED_FRAMES_RCV,
1017612a43dSVitaly Kuzmichev 	OID_GEN_MULTICAST_BYTES_RCV,
1027612a43dSVitaly Kuzmichev 	OID_GEN_MULTICAST_FRAMES_RCV,
1037612a43dSVitaly Kuzmichev 	OID_GEN_BROADCAST_BYTES_RCV,
1047612a43dSVitaly Kuzmichev 	OID_GEN_BROADCAST_FRAMES_RCV,
1057612a43dSVitaly Kuzmichev 	OID_GEN_RCV_CRC_ERROR,
1067612a43dSVitaly Kuzmichev 	OID_GEN_TRANSMIT_QUEUE_LENGTH,
1077612a43dSVitaly Kuzmichev #endif	/* RNDIS_OPTIONAL_STATS */
1087612a43dSVitaly Kuzmichev 
1097612a43dSVitaly Kuzmichev 	/* mandatory 802.3 */
1107612a43dSVitaly Kuzmichev 	/* the general stuff */
1117612a43dSVitaly Kuzmichev 	OID_802_3_PERMANENT_ADDRESS,
1127612a43dSVitaly Kuzmichev 	OID_802_3_CURRENT_ADDRESS,
1137612a43dSVitaly Kuzmichev 	OID_802_3_MULTICAST_LIST,
1147612a43dSVitaly Kuzmichev 	OID_802_3_MAC_OPTIONS,
1157612a43dSVitaly Kuzmichev 	OID_802_3_MAXIMUM_LIST_SIZE,
1167612a43dSVitaly Kuzmichev 
1177612a43dSVitaly Kuzmichev 	/* the statistical stuff */
1187612a43dSVitaly Kuzmichev 	OID_802_3_RCV_ERROR_ALIGNMENT,
1197612a43dSVitaly Kuzmichev 	OID_802_3_XMIT_ONE_COLLISION,
1207612a43dSVitaly Kuzmichev 	OID_802_3_XMIT_MORE_COLLISIONS,
1217612a43dSVitaly Kuzmichev #ifdef	RNDIS_OPTIONAL_STATS
1227612a43dSVitaly Kuzmichev 	OID_802_3_XMIT_DEFERRED,
1237612a43dSVitaly Kuzmichev 	OID_802_3_XMIT_MAX_COLLISIONS,
1247612a43dSVitaly Kuzmichev 	OID_802_3_RCV_OVERRUN,
1257612a43dSVitaly Kuzmichev 	OID_802_3_XMIT_UNDERRUN,
1267612a43dSVitaly Kuzmichev 	OID_802_3_XMIT_HEARTBEAT_FAILURE,
1277612a43dSVitaly Kuzmichev 	OID_802_3_XMIT_TIMES_CRS_LOST,
1287612a43dSVitaly Kuzmichev 	OID_802_3_XMIT_LATE_COLLISIONS,
1297612a43dSVitaly Kuzmichev #endif	/* RNDIS_OPTIONAL_STATS */
1307612a43dSVitaly Kuzmichev 
1317612a43dSVitaly Kuzmichev #ifdef	RNDIS_PM
1327612a43dSVitaly Kuzmichev 	/* PM and wakeup are mandatory for USB: */
1337612a43dSVitaly Kuzmichev 
1347612a43dSVitaly Kuzmichev 	/* power management */
1357612a43dSVitaly Kuzmichev 	OID_PNP_CAPABILITIES,
1367612a43dSVitaly Kuzmichev 	OID_PNP_QUERY_POWER,
1377612a43dSVitaly Kuzmichev 	OID_PNP_SET_POWER,
1387612a43dSVitaly Kuzmichev 
1397612a43dSVitaly Kuzmichev #ifdef	RNDIS_WAKEUP
1407612a43dSVitaly Kuzmichev 	/* wake up host */
1417612a43dSVitaly Kuzmichev 	OID_PNP_ENABLE_WAKE_UP,
1427612a43dSVitaly Kuzmichev 	OID_PNP_ADD_WAKE_UP_PATTERN,
1437612a43dSVitaly Kuzmichev 	OID_PNP_REMOVE_WAKE_UP_PATTERN,
1447612a43dSVitaly Kuzmichev #endif	/* RNDIS_WAKEUP */
1457612a43dSVitaly Kuzmichev #endif	/* RNDIS_PM */
1467612a43dSVitaly Kuzmichev };
1477612a43dSVitaly Kuzmichev 
1487612a43dSVitaly Kuzmichev 
1497612a43dSVitaly Kuzmichev /* NDIS Functions */
gen_ndis_query_resp(int configNr,u32 OID,u8 * buf,unsigned buf_len,rndis_resp_t * r)1507612a43dSVitaly Kuzmichev static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
1517612a43dSVitaly Kuzmichev 				unsigned buf_len, rndis_resp_t *r)
1527612a43dSVitaly Kuzmichev {
1537612a43dSVitaly Kuzmichev 	int				retval = -ENOTSUPP;
1547612a43dSVitaly Kuzmichev 	u32				length = 4;	/* usually */
1557612a43dSVitaly Kuzmichev 	__le32				*outbuf;
1567612a43dSVitaly Kuzmichev 	int				i, count;
1577612a43dSVitaly Kuzmichev 	rndis_query_cmplt_type		*resp;
1587612a43dSVitaly Kuzmichev 	rndis_params			*params;
1597612a43dSVitaly Kuzmichev 
1607612a43dSVitaly Kuzmichev 	if (!r)
1617612a43dSVitaly Kuzmichev 		return -ENOMEM;
1627612a43dSVitaly Kuzmichev 	resp = (rndis_query_cmplt_type *) r->buf;
1637612a43dSVitaly Kuzmichev 
1647612a43dSVitaly Kuzmichev 	if (!resp)
1657612a43dSVitaly Kuzmichev 		return -ENOMEM;
1667612a43dSVitaly Kuzmichev 
1677612a43dSVitaly Kuzmichev #if defined(DEBUG) && defined(DEBUG_VERBOSE)
1687612a43dSVitaly Kuzmichev 	if (buf_len) {
1697612a43dSVitaly Kuzmichev 		debug("query OID %08x value, len %d:\n", OID, buf_len);
1707612a43dSVitaly Kuzmichev 		for (i = 0; i < buf_len; i += 16) {
1717612a43dSVitaly Kuzmichev 			debug("%03d: %08x %08x %08x %08x\n", i,
1727612a43dSVitaly Kuzmichev 				get_unaligned_le32(&buf[i]),
1737612a43dSVitaly Kuzmichev 				get_unaligned_le32(&buf[i + 4]),
1747612a43dSVitaly Kuzmichev 				get_unaligned_le32(&buf[i + 8]),
1757612a43dSVitaly Kuzmichev 				get_unaligned_le32(&buf[i + 12]));
1767612a43dSVitaly Kuzmichev 		}
1777612a43dSVitaly Kuzmichev 	}
1787612a43dSVitaly Kuzmichev #endif
1797612a43dSVitaly Kuzmichev 
1807612a43dSVitaly Kuzmichev 	/* response goes here, right after the header */
1817612a43dSVitaly Kuzmichev 	outbuf = (__le32 *) &resp[1];
1827612a43dSVitaly Kuzmichev 	resp->InformationBufferOffset = __constant_cpu_to_le32(16);
1837612a43dSVitaly Kuzmichev 
1847612a43dSVitaly Kuzmichev 	params = &rndis_per_dev_params[configNr];
1857612a43dSVitaly Kuzmichev 	switch (OID) {
1867612a43dSVitaly Kuzmichev 
1877612a43dSVitaly Kuzmichev 	/* general oids (table 4-1) */
1887612a43dSVitaly Kuzmichev 
1897612a43dSVitaly Kuzmichev 	/* mandatory */
1907612a43dSVitaly Kuzmichev 	case OID_GEN_SUPPORTED_LIST:
1917612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_SUPPORTED_LIST\n", __func__);
1927612a43dSVitaly Kuzmichev 		length = sizeof(oid_supported_list);
1937612a43dSVitaly Kuzmichev 		count  = length / sizeof(u32);
1947612a43dSVitaly Kuzmichev 		for (i = 0; i < count; i++)
1957612a43dSVitaly Kuzmichev 			outbuf[i] = cpu_to_le32(oid_supported_list[i]);
1967612a43dSVitaly Kuzmichev 		retval = 0;
1977612a43dSVitaly Kuzmichev 		break;
1987612a43dSVitaly Kuzmichev 
1997612a43dSVitaly Kuzmichev 	/* mandatory */
2007612a43dSVitaly Kuzmichev 	case OID_GEN_HARDWARE_STATUS:
2017612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_HARDWARE_STATUS\n", __func__);
2027612a43dSVitaly Kuzmichev 		/*
2037612a43dSVitaly Kuzmichev 		 * Bogus question!
2047612a43dSVitaly Kuzmichev 		 * Hardware must be ready to receive high level protocols.
2057612a43dSVitaly Kuzmichev 		 * BTW:
2067612a43dSVitaly Kuzmichev 		 * reddite ergo quae sunt Caesaris Caesari
2077612a43dSVitaly Kuzmichev 		 * et quae sunt Dei Deo!
2087612a43dSVitaly Kuzmichev 		 */
2097612a43dSVitaly Kuzmichev 		*outbuf = __constant_cpu_to_le32(0);
2107612a43dSVitaly Kuzmichev 		retval = 0;
2117612a43dSVitaly Kuzmichev 		break;
2127612a43dSVitaly Kuzmichev 
2137612a43dSVitaly Kuzmichev 	/* mandatory */
2147612a43dSVitaly Kuzmichev 	case OID_GEN_MEDIA_SUPPORTED:
2157612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_MEDIA_SUPPORTED\n", __func__);
2167612a43dSVitaly Kuzmichev 		*outbuf = cpu_to_le32(params->medium);
2177612a43dSVitaly Kuzmichev 		retval = 0;
2187612a43dSVitaly Kuzmichev 		break;
2197612a43dSVitaly Kuzmichev 
2207612a43dSVitaly Kuzmichev 	/* mandatory */
2217612a43dSVitaly Kuzmichev 	case OID_GEN_MEDIA_IN_USE:
2227612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_MEDIA_IN_USE\n", __func__);
2237612a43dSVitaly Kuzmichev 		/* one medium, one transport... (maybe you do it better) */
2247612a43dSVitaly Kuzmichev 		*outbuf = cpu_to_le32(params->medium);
2257612a43dSVitaly Kuzmichev 		retval = 0;
2267612a43dSVitaly Kuzmichev 		break;
2277612a43dSVitaly Kuzmichev 
2287612a43dSVitaly Kuzmichev 	/* mandatory */
2297612a43dSVitaly Kuzmichev 	case OID_GEN_MAXIMUM_FRAME_SIZE:
2307612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __func__);
2317612a43dSVitaly Kuzmichev 		if (params->dev) {
2327612a43dSVitaly Kuzmichev 			*outbuf = cpu_to_le32(params->mtu);
2337612a43dSVitaly Kuzmichev 			retval = 0;
2347612a43dSVitaly Kuzmichev 		}
2357612a43dSVitaly Kuzmichev 		break;
2367612a43dSVitaly Kuzmichev 
2377612a43dSVitaly Kuzmichev 	/* mandatory */
2387612a43dSVitaly Kuzmichev 	case OID_GEN_LINK_SPEED:
2397612a43dSVitaly Kuzmichev #if defined(DEBUG) && defined(DEBUG_VERBOSE)
2407612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_LINK_SPEED\n", __func__);
2417612a43dSVitaly Kuzmichev #endif
2427612a43dSVitaly Kuzmichev 		if (params->media_state == NDIS_MEDIA_STATE_DISCONNECTED)
2437612a43dSVitaly Kuzmichev 			*outbuf = __constant_cpu_to_le32(0);
2447612a43dSVitaly Kuzmichev 		else
2457612a43dSVitaly Kuzmichev 			*outbuf = cpu_to_le32(params->speed);
2467612a43dSVitaly Kuzmichev 		retval = 0;
2477612a43dSVitaly Kuzmichev 		break;
2487612a43dSVitaly Kuzmichev 
2497612a43dSVitaly Kuzmichev 	/* mandatory */
2507612a43dSVitaly Kuzmichev 	case OID_GEN_TRANSMIT_BLOCK_SIZE:
2517612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __func__);
2527612a43dSVitaly Kuzmichev 		if (params->dev) {
2537612a43dSVitaly Kuzmichev 			*outbuf = cpu_to_le32(params->mtu);
2547612a43dSVitaly Kuzmichev 			retval = 0;
2557612a43dSVitaly Kuzmichev 		}
2567612a43dSVitaly Kuzmichev 		break;
2577612a43dSVitaly Kuzmichev 
2587612a43dSVitaly Kuzmichev 	/* mandatory */
2597612a43dSVitaly Kuzmichev 	case OID_GEN_RECEIVE_BLOCK_SIZE:
2607612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __func__);
2617612a43dSVitaly Kuzmichev 		if (params->dev) {
2627612a43dSVitaly Kuzmichev 			*outbuf = cpu_to_le32(params->mtu);
2637612a43dSVitaly Kuzmichev 			retval = 0;
2647612a43dSVitaly Kuzmichev 		}
2657612a43dSVitaly Kuzmichev 		break;
2667612a43dSVitaly Kuzmichev 
2677612a43dSVitaly Kuzmichev 	/* mandatory */
2687612a43dSVitaly Kuzmichev 	case OID_GEN_VENDOR_ID:
2697612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_VENDOR_ID\n", __func__);
2707612a43dSVitaly Kuzmichev 		*outbuf = cpu_to_le32(params->vendorID);
2717612a43dSVitaly Kuzmichev 		retval = 0;
2727612a43dSVitaly Kuzmichev 		break;
2737612a43dSVitaly Kuzmichev 
2747612a43dSVitaly Kuzmichev 	/* mandatory */
2757612a43dSVitaly Kuzmichev 	case OID_GEN_VENDOR_DESCRIPTION:
2767612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_VENDOR_DESCRIPTION\n", __func__);
2777612a43dSVitaly Kuzmichev 		length = strlen(params->vendorDescr);
2787612a43dSVitaly Kuzmichev 		memcpy(outbuf, params->vendorDescr, length);
2797612a43dSVitaly Kuzmichev 		retval = 0;
2807612a43dSVitaly Kuzmichev 		break;
2817612a43dSVitaly Kuzmichev 
2827612a43dSVitaly Kuzmichev 	case OID_GEN_VENDOR_DRIVER_VERSION:
2837612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __func__);
2847612a43dSVitaly Kuzmichev 		/* Created as LE */
2857612a43dSVitaly Kuzmichev 		*outbuf = rndis_driver_version;
2867612a43dSVitaly Kuzmichev 		retval = 0;
2877612a43dSVitaly Kuzmichev 		break;
2887612a43dSVitaly Kuzmichev 
2897612a43dSVitaly Kuzmichev 	/* mandatory */
2907612a43dSVitaly Kuzmichev 	case OID_GEN_CURRENT_PACKET_FILTER:
2917612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __func__);
2927612a43dSVitaly Kuzmichev 		*outbuf = cpu_to_le32(*params->filter);
2937612a43dSVitaly Kuzmichev 		retval = 0;
2947612a43dSVitaly Kuzmichev 		break;
2957612a43dSVitaly Kuzmichev 
2967612a43dSVitaly Kuzmichev 	/* mandatory */
2977612a43dSVitaly Kuzmichev 	case OID_GEN_MAXIMUM_TOTAL_SIZE:
2987612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __func__);
2997612a43dSVitaly Kuzmichev 		*outbuf = __constant_cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
3007612a43dSVitaly Kuzmichev 		retval = 0;
3017612a43dSVitaly Kuzmichev 		break;
3027612a43dSVitaly Kuzmichev 
3037612a43dSVitaly Kuzmichev 	/* mandatory */
3047612a43dSVitaly Kuzmichev 	case OID_GEN_MEDIA_CONNECT_STATUS:
3057612a43dSVitaly Kuzmichev #if defined(DEBUG) && defined(DEBUG_VERBOSE)
3067612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __func__);
3077612a43dSVitaly Kuzmichev #endif
3087612a43dSVitaly Kuzmichev 		*outbuf = cpu_to_le32(params->media_state);
3097612a43dSVitaly Kuzmichev 		retval = 0;
3107612a43dSVitaly Kuzmichev 		break;
3117612a43dSVitaly Kuzmichev 
3127612a43dSVitaly Kuzmichev 	case OID_GEN_PHYSICAL_MEDIUM:
3137612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_PHYSICAL_MEDIUM\n", __func__);
3147612a43dSVitaly Kuzmichev 		*outbuf = __constant_cpu_to_le32(0);
3157612a43dSVitaly Kuzmichev 		retval = 0;
3167612a43dSVitaly Kuzmichev 		break;
3177612a43dSVitaly Kuzmichev 
3187612a43dSVitaly Kuzmichev 	/*
3197612a43dSVitaly Kuzmichev 	 * The RNDIS specification is incomplete/wrong.   Some versions
3207612a43dSVitaly Kuzmichev 	 * of MS-Windows expect OIDs that aren't specified there.  Other
3217612a43dSVitaly Kuzmichev 	 * versions emit undefined RNDIS messages. DOCUMENT ALL THESE!
3227612a43dSVitaly Kuzmichev 	 */
3237612a43dSVitaly Kuzmichev 	case OID_GEN_MAC_OPTIONS:		/* from WinME */
3247612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_MAC_OPTIONS\n", __func__);
3257612a43dSVitaly Kuzmichev 		*outbuf = __constant_cpu_to_le32(
3267612a43dSVitaly Kuzmichev 				  NDIS_MAC_OPTION_RECEIVE_SERIALIZED
3277612a43dSVitaly Kuzmichev 				| NDIS_MAC_OPTION_FULL_DUPLEX);
3287612a43dSVitaly Kuzmichev 		retval = 0;
3297612a43dSVitaly Kuzmichev 		break;
3307612a43dSVitaly Kuzmichev 
3317612a43dSVitaly Kuzmichev 	/* statistics OIDs (table 4-2) */
3327612a43dSVitaly Kuzmichev 
3337612a43dSVitaly Kuzmichev 	/* mandatory */
3347612a43dSVitaly Kuzmichev 	case OID_GEN_XMIT_OK:
3357612a43dSVitaly Kuzmichev #if defined(DEBUG) && defined(DEBUG_VERBOSE)
3367612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_XMIT_OK\n", __func__);
3377612a43dSVitaly Kuzmichev #endif
3387612a43dSVitaly Kuzmichev 		if (params->stats) {
3397612a43dSVitaly Kuzmichev 			*outbuf = cpu_to_le32(
3407612a43dSVitaly Kuzmichev 					params->stats->tx_packets -
3417612a43dSVitaly Kuzmichev 					params->stats->tx_errors -
3427612a43dSVitaly Kuzmichev 					params->stats->tx_dropped);
3437612a43dSVitaly Kuzmichev 			retval = 0;
3447612a43dSVitaly Kuzmichev 		}
3457612a43dSVitaly Kuzmichev 		break;
3467612a43dSVitaly Kuzmichev 
3477612a43dSVitaly Kuzmichev 	/* mandatory */
3487612a43dSVitaly Kuzmichev 	case OID_GEN_RCV_OK:
3497612a43dSVitaly Kuzmichev #if defined(DEBUG) && defined(DEBUG_VERBOSE)
3507612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_RCV_OK\n", __func__);
3517612a43dSVitaly Kuzmichev #endif
3527612a43dSVitaly Kuzmichev 		if (params->stats) {
3537612a43dSVitaly Kuzmichev 			*outbuf = cpu_to_le32(
3547612a43dSVitaly Kuzmichev 					params->stats->rx_packets -
3557612a43dSVitaly Kuzmichev 					params->stats->rx_errors -
3567612a43dSVitaly Kuzmichev 					params->stats->rx_dropped);
3577612a43dSVitaly Kuzmichev 			retval = 0;
3587612a43dSVitaly Kuzmichev 		}
3597612a43dSVitaly Kuzmichev 		break;
3607612a43dSVitaly Kuzmichev 
3617612a43dSVitaly Kuzmichev 	/* mandatory */
3627612a43dSVitaly Kuzmichev 	case OID_GEN_XMIT_ERROR:
3637612a43dSVitaly Kuzmichev #if defined(DEBUG) && defined(DEBUG_VERBOSE)
3647612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_XMIT_ERROR\n", __func__);
3657612a43dSVitaly Kuzmichev #endif
3667612a43dSVitaly Kuzmichev 		if (params->stats) {
3677612a43dSVitaly Kuzmichev 			*outbuf = cpu_to_le32(params->stats->tx_errors);
3687612a43dSVitaly Kuzmichev 			retval = 0;
3697612a43dSVitaly Kuzmichev 		}
3707612a43dSVitaly Kuzmichev 		break;
3717612a43dSVitaly Kuzmichev 
3727612a43dSVitaly Kuzmichev 	/* mandatory */
3737612a43dSVitaly Kuzmichev 	case OID_GEN_RCV_ERROR:
3747612a43dSVitaly Kuzmichev #if defined(DEBUG) && defined(DEBUG_VERBOSE)
3757612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_RCV_ERROR\n", __func__);
3767612a43dSVitaly Kuzmichev #endif
3777612a43dSVitaly Kuzmichev 		if (params->stats) {
3787612a43dSVitaly Kuzmichev 			*outbuf = cpu_to_le32(params->stats->rx_errors);
3797612a43dSVitaly Kuzmichev 			retval = 0;
3807612a43dSVitaly Kuzmichev 		}
3817612a43dSVitaly Kuzmichev 		break;
3827612a43dSVitaly Kuzmichev 
3837612a43dSVitaly Kuzmichev 	/* mandatory */
3847612a43dSVitaly Kuzmichev 	case OID_GEN_RCV_NO_BUFFER:
3857612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_RCV_NO_BUFFER\n", __func__);
3867612a43dSVitaly Kuzmichev 		if (params->stats) {
3877612a43dSVitaly Kuzmichev 			*outbuf = cpu_to_le32(params->stats->rx_dropped);
3887612a43dSVitaly Kuzmichev 			retval = 0;
3897612a43dSVitaly Kuzmichev 		}
3907612a43dSVitaly Kuzmichev 		break;
3917612a43dSVitaly Kuzmichev 
3927612a43dSVitaly Kuzmichev #ifdef	RNDIS_OPTIONAL_STATS
3937612a43dSVitaly Kuzmichev 	case OID_GEN_DIRECTED_BYTES_XMIT:
3947612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __func__);
3957612a43dSVitaly Kuzmichev 		/*
3967612a43dSVitaly Kuzmichev 		 * Aunt Tilly's size of shoes
3977612a43dSVitaly Kuzmichev 		 * minus antarctica count of penguins
3987612a43dSVitaly Kuzmichev 		 * divided by weight of Alpha Centauri
3997612a43dSVitaly Kuzmichev 		 */
4007612a43dSVitaly Kuzmichev 		if (params->stats) {
4017612a43dSVitaly Kuzmichev 			*outbuf = cpu_to_le32(
4027612a43dSVitaly Kuzmichev 					(params->stats->tx_packets -
4037612a43dSVitaly Kuzmichev 					 params->stats->tx_errors -
4047612a43dSVitaly Kuzmichev 					 params->stats->tx_dropped)
4057612a43dSVitaly Kuzmichev 					* 123);
4067612a43dSVitaly Kuzmichev 			retval = 0;
4077612a43dSVitaly Kuzmichev 		}
4087612a43dSVitaly Kuzmichev 		break;
4097612a43dSVitaly Kuzmichev 
4107612a43dSVitaly Kuzmichev 	case OID_GEN_DIRECTED_FRAMES_XMIT:
4117612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __func__);
4127612a43dSVitaly Kuzmichev 		/* dito */
4137612a43dSVitaly Kuzmichev 		if (params->stats) {
4147612a43dSVitaly Kuzmichev 			*outbuf = cpu_to_le32(
4157612a43dSVitaly Kuzmichev 					(params->stats->tx_packets -
4167612a43dSVitaly Kuzmichev 					 params->stats->tx_errors -
4177612a43dSVitaly Kuzmichev 					 params->stats->tx_dropped)
4187612a43dSVitaly Kuzmichev 					/ 123);
4197612a43dSVitaly Kuzmichev 			retval = 0;
4207612a43dSVitaly Kuzmichev 		}
4217612a43dSVitaly Kuzmichev 		break;
4227612a43dSVitaly Kuzmichev 
4237612a43dSVitaly Kuzmichev 	case OID_GEN_MULTICAST_BYTES_XMIT:
4247612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __func__);
4257612a43dSVitaly Kuzmichev 		if (params->stats) {
4267612a43dSVitaly Kuzmichev 			*outbuf = cpu_to_le32(params->stats->multicast * 1234);
4277612a43dSVitaly Kuzmichev 			retval = 0;
4287612a43dSVitaly Kuzmichev 		}
4297612a43dSVitaly Kuzmichev 		break;
4307612a43dSVitaly Kuzmichev 
4317612a43dSVitaly Kuzmichev 	case OID_GEN_MULTICAST_FRAMES_XMIT:
4327612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __func__);
4337612a43dSVitaly Kuzmichev 		if (params->stats) {
4347612a43dSVitaly Kuzmichev 			*outbuf = cpu_to_le32(params->stats->multicast);
4357612a43dSVitaly Kuzmichev 			retval = 0;
4367612a43dSVitaly Kuzmichev 		}
4377612a43dSVitaly Kuzmichev 		break;
4387612a43dSVitaly Kuzmichev 
4397612a43dSVitaly Kuzmichev 	case OID_GEN_BROADCAST_BYTES_XMIT:
4407612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __func__);
4417612a43dSVitaly Kuzmichev 		if (params->stats) {
4427612a43dSVitaly Kuzmichev 			*outbuf = cpu_to_le32(params->stats->tx_packets/42*255);
4437612a43dSVitaly Kuzmichev 			retval = 0;
4447612a43dSVitaly Kuzmichev 		}
4457612a43dSVitaly Kuzmichev 		break;
4467612a43dSVitaly Kuzmichev 
4477612a43dSVitaly Kuzmichev 	case OID_GEN_BROADCAST_FRAMES_XMIT:
4487612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __func__);
4497612a43dSVitaly Kuzmichev 		if (params->stats) {
4507612a43dSVitaly Kuzmichev 			*outbuf = cpu_to_le32(params->stats->tx_packets / 42);
4517612a43dSVitaly Kuzmichev 			retval = 0;
4527612a43dSVitaly Kuzmichev 		}
4537612a43dSVitaly Kuzmichev 		break;
4547612a43dSVitaly Kuzmichev 
4557612a43dSVitaly Kuzmichev 	case OID_GEN_DIRECTED_BYTES_RCV:
4567612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __func__);
4577612a43dSVitaly Kuzmichev 		*outbuf = __constant_cpu_to_le32(0);
4587612a43dSVitaly Kuzmichev 		retval = 0;
4597612a43dSVitaly Kuzmichev 		break;
4607612a43dSVitaly Kuzmichev 
4617612a43dSVitaly Kuzmichev 	case OID_GEN_DIRECTED_FRAMES_RCV:
4627612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __func__);
4637612a43dSVitaly Kuzmichev 		*outbuf = __constant_cpu_to_le32(0);
4647612a43dSVitaly Kuzmichev 		retval = 0;
4657612a43dSVitaly Kuzmichev 		break;
4667612a43dSVitaly Kuzmichev 
4677612a43dSVitaly Kuzmichev 	case OID_GEN_MULTICAST_BYTES_RCV:
4687612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __func__);
4697612a43dSVitaly Kuzmichev 		if (params->stats) {
4707612a43dSVitaly Kuzmichev 			*outbuf = cpu_to_le32(params->stats->multicast * 1111);
4717612a43dSVitaly Kuzmichev 			retval = 0;
4727612a43dSVitaly Kuzmichev 		}
4737612a43dSVitaly Kuzmichev 		break;
4747612a43dSVitaly Kuzmichev 
4757612a43dSVitaly Kuzmichev 	case OID_GEN_MULTICAST_FRAMES_RCV:
4767612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __func__);
4777612a43dSVitaly Kuzmichev 		if (params->stats) {
4787612a43dSVitaly Kuzmichev 			*outbuf = cpu_to_le32(params->stats->multicast);
4797612a43dSVitaly Kuzmichev 			retval = 0;
4807612a43dSVitaly Kuzmichev 		}
4817612a43dSVitaly Kuzmichev 		break;
4827612a43dSVitaly Kuzmichev 
4837612a43dSVitaly Kuzmichev 	case OID_GEN_BROADCAST_BYTES_RCV:
4847612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __func__);
4857612a43dSVitaly Kuzmichev 		if (params->stats) {
4867612a43dSVitaly Kuzmichev 			*outbuf = cpu_to_le32(params->stats->rx_packets/42*255);
4877612a43dSVitaly Kuzmichev 			retval = 0;
4887612a43dSVitaly Kuzmichev 		}
4897612a43dSVitaly Kuzmichev 		break;
4907612a43dSVitaly Kuzmichev 
4917612a43dSVitaly Kuzmichev 	case OID_GEN_BROADCAST_FRAMES_RCV:
4927612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __func__);
4937612a43dSVitaly Kuzmichev 		if (params->stats) {
4947612a43dSVitaly Kuzmichev 			*outbuf = cpu_to_le32(params->stats->rx_packets / 42);
4957612a43dSVitaly Kuzmichev 			retval = 0;
4967612a43dSVitaly Kuzmichev 		}
4977612a43dSVitaly Kuzmichev 		break;
4987612a43dSVitaly Kuzmichev 
4997612a43dSVitaly Kuzmichev 	case OID_GEN_RCV_CRC_ERROR:
5007612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_RCV_CRC_ERROR\n", __func__);
5017612a43dSVitaly Kuzmichev 		if (params->stats) {
5027612a43dSVitaly Kuzmichev 			*outbuf = cpu_to_le32(params->stats->rx_crc_errors);
5037612a43dSVitaly Kuzmichev 			retval = 0;
5047612a43dSVitaly Kuzmichev 		}
5057612a43dSVitaly Kuzmichev 		break;
5067612a43dSVitaly Kuzmichev 
5077612a43dSVitaly Kuzmichev 	case OID_GEN_TRANSMIT_QUEUE_LENGTH:
5087612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __func__);
5097612a43dSVitaly Kuzmichev 		*outbuf = __constant_cpu_to_le32(0);
5107612a43dSVitaly Kuzmichev 		retval = 0;
5117612a43dSVitaly Kuzmichev 		break;
5127612a43dSVitaly Kuzmichev #endif	/* RNDIS_OPTIONAL_STATS */
5137612a43dSVitaly Kuzmichev 
5147612a43dSVitaly Kuzmichev 	/* ieee802.3 OIDs (table 4-3) */
5157612a43dSVitaly Kuzmichev 
5167612a43dSVitaly Kuzmichev 	/* mandatory */
5177612a43dSVitaly Kuzmichev 	case OID_802_3_PERMANENT_ADDRESS:
5187612a43dSVitaly Kuzmichev 		debug("%s: OID_802_3_PERMANENT_ADDRESS\n", __func__);
5197612a43dSVitaly Kuzmichev 		if (params->dev) {
5207612a43dSVitaly Kuzmichev 			length = ETH_ALEN;
5217612a43dSVitaly Kuzmichev 			memcpy(outbuf, params->host_mac, length);
5227612a43dSVitaly Kuzmichev 			retval = 0;
5237612a43dSVitaly Kuzmichev 		}
5247612a43dSVitaly Kuzmichev 		break;
5257612a43dSVitaly Kuzmichev 
5267612a43dSVitaly Kuzmichev 	/* mandatory */
5277612a43dSVitaly Kuzmichev 	case OID_802_3_CURRENT_ADDRESS:
5287612a43dSVitaly Kuzmichev 		debug("%s: OID_802_3_CURRENT_ADDRESS\n", __func__);
5297612a43dSVitaly Kuzmichev 		if (params->dev) {
5307612a43dSVitaly Kuzmichev 			length = ETH_ALEN;
5317612a43dSVitaly Kuzmichev 			memcpy(outbuf, params->host_mac, length);
5327612a43dSVitaly Kuzmichev 			retval = 0;
5337612a43dSVitaly Kuzmichev 		}
5347612a43dSVitaly Kuzmichev 		break;
5357612a43dSVitaly Kuzmichev 
5367612a43dSVitaly Kuzmichev 	/* mandatory */
5377612a43dSVitaly Kuzmichev 	case OID_802_3_MULTICAST_LIST:
5387612a43dSVitaly Kuzmichev 		debug("%s: OID_802_3_MULTICAST_LIST\n", __func__);
5397612a43dSVitaly Kuzmichev 		/* Multicast base address only */
5407612a43dSVitaly Kuzmichev 		*outbuf = __constant_cpu_to_le32(0xE0000000);
5417612a43dSVitaly Kuzmichev 		retval = 0;
5427612a43dSVitaly Kuzmichev 		break;
5437612a43dSVitaly Kuzmichev 
5447612a43dSVitaly Kuzmichev 	/* mandatory */
5457612a43dSVitaly Kuzmichev 	case OID_802_3_MAXIMUM_LIST_SIZE:
5467612a43dSVitaly Kuzmichev 		debug("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __func__);
5477612a43dSVitaly Kuzmichev 		/* Multicast base address only */
5487612a43dSVitaly Kuzmichev 		*outbuf = __constant_cpu_to_le32(1);
5497612a43dSVitaly Kuzmichev 		retval = 0;
5507612a43dSVitaly Kuzmichev 		break;
5517612a43dSVitaly Kuzmichev 
5527612a43dSVitaly Kuzmichev 	case OID_802_3_MAC_OPTIONS:
5537612a43dSVitaly Kuzmichev 		debug("%s: OID_802_3_MAC_OPTIONS\n", __func__);
5547612a43dSVitaly Kuzmichev 		break;
5557612a43dSVitaly Kuzmichev 
5567612a43dSVitaly Kuzmichev 	/* ieee802.3 statistics OIDs (table 4-4) */
5577612a43dSVitaly Kuzmichev 
5587612a43dSVitaly Kuzmichev 	/* mandatory */
5597612a43dSVitaly Kuzmichev 	case OID_802_3_RCV_ERROR_ALIGNMENT:
5607612a43dSVitaly Kuzmichev 		debug("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __func__);
5617612a43dSVitaly Kuzmichev 		if (params->stats) {
5627612a43dSVitaly Kuzmichev 			*outbuf = cpu_to_le32(params->stats->rx_frame_errors);
5637612a43dSVitaly Kuzmichev 			retval = 0;
5647612a43dSVitaly Kuzmichev 		}
5657612a43dSVitaly Kuzmichev 		break;
5667612a43dSVitaly Kuzmichev 
5677612a43dSVitaly Kuzmichev 	/* mandatory */
5687612a43dSVitaly Kuzmichev 	case OID_802_3_XMIT_ONE_COLLISION:
5697612a43dSVitaly Kuzmichev 		debug("%s: OID_802_3_XMIT_ONE_COLLISION\n", __func__);
5707612a43dSVitaly Kuzmichev 		*outbuf = __constant_cpu_to_le32(0);
5717612a43dSVitaly Kuzmichev 		retval = 0;
5727612a43dSVitaly Kuzmichev 		break;
5737612a43dSVitaly Kuzmichev 
5747612a43dSVitaly Kuzmichev 	/* mandatory */
5757612a43dSVitaly Kuzmichev 	case OID_802_3_XMIT_MORE_COLLISIONS:
5767612a43dSVitaly Kuzmichev 		debug("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __func__);
5777612a43dSVitaly Kuzmichev 		*outbuf = __constant_cpu_to_le32(0);
5787612a43dSVitaly Kuzmichev 		retval = 0;
5797612a43dSVitaly Kuzmichev 		break;
5807612a43dSVitaly Kuzmichev 
5817612a43dSVitaly Kuzmichev #ifdef	RNDIS_OPTIONAL_STATS
5827612a43dSVitaly Kuzmichev 	case OID_802_3_XMIT_DEFERRED:
5837612a43dSVitaly Kuzmichev 		debug("%s: OID_802_3_XMIT_DEFERRED\n", __func__);
5847612a43dSVitaly Kuzmichev 		/* TODO */
5857612a43dSVitaly Kuzmichev 		break;
5867612a43dSVitaly Kuzmichev 
5877612a43dSVitaly Kuzmichev 	case OID_802_3_XMIT_MAX_COLLISIONS:
5887612a43dSVitaly Kuzmichev 		debug("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __func__);
5897612a43dSVitaly Kuzmichev 		/* TODO */
5907612a43dSVitaly Kuzmichev 		break;
5917612a43dSVitaly Kuzmichev 
5927612a43dSVitaly Kuzmichev 	case OID_802_3_RCV_OVERRUN:
5937612a43dSVitaly Kuzmichev 		debug("%s: OID_802_3_RCV_OVERRUN\n", __func__);
5947612a43dSVitaly Kuzmichev 		/* TODO */
5957612a43dSVitaly Kuzmichev 		break;
5967612a43dSVitaly Kuzmichev 
5977612a43dSVitaly Kuzmichev 	case OID_802_3_XMIT_UNDERRUN:
5987612a43dSVitaly Kuzmichev 		debug("%s: OID_802_3_XMIT_UNDERRUN\n", __func__);
5997612a43dSVitaly Kuzmichev 		/* TODO */
6007612a43dSVitaly Kuzmichev 		break;
6017612a43dSVitaly Kuzmichev 
6027612a43dSVitaly Kuzmichev 	case OID_802_3_XMIT_HEARTBEAT_FAILURE:
6037612a43dSVitaly Kuzmichev 		debug("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __func__);
6047612a43dSVitaly Kuzmichev 		/* TODO */
6057612a43dSVitaly Kuzmichev 		break;
6067612a43dSVitaly Kuzmichev 
6077612a43dSVitaly Kuzmichev 	case OID_802_3_XMIT_TIMES_CRS_LOST:
6087612a43dSVitaly Kuzmichev 		debug("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __func__);
6097612a43dSVitaly Kuzmichev 		/* TODO */
6107612a43dSVitaly Kuzmichev 		break;
6117612a43dSVitaly Kuzmichev 
6127612a43dSVitaly Kuzmichev 	case OID_802_3_XMIT_LATE_COLLISIONS:
6137612a43dSVitaly Kuzmichev 		debug("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __func__);
6147612a43dSVitaly Kuzmichev 		/* TODO */
6157612a43dSVitaly Kuzmichev 		break;
6167612a43dSVitaly Kuzmichev #endif	/* RNDIS_OPTIONAL_STATS */
6177612a43dSVitaly Kuzmichev 
6187612a43dSVitaly Kuzmichev #ifdef	RNDIS_PM
6197612a43dSVitaly Kuzmichev 	/* power management OIDs (table 4-5) */
6207612a43dSVitaly Kuzmichev 	case OID_PNP_CAPABILITIES:
6217612a43dSVitaly Kuzmichev 		debug("%s: OID_PNP_CAPABILITIES\n", __func__);
6227612a43dSVitaly Kuzmichev 
6237612a43dSVitaly Kuzmichev 		/* for now, no wakeup capabilities */
6247612a43dSVitaly Kuzmichev 		length = sizeof(struct NDIS_PNP_CAPABILITIES);
6257612a43dSVitaly Kuzmichev 		memset(outbuf, 0, length);
6267612a43dSVitaly Kuzmichev 		retval = 0;
6277612a43dSVitaly Kuzmichev 		break;
6287612a43dSVitaly Kuzmichev 	case OID_PNP_QUERY_POWER:
6297612a43dSVitaly Kuzmichev 		debug("%s: OID_PNP_QUERY_POWER D%d\n", __func__,
6307612a43dSVitaly Kuzmichev 				get_unaligned_le32(buf) - 1);
6317612a43dSVitaly Kuzmichev 		/*
6327612a43dSVitaly Kuzmichev 		 * only suspend is a real power state, and
6337612a43dSVitaly Kuzmichev 		 * it can't be entered by OID_PNP_SET_POWER...
6347612a43dSVitaly Kuzmichev 		 */
6357612a43dSVitaly Kuzmichev 		length = 0;
6367612a43dSVitaly Kuzmichev 		retval = 0;
6377612a43dSVitaly Kuzmichev 		break;
6387612a43dSVitaly Kuzmichev #endif
6397612a43dSVitaly Kuzmichev 
6407612a43dSVitaly Kuzmichev 	default:
6417612a43dSVitaly Kuzmichev 		debug("%s: query unknown OID 0x%08X\n", __func__, OID);
6427612a43dSVitaly Kuzmichev 	}
6437612a43dSVitaly Kuzmichev 	if (retval < 0)
6447612a43dSVitaly Kuzmichev 		length = 0;
6457612a43dSVitaly Kuzmichev 
6467612a43dSVitaly Kuzmichev 	resp->InformationBufferLength = cpu_to_le32(length);
6477612a43dSVitaly Kuzmichev 	r->length = length + sizeof *resp;
6487612a43dSVitaly Kuzmichev 	resp->MessageLength = cpu_to_le32(r->length);
6497612a43dSVitaly Kuzmichev 	return retval;
6507612a43dSVitaly Kuzmichev }
6517612a43dSVitaly Kuzmichev 
gen_ndis_set_resp(u8 configNr,u32 OID,u8 * buf,u32 buf_len,rndis_resp_t * r)6527612a43dSVitaly Kuzmichev static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len,
6537612a43dSVitaly Kuzmichev 				rndis_resp_t *r)
6547612a43dSVitaly Kuzmichev {
6557612a43dSVitaly Kuzmichev 	rndis_set_cmplt_type		*resp;
6567612a43dSVitaly Kuzmichev 	int				retval = -ENOTSUPP;
6577612a43dSVitaly Kuzmichev 	struct rndis_params		*params;
6587612a43dSVitaly Kuzmichev #if (defined(DEBUG) && defined(DEBUG_VERBOSE)) || defined(RNDIS_PM)
6597612a43dSVitaly Kuzmichev 	int				i;
6607612a43dSVitaly Kuzmichev #endif
6617612a43dSVitaly Kuzmichev 
6627612a43dSVitaly Kuzmichev 	if (!r)
6637612a43dSVitaly Kuzmichev 		return -ENOMEM;
6647612a43dSVitaly Kuzmichev 	resp = (rndis_set_cmplt_type *) r->buf;
6657612a43dSVitaly Kuzmichev 	if (!resp)
6667612a43dSVitaly Kuzmichev 		return -ENOMEM;
6677612a43dSVitaly Kuzmichev 
6687612a43dSVitaly Kuzmichev #if defined(DEBUG) && defined(DEBUG_VERBOSE)
6697612a43dSVitaly Kuzmichev 	if (buf_len) {
6707612a43dSVitaly Kuzmichev 		debug("set OID %08x value, len %d:\n", OID, buf_len);
6717612a43dSVitaly Kuzmichev 		for (i = 0; i < buf_len; i += 16) {
6727612a43dSVitaly Kuzmichev 			debug("%03d: %08x %08x %08x %08x\n", i,
6737612a43dSVitaly Kuzmichev 				get_unaligned_le32(&buf[i]),
6747612a43dSVitaly Kuzmichev 				get_unaligned_le32(&buf[i + 4]),
6757612a43dSVitaly Kuzmichev 				get_unaligned_le32(&buf[i + 8]),
6767612a43dSVitaly Kuzmichev 				get_unaligned_le32(&buf[i + 12]));
6777612a43dSVitaly Kuzmichev 		}
6787612a43dSVitaly Kuzmichev 	}
6797612a43dSVitaly Kuzmichev #endif
6807612a43dSVitaly Kuzmichev 
6817612a43dSVitaly Kuzmichev 	params = &rndis_per_dev_params[configNr];
6827612a43dSVitaly Kuzmichev 	switch (OID) {
6837612a43dSVitaly Kuzmichev 	case OID_GEN_CURRENT_PACKET_FILTER:
6847612a43dSVitaly Kuzmichev 
6857612a43dSVitaly Kuzmichev 		/*
6867612a43dSVitaly Kuzmichev 		 * these NDIS_PACKET_TYPE_* bitflags are shared with
6877612a43dSVitaly Kuzmichev 		 * cdc_filter; it's not RNDIS-specific
6887612a43dSVitaly Kuzmichev 		 * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in:
6897612a43dSVitaly Kuzmichev 		 *	PROMISCUOUS, DIRECTED,
6907612a43dSVitaly Kuzmichev 		 *	MULTICAST, ALL_MULTICAST, BROADCAST
6917612a43dSVitaly Kuzmichev 		 */
6927612a43dSVitaly Kuzmichev 		*params->filter = (u16) get_unaligned_le32(buf);
6937612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
6947612a43dSVitaly Kuzmichev 			__func__, *params->filter);
6957612a43dSVitaly Kuzmichev 
6967612a43dSVitaly Kuzmichev 		/*
6977612a43dSVitaly Kuzmichev 		 * this call has a significant side effect:  it's
6987612a43dSVitaly Kuzmichev 		 * what makes the packet flow start and stop, like
6997612a43dSVitaly Kuzmichev 		 * activating the CDC Ethernet altsetting.
7007612a43dSVitaly Kuzmichev 		 */
7017612a43dSVitaly Kuzmichev #ifdef	RNDIS_PM
7027612a43dSVitaly Kuzmichev update_linkstate:
7037612a43dSVitaly Kuzmichev #endif
7047612a43dSVitaly Kuzmichev 		retval = 0;
7057612a43dSVitaly Kuzmichev 		if (*params->filter)
7067612a43dSVitaly Kuzmichev 			params->state = RNDIS_DATA_INITIALIZED;
7077612a43dSVitaly Kuzmichev 		else
7087612a43dSVitaly Kuzmichev 			params->state = RNDIS_INITIALIZED;
7097612a43dSVitaly Kuzmichev 		break;
7107612a43dSVitaly Kuzmichev 
7117612a43dSVitaly Kuzmichev 	case OID_802_3_MULTICAST_LIST:
7127612a43dSVitaly Kuzmichev 		/* I think we can ignore this */
7137612a43dSVitaly Kuzmichev 		debug("%s: OID_802_3_MULTICAST_LIST\n", __func__);
7147612a43dSVitaly Kuzmichev 		retval = 0;
7157612a43dSVitaly Kuzmichev 		break;
7167612a43dSVitaly Kuzmichev #if 0
7177612a43dSVitaly Kuzmichev 	case OID_GEN_RNDIS_CONFIG_PARAMETER:
7187612a43dSVitaly Kuzmichev 		{
7197612a43dSVitaly Kuzmichev 		struct rndis_config_parameter	*param;
7207612a43dSVitaly Kuzmichev 		param = (struct rndis_config_parameter *) buf;
7217612a43dSVitaly Kuzmichev 		debug("%s: OID_GEN_RNDIS_CONFIG_PARAMETER '%*s'\n",
7227612a43dSVitaly Kuzmichev 			__func__,
7237612a43dSVitaly Kuzmichev 			min(cpu_to_le32(param->ParameterNameLength), 80),
7247612a43dSVitaly Kuzmichev 			buf + param->ParameterNameOffset);
7257612a43dSVitaly Kuzmichev 		retval = 0;
7267612a43dSVitaly Kuzmichev 		}
7277612a43dSVitaly Kuzmichev 		break;
7287612a43dSVitaly Kuzmichev #endif
7297612a43dSVitaly Kuzmichev 
7307612a43dSVitaly Kuzmichev #ifdef	RNDIS_PM
7317612a43dSVitaly Kuzmichev 	case OID_PNP_SET_POWER:
7327612a43dSVitaly Kuzmichev 		/*
7337612a43dSVitaly Kuzmichev 		 * The only real power state is USB suspend, and RNDIS requests
7347612a43dSVitaly Kuzmichev 		 * can't enter it; this one isn't really about power.  After
7357612a43dSVitaly Kuzmichev 		 * resuming, Windows forces a reset, and then SET_POWER D0.
7367612a43dSVitaly Kuzmichev 		 * FIXME ... then things go batty; Windows wedges itself.
7377612a43dSVitaly Kuzmichev 		 */
7387612a43dSVitaly Kuzmichev 		i = get_unaligned_le32(buf);
7397612a43dSVitaly Kuzmichev 		debug("%s: OID_PNP_SET_POWER D%d\n", __func__, i - 1);
7407612a43dSVitaly Kuzmichev 		switch (i) {
7417612a43dSVitaly Kuzmichev 		case NdisDeviceStateD0:
7427612a43dSVitaly Kuzmichev 			*params->filter = params->saved_filter;
7437612a43dSVitaly Kuzmichev 			goto update_linkstate;
7447612a43dSVitaly Kuzmichev 		case NdisDeviceStateD3:
7457612a43dSVitaly Kuzmichev 		case NdisDeviceStateD2:
7467612a43dSVitaly Kuzmichev 		case NdisDeviceStateD1:
7477612a43dSVitaly Kuzmichev 			params->saved_filter = *params->filter;
7487612a43dSVitaly Kuzmichev 			retval = 0;
7497612a43dSVitaly Kuzmichev 			break;
7507612a43dSVitaly Kuzmichev 		}
7517612a43dSVitaly Kuzmichev 		break;
7527612a43dSVitaly Kuzmichev 
7537612a43dSVitaly Kuzmichev #ifdef	RNDIS_WAKEUP
7547612a43dSVitaly Kuzmichev 	/*
7557612a43dSVitaly Kuzmichev 	 * no wakeup support advertised, so wakeup OIDs always fail:
7567612a43dSVitaly Kuzmichev 	 *  - OID_PNP_ENABLE_WAKE_UP
7577612a43dSVitaly Kuzmichev 	 *  - OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN
7587612a43dSVitaly Kuzmichev 	 */
7597612a43dSVitaly Kuzmichev #endif
7607612a43dSVitaly Kuzmichev 
7617612a43dSVitaly Kuzmichev #endif	/* RNDIS_PM */
7627612a43dSVitaly Kuzmichev 
7637612a43dSVitaly Kuzmichev 	default:
7647612a43dSVitaly Kuzmichev 		debug("%s: set unknown OID 0x%08X, size %d\n",
7657612a43dSVitaly Kuzmichev 			__func__, OID, buf_len);
7667612a43dSVitaly Kuzmichev 	}
7677612a43dSVitaly Kuzmichev 
7687612a43dSVitaly Kuzmichev 	return retval;
7697612a43dSVitaly Kuzmichev }
7707612a43dSVitaly Kuzmichev 
7717612a43dSVitaly Kuzmichev /*
7727612a43dSVitaly Kuzmichev  * Response Functions
7737612a43dSVitaly Kuzmichev  */
7747612a43dSVitaly Kuzmichev 
rndis_init_response(int configNr,rndis_init_msg_type * buf)7757612a43dSVitaly Kuzmichev static int rndis_init_response(int configNr, rndis_init_msg_type *buf)
7767612a43dSVitaly Kuzmichev {
7777612a43dSVitaly Kuzmichev 	rndis_init_cmplt_type	*resp;
7787612a43dSVitaly Kuzmichev 	rndis_resp_t            *r;
7797612a43dSVitaly Kuzmichev 
7807612a43dSVitaly Kuzmichev 	if (!rndis_per_dev_params[configNr].dev)
7817612a43dSVitaly Kuzmichev 		return -ENOTSUPP;
7827612a43dSVitaly Kuzmichev 
7837612a43dSVitaly Kuzmichev 	r = rndis_add_response(configNr, sizeof(rndis_init_cmplt_type));
7847612a43dSVitaly Kuzmichev 	if (!r)
7857612a43dSVitaly Kuzmichev 		return -ENOMEM;
7867612a43dSVitaly Kuzmichev 	resp = (rndis_init_cmplt_type *) r->buf;
7877612a43dSVitaly Kuzmichev 
7887612a43dSVitaly Kuzmichev 	resp->MessageType = __constant_cpu_to_le32(
7897612a43dSVitaly Kuzmichev 			REMOTE_NDIS_INITIALIZE_CMPLT);
7907612a43dSVitaly Kuzmichev 	resp->MessageLength = __constant_cpu_to_le32(52);
7917612a43dSVitaly Kuzmichev 	resp->RequestID = get_unaligned(&buf->RequestID); /* Still LE in msg buffer */
7927612a43dSVitaly Kuzmichev 	resp->Status = __constant_cpu_to_le32(RNDIS_STATUS_SUCCESS);
7937612a43dSVitaly Kuzmichev 	resp->MajorVersion = __constant_cpu_to_le32(RNDIS_MAJOR_VERSION);
7947612a43dSVitaly Kuzmichev 	resp->MinorVersion = __constant_cpu_to_le32(RNDIS_MINOR_VERSION);
7957612a43dSVitaly Kuzmichev 	resp->DeviceFlags = __constant_cpu_to_le32(RNDIS_DF_CONNECTIONLESS);
7967612a43dSVitaly Kuzmichev 	resp->Medium = __constant_cpu_to_le32(RNDIS_MEDIUM_802_3);
7977612a43dSVitaly Kuzmichev 	resp->MaxPacketsPerTransfer = __constant_cpu_to_le32(1);
7987612a43dSVitaly Kuzmichev 	resp->MaxTransferSize = cpu_to_le32(
7997612a43dSVitaly Kuzmichev 		  rndis_per_dev_params[configNr].mtu
8007612a43dSVitaly Kuzmichev 		+ ETHER_HDR_SIZE
8017612a43dSVitaly Kuzmichev 		+ sizeof(struct rndis_packet_msg_type)
8027612a43dSVitaly Kuzmichev 		+ 22);
8037612a43dSVitaly Kuzmichev 	resp->PacketAlignmentFactor = __constant_cpu_to_le32(0);
8047612a43dSVitaly Kuzmichev 	resp->AFListOffset = __constant_cpu_to_le32(0);
8057612a43dSVitaly Kuzmichev 	resp->AFListSize = __constant_cpu_to_le32(0);
8067612a43dSVitaly Kuzmichev 
8077612a43dSVitaly Kuzmichev 	if (rndis_per_dev_params[configNr].ack)
8087612a43dSVitaly Kuzmichev 		rndis_per_dev_params[configNr].ack(
8097612a43dSVitaly Kuzmichev 			rndis_per_dev_params[configNr].dev);
8107612a43dSVitaly Kuzmichev 
8117612a43dSVitaly Kuzmichev 	return 0;
8127612a43dSVitaly Kuzmichev }
8137612a43dSVitaly Kuzmichev 
rndis_query_response(int configNr,rndis_query_msg_type * buf)8147612a43dSVitaly Kuzmichev static int rndis_query_response(int configNr, rndis_query_msg_type *buf)
8157612a43dSVitaly Kuzmichev {
8167612a43dSVitaly Kuzmichev 	rndis_query_cmplt_type *resp;
8177612a43dSVitaly Kuzmichev 	rndis_resp_t            *r;
8187612a43dSVitaly Kuzmichev 
8197612a43dSVitaly Kuzmichev 	debug("%s: OID = %08X\n", __func__, get_unaligned_le32(&buf->OID));
8207612a43dSVitaly Kuzmichev 	if (!rndis_per_dev_params[configNr].dev)
8217612a43dSVitaly Kuzmichev 		return -ENOTSUPP;
8227612a43dSVitaly Kuzmichev 
8237612a43dSVitaly Kuzmichev 	/*
8247612a43dSVitaly Kuzmichev 	 * we need more memory:
8257612a43dSVitaly Kuzmichev 	 * gen_ndis_query_resp expects enough space for
8267612a43dSVitaly Kuzmichev 	 * rndis_query_cmplt_type followed by data.
8277612a43dSVitaly Kuzmichev 	 * oid_supported_list is the largest data reply
8287612a43dSVitaly Kuzmichev 	 */
8297612a43dSVitaly Kuzmichev 	r = rndis_add_response(configNr,
8307612a43dSVitaly Kuzmichev 		sizeof(oid_supported_list) + sizeof(rndis_query_cmplt_type));
8317612a43dSVitaly Kuzmichev 	if (!r)
8327612a43dSVitaly Kuzmichev 		return -ENOMEM;
8337612a43dSVitaly Kuzmichev 	resp = (rndis_query_cmplt_type *) r->buf;
8347612a43dSVitaly Kuzmichev 
8357612a43dSVitaly Kuzmichev 	resp->MessageType = __constant_cpu_to_le32(REMOTE_NDIS_QUERY_CMPLT);
8367612a43dSVitaly Kuzmichev 	resp->RequestID = get_unaligned(&buf->RequestID); /* Still LE in msg buffer */
8377612a43dSVitaly Kuzmichev 
8387612a43dSVitaly Kuzmichev 	if (gen_ndis_query_resp(configNr, get_unaligned_le32(&buf->OID),
8397612a43dSVitaly Kuzmichev 			get_unaligned_le32(&buf->InformationBufferOffset)
8407612a43dSVitaly Kuzmichev 					+ 8 + (u8 *) buf,
8417612a43dSVitaly Kuzmichev 			get_unaligned_le32(&buf->InformationBufferLength),
8427612a43dSVitaly Kuzmichev 			r)) {
8437612a43dSVitaly Kuzmichev 		/* OID not supported */
8447612a43dSVitaly Kuzmichev 		resp->Status = __constant_cpu_to_le32(
8457612a43dSVitaly Kuzmichev 						RNDIS_STATUS_NOT_SUPPORTED);
8467612a43dSVitaly Kuzmichev 		resp->MessageLength = __constant_cpu_to_le32(sizeof *resp);
8477612a43dSVitaly Kuzmichev 		resp->InformationBufferLength = __constant_cpu_to_le32(0);
8487612a43dSVitaly Kuzmichev 		resp->InformationBufferOffset = __constant_cpu_to_le32(0);
8497612a43dSVitaly Kuzmichev 	} else
8507612a43dSVitaly Kuzmichev 		resp->Status = __constant_cpu_to_le32(RNDIS_STATUS_SUCCESS);
8517612a43dSVitaly Kuzmichev 
8527612a43dSVitaly Kuzmichev 	if (rndis_per_dev_params[configNr].ack)
8537612a43dSVitaly Kuzmichev 		rndis_per_dev_params[configNr].ack(
8547612a43dSVitaly Kuzmichev 			rndis_per_dev_params[configNr].dev);
8557612a43dSVitaly Kuzmichev 	return 0;
8567612a43dSVitaly Kuzmichev }
8577612a43dSVitaly Kuzmichev 
rndis_set_response(int configNr,rndis_set_msg_type * buf)8587612a43dSVitaly Kuzmichev static int rndis_set_response(int configNr, rndis_set_msg_type *buf)
8597612a43dSVitaly Kuzmichev {
8607612a43dSVitaly Kuzmichev 	u32			BufLength, BufOffset;
8617612a43dSVitaly Kuzmichev 	rndis_set_cmplt_type	*resp;
8627612a43dSVitaly Kuzmichev 	rndis_resp_t		*r;
8637612a43dSVitaly Kuzmichev 
8647612a43dSVitaly Kuzmichev 	r = rndis_add_response(configNr, sizeof(rndis_set_cmplt_type));
8657612a43dSVitaly Kuzmichev 	if (!r)
8667612a43dSVitaly Kuzmichev 		return -ENOMEM;
8677612a43dSVitaly Kuzmichev 	resp = (rndis_set_cmplt_type *) r->buf;
8687612a43dSVitaly Kuzmichev 
8697612a43dSVitaly Kuzmichev 	BufLength = get_unaligned_le32(&buf->InformationBufferLength);
8707612a43dSVitaly Kuzmichev 	BufOffset = get_unaligned_le32(&buf->InformationBufferOffset);
8717612a43dSVitaly Kuzmichev 
8727612a43dSVitaly Kuzmichev #ifdef	VERBOSE
8737612a43dSVitaly Kuzmichev 	debug("%s: Length: %d\n", __func__, BufLength);
8747612a43dSVitaly Kuzmichev 	debug("%s: Offset: %d\n", __func__, BufOffset);
8757612a43dSVitaly Kuzmichev 	debug("%s: InfoBuffer: ", __func__);
8767612a43dSVitaly Kuzmichev 
8777612a43dSVitaly Kuzmichev 	for (i = 0; i < BufLength; i++)
8787612a43dSVitaly Kuzmichev 		debug("%02x ", *(((u8 *) buf) + i + 8 + BufOffset));
8797612a43dSVitaly Kuzmichev 
8807612a43dSVitaly Kuzmichev 	debug("\n");
8817612a43dSVitaly Kuzmichev #endif
8827612a43dSVitaly Kuzmichev 
8837612a43dSVitaly Kuzmichev 	resp->MessageType = __constant_cpu_to_le32(REMOTE_NDIS_SET_CMPLT);
8847612a43dSVitaly Kuzmichev 	resp->MessageLength = __constant_cpu_to_le32(16);
8857612a43dSVitaly Kuzmichev 	resp->RequestID = get_unaligned(&buf->RequestID); /* Still LE in msg buffer */
8867612a43dSVitaly Kuzmichev 	if (gen_ndis_set_resp(configNr, get_unaligned_le32(&buf->OID),
8877612a43dSVitaly Kuzmichev 			((u8 *) buf) + 8 + BufOffset, BufLength, r))
8887612a43dSVitaly Kuzmichev 		resp->Status = __constant_cpu_to_le32(
8897612a43dSVitaly Kuzmichev 						RNDIS_STATUS_NOT_SUPPORTED);
8907612a43dSVitaly Kuzmichev 	else
8917612a43dSVitaly Kuzmichev 		resp->Status = __constant_cpu_to_le32(RNDIS_STATUS_SUCCESS);
8927612a43dSVitaly Kuzmichev 
8937612a43dSVitaly Kuzmichev 	if (rndis_per_dev_params[configNr].ack)
8947612a43dSVitaly Kuzmichev 		rndis_per_dev_params[configNr].ack(
8957612a43dSVitaly Kuzmichev 			rndis_per_dev_params[configNr].dev);
8967612a43dSVitaly Kuzmichev 
8977612a43dSVitaly Kuzmichev 	return 0;
8987612a43dSVitaly Kuzmichev }
8997612a43dSVitaly Kuzmichev 
rndis_reset_response(int configNr,rndis_reset_msg_type * buf)9007612a43dSVitaly Kuzmichev static int rndis_reset_response(int configNr, rndis_reset_msg_type *buf)
9017612a43dSVitaly Kuzmichev {
9027612a43dSVitaly Kuzmichev 	rndis_reset_cmplt_type	*resp;
9037612a43dSVitaly Kuzmichev 	rndis_resp_t		*r;
9047612a43dSVitaly Kuzmichev 
9057612a43dSVitaly Kuzmichev 	r = rndis_add_response(configNr, sizeof(rndis_reset_cmplt_type));
9067612a43dSVitaly Kuzmichev 	if (!r)
9077612a43dSVitaly Kuzmichev 		return -ENOMEM;
9087612a43dSVitaly Kuzmichev 	resp = (rndis_reset_cmplt_type *) r->buf;
9097612a43dSVitaly Kuzmichev 
9107612a43dSVitaly Kuzmichev 	resp->MessageType = __constant_cpu_to_le32(REMOTE_NDIS_RESET_CMPLT);
9117612a43dSVitaly Kuzmichev 	resp->MessageLength = __constant_cpu_to_le32(16);
9127612a43dSVitaly Kuzmichev 	resp->Status = __constant_cpu_to_le32(RNDIS_STATUS_SUCCESS);
9137612a43dSVitaly Kuzmichev 	/* resent information */
9147612a43dSVitaly Kuzmichev 	resp->AddressingReset = __constant_cpu_to_le32(1);
9157612a43dSVitaly Kuzmichev 
9167612a43dSVitaly Kuzmichev 	if (rndis_per_dev_params[configNr].ack)
9177612a43dSVitaly Kuzmichev 		rndis_per_dev_params[configNr].ack(
9187612a43dSVitaly Kuzmichev 			rndis_per_dev_params[configNr].dev);
9197612a43dSVitaly Kuzmichev 
9207612a43dSVitaly Kuzmichev 	return 0;
9217612a43dSVitaly Kuzmichev }
9227612a43dSVitaly Kuzmichev 
rndis_keepalive_response(int configNr,rndis_keepalive_msg_type * buf)9237612a43dSVitaly Kuzmichev static int rndis_keepalive_response(int configNr,
9247612a43dSVitaly Kuzmichev 					rndis_keepalive_msg_type *buf)
9257612a43dSVitaly Kuzmichev {
9267612a43dSVitaly Kuzmichev 	rndis_keepalive_cmplt_type	*resp;
9277612a43dSVitaly Kuzmichev 	rndis_resp_t			*r;
9287612a43dSVitaly Kuzmichev 
9297612a43dSVitaly Kuzmichev 	/* host "should" check only in RNDIS_DATA_INITIALIZED state */
9307612a43dSVitaly Kuzmichev 
9317612a43dSVitaly Kuzmichev 	r = rndis_add_response(configNr, sizeof(rndis_keepalive_cmplt_type));
9327612a43dSVitaly Kuzmichev 	if (!r)
9337612a43dSVitaly Kuzmichev 		return -ENOMEM;
9347612a43dSVitaly Kuzmichev 	resp = (rndis_keepalive_cmplt_type *) r->buf;
9357612a43dSVitaly Kuzmichev 
9367612a43dSVitaly Kuzmichev 	resp->MessageType = __constant_cpu_to_le32(
9377612a43dSVitaly Kuzmichev 			REMOTE_NDIS_KEEPALIVE_CMPLT);
9387612a43dSVitaly Kuzmichev 	resp->MessageLength = __constant_cpu_to_le32(16);
9397612a43dSVitaly Kuzmichev 	resp->RequestID = get_unaligned(&buf->RequestID); /* Still LE in msg buffer */
9407612a43dSVitaly Kuzmichev 	resp->Status = __constant_cpu_to_le32(RNDIS_STATUS_SUCCESS);
9417612a43dSVitaly Kuzmichev 
9427612a43dSVitaly Kuzmichev 	if (rndis_per_dev_params[configNr].ack)
9437612a43dSVitaly Kuzmichev 		rndis_per_dev_params[configNr].ack(
9447612a43dSVitaly Kuzmichev 			rndis_per_dev_params[configNr].dev);
9457612a43dSVitaly Kuzmichev 
9467612a43dSVitaly Kuzmichev 	return 0;
9477612a43dSVitaly Kuzmichev }
9487612a43dSVitaly Kuzmichev 
9497612a43dSVitaly Kuzmichev 
9507612a43dSVitaly Kuzmichev /*
9517612a43dSVitaly Kuzmichev  * Device to Host Comunication
9527612a43dSVitaly Kuzmichev  */
rndis_indicate_status_msg(int configNr,u32 status)9537612a43dSVitaly Kuzmichev static int rndis_indicate_status_msg(int configNr, u32 status)
9547612a43dSVitaly Kuzmichev {
9557612a43dSVitaly Kuzmichev 	rndis_indicate_status_msg_type	*resp;
9567612a43dSVitaly Kuzmichev 	rndis_resp_t			*r;
9577612a43dSVitaly Kuzmichev 
9587612a43dSVitaly Kuzmichev 	if (rndis_per_dev_params[configNr].state == RNDIS_UNINITIALIZED)
9597612a43dSVitaly Kuzmichev 		return -ENOTSUPP;
9607612a43dSVitaly Kuzmichev 
9617612a43dSVitaly Kuzmichev 	r = rndis_add_response(configNr,
9627612a43dSVitaly Kuzmichev 				sizeof(rndis_indicate_status_msg_type));
9637612a43dSVitaly Kuzmichev 	if (!r)
9647612a43dSVitaly Kuzmichev 		return -ENOMEM;
9657612a43dSVitaly Kuzmichev 	resp = (rndis_indicate_status_msg_type *) r->buf;
9667612a43dSVitaly Kuzmichev 
9677612a43dSVitaly Kuzmichev 	resp->MessageType = __constant_cpu_to_le32(
9687612a43dSVitaly Kuzmichev 			REMOTE_NDIS_INDICATE_STATUS_MSG);
9697612a43dSVitaly Kuzmichev 	resp->MessageLength = __constant_cpu_to_le32(20);
9707612a43dSVitaly Kuzmichev 	resp->Status = cpu_to_le32(status);
9717612a43dSVitaly Kuzmichev 	resp->StatusBufferLength = __constant_cpu_to_le32(0);
9727612a43dSVitaly Kuzmichev 	resp->StatusBufferOffset = __constant_cpu_to_le32(0);
9737612a43dSVitaly Kuzmichev 
9747612a43dSVitaly Kuzmichev 	if (rndis_per_dev_params[configNr].ack)
9757612a43dSVitaly Kuzmichev 		rndis_per_dev_params[configNr].ack(
9767612a43dSVitaly Kuzmichev 			rndis_per_dev_params[configNr].dev);
9777612a43dSVitaly Kuzmichev 	return 0;
9787612a43dSVitaly Kuzmichev }
9797612a43dSVitaly Kuzmichev 
rndis_signal_connect(int configNr)9807612a43dSVitaly Kuzmichev int rndis_signal_connect(int configNr)
9817612a43dSVitaly Kuzmichev {
9827612a43dSVitaly Kuzmichev 	rndis_per_dev_params[configNr].media_state
9837612a43dSVitaly Kuzmichev 			= NDIS_MEDIA_STATE_CONNECTED;
9847612a43dSVitaly Kuzmichev 	return rndis_indicate_status_msg(configNr,
9857612a43dSVitaly Kuzmichev 					  RNDIS_STATUS_MEDIA_CONNECT);
9867612a43dSVitaly Kuzmichev }
9877612a43dSVitaly Kuzmichev 
rndis_signal_disconnect(int configNr)9887612a43dSVitaly Kuzmichev int rndis_signal_disconnect(int configNr)
9897612a43dSVitaly Kuzmichev {
9907612a43dSVitaly Kuzmichev 	rndis_per_dev_params[configNr].media_state
9917612a43dSVitaly Kuzmichev 			= NDIS_MEDIA_STATE_DISCONNECTED;
9927612a43dSVitaly Kuzmichev 
993e4ae6660SVitaly Kuzmichev #ifdef RNDIS_COMPLETE_SIGNAL_DISCONNECT
994e4ae6660SVitaly Kuzmichev 	return rndis_indicate_status_msg(configNr,
995e4ae6660SVitaly Kuzmichev 					  RNDIS_STATUS_MEDIA_DISCONNECT);
996e4ae6660SVitaly Kuzmichev #else
9977612a43dSVitaly Kuzmichev 	return 0;
998e4ae6660SVitaly Kuzmichev #endif
9997612a43dSVitaly Kuzmichev }
10007612a43dSVitaly Kuzmichev 
rndis_uninit(int configNr)10017612a43dSVitaly Kuzmichev void rndis_uninit(int configNr)
10027612a43dSVitaly Kuzmichev {
10037612a43dSVitaly Kuzmichev 	u8 *buf;
10047612a43dSVitaly Kuzmichev 	u32 length;
10057612a43dSVitaly Kuzmichev 
10067612a43dSVitaly Kuzmichev 	if (configNr >= RNDIS_MAX_CONFIGS)
10077612a43dSVitaly Kuzmichev 		return;
10087612a43dSVitaly Kuzmichev 	rndis_per_dev_params[configNr].used = 0;
10097612a43dSVitaly Kuzmichev 	rndis_per_dev_params[configNr].state = RNDIS_UNINITIALIZED;
10107612a43dSVitaly Kuzmichev 
10117612a43dSVitaly Kuzmichev 	/* drain the response queue */
10127612a43dSVitaly Kuzmichev 	while ((buf = rndis_get_next_response(configNr, &length)))
10137612a43dSVitaly Kuzmichev 		rndis_free_response(configNr, buf);
10147612a43dSVitaly Kuzmichev }
10157612a43dSVitaly Kuzmichev 
rndis_set_host_mac(int configNr,const u8 * addr)10167612a43dSVitaly Kuzmichev void rndis_set_host_mac(int configNr, const u8 *addr)
10177612a43dSVitaly Kuzmichev {
10187612a43dSVitaly Kuzmichev 	rndis_per_dev_params[configNr].host_mac = addr;
10197612a43dSVitaly Kuzmichev }
10207612a43dSVitaly Kuzmichev 
rndis_get_state(int configNr)10217612a43dSVitaly Kuzmichev enum rndis_state rndis_get_state(int configNr)
10227612a43dSVitaly Kuzmichev {
10237612a43dSVitaly Kuzmichev 	if (configNr >= RNDIS_MAX_CONFIGS || configNr < 0)
10247612a43dSVitaly Kuzmichev 		return -ENOTSUPP;
10257612a43dSVitaly Kuzmichev 	return rndis_per_dev_params[configNr].state;
10267612a43dSVitaly Kuzmichev }
10277612a43dSVitaly Kuzmichev 
10287612a43dSVitaly Kuzmichev /*
10297612a43dSVitaly Kuzmichev  * Message Parser
10307612a43dSVitaly Kuzmichev  */
rndis_msg_parser(u8 configNr,u8 * buf)10317612a43dSVitaly Kuzmichev int rndis_msg_parser(u8 configNr, u8 *buf)
10327612a43dSVitaly Kuzmichev {
10337612a43dSVitaly Kuzmichev 	u32				MsgType, MsgLength;
10347612a43dSVitaly Kuzmichev 	__le32				*tmp;
10357612a43dSVitaly Kuzmichev 	struct rndis_params		*params;
10367612a43dSVitaly Kuzmichev 
10377612a43dSVitaly Kuzmichev 	debug("%s: configNr = %d, %p\n", __func__, configNr, buf);
10387612a43dSVitaly Kuzmichev 
10397612a43dSVitaly Kuzmichev 	if (!buf)
10407612a43dSVitaly Kuzmichev 		return -ENOMEM;
10417612a43dSVitaly Kuzmichev 
10427612a43dSVitaly Kuzmichev 	tmp = (__le32 *) buf;
10437612a43dSVitaly Kuzmichev 	MsgType   = get_unaligned_le32(tmp++);
10447612a43dSVitaly Kuzmichev 	MsgLength = get_unaligned_le32(tmp++);
10457612a43dSVitaly Kuzmichev 
10467612a43dSVitaly Kuzmichev 	if (configNr >= RNDIS_MAX_CONFIGS)
10477612a43dSVitaly Kuzmichev 		return -ENOTSUPP;
10487612a43dSVitaly Kuzmichev 	params = &rndis_per_dev_params[configNr];
10497612a43dSVitaly Kuzmichev 
10507612a43dSVitaly Kuzmichev 	/*
10517612a43dSVitaly Kuzmichev 	 * NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for
10527612a43dSVitaly Kuzmichev 	 * rx/tx statistics and link status, in addition to KEEPALIVE traffic
10537612a43dSVitaly Kuzmichev 	 * and normal HC level polling to see if there's any IN traffic.
10547612a43dSVitaly Kuzmichev 	 */
10557612a43dSVitaly Kuzmichev 
10567612a43dSVitaly Kuzmichev 	/* For USB: responses may take up to 10 seconds */
10577612a43dSVitaly Kuzmichev 	switch (MsgType) {
10587612a43dSVitaly Kuzmichev 	case REMOTE_NDIS_INITIALIZE_MSG:
10597612a43dSVitaly Kuzmichev 		debug("%s: REMOTE_NDIS_INITIALIZE_MSG\n", __func__);
10607612a43dSVitaly Kuzmichev 		params->state = RNDIS_INITIALIZED;
10617612a43dSVitaly Kuzmichev 		return  rndis_init_response(configNr,
10627612a43dSVitaly Kuzmichev 					(rndis_init_msg_type *) buf);
10637612a43dSVitaly Kuzmichev 
10647612a43dSVitaly Kuzmichev 	case REMOTE_NDIS_HALT_MSG:
10657612a43dSVitaly Kuzmichev 		debug("%s: REMOTE_NDIS_HALT_MSG\n", __func__);
10667612a43dSVitaly Kuzmichev 		params->state = RNDIS_UNINITIALIZED;
10677612a43dSVitaly Kuzmichev 		return 0;
10687612a43dSVitaly Kuzmichev 
10697612a43dSVitaly Kuzmichev 	case REMOTE_NDIS_QUERY_MSG:
10707612a43dSVitaly Kuzmichev 		return rndis_query_response(configNr,
10717612a43dSVitaly Kuzmichev 					(rndis_query_msg_type *) buf);
10727612a43dSVitaly Kuzmichev 
10737612a43dSVitaly Kuzmichev 	case REMOTE_NDIS_SET_MSG:
10747612a43dSVitaly Kuzmichev 		return rndis_set_response(configNr,
10757612a43dSVitaly Kuzmichev 					(rndis_set_msg_type *) buf);
10767612a43dSVitaly Kuzmichev 
10777612a43dSVitaly Kuzmichev 	case REMOTE_NDIS_RESET_MSG:
10787612a43dSVitaly Kuzmichev 		debug("%s: REMOTE_NDIS_RESET_MSG\n", __func__);
10797612a43dSVitaly Kuzmichev 		return rndis_reset_response(configNr,
10807612a43dSVitaly Kuzmichev 					(rndis_reset_msg_type *) buf);
10817612a43dSVitaly Kuzmichev 
10827612a43dSVitaly Kuzmichev 	case REMOTE_NDIS_KEEPALIVE_MSG:
10837612a43dSVitaly Kuzmichev 		/* For USB: host does this every 5 seconds */
10847612a43dSVitaly Kuzmichev #if defined(DEBUG) && defined(DEBUG_VERBOSE)
10857612a43dSVitaly Kuzmichev 		debug("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", __func__);
10867612a43dSVitaly Kuzmichev #endif
10877612a43dSVitaly Kuzmichev 		return rndis_keepalive_response(configNr,
10887612a43dSVitaly Kuzmichev 					(rndis_keepalive_msg_type *) buf);
10897612a43dSVitaly Kuzmichev 
10907612a43dSVitaly Kuzmichev 	default:
10917612a43dSVitaly Kuzmichev 		/*
10927612a43dSVitaly Kuzmichev 		 * At least Windows XP emits some undefined RNDIS messages.
10937612a43dSVitaly Kuzmichev 		 * In one case those messages seemed to relate to the host
10947612a43dSVitaly Kuzmichev 		 * suspending itself.
10957612a43dSVitaly Kuzmichev 		 */
10967612a43dSVitaly Kuzmichev 		debug("%s: unknown RNDIS message 0x%08X len %d\n",
10977612a43dSVitaly Kuzmichev 			__func__ , MsgType, MsgLength);
10987612a43dSVitaly Kuzmichev 		{
10997612a43dSVitaly Kuzmichev 			unsigned i;
11007612a43dSVitaly Kuzmichev 			for (i = 0; i < MsgLength; i += 16) {
11017612a43dSVitaly Kuzmichev 				debug("%03d: "
11027612a43dSVitaly Kuzmichev 					" %02x %02x %02x %02x"
11037612a43dSVitaly Kuzmichev 					" %02x %02x %02x %02x"
11047612a43dSVitaly Kuzmichev 					" %02x %02x %02x %02x"
11057612a43dSVitaly Kuzmichev 					" %02x %02x %02x %02x"
11067612a43dSVitaly Kuzmichev 					"\n",
11077612a43dSVitaly Kuzmichev 					i,
11087612a43dSVitaly Kuzmichev 					buf[i], buf[i+1],
11097612a43dSVitaly Kuzmichev 						buf[i+2], buf[i+3],
11107612a43dSVitaly Kuzmichev 					buf[i+4], buf[i+5],
11117612a43dSVitaly Kuzmichev 						buf[i+6], buf[i+7],
11127612a43dSVitaly Kuzmichev 					buf[i+8], buf[i+9],
11137612a43dSVitaly Kuzmichev 						buf[i+10], buf[i+11],
11147612a43dSVitaly Kuzmichev 					buf[i+12], buf[i+13],
11157612a43dSVitaly Kuzmichev 						buf[i+14], buf[i+15]);
11167612a43dSVitaly Kuzmichev 			}
11177612a43dSVitaly Kuzmichev 		}
11187612a43dSVitaly Kuzmichev 		break;
11197612a43dSVitaly Kuzmichev 	}
11207612a43dSVitaly Kuzmichev 
11217612a43dSVitaly Kuzmichev 	return -ENOTSUPP;
11227612a43dSVitaly Kuzmichev }
11237612a43dSVitaly Kuzmichev 
1124*d4a37553SMugunthan V N #ifndef CONFIG_DM_ETH
rndis_register(int (* rndis_control_ack)(struct eth_device *))11257612a43dSVitaly Kuzmichev int rndis_register(int (*rndis_control_ack)(struct eth_device *))
1126*d4a37553SMugunthan V N #else
1127*d4a37553SMugunthan V N int rndis_register(int (*rndis_control_ack)(struct udevice *))
1128*d4a37553SMugunthan V N #endif
11297612a43dSVitaly Kuzmichev {
11307612a43dSVitaly Kuzmichev 	u8 i;
11317612a43dSVitaly Kuzmichev 
11327612a43dSVitaly Kuzmichev 	for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
11337612a43dSVitaly Kuzmichev 		if (!rndis_per_dev_params[i].used) {
11347612a43dSVitaly Kuzmichev 			rndis_per_dev_params[i].used = 1;
11357612a43dSVitaly Kuzmichev 			rndis_per_dev_params[i].ack = rndis_control_ack;
11367612a43dSVitaly Kuzmichev 			debug("%s: configNr = %d\n", __func__, i);
11377612a43dSVitaly Kuzmichev 			return i;
11387612a43dSVitaly Kuzmichev 		}
11397612a43dSVitaly Kuzmichev 	}
11407612a43dSVitaly Kuzmichev 	debug("%s failed\n", __func__);
11417612a43dSVitaly Kuzmichev 
11427612a43dSVitaly Kuzmichev 	return -1;
11437612a43dSVitaly Kuzmichev }
11447612a43dSVitaly Kuzmichev 
rndis_deregister(int configNr)11457612a43dSVitaly Kuzmichev void rndis_deregister(int configNr)
11467612a43dSVitaly Kuzmichev {
11477612a43dSVitaly Kuzmichev 	debug("%s: configNr = %d\n", __func__, configNr);
11487612a43dSVitaly Kuzmichev 
11497612a43dSVitaly Kuzmichev 	if (configNr >= RNDIS_MAX_CONFIGS)
11507612a43dSVitaly Kuzmichev 		return;
11517612a43dSVitaly Kuzmichev 	rndis_per_dev_params[configNr].used = 0;
11527612a43dSVitaly Kuzmichev 
11537612a43dSVitaly Kuzmichev 	return;
11547612a43dSVitaly Kuzmichev }
11557612a43dSVitaly Kuzmichev 
1156*d4a37553SMugunthan V N #ifndef CONFIG_DM_ETH
rndis_set_param_dev(u8 configNr,struct eth_device * dev,int mtu,struct net_device_stats * stats,u16 * cdc_filter)11577612a43dSVitaly Kuzmichev int  rndis_set_param_dev(u8 configNr, struct eth_device *dev, int mtu,
11587612a43dSVitaly Kuzmichev 			 struct net_device_stats *stats, u16 *cdc_filter)
1159*d4a37553SMugunthan V N #else
1160*d4a37553SMugunthan V N int  rndis_set_param_dev(u8 configNr, struct udevice *dev, int mtu,
1161*d4a37553SMugunthan V N 			 struct net_device_stats *stats, u16 *cdc_filter)
1162*d4a37553SMugunthan V N #endif
11637612a43dSVitaly Kuzmichev {
11647612a43dSVitaly Kuzmichev 	debug("%s: configNr = %d\n", __func__, configNr);
11657612a43dSVitaly Kuzmichev 	if (!dev || !stats)
11667612a43dSVitaly Kuzmichev 		return -1;
11677612a43dSVitaly Kuzmichev 	if (configNr >= RNDIS_MAX_CONFIGS)
11687612a43dSVitaly Kuzmichev 		return -1;
11697612a43dSVitaly Kuzmichev 
11707612a43dSVitaly Kuzmichev 	rndis_per_dev_params[configNr].dev = dev;
11717612a43dSVitaly Kuzmichev 	rndis_per_dev_params[configNr].stats = stats;
11727612a43dSVitaly Kuzmichev 	rndis_per_dev_params[configNr].mtu = mtu;
11737612a43dSVitaly Kuzmichev 	rndis_per_dev_params[configNr].filter = cdc_filter;
11747612a43dSVitaly Kuzmichev 
11757612a43dSVitaly Kuzmichev 	return 0;
11767612a43dSVitaly Kuzmichev }
11777612a43dSVitaly Kuzmichev 
rndis_set_param_vendor(u8 configNr,u32 vendorID,const char * vendorDescr)11787612a43dSVitaly Kuzmichev int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr)
11797612a43dSVitaly Kuzmichev {
11807612a43dSVitaly Kuzmichev 	debug("%s: configNr = %d\n", __func__, configNr);
11817612a43dSVitaly Kuzmichev 	if (!vendorDescr)
11827612a43dSVitaly Kuzmichev 		return -1;
11837612a43dSVitaly Kuzmichev 	if (configNr >= RNDIS_MAX_CONFIGS)
11847612a43dSVitaly Kuzmichev 		return -1;
11857612a43dSVitaly Kuzmichev 
11867612a43dSVitaly Kuzmichev 	rndis_per_dev_params[configNr].vendorID = vendorID;
11877612a43dSVitaly Kuzmichev 	rndis_per_dev_params[configNr].vendorDescr = vendorDescr;
11887612a43dSVitaly Kuzmichev 
11897612a43dSVitaly Kuzmichev 	return 0;
11907612a43dSVitaly Kuzmichev }
11917612a43dSVitaly Kuzmichev 
rndis_set_param_medium(u8 configNr,u32 medium,u32 speed)11927612a43dSVitaly Kuzmichev int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed)
11937612a43dSVitaly Kuzmichev {
11947612a43dSVitaly Kuzmichev 	debug("%s: configNr = %d, %u %u\n", __func__, configNr, medium, speed);
11957612a43dSVitaly Kuzmichev 	if (configNr >= RNDIS_MAX_CONFIGS)
11967612a43dSVitaly Kuzmichev 		return -1;
11977612a43dSVitaly Kuzmichev 
11987612a43dSVitaly Kuzmichev 	rndis_per_dev_params[configNr].medium = medium;
11997612a43dSVitaly Kuzmichev 	rndis_per_dev_params[configNr].speed = speed;
12007612a43dSVitaly Kuzmichev 
12017612a43dSVitaly Kuzmichev 	return 0;
12027612a43dSVitaly Kuzmichev }
12037612a43dSVitaly Kuzmichev 
rndis_add_hdr(void * buf,int length)12047612a43dSVitaly Kuzmichev void rndis_add_hdr(void *buf, int length)
12057612a43dSVitaly Kuzmichev {
12067612a43dSVitaly Kuzmichev 	struct rndis_packet_msg_type	*header;
12077612a43dSVitaly Kuzmichev 
12087612a43dSVitaly Kuzmichev 	header = buf;
12097612a43dSVitaly Kuzmichev 	memset(header, 0, sizeof *header);
12107612a43dSVitaly Kuzmichev 	header->MessageType = __constant_cpu_to_le32(REMOTE_NDIS_PACKET_MSG);
12117612a43dSVitaly Kuzmichev 	header->MessageLength = cpu_to_le32(length + sizeof *header);
12127612a43dSVitaly Kuzmichev 	header->DataOffset = __constant_cpu_to_le32(36);
12137612a43dSVitaly Kuzmichev 	header->DataLength = cpu_to_le32(length);
12147612a43dSVitaly Kuzmichev }
12157612a43dSVitaly Kuzmichev 
rndis_free_response(int configNr,u8 * buf)12167612a43dSVitaly Kuzmichev void rndis_free_response(int configNr, u8 *buf)
12177612a43dSVitaly Kuzmichev {
12187612a43dSVitaly Kuzmichev 	rndis_resp_t		*r;
12197612a43dSVitaly Kuzmichev 	struct list_head	*act, *tmp;
12207612a43dSVitaly Kuzmichev 
12217612a43dSVitaly Kuzmichev 	list_for_each_safe(act, tmp,
12227612a43dSVitaly Kuzmichev 			&(rndis_per_dev_params[configNr].resp_queue))
12237612a43dSVitaly Kuzmichev 	{
12247612a43dSVitaly Kuzmichev 		r = list_entry(act, rndis_resp_t, list);
12257612a43dSVitaly Kuzmichev 		if (r && r->buf == buf) {
12267612a43dSVitaly Kuzmichev 			list_del(&r->list);
12277612a43dSVitaly Kuzmichev 			free(r);
12287612a43dSVitaly Kuzmichev 		}
12297612a43dSVitaly Kuzmichev 	}
12307612a43dSVitaly Kuzmichev }
12317612a43dSVitaly Kuzmichev 
rndis_get_next_response(int configNr,u32 * length)12327612a43dSVitaly Kuzmichev u8 *rndis_get_next_response(int configNr, u32 *length)
12337612a43dSVitaly Kuzmichev {
12347612a43dSVitaly Kuzmichev 	rndis_resp_t		*r;
12357612a43dSVitaly Kuzmichev 	struct list_head	*act, *tmp;
12367612a43dSVitaly Kuzmichev 
12377612a43dSVitaly Kuzmichev 	if (!length)
12387612a43dSVitaly Kuzmichev 		return NULL;
12397612a43dSVitaly Kuzmichev 
12407612a43dSVitaly Kuzmichev 	list_for_each_safe(act, tmp,
12417612a43dSVitaly Kuzmichev 			&(rndis_per_dev_params[configNr].resp_queue))
12427612a43dSVitaly Kuzmichev 	{
12437612a43dSVitaly Kuzmichev 		r = list_entry(act, rndis_resp_t, list);
12447612a43dSVitaly Kuzmichev 		if (!r->send) {
12457612a43dSVitaly Kuzmichev 			r->send = 1;
12467612a43dSVitaly Kuzmichev 			*length = r->length;
12477612a43dSVitaly Kuzmichev 			return r->buf;
12487612a43dSVitaly Kuzmichev 		}
12497612a43dSVitaly Kuzmichev 	}
12507612a43dSVitaly Kuzmichev 
12517612a43dSVitaly Kuzmichev 	return NULL;
12527612a43dSVitaly Kuzmichev }
12537612a43dSVitaly Kuzmichev 
rndis_add_response(int configNr,u32 length)12547612a43dSVitaly Kuzmichev static rndis_resp_t *rndis_add_response(int configNr, u32 length)
12557612a43dSVitaly Kuzmichev {
12567612a43dSVitaly Kuzmichev 	rndis_resp_t	*r;
12577612a43dSVitaly Kuzmichev 
12587612a43dSVitaly Kuzmichev 	/* NOTE:  this gets copied into ether.c USB_BUFSIZ bytes ... */
12597612a43dSVitaly Kuzmichev 	r = malloc(sizeof(rndis_resp_t) + length);
12607612a43dSVitaly Kuzmichev 	if (!r)
12617612a43dSVitaly Kuzmichev 		return NULL;
12627612a43dSVitaly Kuzmichev 
12637612a43dSVitaly Kuzmichev 	r->buf = (u8 *) (r + 1);
12647612a43dSVitaly Kuzmichev 	r->length = length;
12657612a43dSVitaly Kuzmichev 	r->send = 0;
12667612a43dSVitaly Kuzmichev 
12677612a43dSVitaly Kuzmichev 	list_add_tail(&r->list,
12687612a43dSVitaly Kuzmichev 		&(rndis_per_dev_params[configNr].resp_queue));
12697612a43dSVitaly Kuzmichev 	return r;
12707612a43dSVitaly Kuzmichev }
12717612a43dSVitaly Kuzmichev 
rndis_rm_hdr(void * buf,int length)12727612a43dSVitaly Kuzmichev int rndis_rm_hdr(void *buf, int length)
12737612a43dSVitaly Kuzmichev {
12747612a43dSVitaly Kuzmichev 	/* tmp points to a struct rndis_packet_msg_type */
12757612a43dSVitaly Kuzmichev 	__le32		*tmp = buf;
12767612a43dSVitaly Kuzmichev 	int		offs, len;
12777612a43dSVitaly Kuzmichev 
12787612a43dSVitaly Kuzmichev 	/* MessageType, MessageLength */
12797612a43dSVitaly Kuzmichev 	if (__constant_cpu_to_le32(REMOTE_NDIS_PACKET_MSG)
12807612a43dSVitaly Kuzmichev 			!= get_unaligned(tmp++))
12817612a43dSVitaly Kuzmichev 		return -EINVAL;
12827612a43dSVitaly Kuzmichev 	tmp++;
12837612a43dSVitaly Kuzmichev 
12847612a43dSVitaly Kuzmichev 	/* DataOffset, DataLength */
12857612a43dSVitaly Kuzmichev 	offs = get_unaligned_le32(tmp++) + 8 /* offset of DataOffset */;
12867612a43dSVitaly Kuzmichev 	if (offs != sizeof(struct rndis_packet_msg_type))
12877612a43dSVitaly Kuzmichev 		debug("%s: unexpected DataOffset: %d\n", __func__, offs);
12887612a43dSVitaly Kuzmichev 	if (offs >= length)
12897612a43dSVitaly Kuzmichev 		return -EOVERFLOW;
12907612a43dSVitaly Kuzmichev 
12917612a43dSVitaly Kuzmichev 	len = get_unaligned_le32(tmp++);
12927612a43dSVitaly Kuzmichev 	if (len + sizeof(struct rndis_packet_msg_type) != length)
12937612a43dSVitaly Kuzmichev 		debug("%s: unexpected DataLength: %d, packet length=%d\n",
12947612a43dSVitaly Kuzmichev 				__func__, len, length);
12957612a43dSVitaly Kuzmichev 
12967612a43dSVitaly Kuzmichev 	memmove(buf, buf + offs, len);
12977612a43dSVitaly Kuzmichev 
12987612a43dSVitaly Kuzmichev 	return offs;
12997612a43dSVitaly Kuzmichev }
13007612a43dSVitaly Kuzmichev 
rndis_init(void)13017612a43dSVitaly Kuzmichev int rndis_init(void)
13027612a43dSVitaly Kuzmichev {
13037612a43dSVitaly Kuzmichev 	u8 i;
13047612a43dSVitaly Kuzmichev 
13057612a43dSVitaly Kuzmichev 	for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
13067612a43dSVitaly Kuzmichev 		rndis_per_dev_params[i].confignr = i;
13077612a43dSVitaly Kuzmichev 		rndis_per_dev_params[i].used = 0;
13087612a43dSVitaly Kuzmichev 		rndis_per_dev_params[i].state = RNDIS_UNINITIALIZED;
13097612a43dSVitaly Kuzmichev 		rndis_per_dev_params[i].media_state
13107612a43dSVitaly Kuzmichev 				= NDIS_MEDIA_STATE_DISCONNECTED;
13117612a43dSVitaly Kuzmichev 		INIT_LIST_HEAD(&(rndis_per_dev_params[i].resp_queue));
13127612a43dSVitaly Kuzmichev 	}
13137612a43dSVitaly Kuzmichev 
13147612a43dSVitaly Kuzmichev 	return 0;
13157612a43dSVitaly Kuzmichev }
13167612a43dSVitaly Kuzmichev 
rndis_exit(void)13177612a43dSVitaly Kuzmichev void rndis_exit(void)
13187612a43dSVitaly Kuzmichev {
13197612a43dSVitaly Kuzmichev 	/* Nothing to do */
13207612a43dSVitaly Kuzmichev }
1321