rndis.c 28.4 KB
Newer Older
1
/*
L
Linus Torvalds 已提交
2
 * RNDIS MSG parser
3
 *
L
Linus Torvalds 已提交
4
 * Authors:	Benedikt Spranger, Pengutronix
5 6
 *		Robert Schwebel, Pengutronix
 *
L
Linus Torvalds 已提交
7 8
 *              This program is free software; you can redistribute it and/or
 *              modify it under the terms of the GNU General Public License
9 10
 *              version 2, as published by the Free Software Foundation.
 *
L
Linus Torvalds 已提交
11 12
 *		This software was originally developed in conformance with
 *		Microsoft's Remote NDIS Specification License Agreement.
13
 *
L
Linus Torvalds 已提交
14 15
 * 03/12/2004 Kai-Uwe Bloem <linux-development@auerswald.de>
 *		Fixed message length bug in init_response
16
 *
L
Linus Torvalds 已提交
17
 * 03/25/2004 Kai-Uwe Bloem <linux-development@auerswald.de>
18
 *		Fixed rndis_rm_hdr length bug.
L
Linus Torvalds 已提交
19 20 21 22 23 24 25 26 27
 *
 * 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>
28
#include <linux/idr.h>
L
Linus Torvalds 已提交
29 30
#include <linux/list.h>
#include <linux/proc_fs.h>
31
#include <linux/slab.h>
32
#include <linux/seq_file.h>
L
Linus Torvalds 已提交
33 34 35 36
#include <linux/netdevice.h>

#include <asm/io.h>
#include <asm/byteorder.h>
37
#include <asm/unaligned.h>
L
Linus Torvalds 已提交
38

39
#include "u_rndis.h"
L
Linus Torvalds 已提交
40

D
David Brownell 已提交
41
#undef	VERBOSE_DEBUG
L
Linus Torvalds 已提交
42 43 44 45 46 47 48 49 50 51 52 53 54

#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
static int rndis_debug = 0;
55
module_param (rndis_debug, int, 0);
L
Linus Torvalds 已提交
56 57 58 59 60
MODULE_PARM_DESC (rndis_debug, "enable debugging");
#else
#define rndis_debug		0
#endif

61
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
L
Linus Torvalds 已提交
62

63
#define	NAME_TEMPLATE "driver/rndis-%03d"
L
Linus Torvalds 已提交
64

65 66 67
#endif /* CONFIG_USB_GADGET_DEBUG_FILES */

static DEFINE_IDA(rndis_ida);
L
Linus Torvalds 已提交
68 69

/* Driver Version */
70
static const __le32 rndis_driver_version = cpu_to_le32(1);
L
Linus Torvalds 已提交
71 72

/* Function Prototypes */
73 74
static rndis_resp_t *rndis_add_response(struct rndis_params *params,
					u32 length);
L
Linus Torvalds 已提交
75

76 77 78 79 80
#ifdef CONFIG_USB_GADGET_DEBUG_FILES

static const struct file_operations rndis_proc_fops;

#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
L
Linus Torvalds 已提交
81

