rndis.c 36.6 KB
Newer Older
1
/*
L
Linus Torvalds 已提交
2
 * RNDIS MSG parser
3
 *
L
Linus Torvalds 已提交
4
 * Version:     $Id: rndis.c,v 1.19 2004/03/25 21:33:46 robert Exp $
5
 *
L
Linus Torvalds 已提交
6
 * Authors:	Benedikt Spranger, Pengutronix
7 8
 *		Robert Schwebel, Pengutronix
 *
L
Linus Torvalds 已提交
9 10
 *              This program is free software; you can redistribute it and/or
 *              modify it under the terms of the GNU General Public License
11 12
 *              version 2, as published by the Free Software Foundation.
 *
L
Linus Torvalds 已提交
13 14
 *		This software was originally developed in conformance with
 *		Microsoft's Remote NDIS Specification License Agreement.
15
 *
L
Linus Torvalds 已提交
16 17
 * 03/12/2004 Kai-Uwe Bloem <linux-development@auerswald.de>
 *		Fixed message length bug in init_response
18
 *
L
Linus Torvalds 已提交
19
 * 03/25/2004 Kai-Uwe Bloem <linux-development@auerswald.de>
20
 *		Fixed rndis_rm_hdr length bug.
L
Linus Torvalds 已提交
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
 *
 * Copyright (C) 2004 by David Brownell
 *		updates to merge with Linux 2.6, better match RNDIS spec
 */

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/proc_fs.h>
#include <linux/netdevice.h>

#include <asm/io.h>
#include <asm/byteorder.h>
#include <asm/system.h>
38
#include <asm/unaligned.h>
L
Linus Torvalds 已提交
39 40 41


#undef	RNDIS_PM
42
#undef	RNDIS_WAKEUP
L
Linus Torvalds 已提交
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
#undef	VERBOSE

#include "rndis.h"


/* The driver for your USB chip needs to support ep0 OUT to work with
 * RNDIS, plus all three CDC Ethernet endpoints (interrupt not optional).
 *
 * Windows hosts need an INF file like Documentation/usb/linux.inf
 * and will be happier if you provide the host_addr module parameter.
 */

#if 0
#define DEBUG(str,args...) do { \
	if (rndis_debug) \
		printk(KERN_DEBUG str , ## args ); \
	} while (0)
static int rndis_debug = 0;

62
module_param (rndis_debug, int, 0);
L
Linus Torvalds 已提交
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
MODULE_PARM_DESC (rndis_debug, "enable debugging");

#else

#define rndis_debug		0
#define DEBUG(str,args...)	do{}while(0)
#endif

#define RNDIS_MAX_CONFIGS	1


static rndis_params rndis_per_dev_params [RNDIS_MAX_CONFIGS];

/* Driver Version */
static const __le32 rndis_driver_version = __constant_cpu_to_le32 (1);

/* Function Prototypes */
static rndis_resp_t *rndis_add_response (int configNr, u32 length);


83
/* supported OIDs */
84
static const u32 oid_supported_list [] =
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
{
	/* the general stuff */
	OID_GEN_SUPPORTED_LIST,
	OID_GEN_HARDWARE_STATUS,
	OID_GEN_MEDIA_SUPPORTED,
	OID_GEN_MEDIA_IN_USE,
	OID_GEN_MAXIMUM_FRAME_SIZE,
	OID_GEN_LINK_SPEED,
	OID_GEN_TRANSMIT_BLOCK_SIZE,
	OID_GEN_RECEIVE_BLOCK_SIZE,
	OID_GEN_VENDOR_ID,
	OID_GEN_VENDOR_DESCRIPTION,
	OID_GEN_VENDOR_DRIVER_VERSION,
	OID_GEN_CURRENT_PACKET_FILTER,
	OID_GEN_MAXIMUM_TOTAL_SIZE,
	OID_GEN_MEDIA_CONNECT_STATUS,
	OID_GEN_PHYSICAL_MEDIUM,
#if 0
	OID_GEN_RNDIS_CONFIG_PARAMETER,
#endif
105

106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
	/* the statistical stuff */
	OID_GEN_XMIT_OK,
	OID_GEN_RCV_OK,
	OID_GEN_XMIT_ERROR,
	OID_GEN_RCV_ERROR,
	OID_GEN_RCV_NO_BUFFER,
#ifdef	RNDIS_OPTIONAL_STATS
	OID_GEN_DIRECTED_BYTES_XMIT,
	OID_GEN_DIRECTED_FRAMES_XMIT,
	OID_GEN_MULTICAST_BYTES_XMIT,
	OID_GEN_MULTICAST_FRAMES_XMIT,
	OID_GEN_BROADCAST_BYTES_XMIT,
	OID_GEN_BROADCAST_FRAMES_XMIT,
	OID_GEN_DIRECTED_BYTES_RCV,
	OID_GEN_DIRECTED_FRAMES_RCV,
	OID_GEN_MULTICAST_BYTES_RCV,
	OID_GEN_MULTICAST_FRAMES_RCV,
	OID_GEN_BROADCAST_BYTES_RCV,
	OID_GEN_BROADCAST_FRAMES_RCV,
	OID_GEN_RCV_CRC_ERROR,
	OID_GEN_TRANSMIT_QUEUE_LENGTH,
#endif	/* RNDIS_OPTIONAL_STATS */

129
	/* mandatory 802.3 */
130 131 132 133 134 135
	/* the general stuff */
	OID_802_3_PERMANENT_ADDRESS,
	OID_802_3_CURRENT_ADDRESS,
	OID_802_3_MULTICAST_LIST,
	OID_802_3_MAC_OPTIONS,
	OID_802_3_MAXIMUM_LIST_SIZE,
136

137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
	/* the statistical stuff */
	OID_802_3_RCV_ERROR_ALIGNMENT,
	OID_802_3_XMIT_ONE_COLLISION,
	OID_802_3_XMIT_MORE_COLLISIONS,
#ifdef	RNDIS_OPTIONAL_STATS
	OID_802_3_XMIT_DEFERRED,
	OID_802_3_XMIT_MAX_COLLISIONS,
	OID_802_3_RCV_OVERRUN,
	OID_802_3_XMIT_UNDERRUN,
	OID_802_3_XMIT_HEARTBEAT_FAILURE,
	OID_802_3_XMIT_TIMES_CRS_LOST,
	OID_802_3_XMIT_LATE_COLLISIONS,
#endif	/* RNDIS_OPTIONAL_STATS */

#ifdef	RNDIS_PM
	/* PM and wakeup are mandatory for USB: */

	/* power management */
	OID_PNP_CAPABILITIES,
	OID_PNP_QUERY_POWER,
	OID_PNP_SET_POWER,

#ifdef	RNDIS_WAKEUP
	/* wake up host */
	OID_PNP_ENABLE_WAKE_UP,
	OID_PNP_ADD_WAKE_UP_PATTERN,
	OID_PNP_REMOVE_WAKE_UP_PATTERN,
#endif	/* RNDIS_WAKEUP */
#endif	/* RNDIS_PM */
};


L
Linus Torvalds 已提交
169
/* NDIS Functions */
170 171 172
static int
gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
		rndis_resp_t *r)
