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