82
/* supported OIDs */
83
static const u32 oid_supported_list[] =
84 85
{
	/* the general stuff */
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
	RNDIS_OID_GEN_SUPPORTED_LIST,
	RNDIS_OID_GEN_HARDWARE_STATUS,
	RNDIS_OID_GEN_MEDIA_SUPPORTED,
	RNDIS_OID_GEN_MEDIA_IN_USE,
	RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE,
	RNDIS_OID_GEN_LINK_SPEED,
	RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE,
	RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE,
	RNDIS_OID_GEN_VENDOR_ID,
	RNDIS_OID_GEN_VENDOR_DESCRIPTION,
	RNDIS_OID_GEN_VENDOR_DRIVER_VERSION,
	RNDIS_OID_GEN_CURRENT_PACKET_FILTER,
	RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE,
	RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
	RNDIS_OID_GEN_PHYSICAL_MEDIUM,
101

102
	/* the statistical stuff */
103 104 105 106 107
	RNDIS_OID_GEN_XMIT_OK,
	RNDIS_OID_GEN_RCV_OK,
	RNDIS_OID_GEN_XMIT_ERROR,
	RNDIS_OID_GEN_RCV_ERROR,
	RNDIS_OID_GEN_RCV_NO_BUFFER,
108
#ifdef	RNDIS_OPTIONAL_STATS
109 110 111 112 113 114 115 116 117 118 119 120 121 122
	RNDIS_OID_GEN_DIRECTED_BYTES_XMIT,
	RNDIS_OID_GEN_DIRECTED_FRAMES_XMIT,
	RNDIS_OID_GEN_MULTICAST_BYTES_XMIT,
	RNDIS_OID_GEN_MULTICAST_FRAMES_XMIT,
	RNDIS_OID_GEN_BROADCAST_BYTES_XMIT,
	RNDIS_OID_GEN_BROADCAST_FRAMES_XMIT,
	RNDIS_OID_GEN_DIRECTED_BYTES_RCV,
	RNDIS_OID_GEN_DIRECTED_FRAMES_RCV,
	RNDIS_OID_GEN_MULTICAST_BYTES_RCV,
	RNDIS_OID_GEN_MULTICAST_FRAMES_RCV,
	RNDIS_OID_GEN_BROADCAST_BYTES_RCV,
	RNDIS_OID_GEN_BROADCAST_FRAMES_RCV,
	RNDIS_OID_GEN_RCV_CRC_ERROR,
	RNDIS_OID_GEN_TRANSMIT_QUEUE_LENGTH,
123 124
#endif	/* RNDIS_OPTIONAL_STATS */

125
	/* mandatory 802.3 */
126
	/* the general stuff */
127
	RNDIS_OID_802_3_PERMANENT_ADDRESS,
128 129 130 131
	RNDIS_OID_802_3_CURRENT_ADDRESS,
	RNDIS_OID_802_3_MULTICAST_LIST,
	RNDIS_OID_802_3_MAC_OPTIONS,
	RNDIS_OID_802_3_MAXIMUM_LIST_SIZE,
132

133
	/* the statistical stuff */
134 135 136
	RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT,
	RNDIS_OID_802_3_XMIT_ONE_COLLISION,
	RNDIS_OID_802_3_XMIT_MORE_COLLISIONS,
137
#ifdef	RNDIS_OPTIONAL_STATS
138 139 140 141 142 143 144
	RNDIS_OID_802_3_XMIT_DEFERRED,
	RNDIS_OID_802_3_XMIT_MAX_COLLISIONS,
	RNDIS_OID_802_3_RCV_OVERRUN,
	RNDIS_OID_802_3_XMIT_UNDERRUN,
	RNDIS_OID_802_3_XMIT_HEARTBEAT_FAILURE,
	RNDIS_OID_802_3_XMIT_TIMES_CRS_LOST,
	RNDIS_OID_802_3_XMIT_LATE_COLLISIONS,
145 146 147
#endif	/* RNDIS_OPTIONAL_STATS */

#ifdef	RNDIS_PM
D
David Brownell 已提交
148 149 150 151 152 153 154 155
	/* PM and wakeup are "mandatory" for USB, but the RNDIS specs
	 * don't say what they mean ... and the NDIS specs are often
	 * confusing and/or ambiguous in this context.  (That is, more
	 * so than their specs for the other OIDs.)
	 *
	 * FIXME someone who knows what these should do, please
	 * implement them!
	 */
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171

	/* 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 已提交
172
/* NDIS Functions */
173
static int gen_ndis_query_resp(struct rndis_params *params, u32 OID, u8 *buf,
174
			       unsigned buf_len, rndis_resp_t *r)
L
Linus Torvalds 已提交
175
{
176 177 178 179 180 181
	int retval = -ENOTSUPP;
	u32 length = 4;	/* usually */
	__le32 *outbuf;
	int i, count;
	rndis_query_cmplt_type *resp;
	struct net_device *net;
182
	struct rtnl_link_stats64 temp;
183
	const struct rtnl_link_stats64 *stats;
L
Linus Torvalds 已提交
184 185

	if (!r) return -ENOMEM;
186
	resp = (rndis_query_cmplt_type *)r->buf;
L
Linus Torvalds 已提交
187 188

	if (!resp) return -ENOMEM;
189 190

	if (buf_len && rndis_debug > 1) {
191
		pr_debug("query OID %08x value, len %d:\n", OID, buf_len);
192
		for (i = 0; i < buf_len; i += 16) {
193
			pr_debug("%03d: %08x %08x %08x %08x\n", i,
194 195 196 197
				get_unaligned_le32(&buf[i]),
				get_unaligned_le32(&buf[i + 4]),
				get_unaligned_le32(&buf[i + 8]),
				get_unaligned_le32(&buf[i + 12]));
198 199 200 201
		}
	}

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

205
	net = params->dev;
206
	stats = dev_get_stats(net, &temp);
D
David Brownell 已提交
207

L
Linus Torvalds 已提交
208 209 210 211 212
	switch (OID) {

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

	/* mandatory */
213 214
	case RNDIS_OID_GEN_SUPPORTED_LIST:
		pr_debug("%s: RNDIS_OID_GEN_SUPPORTED_LIST\n", __func__);
215 216
		length = sizeof(oid_supported_list);
		count  = length / sizeof(u32);
L
Linus Torvalds 已提交
217
		for (i = 0; i < count; i++)
218
			outbuf[i] = cpu_to_le32(oid_supported_list[i]);
L
Linus Torvalds 已提交
219 220
		retval = 0;
		break;
221

L
Linus Torvalds 已提交
222
	/* mandatory */
223 224
	case RNDIS_OID_GEN_HARDWARE_STATUS:
		pr_debug("%s: RNDIS_OID_GEN_HARDWARE_STATUS\n", __func__);
225
		/* Bogus question!
L
Linus Torvalds 已提交
226
		 * Hardware must be ready to receive high level protocols.
227
		 * BTW:
L
Linus Torvalds 已提交
228 229 230
		 * reddite ergo quae sunt Caesaris Caesari
		 * et quae sunt Dei Deo!
		 */
231
		*outbuf = cpu_to_le32(0);
L
Linus Torvalds 已提交
232 233
		retval = 0;
		break;
234

L
Linus Torvalds 已提交
235
	/* mandatory */
236 237
	case RNDIS_OID_GEN_MEDIA_SUPPORTED:
		pr_debug("%s: RNDIS_OID_GEN_MEDIA_SUPPORTED\n", __func__);
238
		*outbuf = cpu_to_le32(params->medium);
L
Linus Torvalds 已提交
239 240
		retval = 0;
		break;
241

L
Linus Torvalds 已提交
242
	/* mandatory */
243 244
	case RNDIS_OID_GEN_MEDIA_IN_USE:
		pr_debug("%s: RNDIS_OID_GEN_MEDIA_IN_USE\n", __func__);
L
Linus Torvalds 已提交
245
		/* one medium, one transport... (maybe you do it better) */
246
		*outbuf = cpu_to_le32(params->medium);
L
Linus Torvalds 已提交
247 248
		retval = 0;
		break;
249

L
Linus Torvalds 已提交
250
	/* mandatory */
251 252
	case RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE:
		pr_debug("%s: RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE\n", __func__);
253 254
		if (params->dev) {
			*outbuf = cpu_to_le32(params->dev->mtu);
L
Linus Torvalds 已提交
255 256 257
			retval = 0;
		}
		break;
258

L
Linus Torvalds 已提交
259
	/* mandatory */
260
	case RNDIS_OID_GEN_LINK_SPEED:
261
		if (rndis_debug > 1)
262
			pr_debug("%s: RNDIS_OID_GEN_LINK_SPEED\n", __func__);
263
		if (params->media_state == RNDIS_MEDIA_STATE_DISCONNECTED)
264
			*outbuf = cpu_to_le32(0);
L
Linus Torvalds 已提交
265
		else
266
			*outbuf = cpu_to_le32(params->speed);
L
Linus Torvalds 已提交
267 268 269 270
		retval = 0;
		break;

	/* mandatory */
271 272
	case RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE:
		pr_debug("%s: RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE\n", __func__);
273 274
		if (params->dev) {
			*outbuf = cpu_to_le32(params->dev->mtu);
L
Linus Torvalds 已提交
275 276 277
			retval = 0;
		}
		break;
278

L
Linus Torvalds 已提交
279
	/* mandatory */
280 281
	case RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE:
		pr_debug("%s: RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE\n", __func__);
282 283
		if (params->dev) {
			*outbuf = cpu_to_le32(params->dev->mtu);
L
Linus Torvalds 已提交
284 285 286
			retval = 0;
		}
		break;
287

L
Linus Torvalds 已提交
288
	/* mandatory */
289 290
	case RNDIS_OID_GEN_VENDOR_ID:
		pr_debug("%s: RNDIS_OID_GEN_VENDOR_ID\n", __func__);
291
		*outbuf = cpu_to_le32(params->vendorID);
L
Linus Torvalds 已提交
292 293
		retval = 0;
		break;
294

L
Linus Torvalds 已提交
295
	/* mandatory */
296 297
	case RNDIS_OID_GEN_VENDOR_DESCRIPTION:
		pr_debug("%s: RNDIS_OID_GEN_VENDOR_DESCRIPTION\n", __func__);
298 299 300
		if (params->vendorDescr) {
			length = strlen(params->vendorDescr);
			memcpy(outbuf, params->vendorDescr, length);
301 302 303
		} else {
			outbuf[0] = 0;
		}
L
Linus Torvalds 已提交
304 305 306
		retval = 0;
		break;

307 308
	case RNDIS_OID_GEN_VENDOR_DRIVER_VERSION:
		pr_debug("%s: RNDIS_OID_GEN_VENDOR_DRIVER_VERSION\n", __func__);
L
Linus Torvalds 已提交
309
		/* Created as LE */
310
		*outbuf = rndis_driver_version;
L
Linus Torvalds 已提交
311 312 313 314
		retval = 0;
		break;

	/* mandatory */
315 316
	case RNDIS_OID_GEN_CURRENT_PACKET_FILTER:
		pr_debug("%s: RNDIS_OID_GEN_CURRENT_PACKET_FILTER\n", __func__);
317
		*outbuf = cpu_to_le32(*params->filter);
L
Linus Torvalds 已提交
318 319 320 321
		retval = 0;
		break;

	/* mandatory */
322 323
	case RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE:
		pr_debug("%s: RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE\n", __func__);
324
		*outbuf = cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
L
Linus Torvalds 已提交
325 326 327 328
		retval = 0;
		break;

	/* mandatory */
329
	case RNDIS_OID_GEN_MEDIA_CONNECT_STATUS:
330
		if (rndis_debug > 1)
331
			pr_debug("%s: RNDIS_OID_GEN_MEDIA_CONNECT_STATUS\n", __func__);
332
		*outbuf = cpu_to_le32(params->media_state);
L
Linus Torvalds 已提交
333 334 335
		retval = 0;
		break;

336 337
	case RNDIS_OID_GEN_PHYSICAL_MEDIUM:
		pr_debug("%s: RNDIS_OID_GEN_PHYSICAL_MEDIUM\n", __func__);
338
		*outbuf = cpu_to_le32(0);
L
Linus Torvalds 已提交
339 340 341 342 343 344 345
		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!
	 */
346 347
	case RNDIS_OID_GEN_MAC_OPTIONS:		/* from WinME */
		pr_debug("%s: RNDIS_OID_GEN_MAC_OPTIONS\n", __func__);
348
		*outbuf = cpu_to_le32(
349 350
			  RNDIS_MAC_OPTION_RECEIVE_SERIALIZED
			| RNDIS_MAC_OPTION_FULL_DUPLEX);
L
Linus Torvalds 已提交
351 352 353 354 355 356
		retval = 0;
		break;

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

	/* mandatory */
357
	case RNDIS_OID_GEN_XMIT_OK:
358
		if (rndis_debug > 1)
359
			pr_debug("%s: RNDIS_OID_GEN_XMIT_OK\n", __func__);
D
David Brownell 已提交
360 361 362
		if (stats) {
			*outbuf = cpu_to_le32(stats->tx_packets
				- stats->tx_errors - stats->tx_dropped);
L
Linus Torvalds 已提交
363 364 365 366 367
			retval = 0;
		}
		break;

	/* mandatory */
368
	case RNDIS_OID_GEN_RCV_OK:
369
		if (rndis_debug > 1)
370
			pr_debug("%s: RNDIS_OID_GEN_RCV_OK\n", __func__);
D
David Brownell 已提交
371 372 373
		if (stats) {
			*outbuf = cpu_to_le32(stats->rx_packets
				- stats->rx_errors - stats->rx_dropped);
L
Linus Torvalds 已提交
374 375 376
			retval = 0;
		}
		break;
377

L
Linus Torvalds 已提交
378
	/* mandatory */
379
	case RNDIS_OID_GEN_XMIT_ERROR:
380
		if (rndis_debug > 1)
381
			pr_debug("%s: RNDIS_OID_GEN_XMIT_ERROR\n", __func__);
D
David Brownell 已提交
382 383
		if (stats) {
			*outbuf = cpu_to_le32(stats->tx_errors);
L
Linus Torvalds 已提交
384 385 386
			retval = 0;
		}
		break;
387

L
Linus Torvalds 已提交
388
	/* mandatory */
389
	case RNDIS_OID_GEN_RCV_ERROR:
390
		if (rndis_debug > 1)
391
			pr_debug("%s: RNDIS_OID_GEN_RCV_ERROR\n", __func__);
D
David Brownell 已提交
392 393
		if (stats) {
			*outbuf = cpu_to_le32(stats->rx_errors);
L
Linus Torvalds 已提交
394 395 396
			retval = 0;
		}
		break;
397

L
Linus Torvalds 已提交
398
	/* mandatory */
399 400
	case RNDIS_OID_GEN_RCV_NO_BUFFER:
		pr_debug("%s: RNDIS_OID_GEN_RCV_NO_BUFFER\n", __func__);
D
David Brownell 已提交
401 402
		if (stats) {
			*outbuf = cpu_to_le32(stats->rx_dropped);
L
Linus Torvalds 已提交
403 404 405
			retval = 0;
		}
		break;
406

L
Linus Torvalds 已提交
407 408 409
	/* ieee802.3 OIDs (table 4-3) */

	/* mandatory */
410
	case RNDIS_OID_802_3_PERMANENT_ADDRESS:
411
		pr_debug("%s: RNDIS_OID_802_3_PERMANENT_ADDRESS\n", __func__);
412
		if (params->dev) {
L
Linus Torvalds 已提交
413
			length = ETH_ALEN;
414
			memcpy(outbuf, params->host_mac, length);
L
Linus Torvalds 已提交
415 416 417
			retval = 0;
		}
		break;
418

L
Linus Torvalds 已提交
419
	/* mandatory */
420 421
	case RNDIS_OID_802_3_CURRENT_ADDRESS:
		pr_debug("%s: RNDIS_OID_802_3_CURRENT_ADDRESS\n", __func__);
422
		if (params->dev) {
L
Linus Torvalds 已提交
423
			length = ETH_ALEN;
424
			memcpy(outbuf, params->host_mac, length);
L
Linus Torvalds 已提交
425 426 427
			retval = 0;
		}
		break;
428

L
Linus Torvalds 已提交
429
	/* mandatory */
430 431
	case RNDIS_OID_802_3_MULTICAST_LIST:
		pr_debug("%s: RNDIS_OID_802_3_MULTICAST_LIST\n", __func__);
L
Linus Torvalds 已提交
432
		/* Multicast base address only */
433
		*outbuf = cpu_to_le32(0xE0000000);
L
Linus Torvalds 已提交
434 435
		retval = 0;
		break;
436

L
Linus Torvalds 已提交
437
	/* mandatory */
438 439
	case RNDIS_OID_802_3_MAXIMUM_LIST_SIZE:
		pr_debug("%s: RNDIS_OID_802_3_MAXIMUM_LIST_SIZE\n", __func__);
L
Linus Torvalds 已提交
440
		/* Multicast base address only */
441
		*outbuf = cpu_to_le32(1);
L
Linus Torvalds 已提交
442 443
		retval = 0;
		break;
444

445 446
	case RNDIS_OID_802_3_MAC_OPTIONS:
		pr_debug("%s: RNDIS_OID_802_3_MAC_OPTIONS\n", __func__);
447 448
		*outbuf = cpu_to_le32(0);
		retval = 0;
L
Linus Torvalds 已提交
449 450 451 452 453
		break;

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

	/* mandatory */
454 455
	case RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT:
		pr_debug("%s: RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT\n", __func__);
D
David Brownell 已提交
456 457
		if (stats) {
			*outbuf = cpu_to_le32(stats->rx_frame_errors);
L
Linus Torvalds 已提交
458 459 460
			retval = 0;
		}
		break;
461

L
Linus Torvalds 已提交
462
	/* mandatory */
463 464
	case RNDIS_OID_802_3_XMIT_ONE_COLLISION:
		pr_debug("%s: RNDIS_OID_802_3_XMIT_ONE_COLLISION\n", __func__);
465
		*outbuf = cpu_to_le32(0);
L
Linus Torvalds 已提交
466 467
		retval = 0;
		break;
468

L
Linus Torvalds 已提交
469
	/* mandatory */
470 471
	case RNDIS_OID_802_3_XMIT_MORE_COLLISIONS:
		pr_debug("%s: RNDIS_OID_802_3_XMIT_MORE_COLLISIONS\n", __func__);
472
		*outbuf = cpu_to_le32(0);
L
Linus Torvalds 已提交
473 474
		retval = 0;
		break;
475

L
Linus Torvalds 已提交
476
	default:
477
		pr_warning("%s: query unknown OID 0x%08X\n",
478
			 __func__, OID);
L
Linus Torvalds 已提交
479
	}
480 481
	if (retval < 0)
		length = 0;
482

483 484 485
	resp->InformationBufferLength = cpu_to_le32(length);
	r->length = length + sizeof(*resp);
	resp->MessageLength = cpu_to_le32(r->length);
L
Linus Torvalds 已提交
486 487 488
	return retval;
}

489 490
static int gen_ndis_set_resp(struct rndis_params *params, u32 OID,
			     u8 *buf, u32 buf_len, rndis_resp_t *r)
L
Linus Torvalds 已提交
491
{
492 493
	rndis_set_cmplt_type *resp;
	int i, retval = -ENOTSUPP;
L
Linus Torvalds 已提交
494 495 496

	if (!r)
		return -ENOMEM;
497
	resp = (rndis_set_cmplt_type *)r->buf;
L
Linus Torvalds 已提交
498 499 500
	if (!resp)
		return -ENOMEM;

501
	if (buf_len && rndis_debug > 1) {
502
		pr_debug("set OID %08x value, len %d:\n", OID, buf_len);
503
		for (i = 0; i < buf_len; i += 16) {
504
			pr_debug("%03d: %08x %08x %08x %08x\n", i,
505 506 507 508
				get_unaligned_le32(&buf[i]),
				get_unaligned_le32(&buf[i + 4]),
				get_unaligned_le32(&buf[i + 8]),
				get_unaligned_le32(&buf[i + 12]));
509
		}
L
Linus Torvalds 已提交
510 511 512
	}

	switch (OID) {
513
	case RNDIS_OID_GEN_CURRENT_PACKET_FILTER:
L
Linus Torvalds 已提交
514

515 516
		/* these NDIS_PACKET_TYPE_* bitflags are shared with
		 * cdc_filter; it's not RNDIS-specific
L
Linus Torvalds 已提交
517 518 519 520
		 * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in:
		 *	PROMISCUOUS, DIRECTED,
		 *	MULTICAST, ALL_MULTICAST, BROADCAST
		 */
521
		*params->filter = (u16)get_unaligned_le32(buf);
522
		pr_debug("%s: RNDIS_OID_GEN_CURRENT_PACKET_FILTER %08x\n",
523
			__func__, *params->filter);
L
Linus Torvalds 已提交
524 525 526 527 528

		/* this call has a significant side effect:  it's
		 * what makes the packet flow start and stop, like
		 * activating the CDC Ethernet altsetting.
		 */
529 530
		retval = 0;
		if (*params->filter) {
L
Linus Torvalds 已提交
531 532 533
			params->state = RNDIS_DATA_INITIALIZED;
			netif_carrier_on(params->dev);
			if (netif_running(params->dev))
534
				netif_wake_queue(params->dev);
L
Linus Torvalds 已提交
535 536
		} else {
			params->state = RNDIS_INITIALIZED;
537 538
			netif_carrier_off(params->dev);
			netif_stop_queue(params->dev);
L
Linus Torvalds 已提交
539 540
		}
		break;
541

542
	case RNDIS_OID_802_3_MULTICAST_LIST:
543
		/* I think we can ignore this */
544
		pr_debug("%s: RNDIS_OID_802_3_MULTICAST_LIST\n", __func__);
L
Linus Torvalds 已提交
545 546
		retval = 0;
		break;
547

L
Linus Torvalds 已提交
548
	default:
549
		pr_warning("%s: set unknown OID 0x%08X, size %d\n",
550
			 __func__, OID, buf_len);
L
Linus Torvalds 已提交
551
	}
552

L
Linus Torvalds 已提交
553 554 555
	return retval;
}

556 557
/*
 * Response Functions
L
Linus Torvalds 已提交
558 559
 */

560 561
static int rndis_init_response(struct rndis_params *params,
			       rndis_init_msg_type *buf)
L
Linus Torvalds 已提交
562
{
563 564
	rndis_init_cmplt_type *resp;
	rndis_resp_t *r;
565

D
David Brownell 已提交
566 567
	if (!params->dev)
		return -ENOTSUPP;
568

569
	r = rndis_add_response(params, sizeof(rndis_init_cmplt_type));
570 571
	if (!r)
		return -ENOMEM;
572
	resp = (rndis_init_cmplt_type *)r->buf;
573

574
	resp->MessageType = cpu_to_le32(RNDIS_MSG_INIT_C);
575
	resp->MessageLength = cpu_to_le32(52);
L
Linus Torvalds 已提交
576
	resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
577 578 579 580 581 582 583
	resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
	resp->MajorVersion = cpu_to_le32(RNDIS_MAJOR_VERSION);
	resp->MinorVersion = cpu_to_le32(RNDIS_MINOR_VERSION);
	resp->DeviceFlags = cpu_to_le32(RNDIS_DF_CONNECTIONLESS);
	resp->Medium = cpu_to_le32(RNDIS_MEDIUM_802_3);
	resp->MaxPacketsPerTransfer = cpu_to_le32(1);
	resp->MaxTransferSize = cpu_to_le32(
D
David Brownell 已提交
584
		  params->dev->mtu
585 586
		+ sizeof(struct ethhdr)
		+ sizeof(struct rndis_packet_msg_type)
L
Linus Torvalds 已提交
587
		+ 22);
588 589 590
	resp->PacketAlignmentFactor = cpu_to_le32(0);
	resp->AFListOffset = cpu_to_le32(0);
	resp->AFListSize = cpu_to_le32(0);
591

D
David Brownell 已提交
592
	params->resp_avail(params->v);
L
Linus Torvalds 已提交
593 594 595
	return 0;
}

596 597
static int rndis_query_response(struct rndis_params *params,
				rndis_query_msg_type *buf)
L
Linus Torvalds 已提交
598 599
{
	rndis_query_cmplt_type *resp;
600
	rndis_resp_t *r;
601

602
	/* pr_debug("%s: OID = %08X\n", __func__, cpu_to_le32(buf->OID)); */
D
David Brownell 已提交
603 604
	if (!params->dev)
		return -ENOTSUPP;
605

606 607 608 609 610
	/*
	 * 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 已提交
611
	 */
612
	r = rndis_add_response(params,
613
		sizeof(oid_supported_list) + sizeof(rndis_query_cmplt_type));
614 615
	if (!r)
		return -ENOMEM;
616
	resp = (rndis_query_cmplt_type *)r->buf;
617

618
	resp->MessageType = cpu_to_le32(RNDIS_MSG_QUERY_C);
L
Linus Torvalds 已提交
619
	resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
620

621
	if (gen_ndis_query_resp(params, le32_to_cpu(buf->OID),
622
			le32_to_cpu(buf->InformationBufferOffset)
623
					+ 8 + (u8 *)buf,
624 625
			le32_to_cpu(buf->InformationBufferLength),
			r)) {
L
Linus Torvalds 已提交
626
		/* OID not supported */
627 628 629 630
		resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
		resp->MessageLength = cpu_to_le32(sizeof *resp);
		resp->InformationBufferLength = cpu_to_le32(0);
		resp->InformationBufferOffset = cpu_to_le32(0);
L
Linus Torvalds 已提交
631
	} else
632
		resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
633

D
David Brownell 已提交
634
	params->resp_avail(params->v);
L
Linus Torvalds 已提交
635 636 637
	return 0;
}

638 639
static int rndis_set_response(struct rndis_params *params,
			      rndis_set_msg_type *buf)
L
Linus Torvalds 已提交
640
{
641 642 643
	u32 BufLength, BufOffset;
	rndis_set_cmplt_type *resp;
	rndis_resp_t *r;
644

645
	r = rndis_add_response(params, sizeof(rndis_set_cmplt_type));
646 647
	if (!r)
		return -ENOMEM;
648
	resp = (rndis_set_cmplt_type *)r->buf;
L
Linus Torvalds 已提交
649

650 651
	BufLength = le32_to_cpu(buf->InformationBufferLength);
	BufOffset = le32_to_cpu(buf->InformationBufferOffset);
L
Linus Torvalds 已提交
652

D
David Brownell 已提交
653
#ifdef	VERBOSE_DEBUG
654 655 656
	pr_debug("%s: Length: %d\n", __func__, BufLength);
	pr_debug("%s: Offset: %d\n", __func__, BufOffset);
	pr_debug("%s: InfoBuffer: ", __func__);
657

L
Linus Torvalds 已提交
658
	for (i = 0; i < BufLength; i++) {
659
		pr_debug("%02x ", *(((u8 *) buf) + i + 8 + BufOffset));
L
Linus Torvalds 已提交
660
	}
661

662
	pr_debug("\n");
L
Linus Torvalds 已提交
663
#endif
664

665
	resp->MessageType = cpu_to_le32(RNDIS_MSG_SET_C);
666
	resp->MessageLength = cpu_to_le32(16);
L
Linus Torvalds 已提交
667
	resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
668
	if (gen_ndis_set_resp(params, le32_to_cpu(buf->OID),
669 670
			((u8 *)buf) + 8 + BufOffset, BufLength, r))
		resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
671
	else
672
		resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
673

D
David Brownell 已提交
674
	params->resp_avail(params->v);
L
Linus Torvalds 已提交
675 676 677
	return 0;
}

678 679
static int rndis_reset_response(struct rndis_params *params,
				rndis_reset_msg_type *buf)
L
Linus Torvalds 已提交
680
{
681 682
	rndis_reset_cmplt_type *resp;
	rndis_resp_t *r;
683

684
	r = rndis_add_response(params, sizeof(rndis_reset_cmplt_type));
685 686
	if (!r)
		return -ENOMEM;
687
	resp = (rndis_reset_cmplt_type *)r->buf;
688

689
	resp->MessageType = cpu_to_le32(RNDIS_MSG_RESET_C);
690 691
	resp->MessageLength = cpu_to_le32(16);
	resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
L
Linus Torvalds 已提交
692
	/* resent information */
693
	resp->AddressingReset = cpu_to_le32(1);
694

D
David Brownell 已提交
695
	params->resp_avail(params->v);
L
Linus Torvalds 已提交
696 697 698
	return 0;
}

699
static int rndis_keepalive_response(struct rndis_params *params,
700
				    rndis_keepalive_msg_type *buf)
L
Linus Torvalds 已提交
701
{
702 703
	rndis_keepalive_cmplt_type *resp;
	rndis_resp_t *r;
L
Linus Torvalds 已提交
704 705 706

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

707
	r = rndis_add_response(params, sizeof(rndis_keepalive_cmplt_type));
708 709
	if (!r)
		return -ENOMEM;
710
	resp = (rndis_keepalive_cmplt_type *)r->buf;
711

712
	resp->MessageType = cpu_to_le32(RNDIS_MSG_KEEPALIVE_C);
713
	resp->MessageLength = cpu_to_le32(16);
L
Linus Torvalds 已提交
714
	resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
715
	resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
716

D
David Brownell 已提交
717
	params->resp_avail(params->v);
L
Linus Torvalds 已提交
718 719 720 721
	return 0;
}


722 723
/*
 * Device to Host Comunication
L
Linus Torvalds 已提交
724
 */
725
static int rndis_indicate_status_msg(struct rndis_params *params, u32 status)
L
Linus Torvalds 已提交
726
{
727 728
	rndis_indicate_status_msg_type *resp;
	rndis_resp_t *r;
729

D
David Brownell 已提交
730
	if (params->state == RNDIS_UNINITIALIZED)
731 732
		return -ENOTSUPP;

733
	r = rndis_add_response(params, sizeof(rndis_indicate_status_msg_type));
734 735
	if (!r)
		return -ENOMEM;
736
	resp = (rndis_indicate_status_msg_type *)r->buf;
737

738
	resp->MessageType = cpu_to_le32(RNDIS_MSG_INDICATE);
739 740 741 742
	resp->MessageLength = cpu_to_le32(20);
	resp->Status = cpu_to_le32(status);
	resp->StatusBufferLength = cpu_to_le32(0);
	resp->StatusBufferOffset = cpu_to_le32(0);
743

D
David Brownell 已提交
744
	params->resp_avail(params->v);
L
Linus Torvalds 已提交
745 746 747
	return 0;
}

748
int rndis_signal_connect(struct rndis_params *params)
L
Linus Torvalds 已提交
749
{
750 751
	params->media_state = RNDIS_MEDIA_STATE_CONNECTED;
	return rndis_indicate_status_msg(params, RNDIS_STATUS_MEDIA_CONNECT);
L
Linus Torvalds 已提交
752
}
753
EXPORT_SYMBOL_GPL(rndis_signal_connect);
L
Linus Torvalds 已提交
754

755
int rndis_signal_disconnect(struct rndis_params *params)
L
Linus Torvalds 已提交
756
{
757 758
	params->media_state = RNDIS_MEDIA_STATE_DISCONNECTED;
	return rndis_indicate_status_msg(params, RNDIS_STATUS_MEDIA_DISCONNECT);
L
Linus Torvalds 已提交
759
}
760
EXPORT_SYMBOL_GPL(rndis_signal_disconnect);
L
Linus Torvalds 已提交
761

762
void rndis_uninit(struct rndis_params *params)
763
{
764 765 766
	u8 *buf;
	u32 length;

767
	if (!params)
768
		return;
769
	params->state = RNDIS_UNINITIALIZED;
770 771

	/* drain the response queue */
772 773
	while ((buf = rndis_get_next_response(params, &length)))
		rndis_free_response(params, buf);
774
}
775
EXPORT_SYMBOL_GPL(rndis_uninit);
776

777
void rndis_set_host_mac(struct rndis_params *params, const u8 *addr)
L
Linus Torvalds 已提交
778
{
779
	params->host_mac = addr;
L
Linus Torvalds 已提交
780
}
781
EXPORT_SYMBOL_GPL(rndis_set_host_mac);
L
Linus Torvalds 已提交
782

783 784
/*
 * Message Parser
L
Linus Torvalds 已提交
785
 */
786
int rndis_msg_parser(struct rndis_params *params, u8 *buf)
L
Linus Torvalds 已提交
787 788 789
{
	u32 MsgType, MsgLength;
	__le32 *tmp;
790

L
Linus Torvalds 已提交
791 792
	if (!buf)
		return -ENOMEM;
793

794
	tmp = (__le32 *)buf;
795 796
	MsgType   = get_unaligned_le32(tmp++);
	MsgLength = get_unaligned_le32(tmp++);
797

798
	if (!params)
L
Linus Torvalds 已提交
799
		return -ENOTSUPP;
800

801 802 803 804 805
	/* 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 已提交
806
	/* For USB: responses may take up to 10 seconds */
807
	switch (MsgType) {
808 809
	case RNDIS_MSG_INIT:
		pr_debug("%s: RNDIS_MSG_INIT\n",
810
			__func__);
L
Linus Torvalds 已提交
811
		params->state = RNDIS_INITIALIZED;
812
		return rndis_init_response(params, (rndis_init_msg_type *)buf);
813

814 815
	case RNDIS_MSG_HALT:
		pr_debug("%s: RNDIS_MSG_HALT\n",
816
			__func__);
L
Linus Torvalds 已提交
817 818
		params->state = RNDIS_UNINITIALIZED;
		if (params->dev) {
819 820
			netif_carrier_off(params->dev);
			netif_stop_queue(params->dev);
L
Linus Torvalds 已提交
821 822
		}
		return 0;
823

824
	case RNDIS_MSG_QUERY:
825
		return rndis_query_response(params,
826
					(rndis_query_msg_type *)buf);
827

828
	case RNDIS_MSG_SET:
829
		return rndis_set_response(params, (rndis_set_msg_type *)buf);
830

831 832
	case RNDIS_MSG_RESET:
		pr_debug("%s: RNDIS_MSG_RESET\n",
833
			__func__);
834
		return rndis_reset_response(params,
835
					(rndis_reset_msg_type *)buf);
L
Linus Torvalds 已提交
836

837
	case RNDIS_MSG_KEEPALIVE:
L
Linus Torvalds 已提交
838
		/* For USB: host does this every 5 seconds */
839
		if (rndis_debug > 1)
840
			pr_debug("%s: RNDIS_MSG_KEEPALIVE\n",
841
				__func__);
842
		return rndis_keepalive_response(params,
843
						 (rndis_keepalive_msg_type *)
L
Linus Torvalds 已提交
844
						 buf);
845 846

	default:
L
Linus Torvalds 已提交
847 848 849 850
		/* At least Windows XP emits some undefined RNDIS messages.
		 * In one case those messages seemed to relate to the host
		 * suspending itself.
		 */
851
		pr_warning("%s: unknown RNDIS message 0x%08X len %d\n",
852
			__func__, MsgType, MsgLength);
853 854
		print_hex_dump_bytes(__func__, DUMP_PREFIX_OFFSET,
				     buf, MsgLength);
L
Linus Torvalds 已提交
855 856
		break;
	}
857

L
Linus Torvalds 已提交
858 859
	return -ENOTSUPP;
}
860
EXPORT_SYMBOL_GPL(rndis_msg_parser);
L
Linus Torvalds 已提交
861

862 863 864 865 866 867 868 869 870 871
static inline int rndis_get_nr(void)
{
	return ida_simple_get(&rndis_ida, 0, 0, GFP_KERNEL);
}

static inline void rndis_put_nr(int nr)
{
	ida_simple_remove(&rndis_ida, nr);
}

872
struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v)
L
Linus Torvalds 已提交
873
{
874
	struct rndis_params *params;
875
	int i;
876

D
David Brownell 已提交
877
	if (!resp_avail)
878
		return ERR_PTR(-EINVAL);
D
David Brownell 已提交
879

880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906
	i = rndis_get_nr();
	if (i < 0) {
		pr_debug("failed\n");

		return ERR_PTR(-ENODEV);
	}

	params = kzalloc(sizeof(*params), GFP_KERNEL);
	if (!params) {
		rndis_put_nr(i);

		return ERR_PTR(-ENOMEM);
	}

#ifdef	CONFIG_USB_GADGET_DEBUG_FILES
	{
		struct proc_dir_entry *proc_entry;
		char name[20];

		sprintf(name, NAME_TEMPLATE, i);
		proc_entry = proc_create_data(name, 0660, NULL,
					      &rndis_proc_fops, params);
		if (!proc_entry) {
			kfree(params);
			rndis_put_nr(i);

			return ERR_PTR(-EIO);
L
Linus Torvalds 已提交
907 908
		}
	}
909
#endif
910

911 912 913 914 915 916
	params->confignr = i;
	params->used = 1;
	params->state = RNDIS_UNINITIALIZED;
	params->media_state = RNDIS_MEDIA_STATE_DISCONNECTED;
	params->resp_avail = resp_avail;
	params->v = v;
917
	INIT_LIST_HEAD(&params->resp_queue);
918 919 920
	pr_debug("%s: configNr = %d\n", __func__, i);

	return params;
L
Linus Torvalds 已提交
921
}
922
EXPORT_SYMBOL_GPL(rndis_register);
L
Linus Torvalds 已提交
923