L
Linus Torvalds 已提交
173
{
174 175
	int			retval = -ENOTSUPP;
	u32			length = 4;	/* usually */
176
	__le32			*outbuf;
L
Linus Torvalds 已提交
177 178 179 180 181 182 183
	int			i, count;
	rndis_query_cmplt_type	*resp;

	if (!r) return -ENOMEM;
	resp = (rndis_query_cmplt_type *) r->buf;

	if (!resp) return -ENOMEM;
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199

	if (buf_len && rndis_debug > 1) {
		DEBUG("query OID %08x value, len %d:\n", OID, buf_len);
		for (i = 0; i < buf_len; i += 16) {
			DEBUG ("%03d: %08x %08x %08x %08x\n", i,
				le32_to_cpup((__le32 *)&buf[i]),
				le32_to_cpup((__le32 *)&buf[i + 4]),
				le32_to_cpup((__le32 *)&buf[i + 8]),
				le32_to_cpup((__le32 *)&buf[i + 12]));
		}
	}

	/* response goes here, right after the header */
	outbuf = (__le32 *) &resp[1];
	resp->InformationBufferOffset = __constant_cpu_to_le32 (16);

L
Linus Torvalds 已提交
200 201 202 203 204 205 206 207 208 209
	switch (OID) {

	/* general oids (table 4-1) */

	/* mandatory */
	case OID_GEN_SUPPORTED_LIST:
		DEBUG ("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__);
		length = sizeof (oid_supported_list);
		count  = length / sizeof (u32);
		for (i = 0; i < count; i++)
210
			outbuf[i] = cpu_to_le32 (oid_supported_list[i]);
L
Linus Torvalds 已提交
211 212
		retval = 0;
		break;
213

L
Linus Torvalds 已提交
214 215 216
	/* mandatory */
	case OID_GEN_HARDWARE_STATUS:
		DEBUG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__);
217
		/* Bogus question!
L
Linus Torvalds 已提交
218
		 * Hardware must be ready to receive high level protocols.
219
		 * BTW:
L
Linus Torvalds 已提交
220 221 222
		 * reddite ergo quae sunt Caesaris Caesari
		 * et quae sunt Dei Deo!
		 */
223
		*outbuf = __constant_cpu_to_le32 (0);
L
Linus Torvalds 已提交
224 225
		retval = 0;
		break;
226

L
Linus Torvalds 已提交
227 228 229
	/* mandatory */
	case OID_GEN_MEDIA_SUPPORTED:
		DEBUG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__);
230
		*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
L
Linus Torvalds 已提交
231 232
		retval = 0;
		break;
233

L
Linus Torvalds 已提交
234 235 236 237
	/* mandatory */
	case OID_GEN_MEDIA_IN_USE:
		DEBUG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__);
		/* one medium, one transport... (maybe you do it better) */
238
		*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
L
Linus Torvalds 已提交
239 240
		retval = 0;
		break;
241

L
Linus Torvalds 已提交
242 243 244 245
	/* mandatory */
	case OID_GEN_MAXIMUM_FRAME_SIZE:
		DEBUG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__);
		if (rndis_per_dev_params [configNr].dev) {
246
			*outbuf = cpu_to_le32 (
L
Linus Torvalds 已提交
247 248 249 250
				rndis_per_dev_params [configNr].dev->mtu);
			retval = 0;
		}
		break;
251

L
Linus Torvalds 已提交
252 253
	/* mandatory */
	case OID_GEN_LINK_SPEED:
254 255
		if (rndis_debug > 1)
			DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
L
Linus Torvalds 已提交
256
		if (rndis_per_dev_params [configNr].media_state
257 258
				== NDIS_MEDIA_STATE_DISCONNECTED)
			*outbuf = __constant_cpu_to_le32 (0);
L
Linus Torvalds 已提交
259
		else
260
			*outbuf = cpu_to_le32 (
L
Linus Torvalds 已提交
261 262 263 264 265 266 267 268
				rndis_per_dev_params [configNr].speed);
		retval = 0;
		break;

	/* mandatory */
	case OID_GEN_TRANSMIT_BLOCK_SIZE:
		DEBUG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__);
		if (rndis_per_dev_params [configNr].dev) {
269
			*outbuf = cpu_to_le32 (
L
Linus Torvalds 已提交
270 271 272 273
				rndis_per_dev_params [configNr].dev->mtu);
			retval = 0;
		}
		break;
274

L
Linus Torvalds 已提交
275 276 277 278
	/* mandatory */
	case OID_GEN_RECEIVE_BLOCK_SIZE:
		DEBUG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__);
		if (rndis_per_dev_params [configNr].dev) {
279
			*outbuf = cpu_to_le32 (
L
Linus Torvalds 已提交
280 281 282 283
				rndis_per_dev_params [configNr].dev->mtu);
			retval = 0;
		}
		break;
284

L
Linus Torvalds 已提交
285 286 287
	/* mandatory */
	case OID_GEN_VENDOR_ID:
		DEBUG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__);
288
		*outbuf = cpu_to_le32 (
L
Linus Torvalds 已提交
289 290 291
			rndis_per_dev_params [configNr].vendorID);
		retval = 0;
		break;
292

L
Linus Torvalds 已提交
293 294 295 296
	/* mandatory */
	case OID_GEN_VENDOR_DESCRIPTION:
		DEBUG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__);
		length = strlen (rndis_per_dev_params [configNr].vendorDescr);
297
		memcpy (outbuf,
L
Linus Torvalds 已提交
298 299 300 301 302 303 304
			rndis_per_dev_params [configNr].vendorDescr, length);
		retval = 0;
		break;

	case OID_GEN_VENDOR_DRIVER_VERSION:
		DEBUG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__);
		/* Created as LE */
305
		*outbuf = rndis_driver_version;
L
Linus Torvalds 已提交
306 307 308 309 310 311
		retval = 0;
		break;

	/* mandatory */
	case OID_GEN_CURRENT_PACKET_FILTER:
		DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__);
312
		*outbuf = cpu_to_le32 (*rndis_per_dev_params[configNr].filter);
L
Linus Torvalds 已提交
313 314 315 316 317 318
		retval = 0;
		break;

	/* mandatory */
	case OID_GEN_MAXIMUM_TOTAL_SIZE:
		DEBUG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__);
319
		*outbuf = __constant_cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
L
Linus Torvalds 已提交
320 321 322 323 324
		retval = 0;
		break;

	/* mandatory */
	case OID_GEN_MEDIA_CONNECT_STATUS:
325 326 327
		if (rndis_debug > 1)
			DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__);
		*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
L
Linus Torvalds 已提交
328 329 330 331 332 333
						.media_state);
		retval = 0;
		break;

	case OID_GEN_PHYSICAL_MEDIUM:
		DEBUG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__);
334
		*outbuf = __constant_cpu_to_le32 (0);
L
Linus Torvalds 已提交
335 336 337 338 339 340 341 342 343
		retval = 0;
		break;

	/* The RNDIS specification is incomplete/wrong.   Some versions
	 * of MS-Windows expect OIDs that aren't specified there.  Other
	 * versions emit undefined RNDIS messages. DOCUMENT ALL THESE!
	 */
	case OID_GEN_MAC_OPTIONS:		/* from WinME */
		DEBUG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__);
344
		*outbuf = __constant_cpu_to_le32(
L
Linus Torvalds 已提交
345 346 347 348 349 350 351 352 353
			  NDIS_MAC_OPTION_RECEIVE_SERIALIZED
			| NDIS_MAC_OPTION_FULL_DUPLEX);
		retval = 0;
		break;

	/* statistics OIDs (table 4-2) */

	/* mandatory */
	case OID_GEN_XMIT_OK:
354 355
		if (rndis_debug > 1)
			DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__);
L
Linus Torvalds 已提交
356
		if (rndis_per_dev_params [configNr].stats) {
357
			*outbuf = cpu_to_le32 (
358
			    rndis_per_dev_params [configNr].stats->tx_packets -
L
Linus Torvalds 已提交
359 360 361 362 363 364 365 366
			    rndis_per_dev_params [configNr].stats->tx_errors -
			    rndis_per_dev_params [configNr].stats->tx_dropped);
			retval = 0;
		}
		break;

	/* mandatory */
	case OID_GEN_RCV_OK:
