Rename new Audio class driver functions, callbacks and events to ensure that they...
[pub/USBasp.git] / LUFA / Drivers / USB / Class / Device / RNDIS.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2011.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7 */
8
9 /*
10 Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaim all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29 */
30
31 #define __INCLUDE_FROM_USB_DRIVER
32 #include "../../Core/USBMode.h"
33
34 #if defined(USB_CAN_BE_DEVICE)
35
36 #define __INCLUDE_FROM_RNDIS_DRIVER
37 #define __INCLUDE_FROM_RNDIS_DEVICE_C
38 #include "RNDIS.h"
39
40 static const uint32_t PROGMEM AdapterSupportedOIDList[] =
41 {
42 OID_GEN_SUPPORTED_LIST,
43 OID_GEN_PHYSICAL_MEDIUM,
44 OID_GEN_HARDWARE_STATUS,
45 OID_GEN_MEDIA_SUPPORTED,
46 OID_GEN_MEDIA_IN_USE,
47 OID_GEN_MAXIMUM_FRAME_SIZE,
48 OID_GEN_MAXIMUM_TOTAL_SIZE,
49 OID_GEN_LINK_SPEED,
50 OID_GEN_TRANSMIT_BLOCK_SIZE,
51 OID_GEN_RECEIVE_BLOCK_SIZE,
52 OID_GEN_VENDOR_ID,
53 OID_GEN_VENDOR_DESCRIPTION,
54 OID_GEN_CURRENT_PACKET_FILTER,
55 OID_GEN_MAXIMUM_TOTAL_SIZE,
56 OID_GEN_MEDIA_CONNECT_STATUS,
57 OID_GEN_XMIT_OK,
58 OID_GEN_RCV_OK,
59 OID_GEN_XMIT_ERROR,
60 OID_GEN_RCV_ERROR,
61 OID_GEN_RCV_NO_BUFFER,
62 OID_802_3_PERMANENT_ADDRESS,
63 OID_802_3_CURRENT_ADDRESS,
64 OID_802_3_MULTICAST_LIST,
65 OID_802_3_MAXIMUM_LIST_SIZE,
66 OID_802_3_RCV_ERROR_ALIGNMENT,
67 OID_802_3_XMIT_ONE_COLLISION,
68 OID_802_3_XMIT_MORE_COLLISIONS,
69 };
70
71 void RNDIS_Device_ProcessControlRequest(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo)
72 {
73 if (!(Endpoint_IsSETUPReceived()))
74 return;
75
76 if (USB_ControlRequest.wIndex != RNDISInterfaceInfo->Config.ControlInterfaceNumber)
77 return;
78
79 switch (USB_ControlRequest.bRequest)
80 {
81 case RNDIS_REQ_SendEncapsulatedCommand:
82 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
83 {
84 Endpoint_ClearSETUP();
85 Endpoint_Read_Control_Stream_LE(RNDISInterfaceInfo->State.RNDISMessageBuffer, USB_ControlRequest.wLength);
86 Endpoint_ClearIN();
87
88 RNDIS_Device_ProcessRNDISControlMessage(RNDISInterfaceInfo);
89 }
90
91 break;
92 case RNDIS_REQ_GetEncapsulatedResponse:
93 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
94 {
95 RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;
96
97 if (!(MessageHeader->MessageLength))
98 {
99 RNDISInterfaceInfo->State.RNDISMessageBuffer[0] = 0;
100 MessageHeader->MessageLength = 1;
101 }
102
103 Endpoint_ClearSETUP();
104 Endpoint_Write_Control_Stream_LE(RNDISInterfaceInfo->State.RNDISMessageBuffer, MessageHeader->MessageLength);
105 Endpoint_ClearOUT();
106
107 MessageHeader->MessageLength = 0;
108 }
109
110 break;
111 }
112 }
113
114 bool RNDIS_Device_ConfigureEndpoints(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo)
115 {
116 memset(&RNDISInterfaceInfo->State, 0x00, sizeof(RNDISInterfaceInfo->State));
117
118 for (uint8_t EndpointNum = 1; EndpointNum < ENDPOINT_TOTAL_ENDPOINTS; EndpointNum++)
119 {
120 uint16_t Size;
121 uint8_t Type;
122 uint8_t Direction;
123 bool DoubleBanked;
124
125 if (EndpointNum == RNDISInterfaceInfo->Config.DataINEndpointNumber)
126 {
127 Size = RNDISInterfaceInfo->Config.DataINEndpointSize;
128 Direction = ENDPOINT_DIR_IN;
129 Type = EP_TYPE_BULK;
130 DoubleBanked = RNDISInterfaceInfo->Config.DataINEndpointDoubleBank;
131 }
132 else if (EndpointNum == RNDISInterfaceInfo->Config.DataOUTEndpointNumber)
133 {
134 Size = RNDISInterfaceInfo->Config.DataOUTEndpointSize;
135 Direction = ENDPOINT_DIR_OUT;
136 Type = EP_TYPE_BULK;
137 DoubleBanked = RNDISInterfaceInfo->Config.DataOUTEndpointDoubleBank;
138 }
139 else if (EndpointNum == RNDISInterfaceInfo->Config.NotificationEndpointNumber)
140 {
141 Size = RNDISInterfaceInfo->Config.NotificationEndpointSize;
142 Direction = ENDPOINT_DIR_IN;
143 Type = EP_TYPE_INTERRUPT;
144 DoubleBanked = RNDISInterfaceInfo->Config.NotificationEndpointDoubleBank;
145 }
146 else
147 {
148 continue;
149 }
150
151 if (!(Endpoint_ConfigureEndpoint(EndpointNum, Type, Direction, Size,
152 DoubleBanked ? ENDPOINT_BANK_DOUBLE : ENDPOINT_BANK_SINGLE)))
153 {
154 return false;
155 }
156 }
157
158 return true;
159 }
160
161 void RNDIS_Device_USBTask(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo)
162 {
163 if (USB_DeviceState != DEVICE_STATE_Configured)
164 return;
165
166 Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.NotificationEndpointNumber);
167
168 if (Endpoint_IsINReady() && RNDISInterfaceInfo->State.ResponseReady)
169 {
170 USB_Request_Header_t Notification = (USB_Request_Header_t)
171 {
172 .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
173 .bRequest = RNDIS_NOTIF_ResponseAvailable,
174 .wValue = 0,
175 .wIndex = 0,
176 .wLength = 0,
177 };
178
179 Endpoint_Write_Stream_LE(&Notification, sizeof(USB_Request_Header_t), NULL);
180
181 Endpoint_ClearIN();
182
183 RNDISInterfaceInfo->State.ResponseReady = false;
184 }
185 }
186
187 void RNDIS_Device_ProcessRNDISControlMessage(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo)
188 {
189 /* Note: Only a single buffer is used for both the received message and its response to save SRAM. Because of
190 this, response bytes should be filled in order so that they do not clobber unread data in the buffer. */
191
192 RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;
193
194 switch (MessageHeader->MessageType)
195 {
196 case REMOTE_NDIS_INITIALIZE_MSG:
197 RNDISInterfaceInfo->State.ResponseReady = true;
198
199 RNDIS_Initialize_Message_t* INITIALIZE_Message =
200 (RNDIS_Initialize_Message_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;
201 RNDIS_Initialize_Complete_t* INITIALIZE_Response =
202 (RNDIS_Initialize_Complete_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;
203
204 INITIALIZE_Response->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT;
205 INITIALIZE_Response->MessageLength = sizeof(RNDIS_Initialize_Complete_t);
206 INITIALIZE_Response->RequestId = INITIALIZE_Message->RequestId;
207 INITIALIZE_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
208
209 INITIALIZE_Response->MajorVersion = REMOTE_NDIS_VERSION_MAJOR;
210 INITIALIZE_Response->MinorVersion = REMOTE_NDIS_VERSION_MINOR;
211 INITIALIZE_Response->DeviceFlags = REMOTE_NDIS_DF_CONNECTIONLESS;
212 INITIALIZE_Response->Medium = REMOTE_NDIS_MEDIUM_802_3;
213 INITIALIZE_Response->MaxPacketsPerTransfer = 1;
214 INITIALIZE_Response->MaxTransferSize = (sizeof(RNDIS_Packet_Message_t) + ETHERNET_FRAME_SIZE_MAX);
215 INITIALIZE_Response->PacketAlignmentFactor = 0;
216 INITIALIZE_Response->AFListOffset = 0;
217 INITIALIZE_Response->AFListSize = 0;
218
219 RNDISInterfaceInfo->State.CurrRNDISState = RNDIS_Initialized;
220
221 break;
222 case REMOTE_NDIS_HALT_MSG:
223 RNDISInterfaceInfo->State.ResponseReady = false;
224 MessageHeader->MessageLength = 0;
225
226 RNDISInterfaceInfo->State.CurrRNDISState = RNDIS_Uninitialized;
227
228 break;
229 case REMOTE_NDIS_QUERY_MSG:
230 RNDISInterfaceInfo->State.ResponseReady = true;
231
232 RNDIS_Query_Message_t* QUERY_Message = (RNDIS_Query_Message_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;
233 RNDIS_Query_Complete_t* QUERY_Response = (RNDIS_Query_Complete_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;
234 uint32_t Query_Oid = QUERY_Message->Oid;
235
236 void* QueryData = &RNDISInterfaceInfo->State.RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) +
237 QUERY_Message->InformationBufferOffset];
238 void* ResponseData = &RNDISInterfaceInfo->State.RNDISMessageBuffer[sizeof(RNDIS_Query_Complete_t)];
239 uint16_t ResponseSize;
240
241 QUERY_Response->MessageType = REMOTE_NDIS_QUERY_CMPLT;
242 QUERY_Response->MessageLength = sizeof(RNDIS_Query_Complete_t);
243
244 if (RNDIS_Device_ProcessNDISQuery(RNDISInterfaceInfo, Query_Oid, QueryData, QUERY_Message->InformationBufferLength,
245 ResponseData, &ResponseSize))
246 {
247 QUERY_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
248 QUERY_Response->MessageLength += ResponseSize;
249
250 QUERY_Response->InformationBufferLength = ResponseSize;
251 QUERY_Response->InformationBufferOffset = (sizeof(RNDIS_Query_Complete_t) - sizeof(RNDIS_Message_Header_t));
252 }
253 else
254 {
255 QUERY_Response->Status = REMOTE_NDIS_STATUS_NOT_SUPPORTED;
256
257 QUERY_Response->InformationBufferLength = 0;
258 QUERY_Response->InformationBufferOffset = 0;
259 }
260
261 break;
262 case REMOTE_NDIS_SET_MSG:
263 RNDISInterfaceInfo->State.ResponseReady = true;
264
265 RNDIS_Set_Message_t* SET_Message = (RNDIS_Set_Message_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;
266 RNDIS_Set_Complete_t* SET_Response = (RNDIS_Set_Complete_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;
267 uint32_t SET_Oid = SET_Message->Oid;
268
269 SET_Response->MessageType = REMOTE_NDIS_SET_CMPLT;
270 SET_Response->MessageLength = sizeof(RNDIS_Set_Complete_t);
271 SET_Response->RequestId = SET_Message->RequestId;
272
273 void* SetData = &RNDISInterfaceInfo->State.RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) +
274 SET_Message->InformationBufferOffset];
275
276 SET_Response->Status = RNDIS_Device_ProcessNDISSet(RNDISInterfaceInfo, SET_Oid, SetData,
277 SET_Message->InformationBufferLength) ?
278 REMOTE_NDIS_STATUS_SUCCESS : REMOTE_NDIS_STATUS_NOT_SUPPORTED;
279 break;
280 case REMOTE_NDIS_RESET_MSG:
281 RNDISInterfaceInfo->State.ResponseReady = true;
282
283 RNDIS_Reset_Complete_t* RESET_Response = (RNDIS_Reset_Complete_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;
284
285 RESET_Response->MessageType = REMOTE_NDIS_RESET_CMPLT;
286 RESET_Response->MessageLength = sizeof(RNDIS_Reset_Complete_t);
287 RESET_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
288 RESET_Response->AddressingReset = 0;
289
290 break;
291 case REMOTE_NDIS_KEEPALIVE_MSG:
292 RNDISInterfaceInfo->State.ResponseReady = true;
293
294 RNDIS_KeepAlive_Message_t* KEEPALIVE_Message =
295 (RNDIS_KeepAlive_Message_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;
296 RNDIS_KeepAlive_Complete_t* KEEPALIVE_Response =
297 (RNDIS_KeepAlive_Complete_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer;
298
299 KEEPALIVE_Response->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT;
300 KEEPALIVE_Response->MessageLength = sizeof(RNDIS_KeepAlive_Complete_t);
301 KEEPALIVE_Response->RequestId = KEEPALIVE_Message->RequestId;
302 KEEPALIVE_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;
303
304 break;
305 }
306 }
307
308 static bool RNDIS_Device_ProcessNDISQuery(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo,
309 const uint32_t OId,
310 void* const QueryData,
311 const uint16_t QuerySize,
312 void* ResponseData,
313 uint16_t* const ResponseSize)
314 {
315 (void)QueryData;
316 (void)QuerySize;
317
318 switch (OId)
319 {
320 case OID_GEN_SUPPORTED_LIST:
321 *ResponseSize = sizeof(AdapterSupportedOIDList);
322
323 memcpy_P(ResponseData, AdapterSupportedOIDList, sizeof(AdapterSupportedOIDList));
324
325 return true;
326 case OID_GEN_PHYSICAL_MEDIUM:
327 *ResponseSize = sizeof(uint32_t);
328
329 /* Indicate that the device is a true ethernet link */
330 *((uint32_t*)ResponseData) = 0;
331
332 return true;
333 case OID_GEN_HARDWARE_STATUS:
334 *ResponseSize = sizeof(uint32_t);
335
336 *((uint32_t*)ResponseData) = NDIS_HardwareStatus_Ready;
337
338 return true;
339 case OID_GEN_MEDIA_SUPPORTED:
340 case OID_GEN_MEDIA_IN_USE:
341 *ResponseSize = sizeof(uint32_t);
342
343 *((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIUM_802_3;
344
345 return true;
346 case OID_GEN_VENDOR_ID:
347 *ResponseSize = sizeof(uint32_t);
348
349 /* Vendor ID 0x0xFFFFFF is reserved for vendors who have not purchased a NDIS VID */
350 *((uint32_t*)ResponseData) = 0x00FFFFFF;
351
352 return true;
353 case OID_GEN_MAXIMUM_FRAME_SIZE:
354 case OID_GEN_TRANSMIT_BLOCK_SIZE:
355 case OID_GEN_RECEIVE_BLOCK_SIZE:
356 *ResponseSize = sizeof(uint32_t);
357
358 *((uint32_t*)ResponseData) = ETHERNET_FRAME_SIZE_MAX;
359
360 return true;
361 case OID_GEN_VENDOR_DESCRIPTION:
362 *ResponseSize = (strlen(RNDISInterfaceInfo->Config.AdapterVendorDescription) + 1);
363
364 memcpy(ResponseData, RNDISInterfaceInfo->Config.AdapterVendorDescription, *ResponseSize);
365
366 return true;
367 case OID_GEN_MEDIA_CONNECT_STATUS:
368 *ResponseSize = sizeof(uint32_t);
369
370 *((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIA_STATE_CONNECTED;
371
372 return true;
373 case OID_GEN_LINK_SPEED:
374 *ResponseSize = sizeof(uint32_t);
375
376 /* Indicate 10Mb/s link speed */
377 *((uint32_t*)ResponseData) = 100000;
378
379 return true;
380 case OID_802_3_PERMANENT_ADDRESS:
381 case OID_802_3_CURRENT_ADDRESS:
382 *ResponseSize = sizeof(MAC_Address_t);
383
384 memcpy(ResponseData, &RNDISInterfaceInfo->Config.AdapterMACAddress, sizeof(MAC_Address_t));
385
386 return true;
387 case OID_802_3_MAXIMUM_LIST_SIZE:
388 *ResponseSize = sizeof(uint32_t);
389
390 /* Indicate only one multicast address supported */
391 *((uint32_t*)ResponseData) = 1;
392
393 return true;
394 case OID_GEN_CURRENT_PACKET_FILTER:
395 *ResponseSize = sizeof(uint32_t);
396
397 *((uint32_t*)ResponseData) = RNDISInterfaceInfo->State.CurrPacketFilter;
398
399 return true;
400 case OID_GEN_XMIT_OK:
401 case OID_GEN_RCV_OK:
402 case OID_GEN_XMIT_ERROR:
403 case OID_GEN_RCV_ERROR:
404 case OID_GEN_RCV_NO_BUFFER:
405 case OID_802_3_RCV_ERROR_ALIGNMENT:
406 case OID_802_3_XMIT_ONE_COLLISION:
407 case OID_802_3_XMIT_MORE_COLLISIONS:
408 *ResponseSize = sizeof(uint32_t);
409
410 /* Unused statistic OIDs - always return 0 for each */
411 *((uint32_t*)ResponseData) = 0;
412
413 return true;
414 case OID_GEN_MAXIMUM_TOTAL_SIZE:
415 *ResponseSize = sizeof(uint32_t);
416
417 /* Indicate maximum overall buffer (Ethernet frame and RNDIS header) the adapter can handle */
418 *((uint32_t*)ResponseData) = (RNDIS_MESSAGE_BUFFER_SIZE + ETHERNET_FRAME_SIZE_MAX);
419
420 return true;
421 default:
422 return false;
423 }
424 }
425
426 static bool RNDIS_Device_ProcessNDISSet(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo,
427 const uint32_t OId,
428 const void* SetData,
429 const uint16_t SetSize)
430 {
431 (void)SetSize;
432
433 switch (OId)
434 {
435 case OID_GEN_CURRENT_PACKET_FILTER:
436 RNDISInterfaceInfo->State.CurrPacketFilter = *((uint32_t*)SetData);
437 RNDISInterfaceInfo->State.CurrRNDISState = ((RNDISInterfaceInfo->State.CurrPacketFilter) ?
438 RNDIS_Data_Initialized : RNDIS_Data_Initialized);
439
440 return true;
441 case OID_802_3_MULTICAST_LIST:
442 /* Do nothing - throw away the value from the host as it is unused */
443
444 return true;
445 default:
446 return false;
447 }
448 }
449
450 bool RNDIS_Device_IsPacketReceived(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo)
451 {
452 if ((USB_DeviceState != DEVICE_STATE_Configured) ||
453 (RNDISInterfaceInfo->State.CurrRNDISState != RNDIS_Data_Initialized))
454 {
455 return false;
456 }
457
458 Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.DataOUTEndpointNumber);
459 return Endpoint_IsOUTReceived();
460 }
461
462 uint8_t RNDIS_Device_ReadPacket(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo,
463 void* Buffer,
464 uint16_t* const PacketLength)
465 {
466 if ((USB_DeviceState != DEVICE_STATE_Configured) ||
467 (RNDISInterfaceInfo->State.CurrRNDISState != RNDIS_Data_Initialized))
468 {
469 return ENDPOINT_RWSTREAM_DeviceDisconnected;
470 }
471
472 Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.DataOUTEndpointNumber);
473
474 *PacketLength = 0;
475
476 if (!(Endpoint_IsOUTReceived()))
477 return ENDPOINT_RWSTREAM_NoError;
478
479 RNDIS_Packet_Message_t RNDISPacketHeader;
480 Endpoint_Read_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_Packet_Message_t), NULL);
481
482 if (RNDISPacketHeader.DataLength > ETHERNET_FRAME_SIZE_MAX)
483 {
484 Endpoint_StallTransaction();
485
486 return RNDIS_ERROR_LOGICAL_CMD_FAILED;
487 }
488
489 *PacketLength = (uint16_t)RNDISPacketHeader.DataLength;
490
491 Endpoint_Read_Stream_LE(Buffer, RNDISPacketHeader.DataLength, NULL);
492 Endpoint_ClearOUT();
493
494 return ENDPOINT_RWSTREAM_NoError;
495 }
496
497 uint8_t RNDIS_Device_SendPacket(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo,
498 void* Buffer,
499 const uint16_t PacketLength)
500 {
501 uint8_t ErrorCode;
502
503 if ((USB_DeviceState != DEVICE_STATE_Configured) ||
504 (RNDISInterfaceInfo->State.CurrRNDISState != RNDIS_Data_Initialized))
505 {
506 return ENDPOINT_RWSTREAM_DeviceDisconnected;
507 }
508
509 Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.DataINEndpointNumber);
510
511 if ((ErrorCode = Endpoint_WaitUntilReady()) != ENDPOINT_READYWAIT_NoError)
512 return ErrorCode;
513
514 RNDIS_Packet_Message_t RNDISPacketHeader;
515
516 memset(&RNDISPacketHeader, 0, sizeof(RNDIS_Packet_Message_t));
517
518 RNDISPacketHeader.MessageType = REMOTE_NDIS_PACKET_MSG;
519 RNDISPacketHeader.MessageLength = (sizeof(RNDIS_Packet_Message_t) + PacketLength);
520 RNDISPacketHeader.DataOffset = (sizeof(RNDIS_Packet_Message_t) - sizeof(RNDIS_Message_Header_t));
521 RNDISPacketHeader.DataLength = PacketLength;
522
523 Endpoint_Write_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_Packet_Message_t), NULL);
524 Endpoint_Write_Stream_LE(Buffer, PacketLength, NULL);
525 Endpoint_ClearIN();
526
527 return ENDPOINT_RWSTREAM_NoError;
528 }
529
530 #endif
531