924
void rndis_deregister(struct rndis_params *params)
L
Linus Torvalds 已提交
925
{
926
	int i;
927

928
	pr_debug("%s:\n", __func__);
929

930 931
	if (!params)
		return;
932 933 934 935 936 937 938 939 940 941 942 943 944 945

	i = params->confignr;

#ifdef CONFIG_USB_GADGET_DEBUG_FILES
	{
		char name[20];

		sprintf(name, NAME_TEMPLATE, i);
		remove_proc_entry(name, NULL);
	}
#endif

	kfree(params);
	rndis_put_nr(i);
L
Linus Torvalds 已提交
946
}
947
EXPORT_SYMBOL_GPL(rndis_deregister);
948 949
int rndis_set_param_dev(struct rndis_params *params, struct net_device *dev,
			u16 *cdc_filter)
L
Linus Torvalds 已提交
950
{
951
	pr_debug("%s:\n", __func__);
D
David Brownell 已提交
952 953
	if (!dev)
		return -EINVAL;
954 955
	if (!params)
		return -1;
956

957 958
	params->dev = dev;
	params->filter = cdc_filter;
959

L
Linus Torvalds 已提交
960 961
	return 0;
}
962
EXPORT_SYMBOL_GPL(rndis_set_param_dev);
L
Linus Torvalds 已提交
963