367 368
		if (rndis_debug > 1)
			DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__);
L
Linus Torvalds 已提交
369
		if (rndis_per_dev_params [configNr].stats) {
370
			*outbuf = cpu_to_le32 (
371
			    rndis_per_dev_params [configNr].stats->rx_packets -
L
Linus Torvalds 已提交
372 373 374 375 376
			    rndis_per_dev_params [configNr].stats->rx_errors -
			    rndis_per_dev_params [configNr].stats->rx_dropped);
			retval = 0;
		}
		break;
377

L
Linus Torvalds 已提交
378 379
	/* mandatory */
	case OID_GEN_XMIT_ERROR:
380 381
		if (rndis_debug > 1)
			DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__);
L
Linus Torvalds 已提交
382
		if (rndis_per_dev_params [configNr].stats) {
383
			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
L
Linus Torvalds 已提交
384 385 386 387
					.stats->tx_errors);
			retval = 0;
		}
		break;
388

L
Linus Torvalds 已提交
389 390
	/* mandatory */
	case OID_GEN_RCV_ERROR:
391 392
		if (rndis_debug > 1)
			DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__);
L
Linus Torvalds 已提交
393
		if (rndis_per_dev_params [configNr].stats) {
394
			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
L
Linus Torvalds 已提交
395 396 397 398
					.stats->rx_errors);
			retval = 0;
		}
		break;
399

L
Linus Torvalds 已提交
400 401 402 403
	/* mandatory */
	case OID_GEN_RCV_NO_BUFFER:
		DEBUG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__);
		if (rndis_per_dev_params [configNr].stats) {
404
			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
L
Linus Torvalds 已提交
405 406 407 408 409 410 411 412
					.stats->rx_dropped);
			retval = 0;
		}
		break;

#ifdef	RNDIS_OPTIONAL_STATS
	case OID_GEN_DIRECTED_BYTES_XMIT:
		DEBUG("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __FUNCTION__);
413
		/*
L
Linus Torvalds 已提交
414 415 416 417 418
		 * Aunt Tilly's size of shoes
		 * minus antarctica count of penguins
		 * divided by weight of Alpha Centauri
		 */
		if (rndis_per_dev_params [configNr].stats) {
419
			*outbuf = cpu_to_le32 (
L
Linus Torvalds 已提交
420
				(rndis_per_dev_params [configNr]
421
					.stats->tx_packets -
L
Linus Torvalds 已提交
422 423 424 425 426 427 428 429
				 rndis_per_dev_params [configNr]
					 .stats->tx_errors -
				 rndis_per_dev_params [configNr]
					 .stats->tx_dropped)
				* 123);
			retval = 0;
		}
		break;
430

L
Linus Torvalds 已提交
431 432 433 434
	case OID_GEN_DIRECTED_FRAMES_XMIT:
		DEBUG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__);
		/* dito */
		if (rndis_per_dev_params [configNr].stats) {
435
			*outbuf = cpu_to_le32 (
L
Linus Torvalds 已提交
436
				(rndis_per_dev_params [configNr]
437
					.stats->tx_packets -
L
Linus Torvalds 已提交
438 439 440 441 442 443 444 445
				 rndis_per_dev_params [configNr]
					 .stats->tx_errors -
				 rndis_per_dev_params [configNr]
					 .stats->tx_dropped)
				/ 123);
			retval = 0;
		}
		break;
446

L
Linus Torvalds 已提交
447 448 449
	case OID_GEN_MULTICAST_BYTES_XMIT:
		DEBUG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__);
		if (rndis_per_dev_params [configNr].stats) {
450
			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
L
Linus Torvalds 已提交
451 452 453 454
					.stats->multicast*1234);
			retval = 0;
		}
		break;
455

L
Linus Torvalds 已提交
456 457 458
	case OID_GEN_MULTICAST_FRAMES_XMIT:
		DEBUG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__);
		if (rndis_per_dev_params [configNr].stats) {
459
			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
L
Linus Torvalds 已提交
460 461 462 463
					.stats->multicast);
			retval = 0;
		}
		break;
464

L
Linus Torvalds 已提交
465 466 467
	case OID_GEN_BROADCAST_BYTES_XMIT:
		DEBUG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__);
		if (rndis_per_dev_params [configNr].stats) {
468
			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
L
Linus Torvalds 已提交
469 470 471 472
					.stats->tx_packets/42*255);
			retval = 0;
		}
		break;
473

L
Linus Torvalds 已提交
474 475 476
	case OID_GEN_BROADCAST_FRAMES_XMIT:
		DEBUG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__);
		if (rndis_per_dev_params [configNr].stats) {
477
			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
L
Linus Torvalds 已提交
478 479 480 481
					.stats->tx_packets/42);
			retval = 0;
		}
		break;
482

L
Linus Torvalds 已提交
483 484
	case OID_GEN_DIRECTED_BYTES_RCV:
		DEBUG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__);
485
		*outbuf = __constant_cpu_to_le32 (0);
L
Linus Torvalds 已提交
486 487
		retval = 0;
		break;
488

L
Linus Torvalds 已提交
489 490
	case OID_GEN_DIRECTED_FRAMES_RCV:
		DEBUG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__);
491
		*outbuf = __constant_cpu_to_le32 (0);
L
Linus Torvalds 已提交
492 493
		retval = 0;
		break;
494

L
Linus Torvalds 已提交
495 496 497
	case OID_GEN_MULTICAST_BYTES_RCV:
		DEBUG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__);
		if (rndis_per_dev_params [configNr].stats) {
498
			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
L
Linus Torvalds 已提交
499 500 501 502
					.stats->multicast * 1111);
			retval = 0;
		}
		break;
503

L
Linus Torvalds 已提交
504 505 506
	case OID_GEN_MULTICAST_FRAMES_RCV:
		DEBUG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__);
		if (rndis_per_dev_params [configNr].stats) {
507
			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
L
Linus Torvalds 已提交
508 509 510 511
					.stats->multicast);
			retval = 0;
		}
		break;
512

L
Linus Torvalds 已提交
513 514 515
	case OID_GEN_BROADCAST_BYTES_RCV:
		DEBUG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__);
		if (rndis_per_dev_params [configNr].stats) {
516
			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
L
Linus Torvalds 已提交
517 518 519 520
					.stats->rx_packets/42*255);
			retval = 0;
		}
		break;
521

L
Linus Torvalds 已提交
522 523 524
	case OID_GEN_BROADCAST_FRAMES_RCV:
		DEBUG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__);
		if (rndis_per_dev_params [configNr].stats) {
525
			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
L
Linus Torvalds 已提交
526 527 528 529
					.stats->rx_packets/42);
			retval = 0;
		}
		break;
530

L
Linus Torvalds 已提交
531 532 533
	case OID_GEN_RCV_CRC_ERROR:
		DEBUG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__);
		if (rndis_per_dev_params [configNr].stats) {
534
			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
L
Linus Torvalds 已提交
535 536 537 538
					.stats->rx_crc_errors);
			retval = 0;
		}
		break;
539

L
Linus Torvalds 已提交
540 541
	case OID_GEN_TRANSMIT_QUEUE_LENGTH:
		DEBUG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__);
542
		*outbuf = __constant_cpu_to_le32 (0);
L
Linus Torvalds 已提交
543 544 545 546 547 548 549 550 551 552 553
		retval = 0;
		break;
