blob: 5e6e5a054ca745a40ec0897d3fdce75b10147cd1 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0
Vitaly Kuzmichev216c4472011-02-11 18:18:34 +03002/*
3 * RNDIS MSG parser
4 *
5 * Authors: Benedikt Spranger, Pengutronix
6 * Robert Schwebel, Pengutronix
7 *
Vitaly Kuzmichev216c4472011-02-11 18:18:34 +03008 * This software was originally developed in conformance with
9 * Microsoft's Remote NDIS Specification License Agreement.
10 *
11 * 03/12/2004 Kai-Uwe Bloem <linux-development@auerswald.de>
12 * Fixed message length bug in init_response
13 *
14 * 03/25/2004 Kai-Uwe Bloem <linux-development@auerswald.de>
15 * Fixed rndis_rm_hdr length bug.
16 *
17 * Copyright (C) 2004 by David Brownell
18 * updates to merge with Linux 2.6, better match RNDIS spec
19 */
20
Simon Glass0f2af882020-05-10 11:40:05 -060021#include <log.h>
Vitaly Kuzmichev216c4472011-02-11 18:18:34 +030022#include <net.h>
23#include <malloc.h>
24#include <linux/types.h>
25#include <linux/list.h>
26#include <linux/netdevice.h>
27
28#include <asm/byteorder.h>
29#include <asm/unaligned.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090030#include <linux/errno.h>
Vitaly Kuzmichev216c4472011-02-11 18:18:34 +030031
32#undef RNDIS_PM
33#undef RNDIS_WAKEUP
34#undef VERBOSE
35
36#include "rndis.h"
37
Vitaly Kuzmichev216c4472011-02-11 18:18:34 +030038/*
39 * The driver for your USB chip needs to support ep0 OUT to work with
40 * RNDIS, plus all three CDC Ethernet endpoints (interrupt not optional).
41 *
42 * Windows hosts need an INF file like Documentation/usb/linux.inf
43 * and will be happier if you provide the host_addr module parameter.
44 */
45
46#define RNDIS_MAX_CONFIGS 1
47
48static rndis_params rndis_per_dev_params[RNDIS_MAX_CONFIGS];
49
50/* Driver Version */
51static const __le32 rndis_driver_version = __constant_cpu_to_le32(1);
52
53/* Function Prototypes */
54static rndis_resp_t *rndis_add_response(int configNr, u32 length);
55
56
57/* supported OIDs */
58static const u32 oid_supported_list[] = {
59 /* the general stuff */
60 OID_GEN_SUPPORTED_LIST,
61 OID_GEN_HARDWARE_STATUS,
62 OID_GEN_MEDIA_SUPPORTED,
63 OID_GEN_MEDIA_IN_USE,
64 OID_GEN_MAXIMUM_FRAME_SIZE,
65 OID_GEN_LINK_SPEED,
66 OID_GEN_TRANSMIT_BLOCK_SIZE,
67 OID_GEN_RECEIVE_BLOCK_SIZE,
68 OID_GEN_VENDOR_ID,
69 OID_GEN_VENDOR_DESCRIPTION,
70 OID_GEN_VENDOR_DRIVER_VERSION,
71 OID_GEN_CURRENT_PACKET_FILTER,
72 OID_GEN_MAXIMUM_TOTAL_SIZE,
73 OID_GEN_MEDIA_CONNECT_STATUS,
74 OID_GEN_PHYSICAL_MEDIUM,
75#if 0
76 OID_GEN_RNDIS_CONFIG_PARAMETER,
77#endif
78
79 /* the statistical stuff */
80 OID_GEN_XMIT_OK,
81 OID_GEN_RCV_OK,
82 OID_GEN_XMIT_ERROR,
83 OID_GEN_RCV_ERROR,
84 OID_GEN_RCV_NO_BUFFER,
85#ifdef RNDIS_OPTIONAL_STATS
86 OID_GEN_DIRECTED_BYTES_XMIT,
87 OID_GEN_DIRECTED_FRAMES_XMIT,
88 OID_GEN_MULTICAST_BYTES_XMIT,
89 OID_GEN_MULTICAST_FRAMES_XMIT,
90 OID_GEN_BROADCAST_BYTES_XMIT,
91 OID_GEN_BROADCAST_FRAMES_XMIT,
92 OID_GEN_DIRECTED_BYTES_RCV,
93 OID_GEN_DIRECTED_FRAMES_RCV,
94 OID_GEN_MULTICAST_BYTES_RCV,
95 OID_GEN_MULTICAST_FRAMES_RCV,
96 OID_GEN_BROADCAST_BYTES_RCV,
97 OID_GEN_BROADCAST_FRAMES_RCV,
98 OID_GEN_RCV_CRC_ERROR,
99 OID_GEN_TRANSMIT_QUEUE_LENGTH,
100#endif /* RNDIS_OPTIONAL_STATS */
101
102 /* mandatory 802.3 */
103 /* the general stuff */
104 OID_802_3_PERMANENT_ADDRESS,
105 OID_802_3_CURRENT_ADDRESS,
106 OID_802_3_MULTICAST_LIST,
107 OID_802_3_MAC_OPTIONS,
108 OID_802_3_MAXIMUM_LIST_SIZE,
109
110 /* the statistical stuff */
111 OID_802_3_RCV_ERROR_ALIGNMENT,
112 OID_802_3_XMIT_ONE_COLLISION,
113 OID_802_3_XMIT_MORE_COLLISIONS,
114#ifdef RNDIS_OPTIONAL_STATS
115 OID_802_3_XMIT_DEFERRED,
116 OID_802_3_XMIT_MAX_COLLISIONS,
117 OID_802_3_RCV_OVERRUN,
118 OID_802_3_XMIT_UNDERRUN,
119 OID_802_3_XMIT_HEARTBEAT_FAILURE,
120 OID_802_3_XMIT_TIMES_CRS_LOST,
121 OID_802_3_XMIT_LATE_COLLISIONS,
122#endif /* RNDIS_OPTIONAL_STATS */
123
124#ifdef RNDIS_PM
125 /* PM and wakeup are mandatory for USB: */
126
127 /* power management */
128 OID_PNP_CAPABILITIES,
129 OID_PNP_QUERY_POWER,
130 OID_PNP_SET_POWER,
131
132#ifdef RNDIS_WAKEUP
133 /* wake up host */
134 OID_PNP_ENABLE_WAKE_UP,
135 OID_PNP_ADD_WAKE_UP_PATTERN,
136 OID_PNP_REMOVE_WAKE_UP_PATTERN,
137#endif /* RNDIS_WAKEUP */
138#endif /* RNDIS_PM */
139};
140
141
142/* NDIS Functions */
143static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
144 unsigned buf_len, rndis_resp_t *r)
145{
146 int retval = -ENOTSUPP;
147 u32 length = 4; /* usually */
148 __le32 *outbuf;
149 int i, count;
150 rndis_query_cmplt_type *resp;
151 rndis_params *params;
152
153 if (!r)
154 return -ENOMEM;
155 resp = (rndis_query_cmplt_type *) r->buf;
156
157 if (!resp)
158 return -ENOMEM;
159
160#if defined(DEBUG) && defined(DEBUG_VERBOSE)
161 if (buf_len) {
162 debug("query OID %08x value, len %d:\n", OID, buf_len);
163 for (i = 0; i < buf_len; i += 16) {
164 debug("%03d: %08x %08x %08x %08x\n", i,
165 get_unaligned_le32(&buf[i]),
166 get_unaligned_le32(&buf[i + 4]),
167 get_unaligned_le32(&buf[i + 8]),
168 get_unaligned_le32(&buf[i + 12]));
169 }
170 }
171#endif
172
173 /* response goes here, right after the header */
174 outbuf = (__le32 *) &resp[1];
175 resp->InformationBufferOffset = __constant_cpu_to_le32(16);
176
177 params = &rndis_per_dev_params[configNr];
178 switch (OID) {
179
180 /* general oids (table 4-1) */
181
182 /* mandatory */
183 case OID_GEN_SUPPORTED_LIST:
184 debug("%s: OID_GEN_SUPPORTED_LIST\n", __func__);
185 length = sizeof(oid_supported_list);
186 count = length / sizeof(u32);
187 for (i = 0; i < count; i++)
188 outbuf[i] = cpu_to_le32(oid_supported_list[i]);
189 retval = 0;
190 break;
191
192 /* mandatory */
193 case OID_GEN_HARDWARE_STATUS:
194 debug("%s: OID_GEN_HARDWARE_STATUS\n", __func__);
195 /*
196 * Bogus question!
197 * Hardware must be ready to receive high level protocols.
198 * BTW:
199 * reddite ergo quae sunt Caesaris Caesari
200 * et quae sunt Dei Deo!
201 */
202 *outbuf = __constant_cpu_to_le32(0);
203 retval = 0;
204 break;
205
206 /* mandatory */
207 case OID_GEN_MEDIA_SUPPORTED:
208 debug("%s: OID_GEN_MEDIA_SUPPORTED\n", __func__);
209 *outbuf = cpu_to_le32(params->medium);
210 retval = 0;
211 break;
212
213 /* mandatory */
214 case OID_GEN_MEDIA_IN_USE:
215 debug("%s: OID_GEN_MEDIA_IN_USE\n", __func__);
216 /* one medium, one transport... (maybe you do it better) */
217 *outbuf = cpu_to_le32(params->medium);
218 retval = 0;
219 break;
220
221 /* mandatory */
222 case OID_GEN_MAXIMUM_FRAME_SIZE:
223 debug("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __func__);
224 if (params->dev) {
225 *outbuf = cpu_to_le32(params->mtu);
226 retval = 0;
227 }
228 break;
229
230 /* mandatory */
231 case OID_GEN_LINK_SPEED:
232#if defined(DEBUG) && defined(DEBUG_VERBOSE)
233 debug("%s: OID_GEN_LINK_SPEED\n", __func__);
234#endif
235 if (params->media_state == NDIS_MEDIA_STATE_DISCONNECTED)
236 *outbuf = __constant_cpu_to_le32(0);
237 else
238 *outbuf = cpu_to_le32(params->speed);
239 retval = 0;
240 break;
241
242 /* mandatory */
243 case OID_GEN_TRANSMIT_BLOCK_SIZE:
244 debug("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __func__);
245 if (params->dev) {
246 *outbuf = cpu_to_le32(params->mtu);
247 retval = 0;
248 }
249 break;
250
251 /* mandatory */
252 case OID_GEN_RECEIVE_BLOCK_SIZE:
253 debug("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __func__);
254 if (params->dev) {
255 *outbuf = cpu_to_le32(params->mtu);
256 retval = 0;
257 }
258 break;
259
260 /* mandatory */
261 case OID_GEN_VENDOR_ID:
262 debug("%s: OID_GEN_VENDOR_ID\n", __func__);
263 *outbuf = cpu_to_le32(params->vendorID);
264 retval = 0;
265 break;
266
267 /* mandatory */
268 case OID_GEN_VENDOR_DESCRIPTION:
269 debug("%s: OID_GEN_VENDOR_DESCRIPTION\n", __func__);
270 length = strlen(params->vendorDescr);
271 memcpy(outbuf, params->vendorDescr, length);
272 retval = 0;
273 break;
274
275 case OID_GEN_VENDOR_DRIVER_VERSION:
276 debug("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __func__);
277 /* Created as LE */
278 *outbuf = rndis_driver_version;
279 retval = 0;
280 break;
281
282 /* mandatory */
283 case OID_GEN_CURRENT_PACKET_FILTER:
284 debug("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __func__);
285 *outbuf = cpu_to_le32(*params->filter);
286 retval = 0;
287 break;
288
289 /* mandatory */
290 case OID_GEN_MAXIMUM_TOTAL_SIZE:
291 debug("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __func__);
292 *outbuf = __constant_cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
293 retval = 0;
294 break;
295
296 /* mandatory */
297 case OID_GEN_MEDIA_CONNECT_STATUS:
298#if defined(DEBUG) && defined(DEBUG_VERBOSE)
299 debug("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __func__);
300#endif
301 *outbuf = cpu_to_le32(params->media_state);
302 retval = 0;
303 break;
304
305 case OID_GEN_PHYSICAL_MEDIUM:
306 debug("%s: OID_GEN_PHYSICAL_MEDIUM\n", __func__);
307 *outbuf = __constant_cpu_to_le32(0);
308 retval = 0;
309 break;
310
311 /*
312 * The RNDIS specification is incomplete/wrong. Some versions
313 * of MS-Windows expect OIDs that aren't specified there. Other
314 * versions emit undefined RNDIS messages. DOCUMENT ALL THESE!
315 */
316 case OID_GEN_MAC_OPTIONS: /* from WinME */
317 debug("%s: OID_GEN_MAC_OPTIONS\n", __func__);
318 *outbuf = __constant_cpu_to_le32(
319 NDIS_MAC_OPTION_RECEIVE_SERIALIZED
320 | NDIS_MAC_OPTION_FULL_DUPLEX);
321 retval = 0;
322 break;
323
324 /* statistics OIDs (table 4-2) */
325
326 /* mandatory */
327 case OID_GEN_XMIT_OK:
328#if defined(DEBUG) && defined(DEBUG_VERBOSE)
329 debug("%s: OID_GEN_XMIT_OK\n", __func__);
330#endif
331 if (params->stats) {
332 *outbuf = cpu_to_le32(
333 params->stats->tx_packets -
334 params->stats->tx_errors -
335 params->stats->tx_dropped);
336 retval = 0;
337 }
338 break;
339
340 /* mandatory */
341 case OID_GEN_RCV_OK:
342#if defined(DEBUG) && defined(DEBUG_VERBOSE)
343 debug("%s: OID_GEN_RCV_OK\n", __func__);
344#endif
345 if (params->stats) {
346 *outbuf = cpu_to_le32(
347 params->stats->rx_packets -
348 params->stats->rx_errors -
349 params->stats->rx_dropped);
350 retval = 0;
351 }
352 break;
353
354 /* mandatory */
355 case OID_GEN_XMIT_ERROR:
356#if defined(DEBUG) && defined(DEBUG_VERBOSE)
357 debug("%s: OID_GEN_XMIT_ERROR\n", __func__);
358#endif
359 if (params->stats) {
360 *outbuf = cpu_to_le32(params->stats->tx_errors);
361 retval = 0;
362 }
363 break;
364
365 /* mandatory */
366 case OID_GEN_RCV_ERROR:
367#if defined(DEBUG) && defined(DEBUG_VERBOSE)
368 debug("%s: OID_GEN_RCV_ERROR\n", __func__);
369#endif
370 if (params->stats) {
371 *outbuf = cpu_to_le32(params->stats->rx_errors);
372 retval = 0;
373 }
374 break;
375
376 /* mandatory */
377 case OID_GEN_RCV_NO_BUFFER:
378 debug("%s: OID_GEN_RCV_NO_BUFFER\n", __func__);
379 if (params->stats) {
380 *outbuf = cpu_to_le32(params->stats->rx_dropped);
381 retval = 0;
382 }
383 break;
384
385#ifdef RNDIS_OPTIONAL_STATS
386 case OID_GEN_DIRECTED_BYTES_XMIT:
387 debug("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __func__);
388 /*
389 * Aunt Tilly's size of shoes
390 * minus antarctica count of penguins
391 * divided by weight of Alpha Centauri
392 */
393 if (params->stats) {
394 *outbuf = cpu_to_le32(
395 (params->stats->tx_packets -
396 params->stats->tx_errors -
397 params->stats->tx_dropped)
398 * 123);
399 retval = 0;
400 }
401 break;
402
403 case OID_GEN_DIRECTED_FRAMES_XMIT:
404 debug("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __func__);
405 /* dito */
406 if (params->stats) {
407 *outbuf = cpu_to_le32(
408 (params->stats->tx_packets -
409 params->stats->tx_errors -
410 params->stats->tx_dropped)
411 / 123);
412 retval = 0;
413 }
414 break;
415
416 case OID_GEN_MULTICAST_BYTES_XMIT:
417 debug("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __func__);
418 if (params->stats) {
419 *outbuf = cpu_to_le32(params->stats->multicast * 1234);
420 retval = 0;
421 }
422 break;
423
424 case OID_GEN_MULTICAST_FRAMES_XMIT:
425 debug("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __func__);
426 if (params->stats) {
427 *outbuf = cpu_to_le32(params->stats->multicast);
428 retval = 0;
429 }
430 break;
431
432 case OID_GEN_BROADCAST_BYTES_XMIT:
433 debug("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __func__);
434 if (params->stats) {
435 *outbuf = cpu_to_le32(params->stats->tx_packets/42*255);
436 retval = 0;
437 }
438 break;
439
440 case OID_GEN_BROADCAST_FRAMES_XMIT:
441 debug("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __func__);
442 if (params->stats) {
443 *outbuf = cpu_to_le32(params->stats->tx_packets / 42);
444 retval = 0;
445 }
446 break;
447
448 case OID_GEN_DIRECTED_BYTES_RCV:
449 debug("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __func__);
450 *outbuf = __constant_cpu_to_le32(0);
451 retval = 0;
452 break;
453
454 case OID_GEN_DIRECTED_FRAMES_RCV:
455 debug("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __func__);
456 *outbuf = __constant_cpu_to_le32(0);
457 retval = 0;
458 break;
459
460 case OID_GEN_MULTICAST_BYTES_RCV:
461 debug("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __func__);
462 if (params->stats) {
463 *outbuf = cpu_to_le32(params->stats->multicast * 1111);
464 retval = 0;
465 }
466 break;
467
468 case OID_GEN_MULTICAST_FRAMES_RCV:
469 debug("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __func__);
470 if (params->stats) {
471 *outbuf = cpu_to_le32(params->stats->multicast);
472 retval = 0;
473 }
474 break;
475
476 case OID_GEN_BROADCAST_BYTES_RCV:
477 debug("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __func__);
478 if (params->stats) {
479 *outbuf = cpu_to_le32(params->stats->rx_packets/42*255);
480 retval = 0;
481 }
482 break;
483
484 case OID_GEN_BROADCAST_FRAMES_RCV:
485 debug("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __func__);
486 if (params->stats) {
487 *outbuf = cpu_to_le32(params->stats->rx_packets / 42);
488 retval = 0;
489 }
490 break;
491
492 case OID_GEN_RCV_CRC_ERROR:
493 debug("%s: OID_GEN_RCV_CRC_ERROR\n", __func__);
494 if (params->stats) {
495 *outbuf = cpu_to_le32(params->stats->rx_crc_errors);
496 retval = 0;
497 }
498 break;
499
500 case OID_GEN_TRANSMIT_QUEUE_LENGTH:
501 debug("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __func__);
502 *outbuf = __constant_cpu_to_le32(0);
503 retval = 0;
504 break;
505#endif /* RNDIS_OPTIONAL_STATS */
506
507 /* ieee802.3 OIDs (table 4-3) */
508
509 /* mandatory */
510 case OID_802_3_PERMANENT_ADDRESS:
511 debug("%s: OID_802_3_PERMANENT_ADDRESS\n", __func__);
512 if (params->dev) {
513 length = ETH_ALEN;
514 memcpy(outbuf, params->host_mac, length);
515 retval = 0;
516 }
517 break;
518
519 /* mandatory */
520 case OID_802_3_CURRENT_ADDRESS:
521 debug("%s: OID_802_3_CURRENT_ADDRESS\n", __func__);
522 if (params->dev) {
523 length = ETH_ALEN;
524 memcpy(outbuf, params->host_mac, length);
525 retval = 0;
526 }
527 break;
528
529 /* mandatory */
530 case OID_802_3_MULTICAST_LIST:
531 debug("%s: OID_802_3_MULTICAST_LIST\n", __func__);
532 /* Multicast base address only */
533 *outbuf = __constant_cpu_to_le32(0xE0000000);
534 retval = 0;
535 break;
536
537 /* mandatory */
538 case OID_802_3_MAXIMUM_LIST_SIZE:
539 debug("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __func__);
540 /* Multicast base address only */
541 *outbuf = __constant_cpu_to_le32(1);
542 retval = 0;
543 break;
544
545 case OID_802_3_MAC_OPTIONS:
546 debug("%s: OID_802_3_MAC_OPTIONS\n", __func__);
547 break;
548
549 /* ieee802.3 statistics OIDs (table 4-4) */
550
551 /* mandatory */
552 case OID_802_3_RCV_ERROR_ALIGNMENT:
553 debug("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __func__);
554 if (params->stats) {
555 *outbuf = cpu_to_le32(params->stats->rx_frame_errors);
556 retval = 0;
557 }
558 break;
559
560 /* mandatory */
561 case OID_802_3_XMIT_ONE_COLLISION:
562 debug("%s: OID_802_3_XMIT_ONE_COLLISION\n", __func__);
563 *outbuf = __constant_cpu_to_le32(0);
564 retval = 0;
565 break;
566
567 /* mandatory */
568 case OID_802_3_XMIT_MORE_COLLISIONS:
569 debug("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __func__);
570 *outbuf = __constant_cpu_to_le32(0);
571 retval = 0;
572 break;
573
574#ifdef RNDIS_OPTIONAL_STATS
575 case OID_802_3_XMIT_DEFERRED:
576 debug("%s: OID_802_3_XMIT_DEFERRED\n", __func__);
577 /* TODO */
578 break;
579
580 case OID_802_3_XMIT_MAX_COLLISIONS:
581 debug("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __func__);
582 /* TODO */
583 break;
584
585 case OID_802_3_RCV_OVERRUN:
586 debug("%s: OID_802_3_RCV_OVERRUN\n", __func__);
587 /* TODO */
588 break;
589
590 case OID_802_3_XMIT_UNDERRUN:
591 debug("%s: OID_802_3_XMIT_UNDERRUN\n", __func__);
592 /* TODO */
593 break;
594
595 case OID_802_3_XMIT_HEARTBEAT_FAILURE:
596 debug("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __func__);
597 /* TODO */
598 break;
599
600 case OID_802_3_XMIT_TIMES_CRS_LOST:
601 debug("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __func__);
602 /* TODO */
603 break;
604
605 case OID_802_3_XMIT_LATE_COLLISIONS:
606 debug("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __func__);
607 /* TODO */
608 break;
609#endif /* RNDIS_OPTIONAL_STATS */
610
611#ifdef RNDIS_PM
612 /* power management OIDs (table 4-5) */
613 case OID_PNP_CAPABILITIES:
614 debug("%s: OID_PNP_CAPABILITIES\n", __func__);
615
616 /* for now, no wakeup capabilities */
617 length = sizeof(struct NDIS_PNP_CAPABILITIES);
618 memset(outbuf, 0, length);
619 retval = 0;
620 break;
621 case OID_PNP_QUERY_POWER:
622 debug("%s: OID_PNP_QUERY_POWER D%d\n", __func__,
623 get_unaligned_le32(buf) - 1);
624 /*
625 * only suspend is a real power state, and
626 * it can't be entered by OID_PNP_SET_POWER...
627 */
628 length = 0;
629 retval = 0;
630 break;
631#endif
632
633 default:
634 debug("%s: query unknown OID 0x%08X\n", __func__, OID);
635 }
636 if (retval < 0)
637 length = 0;
638
639 resp->InformationBufferLength = cpu_to_le32(length);
640 r->length = length + sizeof *resp;
641 resp->MessageLength = cpu_to_le32(r->length);
642 return retval;
643}
644
645static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len,
646 rndis_resp_t *r)
647{
648 rndis_set_cmplt_type *resp;
649 int retval = -ENOTSUPP;
650 struct rndis_params *params;
651#if (defined(DEBUG) && defined(DEBUG_VERBOSE)) || defined(RNDIS_PM)
652 int i;
653#endif
654
655 if (!r)
656 return -ENOMEM;
657 resp = (rndis_set_cmplt_type *) r->buf;
658 if (!resp)
659 return -ENOMEM;
660
661#if defined(DEBUG) && defined(DEBUG_VERBOSE)
662 if (buf_len) {
663 debug("set OID %08x value, len %d:\n", OID, buf_len);
664 for (i = 0; i < buf_len; i += 16) {
665 debug("%03d: %08x %08x %08x %08x\n", i,
666 get_unaligned_le32(&buf[i]),
667 get_unaligned_le32(&buf[i + 4]),
668 get_unaligned_le32(&buf[i + 8]),
669 get_unaligned_le32(&buf[i + 12]));
670 }
671 }
672#endif
673
674 params = &rndis_per_dev_params[configNr];
675 switch (OID) {
676 case OID_GEN_CURRENT_PACKET_FILTER:
677
678 /*
679 * these NDIS_PACKET_TYPE_* bitflags are shared with
680 * cdc_filter; it's not RNDIS-specific
681 * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in:
682 * PROMISCUOUS, DIRECTED,
683 * MULTICAST, ALL_MULTICAST, BROADCAST
684 */
685 *params->filter = (u16) get_unaligned_le32(buf);
686 debug("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
687 __func__, *params->filter);
688
689 /*
690 * this call has a significant side effect: it's
691 * what makes the packet flow start and stop, like
692 * activating the CDC Ethernet altsetting.
693 */
694#ifdef RNDIS_PM
695update_linkstate:
696#endif
697 retval = 0;
698 if (*params->filter)
699 params->state = RNDIS_DATA_INITIALIZED;
700 else
701 params->state = RNDIS_INITIALIZED;
702 break;
703
704 case OID_802_3_MULTICAST_LIST:
705 /* I think we can ignore this */
706 debug("%s: OID_802_3_MULTICAST_LIST\n", __func__);
707 retval = 0;
708 break;
709#if 0
710 case OID_GEN_RNDIS_CONFIG_PARAMETER:
711 {
712 struct rndis_config_parameter *param;
713 param = (struct rndis_config_parameter *) buf;
714 debug("%s: OID_GEN_RNDIS_CONFIG_PARAMETER '%*s'\n",
715 __func__,
716 min(cpu_to_le32(param->ParameterNameLength), 80),
717 buf + param->ParameterNameOffset);
718 retval = 0;
719 }
720 break;
721#endif
722
723#ifdef RNDIS_PM
724 case OID_PNP_SET_POWER:
725 /*
726 * The only real power state is USB suspend, and RNDIS requests
727 * can't enter it; this one isn't really about power. After
728 * resuming, Windows forces a reset, and then SET_POWER D0.
729 * FIXME ... then things go batty; Windows wedges itself.
730 */
731 i = get_unaligned_le32(buf);
732 debug("%s: OID_PNP_SET_POWER D%d\n", __func__, i - 1);
733 switch (i) {
734 case NdisDeviceStateD0:
735 *params->filter = params->saved_filter;
736 goto update_linkstate;
737 case NdisDeviceStateD3:
738 case NdisDeviceStateD2:
739 case NdisDeviceStateD1:
740 params->saved_filter = *params->filter;
741 retval = 0;
742 break;
743 }
744 break;
745
746#ifdef RNDIS_WAKEUP
747 /*
748 * no wakeup support advertised, so wakeup OIDs always fail:
749 * - OID_PNP_ENABLE_WAKE_UP
750 * - OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN
751 */
752#endif
753
754#endif /* RNDIS_PM */
755
756 default:
757 debug("%s: set unknown OID 0x%08X, size %d\n",
758 __func__, OID, buf_len);
759 }
760
761 return retval;
762}
763
764/*
765 * Response Functions
766 */
767
768static int rndis_init_response(int configNr, rndis_init_msg_type *buf)
769{
770 rndis_init_cmplt_type *resp;
771 rndis_resp_t *r;
772
773 if (!rndis_per_dev_params[configNr].dev)
774 return -ENOTSUPP;
775
776 r = rndis_add_response(configNr, sizeof(rndis_init_cmplt_type));
777 if (!r)
778 return -ENOMEM;
779 resp = (rndis_init_cmplt_type *) r->buf;
780
781 resp->MessageType = __constant_cpu_to_le32(
782 REMOTE_NDIS_INITIALIZE_CMPLT);
783 resp->MessageLength = __constant_cpu_to_le32(52);
784 resp->RequestID = get_unaligned(&buf->RequestID); /* Still LE in msg buffer */
785 resp->Status = __constant_cpu_to_le32(RNDIS_STATUS_SUCCESS);
786 resp->MajorVersion = __constant_cpu_to_le32(RNDIS_MAJOR_VERSION);
787 resp->MinorVersion = __constant_cpu_to_le32(RNDIS_MINOR_VERSION);
788 resp->DeviceFlags = __constant_cpu_to_le32(RNDIS_DF_CONNECTIONLESS);
789 resp->Medium = __constant_cpu_to_le32(RNDIS_MEDIUM_802_3);
790 resp->MaxPacketsPerTransfer = __constant_cpu_to_le32(1);
791 resp->MaxTransferSize = cpu_to_le32(
792 rndis_per_dev_params[configNr].mtu
793 + ETHER_HDR_SIZE
794 + sizeof(struct rndis_packet_msg_type)
795 + 22);
796 resp->PacketAlignmentFactor = __constant_cpu_to_le32(0);
797 resp->AFListOffset = __constant_cpu_to_le32(0);
798 resp->AFListSize = __constant_cpu_to_le32(0);
799
800 if (rndis_per_dev_params[configNr].ack)
801 rndis_per_dev_params[configNr].ack(
802 rndis_per_dev_params[configNr].dev);
803
804 return 0;
805}
806
807static int rndis_query_response(int configNr, rndis_query_msg_type *buf)
808{
809 rndis_query_cmplt_type *resp;
810 rndis_resp_t *r;
811
812 debug("%s: OID = %08X\n", __func__, get_unaligned_le32(&buf->OID));
813 if (!rndis_per_dev_params[configNr].dev)
814 return -ENOTSUPP;
815
816 /*
817 * we need more memory:
818 * gen_ndis_query_resp expects enough space for
819 * rndis_query_cmplt_type followed by data.
820 * oid_supported_list is the largest data reply
821 */
822 r = rndis_add_response(configNr,
823 sizeof(oid_supported_list) + sizeof(rndis_query_cmplt_type));
824 if (!r)
825 return -ENOMEM;
826 resp = (rndis_query_cmplt_type *) r->buf;
827
828 resp->MessageType = __constant_cpu_to_le32(REMOTE_NDIS_QUERY_CMPLT);
829 resp->RequestID = get_unaligned(&buf->RequestID); /* Still LE in msg buffer */
830
831 if (gen_ndis_query_resp(configNr, get_unaligned_le32(&buf->OID),
832 get_unaligned_le32(&buf->InformationBufferOffset)
833 + 8 + (u8 *) buf,
834 get_unaligned_le32(&buf->InformationBufferLength),
835 r)) {
836 /* OID not supported */
837 resp->Status = __constant_cpu_to_le32(
838 RNDIS_STATUS_NOT_SUPPORTED);
839 resp->MessageLength = __constant_cpu_to_le32(sizeof *resp);
840 resp->InformationBufferLength = __constant_cpu_to_le32(0);
841 resp->InformationBufferOffset = __constant_cpu_to_le32(0);
842 } else
843 resp->Status = __constant_cpu_to_le32(RNDIS_STATUS_SUCCESS);
844
845 if (rndis_per_dev_params[configNr].ack)
846 rndis_per_dev_params[configNr].ack(
847 rndis_per_dev_params[configNr].dev);
848 return 0;
849}
850
851static int rndis_set_response(int configNr, rndis_set_msg_type *buf)
852{
853 u32 BufLength, BufOffset;
854 rndis_set_cmplt_type *resp;
855 rndis_resp_t *r;
856
Szymon Heidrichdd1c4552022-12-05 10:28:23 +0100857 BufLength = get_unaligned_le32(&buf->InformationBufferLength);
858 BufOffset = get_unaligned_le32(&buf->InformationBufferOffset);
859 if ((BufOffset > RNDIS_MAX_TOTAL_SIZE - 8) ||
860 (BufLength > RNDIS_MAX_TOTAL_SIZE - 8 - BufOffset))
861 return -EINVAL;
862
Vitaly Kuzmichev216c4472011-02-11 18:18:34 +0300863 r = rndis_add_response(configNr, sizeof(rndis_set_cmplt_type));
864 if (!r)
865 return -ENOMEM;
866 resp = (rndis_set_cmplt_type *) r->buf;
867
Vitaly Kuzmichev216c4472011-02-11 18:18:34 +0300868#ifdef VERBOSE
869 debug("%s: Length: %d\n", __func__, BufLength);
870 debug("%s: Offset: %d\n", __func__, BufOffset);
871 debug("%s: InfoBuffer: ", __func__);
872
873 for (i = 0; i < BufLength; i++)
874 debug("%02x ", *(((u8 *) buf) + i + 8 + BufOffset));
875
876 debug("\n");
877#endif
878
879 resp->MessageType = __constant_cpu_to_le32(REMOTE_NDIS_SET_CMPLT);
880 resp->MessageLength = __constant_cpu_to_le32(16);
881 resp->RequestID = get_unaligned(&buf->RequestID); /* Still LE in msg buffer */
882 if (gen_ndis_set_resp(configNr, get_unaligned_le32(&buf->OID),
883 ((u8 *) buf) + 8 + BufOffset, BufLength, r))
884 resp->Status = __constant_cpu_to_le32(
885 RNDIS_STATUS_NOT_SUPPORTED);
886 else
887 resp->Status = __constant_cpu_to_le32(RNDIS_STATUS_SUCCESS);
888
889 if (rndis_per_dev_params[configNr].ack)
890 rndis_per_dev_params[configNr].ack(
891 rndis_per_dev_params[configNr].dev);
892
893 return 0;
894}
895
896static int rndis_reset_response(int configNr, rndis_reset_msg_type *buf)
897{
898 rndis_reset_cmplt_type *resp;
899 rndis_resp_t *r;
900
901 r = rndis_add_response(configNr, sizeof(rndis_reset_cmplt_type));
902 if (!r)
903 return -ENOMEM;
904 resp = (rndis_reset_cmplt_type *) r->buf;
905
906 resp->MessageType = __constant_cpu_to_le32(REMOTE_NDIS_RESET_CMPLT);
907 resp->MessageLength = __constant_cpu_to_le32(16);
908 resp->Status = __constant_cpu_to_le32(RNDIS_STATUS_SUCCESS);
909 /* resent information */
910 resp->AddressingReset = __constant_cpu_to_le32(1);
911
912 if (rndis_per_dev_params[configNr].ack)
913 rndis_per_dev_params[configNr].ack(
914 rndis_per_dev_params[configNr].dev);
915
916 return 0;
917}
918
919static int rndis_keepalive_response(int configNr,
920 rndis_keepalive_msg_type *buf)
921{
922 rndis_keepalive_cmplt_type *resp;
923 rndis_resp_t *r;
924
925 /* host "should" check only in RNDIS_DATA_INITIALIZED state */
926
927 r = rndis_add_response(configNr, sizeof(rndis_keepalive_cmplt_type));
928 if (!r)
929 return -ENOMEM;
930 resp = (rndis_keepalive_cmplt_type *) r->buf;
931
932 resp->MessageType = __constant_cpu_to_le32(
933 REMOTE_NDIS_KEEPALIVE_CMPLT);
934 resp->MessageLength = __constant_cpu_to_le32(16);
935 resp->RequestID = get_unaligned(&buf->RequestID); /* Still LE in msg buffer */
936 resp->Status = __constant_cpu_to_le32(RNDIS_STATUS_SUCCESS);
937
938 if (rndis_per_dev_params[configNr].ack)
939 rndis_per_dev_params[configNr].ack(
940 rndis_per_dev_params[configNr].dev);
941
942 return 0;
943}
944
945
946/*
947 * Device to Host Comunication
948 */
949static int rndis_indicate_status_msg(int configNr, u32 status)
950{
951 rndis_indicate_status_msg_type *resp;
952 rndis_resp_t *r;
953
954 if (rndis_per_dev_params[configNr].state == RNDIS_UNINITIALIZED)
955 return -ENOTSUPP;
956
957 r = rndis_add_response(configNr,
958 sizeof(rndis_indicate_status_msg_type));
959 if (!r)
960 return -ENOMEM;
961 resp = (rndis_indicate_status_msg_type *) r->buf;
962
963 resp->MessageType = __constant_cpu_to_le32(
964 REMOTE_NDIS_INDICATE_STATUS_MSG);
965 resp->MessageLength = __constant_cpu_to_le32(20);
966 resp->Status = cpu_to_le32(status);
967 resp->StatusBufferLength = __constant_cpu_to_le32(0);
968 resp->StatusBufferOffset = __constant_cpu_to_le32(0);
969
970 if (rndis_per_dev_params[configNr].ack)
971 rndis_per_dev_params[configNr].ack(
972 rndis_per_dev_params[configNr].dev);
973 return 0;
974}
975
976int rndis_signal_connect(int configNr)
977{
978 rndis_per_dev_params[configNr].media_state
979 = NDIS_MEDIA_STATE_CONNECTED;
980 return rndis_indicate_status_msg(configNr,
981 RNDIS_STATUS_MEDIA_CONNECT);
982}
983
984int rndis_signal_disconnect(int configNr)
985{
986 rndis_per_dev_params[configNr].media_state
987 = NDIS_MEDIA_STATE_DISCONNECTED;
988
Vitaly Kuzmichev3433c332011-02-11 18:18:35 +0300989#ifdef RNDIS_COMPLETE_SIGNAL_DISCONNECT
990 return rndis_indicate_status_msg(configNr,
991 RNDIS_STATUS_MEDIA_DISCONNECT);
992#else
Vitaly Kuzmichev216c4472011-02-11 18:18:34 +0300993 return 0;
Vitaly Kuzmichev3433c332011-02-11 18:18:35 +0300994#endif
Vitaly Kuzmichev216c4472011-02-11 18:18:34 +0300995}
996
997void rndis_uninit(int configNr)
998{
999 u8 *buf;
1000 u32 length;
1001
1002 if (configNr >= RNDIS_MAX_CONFIGS)
1003 return;
1004 rndis_per_dev_params[configNr].used = 0;
1005 rndis_per_dev_params[configNr].state = RNDIS_UNINITIALIZED;
1006
1007 /* drain the response queue */
1008 while ((buf = rndis_get_next_response(configNr, &length)))
1009 rndis_free_response(configNr, buf);
1010}
1011
1012void rndis_set_host_mac(int configNr, const u8 *addr)
1013{
1014 rndis_per_dev_params[configNr].host_mac = addr;
1015}
1016
1017enum rndis_state rndis_get_state(int configNr)
1018{
1019 if (configNr >= RNDIS_MAX_CONFIGS || configNr < 0)
1020 return -ENOTSUPP;
1021 return rndis_per_dev_params[configNr].state;
1022}
1023
1024/*
1025 * Message Parser
1026 */
1027int rndis_msg_parser(u8 configNr, u8 *buf)
1028{
1029 u32 MsgType, MsgLength;
1030 __le32 *tmp;
1031 struct rndis_params *params;
1032
1033 debug("%s: configNr = %d, %p\n", __func__, configNr, buf);
1034
1035 if (!buf)
1036 return -ENOMEM;
1037
1038 tmp = (__le32 *) buf;
1039 MsgType = get_unaligned_le32(tmp++);
1040 MsgLength = get_unaligned_le32(tmp++);
1041
1042 if (configNr >= RNDIS_MAX_CONFIGS)
1043 return -ENOTSUPP;
1044 params = &rndis_per_dev_params[configNr];
1045
1046 /*
1047 * NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for
1048 * rx/tx statistics and link status, in addition to KEEPALIVE traffic
1049 * and normal HC level polling to see if there's any IN traffic.
1050 */
1051
1052 /* For USB: responses may take up to 10 seconds */
1053 switch (MsgType) {
1054 case REMOTE_NDIS_INITIALIZE_MSG:
1055 debug("%s: REMOTE_NDIS_INITIALIZE_MSG\n", __func__);
1056 params->state = RNDIS_INITIALIZED;
1057 return rndis_init_response(configNr,
1058 (rndis_init_msg_type *) buf);
1059
1060 case REMOTE_NDIS_HALT_MSG:
1061 debug("%s: REMOTE_NDIS_HALT_MSG\n", __func__);
1062 params->state = RNDIS_UNINITIALIZED;
1063 return 0;
1064
1065 case REMOTE_NDIS_QUERY_MSG:
1066 return rndis_query_response(configNr,
1067 (rndis_query_msg_type *) buf);
1068
1069 case REMOTE_NDIS_SET_MSG:
1070 return rndis_set_response(configNr,
1071 (rndis_set_msg_type *) buf);
1072
1073 case REMOTE_NDIS_RESET_MSG:
1074 debug("%s: REMOTE_NDIS_RESET_MSG\n", __func__);
1075 return rndis_reset_response(configNr,
1076 (rndis_reset_msg_type *) buf);
1077
1078 case REMOTE_NDIS_KEEPALIVE_MSG:
1079 /* For USB: host does this every 5 seconds */
1080#if defined(DEBUG) && defined(DEBUG_VERBOSE)
1081 debug("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", __func__);
1082#endif
1083 return rndis_keepalive_response(configNr,
1084 (rndis_keepalive_msg_type *) buf);
1085
1086 default:
1087 /*
1088 * At least Windows XP emits some undefined RNDIS messages.
1089 * In one case those messages seemed to relate to the host
1090 * suspending itself.
1091 */
1092 debug("%s: unknown RNDIS message 0x%08X len %d\n",
1093 __func__ , MsgType, MsgLength);
1094 {
1095 unsigned i;
1096 for (i = 0; i < MsgLength; i += 16) {
1097 debug("%03d: "
1098 " %02x %02x %02x %02x"
1099 " %02x %02x %02x %02x"
1100 " %02x %02x %02x %02x"
1101 " %02x %02x %02x %02x"
1102 "\n",
1103 i,
1104 buf[i], buf[i+1],
1105 buf[i+2], buf[i+3],
1106 buf[i+4], buf[i+5],
1107 buf[i+6], buf[i+7],
1108 buf[i+8], buf[i+9],
1109 buf[i+10], buf[i+11],
1110 buf[i+12], buf[i+13],
1111 buf[i+14], buf[i+15]);
1112 }
1113 }
1114 break;
1115 }
1116
1117 return -ENOTSUPP;
1118}
1119
Mugunthan V N095b7612016-11-18 11:09:15 +05301120int rndis_register(int (*rndis_control_ack)(struct udevice *))
Vitaly Kuzmichev216c4472011-02-11 18:18:34 +03001121{
1122 u8 i;
1123
1124 for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
1125 if (!rndis_per_dev_params[i].used) {
1126 rndis_per_dev_params[i].used = 1;
1127 rndis_per_dev_params[i].ack = rndis_control_ack;
1128 debug("%s: configNr = %d\n", __func__, i);
1129 return i;
1130 }
1131 }
1132 debug("%s failed\n", __func__);
1133
1134 return -1;
1135}
1136
1137void rndis_deregister(int configNr)
1138{
1139 debug("%s: configNr = %d\n", __func__, configNr);
1140
1141 if (configNr >= RNDIS_MAX_CONFIGS)
1142 return;
1143 rndis_per_dev_params[configNr].used = 0;
1144
1145 return;
1146}
1147
Mugunthan V N095b7612016-11-18 11:09:15 +05301148int rndis_set_param_dev(u8 configNr, struct udevice *dev, int mtu,
1149 struct net_device_stats *stats, u16 *cdc_filter)
Vitaly Kuzmichev216c4472011-02-11 18:18:34 +03001150{
1151 debug("%s: configNr = %d\n", __func__, configNr);
1152 if (!dev || !stats)
1153 return -1;
1154 if (configNr >= RNDIS_MAX_CONFIGS)
1155 return -1;
1156
1157 rndis_per_dev_params[configNr].dev = dev;
1158 rndis_per_dev_params[configNr].stats = stats;
1159 rndis_per_dev_params[configNr].mtu = mtu;
1160 rndis_per_dev_params[configNr].filter = cdc_filter;
1161
1162 return 0;
1163}
1164
1165int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr)
1166{
1167 debug("%s: configNr = %d\n", __func__, configNr);
1168 if (!vendorDescr)
1169 return -1;
1170 if (configNr >= RNDIS_MAX_CONFIGS)
1171 return -1;
1172
1173 rndis_per_dev_params[configNr].vendorID = vendorID;
1174 rndis_per_dev_params[configNr].vendorDescr = vendorDescr;
1175
1176 return 0;
1177}
1178
1179int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed)
1180{
1181 debug("%s: configNr = %d, %u %u\n", __func__, configNr, medium, speed);
1182 if (configNr >= RNDIS_MAX_CONFIGS)
1183 return -1;
1184
1185 rndis_per_dev_params[configNr].medium = medium;
1186 rndis_per_dev_params[configNr].speed = speed;
1187
1188 return 0;
1189}
1190
1191void rndis_add_hdr(void *buf, int length)
1192{
1193 struct rndis_packet_msg_type *header;
1194
1195 header = buf;
1196 memset(header, 0, sizeof *header);
1197 header->MessageType = __constant_cpu_to_le32(REMOTE_NDIS_PACKET_MSG);
1198 header->MessageLength = cpu_to_le32(length + sizeof *header);
1199 header->DataOffset = __constant_cpu_to_le32(36);
1200 header->DataLength = cpu_to_le32(length);
1201}
1202
1203void rndis_free_response(int configNr, u8 *buf)
1204{
1205 rndis_resp_t *r;
1206 struct list_head *act, *tmp;
1207
1208 list_for_each_safe(act, tmp,
1209 &(rndis_per_dev_params[configNr].resp_queue))
1210 {
1211 r = list_entry(act, rndis_resp_t, list);
1212 if (r && r->buf == buf) {
1213 list_del(&r->list);
1214 free(r);
1215 }
1216 }
1217}
1218
1219u8 *rndis_get_next_response(int configNr, u32 *length)
1220{
1221 rndis_resp_t *r;
1222 struct list_head *act, *tmp;
1223
1224 if (!length)
1225 return NULL;
1226
1227 list_for_each_safe(act, tmp,
1228 &(rndis_per_dev_params[configNr].resp_queue))
1229 {
1230 r = list_entry(act, rndis_resp_t, list);
1231 if (!r->send) {
1232 r->send = 1;
1233 *length = r->length;
1234 return r->buf;
1235 }
1236 }
1237
1238 return NULL;
1239}
1240
1241static rndis_resp_t *rndis_add_response(int configNr, u32 length)
1242{
1243 rndis_resp_t *r;
1244
1245 /* NOTE: this gets copied into ether.c USB_BUFSIZ bytes ... */
1246 r = malloc(sizeof(rndis_resp_t) + length);
1247 if (!r)
1248 return NULL;
1249
1250 r->buf = (u8 *) (r + 1);
1251 r->length = length;
1252 r->send = 0;
1253
1254 list_add_tail(&r->list,
1255 &(rndis_per_dev_params[configNr].resp_queue));
1256 return r;
1257}
1258
1259int rndis_rm_hdr(void *buf, int length)
1260{
1261 /* tmp points to a struct rndis_packet_msg_type */
1262 __le32 *tmp = buf;
1263 int offs, len;
1264
1265 /* MessageType, MessageLength */
1266 if (__constant_cpu_to_le32(REMOTE_NDIS_PACKET_MSG)
1267 != get_unaligned(tmp++))
1268 return -EINVAL;
1269 tmp++;
1270
1271 /* DataOffset, DataLength */
1272 offs = get_unaligned_le32(tmp++) + 8 /* offset of DataOffset */;
1273 if (offs != sizeof(struct rndis_packet_msg_type))
1274 debug("%s: unexpected DataOffset: %d\n", __func__, offs);
1275 if (offs >= length)
1276 return -EOVERFLOW;
1277
1278 len = get_unaligned_le32(tmp++);
1279 if (len + sizeof(struct rndis_packet_msg_type) != length)
1280 debug("%s: unexpected DataLength: %d, packet length=%d\n",
1281 __func__, len, length);
1282
1283 memmove(buf, buf + offs, len);
1284
1285 return offs;
1286}
1287
1288int rndis_init(void)
1289{
1290 u8 i;
1291
1292 for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
1293 rndis_per_dev_params[i].confignr = i;
1294 rndis_per_dev_params[i].used = 0;
1295 rndis_per_dev_params[i].state = RNDIS_UNINITIALIZED;
1296 rndis_per_dev_params[i].media_state
1297 = NDIS_MEDIA_STATE_DISCONNECTED;
1298 INIT_LIST_HEAD(&(rndis_per_dev_params[i].resp_queue));
1299 }
1300
1301 return 0;
1302}
1303
1304void rndis_exit(void)
1305{
1306 /* Nothing to do */
1307}