964 965
int rndis_set_param_vendor(struct rndis_params *params, u32 vendorID,
			   const char *vendorDescr)
L
Linus Torvalds 已提交
966
{
967
	pr_debug("%s:\n", __func__);
L
Linus Torvalds 已提交
968
	if (!vendorDescr) return -1;
969 970
	if (!params)
		return -1;
971

972 973
	params->vendorID = vendorID;
	params->vendorDescr = vendorDescr;
974

L
Linus Torvalds 已提交
975 976
	return 0;
}
977
EXPORT_SYMBOL_GPL(rndis_set_param_vendor);
L
Linus Torvalds 已提交
978

979
int rndis_set_param_medium(struct rndis_params *params, u32 medium, u32 speed)
L
Linus Torvalds 已提交
980
{
981
	pr_debug("%s: %u %u\n", __func__, medium, speed);
982 983
	if (!params)
		return -1;
984

985 986
	params->medium = medium;
	params->speed = speed;
987

L
Linus Torvalds 已提交
988 989
	return 0;
}
990
EXPORT_SYMBOL_GPL(rndis_set_param_medium);
L
Linus Torvalds 已提交
991

992
void rndis_add_hdr(struct sk_buff *skb)
L
Linus Torvalds 已提交
993
{
994
	struct rndis_packet_msg_type *header;
L
Linus Torvalds 已提交
995 996 997

	if (!skb)
		return;
998 999
	header = (void *)skb_push(skb, sizeof(*header));
	memset(header, 0, sizeof *header);
1000
	header->MessageType = cpu_to_le32(RNDIS_MSG_PACKET);
L
Linus Torvalds 已提交
1001
	header->MessageLength = cpu_to_le32(skb->len);
1002 1003
	header->DataOffset = cpu_to_le32(36);
	header->DataLength = cpu_to_le32(skb->len - sizeof(*header));
L
Linus Torvalds 已提交
1004
}
1005
EXPORT_SYMBOL_GPL(rndis_add_hdr);
L
Linus Torvalds 已提交
1006