#endif	/* RNDIS_OPTIONAL_STATS */

	/* ieee802.3 OIDs (table 4-3) */

	/* mandatory */
	case OID_802_3_PERMANENT_ADDRESS:
		DEBUG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__);
		if (rndis_per_dev_params [configNr].dev) {
			length = ETH_ALEN;
554
			memcpy (outbuf,
L
Linus Torvalds 已提交
555 556 557 558 559
				rndis_per_dev_params [configNr].host_mac,
				length);
			retval = 0;
		}
		break;
560

L
Linus Torvalds 已提交
561 562 563 564 565
	/* mandatory */
	case OID_802_3_CURRENT_ADDRESS:
		DEBUG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__);
		if (rndis_per_dev_params [configNr].dev) {
			length = ETH_ALEN;
566
			memcpy (outbuf,
L
Linus Torvalds 已提交
567 568 569 570 571
				rndis_per_dev_params [configNr].host_mac,
				length);
			retval = 0;
		}
		break;
572

L
Linus Torvalds 已提交
573 574 575 576
	/* mandatory */
	case OID_802_3_MULTICAST_LIST:
		DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
		/* Multicast base address only */
577
		*outbuf = __constant_cpu_to_le32 (0xE0000000);
L
Linus Torvalds 已提交
578 579
		retval = 0;
		break;
580

L
Linus Torvalds 已提交
581 582 583 584
	/* mandatory */
	case OID_802_3_MAXIMUM_LIST_SIZE:
		DEBUG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__);
		/* Multicast base address only */
585
		*outbuf = __constant_cpu_to_le32 (1);
L
Linus Torvalds 已提交
586 587
		retval = 0;
		break;
588

L
Linus Torvalds 已提交
589 590 591 592 593 594 595 596 597
	case OID_802_3_MAC_OPTIONS:
		DEBUG("%s: OID_802_3_MAC_OPTIONS\n", __FUNCTION__);
		break;

	/* ieee802.3 statistics OIDs (table 4-4) */

	/* mandatory */
	case OID_802_3_RCV_ERROR_ALIGNMENT:
		DEBUG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__);
598 599
		if (rndis_per_dev_params [configNr].stats) {
			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
L
Linus Torvalds 已提交
600 601 602 603
					.stats->rx_frame_errors);
			retval = 0;
		}
		break;
604

L
Linus Torvalds 已提交
605 606 607
	/* mandatory */
	case OID_802_3_XMIT_ONE_COLLISION:
		DEBUG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__);
608
		*outbuf = __constant_cpu_to_le32 (0);
L
Linus Torvalds 已提交
609 610
		retval = 0;
		break;
611

L
Linus Torvalds 已提交
612 613 614
	/* mandatory */
	case OID_802_3_XMIT_MORE_COLLISIONS:
		DEBUG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__);
615
		*outbuf = __constant_cpu_to_le32 (0);
L
Linus Torvalds 已提交
616 617
		retval = 0;
		break;
618

L
Linus Torvalds 已提交
619 620 621 622 623
#ifdef	RNDIS_OPTIONAL_STATS
	case OID_802_3_XMIT_DEFERRED:
		DEBUG("%s: OID_802_3_XMIT_DEFERRED\n", __FUNCTION__);
		/* TODO */
		break;
624

L
Linus Torvalds 已提交
625 626 627 628
	case OID_802_3_XMIT_MAX_COLLISIONS:
		DEBUG("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __FUNCTION__);
		/* TODO */
		break;
629

L
Linus Torvalds 已提交
630 631 632 633
	case OID_802_3_RCV_OVERRUN:
		DEBUG("%s: OID_802_3_RCV_OVERRUN\n", __FUNCTION__);
		/* TODO */
		break;
634

L
Linus Torvalds 已提交
635 636 637 638
	case OID_802_3_XMIT_UNDERRUN:
		DEBUG("%s: OID_802_3_XMIT_UNDERRUN\n", __FUNCTION__);
		/* TODO */
		break;
639

L
Linus Torvalds 已提交
640 641 642 643
	case OID_802_3_XMIT_HEARTBEAT_FAILURE:
		DEBUG("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __FUNCTION__);
		/* TODO */
		break;
644

L
Linus Torvalds 已提交
645 646 647 648
	case OID_802_3_XMIT_TIMES_CRS_LOST:
		DEBUG("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __FUNCTION__);
		/* TODO */
		break;
649

L
Linus Torvalds 已提交
650 651 652
	case OID_802_3_XMIT_LATE_COLLISIONS:
		DEBUG("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __FUNCTION__);
		/* TODO */
653
		break;
L
Linus Torvalds 已提交
654 655 656 657 658 659 660
#endif	/* RNDIS_OPTIONAL_STATS */

#ifdef	RNDIS_PM
	/* power management OIDs (table 4-5) */
	case OID_PNP_CAPABILITIES:
		DEBUG("%s: OID_PNP_CAPABILITIES\n", __FUNCTION__);

661
		/* for now, no wakeup capabilities */
L
Linus Torvalds 已提交
662
		length = sizeof (struct NDIS_PNP_CAPABILITIES);
663
		memset(outbuf, 0, length);
L
Linus Torvalds 已提交
664 665 666
		retval = 0;
		break;
	case OID_PNP_QUERY_POWER:
667 668 669 670 671 672
		DEBUG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__,
				le32_to_cpup((__le32 *) buf) - 1);
		/* only suspend is a real power state, and
		 * it can't be entered by OID_PNP_SET_POWER...
		 */
		length = 0;
L
Linus Torvalds 已提交
673 674 675 676 677
		retval = 0;
		break;
#endif

	default:
678
		printk (KERN_WARNING "%s: query unknown OID 0x%08X\n",
L
Linus Torvalds 已提交
679 680
			 __FUNCTION__, OID);
	}
681 682
	if (retval < 0)
		length = 0;
683

L
Linus Torvalds 已提交
684
	resp->InformationBufferLength = cpu_to_le32 (length);
685 686
	r->length = length + sizeof *resp;
	resp->MessageLength = cpu_to_le32 (r->length);
L
Linus Torvalds 已提交
687 688 689
	return retval;
}

690 691
static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
			rndis_resp_t *r)
L
Linus Torvalds 已提交
692 693
{
	rndis_set_cmplt_type		*resp;
694
	int				i, retval = -ENOTSUPP;
L
Linus Torvalds 已提交
695 696 697 698 699 700 701 702
	struct rndis_params		*params;

	if (!r)
		return -ENOMEM;
	resp = (rndis_set_cmplt_type *) r->buf;
	if (!resp)
		return -ENOMEM;

703 704 705 706 707 708 709 710 711
	if (buf_len && rndis_debug > 1) {
		DEBUG("set OID %08x value, len %d:\n", OID, buf_len);
		for (i = 0; i < buf_len; i += 16) {
			DEBUG ("%03d: %08x %08x %08x %08x\n", i,
				le32_to_cpup((__le32 *)&buf[i]),
				le32_to_cpup((__le32 *)&buf[i + 4]),
				le32_to_cpup((__le32 *)&buf[i + 8]),
				le32_to_cpup((__le32 *)&buf[i + 12]));
		}
L
Linus Torvalds 已提交
712 713
	}

714
	params = &rndis_per_dev_params [configNr];
L
Linus Torvalds 已提交
715 716 717
	switch (OID) {
	case OID_GEN_CURRENT_PACKET_FILTER:

718 719
		/* these NDIS_PACKET_TYPE_* bitflags are shared with
		 * cdc_filter; it's not RNDIS-specific
L
Linus Torvalds 已提交
720 721 722 723
		 * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in:
		 *	PROMISCUOUS, DIRECTED,
		 *	MULTICAST, ALL_MULTICAST, BROADCAST
		 */
724
		*params->filter = (u16) le32_to_cpup((__le32 *)buf);
L
Linus Torvalds 已提交
725
		DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
726
			__FUNCTION__, *params->filter);
L
Linus Torvalds 已提交
727 728 729 730 731

		/* this call has a significant side effect:  it's
		 * what makes the packet flow start and stop, like
		 * activating the CDC Ethernet altsetting.
		 */
732 733 734 735 736
#ifdef	RNDIS_PM
update_linkstate:
#endif
		retval = 0;
		if (*params->filter) {
L
Linus Torvalds 已提交
737 738 739 740 741 742 743 744 745 746
			params->state = RNDIS_DATA_INITIALIZED;
			netif_carrier_on(params->dev);
			if (netif_running(params->dev))
				netif_wake_queue (params->dev);
		} else {
			params->state = RNDIS_INITIALIZED;
			netif_carrier_off (params->dev);
			netif_stop_queue (params->dev);
		}
		break;
747

L
Linus Torvalds 已提交
748
	case OID_802_3_MULTICAST_LIST:
749
		/* I think we can ignore this */
L
Linus Torvalds 已提交
750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768
		DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
		retval = 0;
		break;
#if 0
	case OID_GEN_RNDIS_CONFIG_PARAMETER:
		{
		struct rndis_config_parameter	*param;
		param = (struct rndis_config_parameter *) buf;
		DEBUG("%s: OID_GEN_RNDIS_CONFIG_PARAMETER '%*s'\n",
			__FUNCTION__,
			min(cpu_to_le32(param->ParameterNameLength),80),
			buf + param->ParameterNameOffset);
		retval = 0;
		}
		break;
#endif

#ifdef	RNDIS_PM
	case OID_PNP_SET_POWER:
769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786
		/* The only real power state is USB suspend, and RNDIS requests
		 * can't enter it; this one isn't really about power.  After
		 * resuming, Windows forces a reset, and then SET_POWER D0.
		 * FIXME ... then things go batty; Windows wedges itself.
		 */
		i = le32_to_cpup((__force __le32 *)buf);
		DEBUG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1);
		switch (i) {
		case NdisDeviceStateD0:
			*params->filter = params->saved_filter;
			goto update_linkstate;
		case NdisDeviceStateD3:
		case NdisDeviceStateD2:
		case NdisDeviceStateD1:
			params->saved_filter = *params->filter;
			retval = 0;
			break;
		}
L
Linus Torvalds 已提交
787 788
		break;

789 790 791 792
#ifdef	RNDIS_WAKEUP
	// no wakeup support advertised, so wakeup OIDs always fail:
	//  - OID_PNP_ENABLE_WAKE_UP
	//  - OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN
L
Linus Torvalds 已提交
793 794
#endif

795 796
#endif	/* RNDIS_PM */

L
Linus Torvalds 已提交
797
	default:
798
		printk (KERN_WARNING "%s: set unknown OID 0x%08X, size %d\n",
L
Linus Torvalds 已提交
799 800
			 __FUNCTION__, OID, buf_len);
	}
801

L
Linus Torvalds 已提交
802 803 804
	return retval;
}

805 806
/*
 * Response Functions
L
Linus Torvalds 已提交
807 808 809 810
 */

static int rndis_init_response (int configNr, rndis_init_msg_type *buf)
{
811
	rndis_init_cmplt_type	*resp;
L
Linus Torvalds 已提交
812
	rndis_resp_t            *r;
813

L
Linus Torvalds 已提交
814
	if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP;
815

L
Linus Torvalds 已提交
816
	r = rndis_add_response (configNr, sizeof (rndis_init_cmplt_type));
817 818
	if (!r)
		return -ENOMEM;
L
Linus Torvalds 已提交
819
	resp = (rndis_init_cmplt_type *) r->buf;
820

L
Linus Torvalds 已提交
821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838
	resp->MessageType = __constant_cpu_to_le32 (
			REMOTE_NDIS_INITIALIZE_CMPLT);
	resp->MessageLength = __constant_cpu_to_le32 (52);
	resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
	resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS);
	resp->MajorVersion = __constant_cpu_to_le32 (RNDIS_MAJOR_VERSION);
	resp->MinorVersion = __constant_cpu_to_le32 (RNDIS_MINOR_VERSION);
	resp->DeviceFlags = __constant_cpu_to_le32 (RNDIS_DF_CONNECTIONLESS);
	resp->Medium = __constant_cpu_to_le32 (RNDIS_MEDIUM_802_3);
	resp->MaxPacketsPerTransfer = __constant_cpu_to_le32 (1);
	resp->MaxTransferSize = cpu_to_le32 (
		  rndis_per_dev_params [configNr].dev->mtu
		+ sizeof (struct ethhdr)
		+ sizeof (struct rndis_packet_msg_type)
		+ 22);
	resp->PacketAlignmentFactor = __constant_cpu_to_le32 (0);
	resp->AFListOffset = __constant_cpu_to_le32 (0);
	resp->AFListSize = __constant_cpu_to_le32 (0);
839

L
Linus Torvalds 已提交
840
	if (rndis_per_dev_params [configNr].ack)
841 842 843
		rndis_per_dev_params [configNr].ack (
			rndis_per_dev_params [configNr].dev);

L
Linus Torvalds 已提交
844 845 846 847 848 849 850
	return 0;
}

static int rndis_query_response (int configNr, rndis_query_msg_type *buf)
{
	rndis_query_cmplt_type *resp;
	rndis_resp_t            *r;
851

L
Linus Torvalds 已提交
852 853
	// DEBUG("%s: OID = %08X\n", __FUNCTION__, cpu_to_le32(buf->OID));
	if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP;
854

855 856 857 858 859
	/*
	 * we need more memory:
	 * gen_ndis_query_resp expects enough space for
	 * rndis_query_cmplt_type followed by data.
	 * oid_supported_list is the largest data reply
L
Linus Torvalds 已提交
860
	 */
861 862
	r = rndis_add_response (configNr,
		sizeof (oid_supported_list) + sizeof(rndis_query_cmplt_type));
863 864
	if (!r)
		return -ENOMEM;
L
Linus Torvalds 已提交
865
	resp = (rndis_query_cmplt_type *) r->buf;
866

L
Linus Torvalds 已提交
867 868
	resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_QUERY_CMPLT);
	resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
869

870 871 872 873 874
	if (gen_ndis_query_resp (configNr, le32_to_cpu (buf->OID),
			le32_to_cpu(buf->InformationBufferOffset)
					+ 8 + (u8 *) buf,
			le32_to_cpu(buf->InformationBufferLength),
			r)) {
L
Linus Torvalds 已提交
875 876 877
		/* OID not supported */
		resp->Status = __constant_cpu_to_le32 (
				RNDIS_STATUS_NOT_SUPPORTED);
878
		resp->MessageLength = __constant_cpu_to_le32 (sizeof *resp);
L
Linus Torvalds 已提交
879 880 881 882
		resp->InformationBufferLength = __constant_cpu_to_le32 (0);
		resp->InformationBufferOffset = __constant_cpu_to_le32 (0);
	} else
		resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS);
883

L
Linus Torvalds 已提交
884
	if (rndis_per_dev_params [configNr].ack)
885 886
		rndis_per_dev_params [configNr].ack (
			rndis_per_dev_params [configNr].dev);
L
Linus Torvalds 已提交
887 888 889 890 891 892 893 894
	return 0;
}