1007
void rndis_free_response(struct rndis_params *params, u8 *buf)
L
Linus Torvalds 已提交
1008
{
1009
	rndis_resp_t *r, *n;
1010

1011
	list_for_each_entry_safe(r, n, &params->resp_queue, list) {
1012
		if (r->buf == buf) {
1013 1014
			list_del(&r->list);
			kfree(r);
L
Linus Torvalds 已提交
1015 1016 1017
		}
	}
}
1018
EXPORT_SYMBOL_GPL(rndis_free_response);
L
Linus Torvalds 已提交
1019

1020
u8 *rndis_get_next_response(struct rndis_params *params, u32 *length)
L
Linus Torvalds 已提交
1021
{
1022
	rndis_resp_t *r, *n;
1023

L
Linus Torvalds 已提交
1024
	if (!length) return NULL;
1025

1026
	list_for_each_entry_safe(r, n, &params->resp_queue, list) {
L
Linus Torvalds 已提交
1027 1028 1029 1030 1031 1032
		if (!r->send) {
			r->send = 1;
			*length = r->length;
			return r->buf;
		}
	}
1033

L
Linus Torvalds 已提交
1034 1035
	return NULL;
}
1036
EXPORT_SYMBOL_GPL(rndis_get_next_response);
L
Linus Torvalds 已提交
1037

1038
static rndis_resp_t *rndis_add_response(struct rndis_params *params, u32 length)
L
Linus Torvalds 已提交
1039
{
1040
	rndis_resp_t *r;
1041

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

1046
	r->buf = (u8 *)(r + 1);
L
Linus Torvalds 已提交
1047 1048
	r->length = length;
	r->send = 0;
1049

1050
	list_add_tail(&r->list, &params->resp_queue);
L
Linus Torvalds 已提交
1051 1052 1053
	return r;
}

1054 1055 1056
int rndis_rm_hdr(struct gether *port,
			struct sk_buff *skb,
			struct sk_buff_head *list)
L
Linus Torvalds 已提交
1057
{
1058
	/* tmp points to a struct rndis_packet_msg_type */
1059
	__le32 *tmp = (void *)skb->data;
L
Linus Torvalds 已提交
1060

1061
	/* MessageType, MessageLength */
1062
	if (cpu_to_le32(RNDIS_MSG_PACKET)
1063 1064
			!= get_unaligned(tmp++)) {
		dev_kfree_skb_any(skb);
1065
		return -EINVAL;
1066
	}
1067 1068 1069
	tmp++;

	/* DataOffset, DataLength */
1070 1071
	if (!skb_pull(skb, get_unaligned_le32(tmp++) + 8)) {
		dev_kfree_skb_any(skb);
1072
		return -EOVERFLOW;
1073
	}
1074
	skb_trim(skb, get_unaligned_le32(tmp++));
L
Linus Torvalds 已提交
1075

1076
	skb_queue_tail(list, skb);
L
Linus Torvalds 已提交
1077 1078
	return 0;
}
1079
EXPORT_SYMBOL_GPL(rndis_rm_hdr);
L
Linus Torvalds 已提交
1080