static int rndis_set_response (int configNr, rndis_set_msg_type *buf)
{
	u32			BufLength, BufOffset;
	rndis_set_cmplt_type	*resp;
	rndis_resp_t		*r;
895

L
Linus Torvalds 已提交
896
	r = rndis_add_response (configNr, sizeof (rndis_set_cmplt_type));
897 898
	if (!r)
		return -ENOMEM;
L
Linus Torvalds 已提交
899 900 901 902 903 904 905 906 907
	resp = (rndis_set_cmplt_type *) r->buf;

	BufLength = le32_to_cpu (buf->InformationBufferLength);
	BufOffset = le32_to_cpu (buf->InformationBufferOffset);

#ifdef	VERBOSE
	DEBUG("%s: Length: %d\n", __FUNCTION__, BufLength);
	DEBUG("%s: Offset: %d\n", __FUNCTION__, BufOffset);
	DEBUG("%s: InfoBuffer: ", __FUNCTION__);
908

L
Linus Torvalds 已提交
909 910 911
	for (i = 0; i < BufLength; i++) {
		DEBUG ("%02x ", *(((u8 *) buf) + i + 8 + BufOffset));
	}
912

L
Linus Torvalds 已提交
913 914
	DEBUG ("\n");
#endif
915

L
Linus Torvalds 已提交
916 917 918
	resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_SET_CMPLT);
	resp->MessageLength = __constant_cpu_to_le32 (16);
	resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
919 920 921 922 923 924
	if (gen_ndis_set_resp (configNr, le32_to_cpu (buf->OID),
			((u8 *) buf) + 8 + BufOffset, BufLength, r))
		resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_NOT_SUPPORTED);
	else
		resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS);

L
Linus Torvalds 已提交
925
	if (rndis_per_dev_params [configNr].ack)
926 927 928
		rndis_per_dev_params [configNr].ack (
			rndis_per_dev_params [configNr].dev);

L
Linus Torvalds 已提交
929 930 931 932 933 934 935
	return 0;
}

static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf)
{
	rndis_reset_cmplt_type	*resp;
	rndis_resp_t		*r;
936

L
Linus Torvalds 已提交
937
	r = rndis_add_response (configNr, sizeof (rndis_reset_cmplt_type));
938 939
	if (!r)
		return -ENOMEM;
L
Linus Torvalds 已提交
940
	resp = (rndis_reset_cmplt_type *) r->buf;
941

L
Linus Torvalds 已提交
942 943 944 945 946
	resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_RESET_CMPLT);
	resp->MessageLength = __constant_cpu_to_le32 (16);
	resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS);
	/* resent information */
	resp->AddressingReset = __constant_cpu_to_le32 (1);
947

L
Linus Torvalds 已提交
948
	if (rndis_per_dev_params [configNr].ack)
949 950
		rndis_per_dev_params [configNr].ack (
			rndis_per_dev_params [configNr].dev);
L
Linus Torvalds 已提交
951 952 953 954 955

	return 0;
}

static int rndis_keepalive_response (int configNr,
956
				rndis_keepalive_msg_type *buf)
L
Linus Torvalds 已提交
957 958 959 960 961 962 963
{
	rndis_keepalive_cmplt_type	*resp;
	rndis_resp_t			*r;

	/* host "should" check only in RNDIS_DATA_INITIALIZED state */

	r = rndis_add_response (configNr, sizeof (rndis_keepalive_cmplt_type));
964 965
	if (!r)
		return -ENOMEM;
L
Linus Torvalds 已提交
966
	resp = (rndis_keepalive_cmplt_type *) r->buf;
967

L
Linus Torvalds 已提交
968 969 970 971 972
	resp->MessageType = __constant_cpu_to_le32 (
			REMOTE_NDIS_KEEPALIVE_CMPLT);
	resp->MessageLength = __constant_cpu_to_le32 (16);
	resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
	resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS);
973

L
Linus Torvalds 已提交
974
	if (rndis_per_dev_params [configNr].ack)
975 976 977
		rndis_per_dev_params [configNr].ack (
			rndis_per_dev_params [configNr].dev);

L
Linus Torvalds 已提交
978 979 980 981
	return 0;
}


982 983
/*
 * Device to Host Comunication
L
Linus Torvalds 已提交
984 985 986
 */
static int rndis_indicate_status_msg (int configNr, u32 status)
{
987
	rndis_indicate_status_msg_type	*resp;
L
Linus Torvalds 已提交
988
	rndis_resp_t			*r;
989

L
Linus Torvalds 已提交
990
	if (rndis_per_dev_params [configNr].state == RNDIS_UNINITIALIZED)
991 992 993
		return -ENOTSUPP;

	r = rndis_add_response (configNr,
L
Linus Torvalds 已提交
994
				sizeof (rndis_indicate_status_msg_type));
995 996
	if (!r)
		return -ENOMEM;
L
Linus Torvalds 已提交
997
	resp = (rndis_indicate_status_msg_type *) r->buf;
998

L
Linus Torvalds 已提交
999 1000 1001 1002 1003 1004
	resp->MessageType = __constant_cpu_to_le32 (
			REMOTE_NDIS_INDICATE_STATUS_MSG);
	resp->MessageLength = __constant_cpu_to_le32 (20);
	resp->Status = cpu_to_le32 (status);
	resp->StatusBufferLength = __constant_cpu_to_le32 (0);
	resp->StatusBufferOffset = __constant_cpu_to_le32 (0);
1005 1006 1007 1008

	if (rndis_per_dev_params [configNr].ack)
		rndis_per_dev_params [configNr].ack (
			rndis_per_dev_params [configNr].dev);
L
Linus Torvalds 已提交
1009 1010 1011 1012 1013 1014 1015
	return 0;
}

int rndis_signal_connect (int configNr)
{
	rndis_per_dev_params [configNr].media_state
			= NDIS_MEDIA_STATE_CONNECTED;
1016
	return rndis_indicate_status_msg (configNr,
L
Linus Torvalds 已提交
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027
					  RNDIS_STATUS_MEDIA_CONNECT);
}

int rndis_signal_disconnect (int configNr)
{
	rndis_per_dev_params [configNr].media_state
			= NDIS_MEDIA_STATE_DISCONNECTED;
	return rndis_indicate_status_msg (configNr,
					  RNDIS_STATUS_MEDIA_DISCONNECT);
}

1028 1029
void rndis_uninit (int configNr)
{
1030 1031 1032
	u8 *buf;
	u32 length;

1033 1034 1035 1036
	if (configNr >= RNDIS_MAX_CONFIGS)
		return;
	rndis_per_dev_params [configNr].used = 0;
	rndis_per_dev_params [configNr].state = RNDIS_UNINITIALIZED;
1037 1038 1039 1040

	/* drain the response queue */
	while ((buf = rndis_get_next_response(configNr, &length)))
		rndis_free_response(configNr, buf);
1041 1042
}

L
Linus Torvalds 已提交
1043 1044 1045 1046 1047
void rndis_set_host_mac (int configNr, const u8 *addr)
{
	rndis_per_dev_params [configNr].host_mac = addr;
}

1048 1049
/*
 * Message Parser
L
Linus Torvalds 已提交
1050 1051 1052 1053 1054 1055
 */
int rndis_msg_parser (u8 configNr, u8 *buf)
{
	u32 MsgType, MsgLength;
	__le32 *tmp;
	struct rndis_params		*params;
1056

L
Linus Torvalds 已提交
1057 1058
	if (!buf)
		return -ENOMEM;
1059 1060

	tmp = (__le32 *) buf;
L
Linus Torvalds 已提交
1061 1062
	MsgType   = le32_to_cpup(tmp++);
	MsgLength = le32_to_cpup(tmp++);
1063

L
Linus Torvalds 已提交
1064 1065 1066
	if (configNr >= RNDIS_MAX_CONFIGS)
		return -ENOTSUPP;
	params = &rndis_per_dev_params [configNr];
1067

1068 1069 1070 1071 1072
	/* NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for
	 * rx/tx statistics and link status, in addition to KEEPALIVE traffic
	 * and normal HC level polling to see if there's any IN traffic.
	 */

L
Linus Torvalds 已提交
1073
	/* For USB: responses may take up to 10 seconds */
1074
	switch (MsgType) {
L
Linus Torvalds 已提交
1075
	case REMOTE_NDIS_INITIALIZE_MSG:
1076
		DEBUG("%s: REMOTE_NDIS_INITIALIZE_MSG\n",
L
Linus Torvalds 已提交
1077 1078 1079
			__FUNCTION__ );
		params->state = RNDIS_INITIALIZED;
		return  rndis_init_response (configNr,
1080 1081
					(rndis_init_msg_type *) buf);

L
Linus Torvalds 已提交
1082 1083 1084 1085 1086 1087 1088 1089 1090
	case REMOTE_NDIS_HALT_MSG:
		DEBUG("%s: REMOTE_NDIS_HALT_MSG\n",
			__FUNCTION__ );
		params->state = RNDIS_UNINITIALIZED;
		if (params->dev) {
			netif_carrier_off (params->dev);
			netif_stop_queue (params->dev);
		}
		return 0;
1091

L
Linus Torvalds 已提交
1092
	case REMOTE_NDIS_QUERY_MSG:
1093 1094 1095
		return rndis_query_response (configNr,
					(rndis_query_msg_type *) buf);

L
Linus Torvalds 已提交
1096
	case REMOTE_NDIS_SET_MSG:
1097 1098 1099
		return rndis_set_response (configNr,
					(rndis_set_msg_type *) buf);

L
Linus Torvalds 已提交
1100
	case REMOTE_NDIS_RESET_MSG:
1101
		DEBUG("%s: REMOTE_NDIS_RESET_MSG\n",
L
Linus Torvalds 已提交
1102 1103
			__FUNCTION__ );
		return rndis_reset_response (configNr,
1104
					(rndis_reset_msg_type *) buf);
L
Linus Torvalds 已提交
1105 1106 1107

	case REMOTE_NDIS_KEEPALIVE_MSG:
		/* For USB: host does this every 5 seconds */
1108
		if (rndis_debug > 1)
1109
			DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n",
1110
				__FUNCTION__ );
L
Linus Torvalds 已提交
1111
		return rndis_keepalive_response (configNr,
1112
						 (rndis_keepalive_msg_type *)
L
Linus Torvalds 已提交
1113
						 buf);
1114 1115

	default:
L
Linus Torvalds 已提交
1116 1117 1118 1119 1120
		/* At least Windows XP emits some undefined RNDIS messages.
		 * In one case those messages seemed to relate to the host
		 * suspending itself.
		 */
		printk (KERN_WARNING
1121
			"%s: unknown RNDIS message 0x%08X len %d\n",
L
Linus Torvalds 已提交
1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144
			__FUNCTION__ , MsgType, MsgLength);
		{
			unsigned i;
			for (i = 0; i < MsgLength; i += 16) {
				DEBUG ("%03d: "
					" %02x %02x %02x %02x"
					" %02x %02x %02x %02x"
					" %02x %02x %02x %02x"
					" %02x %02x %02x %02x"
					"\n",
					i,
					buf[i], buf [i+1],
						buf[i+2], buf[i+3],
					buf[i+4], buf [i+5],
						buf[i+6], buf[i+7],
					buf[i+8], buf [i+9],
						buf[i+10], buf[i+11],
					buf[i+12], buf [i+13],
						buf[i+14], buf[i+15]);
			}
		}
		break;
	}
1145

L
Linus Torvalds 已提交
1146 1147 1148 1149 1150 1151
	return -ENOTSUPP;
}

int rndis_register (int (* rndis_control_ack) (struct net_device *))
{
	u8 i;
1152

L
Linus Torvalds 已提交
1153 1154 1155 1156 1157 1158 1159 1160 1161
	for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
		if (!rndis_per_dev_params [i].used) {
			rndis_per_dev_params [i].used = 1;
			rndis_per_dev_params [i].ack = rndis_control_ack;
			DEBUG("%s: configNr = %d\n", __FUNCTION__, i);
			return i;
		}
	}
	DEBUG("failed\n");
1162

L
Linus Torvalds 已提交
1163 1164 1165 1166 1167 1168
	return -1;
}

void rndis_deregister (int configNr)
{
	DEBUG("%s: \n", __FUNCTION__ );
1169

L
Linus Torvalds 已提交
1170 1171
	if (configNr >= RNDIS_MAX_CONFIGS) return;
	rndis_per_dev_params [configNr].used = 0;
1172

L
Linus Torvalds 已提交
1173 1174 1175
	return;
}

1176
int rndis_set_param_dev (u8 configNr, struct net_device *dev,
1177 1178
			 struct net_device_stats *stats,
			 u16 *cdc_filter)
L
Linus Torvalds 已提交
1179 1180 1181 1182
{
	DEBUG("%s:\n", __FUNCTION__ );
	if (!dev || !stats) return -1;
	if (configNr >= RNDIS_MAX_CONFIGS) return -1;
1183

L
Linus Torvalds 已提交
1184 1185
	rndis_per_dev_params [configNr].dev = dev;
	rndis_per_dev_params [configNr].stats = stats;
1186
	rndis_per_dev_params [configNr].filter = cdc_filter;
1187

L
Linus Torvalds 已提交
1188 1189 1190 1191 1192 1193 1194 1195
	return 0;
}

int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr)
{
	DEBUG("%s:\n", __FUNCTION__ );
	if (!vendorDescr) return -1;
	if (configNr >= RNDIS_MAX_CONFIGS) return -1;
1196

L
Linus Torvalds 已提交
1197 1198
	rndis_per_dev_params [configNr].vendorID = vendorID;
	rndis_per_dev_params [configNr].vendorDescr = vendorDescr;
1199

L
Linus Torvalds 已提交
1200 1201 1202 1203 1204
	return 0;
}

int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed)
{
1205
	DEBUG("%s: %u %u\n", __FUNCTION__, medium, speed);
L
Linus Torvalds 已提交
1206
	if (configNr >= RNDIS_MAX_CONFIGS) return -1;
1207

L
Linus Torvalds 已提交
1208 1209
	rndis_per_dev_params [configNr].medium = medium;
	rndis_per_dev_params [configNr].speed = speed;
1210

L
Linus Torvalds 已提交
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221
	return 0;
}

void rndis_add_hdr (struct sk_buff *skb)
{
	struct rndis_packet_msg_type	*header;

	if (!skb)
		return;
	header = (void *) skb_push (skb, sizeof *header);
	memset (header, 0, sizeof *header);
1222
	header->MessageType = __constant_cpu_to_le32(REMOTE_NDIS_PACKET_MSG);
L
Linus Torvalds 已提交
1223 1224
	header->MessageLength = cpu_to_le32(skb->len);
	header->DataOffset = __constant_cpu_to_le32 (36);
1225
	header->DataLength = cpu_to_le32(skb->len - sizeof *header);
L
Linus Torvalds 已提交
1226 1227 1228 1229 1230 1231
}

void rndis_free_response (int configNr, u8 *buf)
{
	rndis_resp_t		*r;
	struct list_head	*act, *tmp;
1232 1233 1234

	list_for_each_safe (act, tmp,
			&(rndis_per_dev_params [configNr].resp_queue))
L
Linus Torvalds 已提交
1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246
	{
		r = list_entry (act, rndis_resp_t, list);
		if (r && r->buf == buf) {
			list_del (&r->list);
			kfree (r);
		}
	}
}