1081
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
L
Linus Torvalds 已提交
1082

1083
static int rndis_proc_show(struct seq_file *m, void *v)
L
Linus Torvalds 已提交
1084
{
1085
	rndis_params *param = m->private;
1086

1087
	seq_printf(m,
L
Linus Torvalds 已提交
1088 1089 1090 1091 1092 1093 1094
			 "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"
1095 1096
			 "vendor    : %s\n",
			 param->confignr, (param->used) ? "y" : "n",
L
Linus Torvalds 已提交
1097 1098 1099 1100 1101 1102 1103 1104
			 ({ 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;
J
Joe Perches 已提交
1105
			} s; }),
1106 1107
			 param->medium,
			 (param->media_state) ? 0 : param->speed*100,
L
Linus Torvalds 已提交
1108
			 (param->media_state) ? "disconnected" : "connected",
1109
			 param->vendorID, param->vendorDescr);
1110
	return 0;
L
Linus Torvalds 已提交
1111 1112
}

1113
static ssize_t rndis_proc_write(struct file *file, const char __user *buffer,
1114
				size_t count, loff_t *ppos)
L
Linus Torvalds 已提交
1115
{
A
Al Viro 已提交
1116
	rndis_params *p = PDE_DATA(file_inode(file));
L
Linus Torvalds 已提交
1117 1118
	u32 speed = 0;
	int i, fl_speed = 0;
1119

L
Linus Torvalds 已提交
1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135
	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;
1136
			speed = speed * 10 + c - '0';
L
Linus Torvalds 已提交
1137 1138 1139
			break;
		case 'C':
		case 'c':
1140
			rndis_signal_connect(p);
L
Linus Torvalds 已提交
1141 1142 1143
			break;
		case 'D':
		case 'd':
1144
			rndis_signal_disconnect(p);
L
Linus Torvalds 已提交
1145
			break;
1146
		default:
L
Linus Torvalds 已提交
1147
			if (fl_speed) p->speed = speed;
1148
			else pr_debug("%c is not valid\n", c);
L
Linus Torvalds 已提交
1149 1150
			break;
		}
1151

L
Linus Torvalds 已提交
1152 1153
		buffer++;
	}
1154

L
Linus Torvalds 已提交
1155 1156 1157
	return count;
}

1158 1159
static int rndis_proc_open(struct inode *inode, struct file *file)
{
A
Al Viro 已提交
1160
	return single_open(file, rndis_proc_show, PDE_DATA(inode));
1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171
}

static const struct file_operations rndis_proc_fops = {
	.owner		= THIS_MODULE,
	.open		= rndis_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
	.write		= rndis_proc_write,
};

1172
#define	NAME_TEMPLATE "driver/rndis-%03d"
L
Linus Torvalds 已提交
1173

1174
#endif /* CONFIG_USB_GADGET_DEBUG_FILES */