u8 *rndis_get_next_response (int configNr, u32 *length)
{
	rndis_resp_t		*r;
1247 1248
	struct list_head	*act, *tmp;

L
Linus Torvalds 已提交
1249
	if (!length) return NULL;
1250 1251 1252

	list_for_each_safe (act, tmp,
			&(rndis_per_dev_params [configNr].resp_queue))
L
Linus Torvalds 已提交
1253 1254 1255 1256 1257 1258 1259 1260
	{
		r = list_entry (act, rndis_resp_t, list);
		if (!r->send) {
			r->send = 1;
			*length = r->length;
			return r->buf;
		}
	}
1261

L
Linus Torvalds 已提交
1262 1263 1264 1265 1266 1267
	return NULL;
}

static rndis_resp_t *rndis_add_response (int configNr, u32 length)
{
	rndis_resp_t	*r;
1268

1269
	/* NOTE:  this gets copied into ether.c USB_BUFSIZ bytes ... */
L
Linus Torvalds 已提交
1270 1271
	r = kmalloc (sizeof (rndis_resp_t) + length, GFP_ATOMIC);
	if (!r) return NULL;
1272

L
Linus Torvalds 已提交
1273 1274 1275
	r->buf = (u8 *) (r + 1);
	r->length = length;
	r->send = 0;
1276 1277 1278

	list_add_tail (&r->list,
		&(rndis_per_dev_params [configNr].resp_queue));
L
Linus Torvalds 已提交
1279 1280 1281
	return r;
}

1282
int rndis_rm_hdr(struct sk_buff *skb)
L
Linus Torvalds 已提交
1283
{
1284 1285
	/* tmp points to a struct rndis_packet_msg_type */
	__le32		*tmp = (void *) skb->data;
L
Linus Torvalds 已提交
1286

1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297
	/* MessageType, MessageLength */
	if (__constant_cpu_to_le32(REMOTE_NDIS_PACKET_MSG)
			!= get_unaligned(tmp++))
		return -EINVAL;
	tmp++;

	/* DataOffset, DataLength */
	if (!skb_pull(skb, le32_to_cpu(get_unaligned(tmp++))
			+ 8 /* offset of DataOffset */))
		return -EOVERFLOW;
	skb_trim(skb, le32_to_cpu(get_unaligned(tmp++)));
L
Linus Torvalds 已提交
1298 1299 1300 1301 1302 1303

	return 0;
}

#ifdef	CONFIG_USB_GADGET_DEBUG_FILES

1304 1305
static int rndis_proc_read (char *page, char **start, off_t off, int count, int *eof,
		void *data)
L
Linus Torvalds 已提交
1306 1307 1308 1309
{
	char *out = page;
	int len;
	rndis_params *param = (rndis_params *) data;
1310 1311

	out += snprintf (out, count,
L
Linus Torvalds 已提交
1312 1313 1314 1315 1316 1317 1318
			 "Config Nr. %d\n"
			 "used      : %s\n"
			 "state     : %s\n"
			 "medium    : 0x%08X\n"
			 "speed     : %d\n"
			 "cable     : %s\n"
			 "vendor ID : 0x%08X\n"
1319 1320
			 "vendor    : %s\n",
			 param->confignr, (param->used) ? "y" : "n",
L
Linus Torvalds 已提交
1321 1322 1323 1324 1325 1326 1327 1328 1329
			 ({ char *s = "?";
			 switch (param->state) {
			 case RNDIS_UNINITIALIZED:
				s = "RNDIS_UNINITIALIZED"; break;
			 case RNDIS_INITIALIZED:
				s = "RNDIS_INITIALIZED"; break;
			 case RNDIS_DATA_INITIALIZED:
				s = "RNDIS_DATA_INITIALIZED"; break;
			}; s; }),
1330 1331
			 param->medium,
			 (param->media_state) ? 0 : param->speed*100,
L
Linus Torvalds 已提交
1332
			 (param->media_state) ? "disconnected" : "connected",
1333 1334
			 param->vendorID, param->vendorDescr);

L
Linus Torvalds 已提交
1335 1336
	len = out - page;
	len -= off;
1337

L
Linus Torvalds 已提交
1338 1339 1340 1341 1342 1343
	if (len < count) {
		*eof = 1;
		if (len <= 0)
			return 0;
	} else
		len = count;
1344

L
Linus Torvalds 已提交
1345 1346 1347 1348
	*start = page + off;
	return len;
}

1349 1350
static int rndis_proc_write (struct file *file, const char __user *buffer,
		unsigned long count, void *data)
L
Linus Torvalds 已提交
1351 1352 1353 1354
{
	rndis_params *p = data;
	u32 speed = 0;
	int i, fl_speed = 0;
1355

L
Linus Torvalds 已提交
1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381
	for (i = 0; i < count; i++) {
		char c;
		if (get_user(c, buffer))
			return -EFAULT;
		switch (c) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			fl_speed = 1;
			speed = speed*10 + c - '0';
			break;
		case 'C':
		case 'c':
			rndis_signal_connect (p->confignr);
			break;
		case 'D':
		case 'd':
			rndis_signal_disconnect(p->confignr);
			break;
1382
		default:
L
Linus Torvalds 已提交
1383 1384 1385 1386
			if (fl_speed) p->speed = speed;
			else DEBUG ("%c is not valid\n", c);
			break;
		}
1387

L
Linus Torvalds 已提交
1388 1389
		buffer++;
	}
1390

L
Linus Torvalds 已提交
1391 1392 1393 1394 1395 1396 1397 1398 1399 1400
	return count;
}

#define	NAME_TEMPLATE	"driver/rndis-%03d"

static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];

#endif	/* CONFIG_USB_GADGET_DEBUG_FILES */


1401
int __devinit rndis_init (void)
L
Linus Torvalds 已提交
1402 1403 1404 1405 1406 1407 1408 1409 1410
{
	u8 i;

	for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
#ifdef	CONFIG_USB_GADGET_DEBUG_FILES
		char name [20];

		sprintf (name, NAME_TEMPLATE, i);
		if (!(rndis_connect_state [i]
1411
				= create_proc_entry (name, 0660, NULL)))
L
Linus Torvalds 已提交
1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434
		{
			DEBUG ("%s :remove entries", __FUNCTION__);
			while (i) {
				sprintf (name, NAME_TEMPLATE, --i);
				remove_proc_entry (name, NULL);
			}
			DEBUG ("\n");
			return -EIO;
		}

		rndis_connect_state [i]->nlink = 1;
		rndis_connect_state [i]->write_proc = rndis_proc_write;
		rndis_connect_state [i]->read_proc = rndis_proc_read;
		rndis_connect_state [i]->data = (void *)
				(rndis_per_dev_params + i);
#endif
		rndis_per_dev_params [i].confignr = i;
		rndis_per_dev_params [i].used = 0;
		rndis_per_dev_params [i].state = RNDIS_UNINITIALIZED;
		rndis_per_dev_params [i].media_state
				= NDIS_MEDIA_STATE_DISCONNECTED;
		INIT_LIST_HEAD (&(rndis_per_dev_params [i].resp_queue));
	}
1435

L
Linus Torvalds 已提交
1436 1437 1438 1439 1440 1441 1442 1443
	return 0;
}

void rndis_exit (void)
{
#ifdef	CONFIG_USB_GADGET_DEBUG_FILES
	u8 i;
	char name [20];
1444

L
Linus Torvalds 已提交
1445 1446 1447 1448 1449 1450 1451
	for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
		sprintf (name, NAME_TEMPLATE, i);
		remove_proc_entry (name, NULL);
	}
#endif
}