3 Copyright (C) Dean Camera, 2013.
5 dean [at] fourwalledcubicle [dot] com
10 Copyright 2013 Dean Camera (dean [at] fourwalledcubicle [dot] com)
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.
21 The author disclaims 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
31 #define __INCLUDE_FROM_USB_DRIVER
32 #include "../../Core/USBMode.h"
34 #if defined(USB_CAN_BE_DEVICE)
36 #define __INCLUDE_FROM_RNDIS_DRIVER
37 #define __INCLUDE_FROM_RNDIS_DEVICE_C
38 #include "RNDISClassDevice.h"
40 static const uint32_t PROGMEM AdapterSupportedOIDList
[] =
42 CPU_TO_LE32(OID_GEN_SUPPORTED_LIST
),
43 CPU_TO_LE32(OID_GEN_PHYSICAL_MEDIUM
),
44 CPU_TO_LE32(OID_GEN_HARDWARE_STATUS
),
45 CPU_TO_LE32(OID_GEN_MEDIA_SUPPORTED
),
46 CPU_TO_LE32(OID_GEN_MEDIA_IN_USE
),
47 CPU_TO_LE32(OID_GEN_MAXIMUM_FRAME_SIZE
),
48 CPU_TO_LE32(OID_GEN_MAXIMUM_TOTAL_SIZE
),
49 CPU_TO_LE32(OID_GEN_LINK_SPEED
),
50 CPU_TO_LE32(OID_GEN_TRANSMIT_BLOCK_SIZE
),
51 CPU_TO_LE32(OID_GEN_RECEIVE_BLOCK_SIZE
),
52 CPU_TO_LE32(OID_GEN_VENDOR_ID
),
53 CPU_TO_LE32(OID_GEN_VENDOR_DESCRIPTION
),
54 CPU_TO_LE32(OID_GEN_CURRENT_PACKET_FILTER
),
55 CPU_TO_LE32(OID_GEN_MAXIMUM_TOTAL_SIZE
),
56 CPU_TO_LE32(OID_GEN_MEDIA_CONNECT_STATUS
),
57 CPU_TO_LE32(OID_GEN_XMIT_OK
),
58 CPU_TO_LE32(OID_GEN_RCV_OK
),
59 CPU_TO_LE32(OID_GEN_XMIT_ERROR
),
60 CPU_TO_LE32(OID_GEN_RCV_ERROR
),
61 CPU_TO_LE32(OID_GEN_RCV_NO_BUFFER
),
62 CPU_TO_LE32(OID_802_3_PERMANENT_ADDRESS
),
63 CPU_TO_LE32(OID_802_3_CURRENT_ADDRESS
),
64 CPU_TO_LE32(OID_802_3_MULTICAST_LIST
),
65 CPU_TO_LE32(OID_802_3_MAXIMUM_LIST_SIZE
),
66 CPU_TO_LE32(OID_802_3_RCV_ERROR_ALIGNMENT
),
67 CPU_TO_LE32(OID_802_3_XMIT_ONE_COLLISION
),
68 CPU_TO_LE32(OID_802_3_XMIT_MORE_COLLISIONS
),
71 void RNDIS_Device_ProcessControlRequest(USB_ClassInfo_RNDIS_Device_t
* const RNDISInterfaceInfo
)
73 if (!(Endpoint_IsSETUPReceived()))
76 if (USB_ControlRequest
.wIndex
!= RNDISInterfaceInfo
->Config
.ControlInterfaceNumber
)
79 switch (USB_ControlRequest
.bRequest
)
81 case RNDIS_REQ_SendEncapsulatedCommand
:
82 if (USB_ControlRequest
.bmRequestType
== (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
))
84 Endpoint_ClearSETUP();
85 Endpoint_Read_Control_Stream_LE(RNDISInterfaceInfo
->State
.RNDISMessageBuffer
, USB_ControlRequest
.wLength
);
88 RNDIS_Device_ProcessRNDISControlMessage(RNDISInterfaceInfo
);
92 case RNDIS_REQ_GetEncapsulatedResponse
:
93 if (USB_ControlRequest
.bmRequestType
== (REQDIR_DEVICETOHOST
| REQTYPE_CLASS
| REQREC_INTERFACE
))
95 RNDIS_Message_Header_t
* MessageHeader
= (RNDIS_Message_Header_t
*)&RNDISInterfaceInfo
->State
.RNDISMessageBuffer
;
97 if (!(MessageHeader
->MessageLength
))
99 RNDISInterfaceInfo
->State
.RNDISMessageBuffer
[0] = 0;
100 MessageHeader
->MessageLength
= CPU_TO_LE32(1);
103 Endpoint_ClearSETUP();
104 Endpoint_Write_Control_Stream_LE(RNDISInterfaceInfo
->State
.RNDISMessageBuffer
, le32_to_cpu(MessageHeader
->MessageLength
));
107 MessageHeader
->MessageLength
= CPU_TO_LE32(0);
114 bool RNDIS_Device_ConfigureEndpoints(USB_ClassInfo_RNDIS_Device_t
* const RNDISInterfaceInfo
)
116 memset(&RNDISInterfaceInfo
->State
, 0x00, sizeof(RNDISInterfaceInfo
->State
));
118 RNDISInterfaceInfo
->Config
.DataINEndpoint
.Type
= EP_TYPE_BULK
;
119 RNDISInterfaceInfo
->Config
.DataOUTEndpoint
.Type
= EP_TYPE_BULK
;
120 RNDISInterfaceInfo
->Config
.NotificationEndpoint
.Type
= EP_TYPE_INTERRUPT
;
122 if (!(Endpoint_ConfigureEndpointTable(&RNDISInterfaceInfo
->Config
.DataINEndpoint
, 1)))
125 if (!(Endpoint_ConfigureEndpointTable(&RNDISInterfaceInfo
->Config
.DataOUTEndpoint
, 1)))
128 if (!(Endpoint_ConfigureEndpointTable(&RNDISInterfaceInfo
->Config
.NotificationEndpoint
, 1)))
134 void RNDIS_Device_USBTask(USB_ClassInfo_RNDIS_Device_t
* const RNDISInterfaceInfo
)
136 if (USB_DeviceState
!= DEVICE_STATE_Configured
)
139 Endpoint_SelectEndpoint(RNDISInterfaceInfo
->Config
.NotificationEndpoint
.Address
);
141 if (Endpoint_IsINReady() && RNDISInterfaceInfo
->State
.ResponseReady
)
143 USB_Request_Header_t Notification
= (USB_Request_Header_t
)
145 .bmRequestType
= (REQDIR_DEVICETOHOST
| REQTYPE_CLASS
| REQREC_INTERFACE
),
146 .bRequest
= RNDIS_NOTIF_ResponseAvailable
,
147 .wValue
= CPU_TO_LE16(0),
148 .wIndex
= CPU_TO_LE16(0),
149 .wLength
= CPU_TO_LE16(0),
152 Endpoint_Write_Stream_LE(&Notification
, sizeof(USB_Request_Header_t
), NULL
);
156 RNDISInterfaceInfo
->State
.ResponseReady
= false;
160 void RNDIS_Device_ProcessRNDISControlMessage(USB_ClassInfo_RNDIS_Device_t
* const RNDISInterfaceInfo
)
162 /* Note: Only a single buffer is used for both the received message and its response to save SRAM. Because of
163 this, response bytes should be filled in order so that they do not clobber unread data in the buffer. */
165 RNDIS_Message_Header_t
* MessageHeader
= (RNDIS_Message_Header_t
*)&RNDISInterfaceInfo
->State
.RNDISMessageBuffer
;
167 switch (le32_to_cpu(MessageHeader
->MessageType
))
169 case REMOTE_NDIS_INITIALIZE_MSG
:
170 RNDISInterfaceInfo
->State
.ResponseReady
= true;
172 RNDIS_Initialize_Message_t
* INITIALIZE_Message
=
173 (RNDIS_Initialize_Message_t
*)&RNDISInterfaceInfo
->State
.RNDISMessageBuffer
;
174 RNDIS_Initialize_Complete_t
* INITIALIZE_Response
=
175 (RNDIS_Initialize_Complete_t
*)&RNDISInterfaceInfo
->State
.RNDISMessageBuffer
;
177 INITIALIZE_Response
->MessageType
= CPU_TO_LE32(REMOTE_NDIS_INITIALIZE_CMPLT
);
178 INITIALIZE_Response
->MessageLength
= CPU_TO_LE32(sizeof(RNDIS_Initialize_Complete_t
));
179 INITIALIZE_Response
->RequestId
= INITIALIZE_Message
->RequestId
;
180 INITIALIZE_Response
->Status
= CPU_TO_LE32(REMOTE_NDIS_STATUS_SUCCESS
);
182 INITIALIZE_Response
->MajorVersion
= CPU_TO_LE32(REMOTE_NDIS_VERSION_MAJOR
);
183 INITIALIZE_Response
->MinorVersion
= CPU_TO_LE32(REMOTE_NDIS_VERSION_MINOR
);
184 INITIALIZE_Response
->DeviceFlags
= CPU_TO_LE32(REMOTE_NDIS_DF_CONNECTIONLESS
);
185 INITIALIZE_Response
->Medium
= CPU_TO_LE32(REMOTE_NDIS_MEDIUM_802_3
);
186 INITIALIZE_Response
->MaxPacketsPerTransfer
= CPU_TO_LE32(1);
187 INITIALIZE_Response
->MaxTransferSize
= CPU_TO_LE32(sizeof(RNDIS_Packet_Message_t
) + ETHERNET_FRAME_SIZE_MAX
);
188 INITIALIZE_Response
->PacketAlignmentFactor
= CPU_TO_LE32(0);
189 INITIALIZE_Response
->AFListOffset
= CPU_TO_LE32(0);
190 INITIALIZE_Response
->AFListSize
= CPU_TO_LE32(0);
192 RNDISInterfaceInfo
->State
.CurrRNDISState
= RNDIS_Initialized
;
194 case REMOTE_NDIS_HALT_MSG
:
195 RNDISInterfaceInfo
->State
.ResponseReady
= false;
197 MessageHeader
->MessageLength
= CPU_TO_LE32(0);
199 RNDISInterfaceInfo
->State
.CurrRNDISState
= RNDIS_Uninitialized
;
201 case REMOTE_NDIS_QUERY_MSG
:
202 RNDISInterfaceInfo
->State
.ResponseReady
= true;
204 RNDIS_Query_Message_t
* QUERY_Message
= (RNDIS_Query_Message_t
*)&RNDISInterfaceInfo
->State
.RNDISMessageBuffer
;
205 RNDIS_Query_Complete_t
* QUERY_Response
= (RNDIS_Query_Complete_t
*)&RNDISInterfaceInfo
->State
.RNDISMessageBuffer
;
206 uint32_t Query_Oid
= CPU_TO_LE32(QUERY_Message
->Oid
);
208 void* QueryData
= &RNDISInterfaceInfo
->State
.RNDISMessageBuffer
[sizeof(RNDIS_Message_Header_t
) +
209 le32_to_cpu(QUERY_Message
->InformationBufferOffset
)];
210 void* ResponseData
= &RNDISInterfaceInfo
->State
.RNDISMessageBuffer
[sizeof(RNDIS_Query_Complete_t
)];
211 uint16_t ResponseSize
;
213 QUERY_Response
->MessageType
= CPU_TO_LE32(REMOTE_NDIS_QUERY_CMPLT
);
215 if (RNDIS_Device_ProcessNDISQuery(RNDISInterfaceInfo
, Query_Oid
, QueryData
, le32_to_cpu(QUERY_Message
->InformationBufferLength
),
216 ResponseData
, &ResponseSize
))
218 QUERY_Response
->Status
= CPU_TO_LE32(REMOTE_NDIS_STATUS_SUCCESS
);
219 QUERY_Response
->MessageLength
= cpu_to_le32(sizeof(RNDIS_Query_Complete_t
) + ResponseSize
);
221 QUERY_Response
->InformationBufferLength
= CPU_TO_LE32(ResponseSize
);
222 QUERY_Response
->InformationBufferOffset
= CPU_TO_LE32(sizeof(RNDIS_Query_Complete_t
) - sizeof(RNDIS_Message_Header_t
));
226 QUERY_Response
->Status
= CPU_TO_LE32(REMOTE_NDIS_STATUS_NOT_SUPPORTED
);
227 QUERY_Response
->MessageLength
= CPU_TO_LE32(sizeof(RNDIS_Query_Complete_t
));
229 QUERY_Response
->InformationBufferLength
= CPU_TO_LE32(0);
230 QUERY_Response
->InformationBufferOffset
= CPU_TO_LE32(0);
234 case REMOTE_NDIS_SET_MSG
:
235 RNDISInterfaceInfo
->State
.ResponseReady
= true;
237 RNDIS_Set_Message_t
* SET_Message
= (RNDIS_Set_Message_t
*)&RNDISInterfaceInfo
->State
.RNDISMessageBuffer
;
238 RNDIS_Set_Complete_t
* SET_Response
= (RNDIS_Set_Complete_t
*)&RNDISInterfaceInfo
->State
.RNDISMessageBuffer
;
239 uint32_t SET_Oid
= le32_to_cpu(SET_Message
->Oid
);
241 SET_Response
->MessageType
= CPU_TO_LE32(REMOTE_NDIS_SET_CMPLT
);
242 SET_Response
->MessageLength
= CPU_TO_LE32(sizeof(RNDIS_Set_Complete_t
));
243 SET_Response
->RequestId
= SET_Message
->RequestId
;
245 void* SetData
= &RNDISInterfaceInfo
->State
.RNDISMessageBuffer
[sizeof(RNDIS_Message_Header_t
) +
246 le32_to_cpu(SET_Message
->InformationBufferOffset
)];
248 SET_Response
->Status
= RNDIS_Device_ProcessNDISSet(RNDISInterfaceInfo
, SET_Oid
, SetData
,
249 le32_to_cpu(SET_Message
->InformationBufferLength
)) ?
250 REMOTE_NDIS_STATUS_SUCCESS
: REMOTE_NDIS_STATUS_NOT_SUPPORTED
;
252 case REMOTE_NDIS_RESET_MSG
:
253 RNDISInterfaceInfo
->State
.ResponseReady
= true;
255 RNDIS_Reset_Complete_t
* RESET_Response
= (RNDIS_Reset_Complete_t
*)&RNDISInterfaceInfo
->State
.RNDISMessageBuffer
;
257 RESET_Response
->MessageType
= CPU_TO_LE32(REMOTE_NDIS_RESET_CMPLT
);
258 RESET_Response
->MessageLength
= CPU_TO_LE32(sizeof(RNDIS_Reset_Complete_t
));
259 RESET_Response
->Status
= CPU_TO_LE32(REMOTE_NDIS_STATUS_SUCCESS
);
260 RESET_Response
->AddressingReset
= CPU_TO_LE32(0);
263 case REMOTE_NDIS_KEEPALIVE_MSG
:
264 RNDISInterfaceInfo
->State
.ResponseReady
= true;
266 RNDIS_KeepAlive_Message_t
* KEEPALIVE_Message
=
267 (RNDIS_KeepAlive_Message_t
*)&RNDISInterfaceInfo
->State
.RNDISMessageBuffer
;
268 RNDIS_KeepAlive_Complete_t
* KEEPALIVE_Response
=
269 (RNDIS_KeepAlive_Complete_t
*)&RNDISInterfaceInfo
->State
.RNDISMessageBuffer
;
271 KEEPALIVE_Response
->MessageType
= CPU_TO_LE32(REMOTE_NDIS_KEEPALIVE_CMPLT
);
272 KEEPALIVE_Response
->MessageLength
= CPU_TO_LE32(sizeof(RNDIS_KeepAlive_Complete_t
));
273 KEEPALIVE_Response
->RequestId
= KEEPALIVE_Message
->RequestId
;
274 KEEPALIVE_Response
->Status
= CPU_TO_LE32(REMOTE_NDIS_STATUS_SUCCESS
);
280 static bool RNDIS_Device_ProcessNDISQuery(USB_ClassInfo_RNDIS_Device_t
* const RNDISInterfaceInfo
,
282 void* const QueryData
,
283 const uint16_t QuerySize
,
285 uint16_t* const ResponseSize
)
292 case OID_GEN_SUPPORTED_LIST
:
293 *ResponseSize
= sizeof(AdapterSupportedOIDList
);
295 memcpy_P(ResponseData
, AdapterSupportedOIDList
, sizeof(AdapterSupportedOIDList
));
298 case OID_GEN_PHYSICAL_MEDIUM
:
299 *ResponseSize
= sizeof(uint32_t);
301 /* Indicate that the device is a true ethernet link */
302 *((uint32_t*)ResponseData
) = CPU_TO_LE32(0);
305 case OID_GEN_HARDWARE_STATUS
:
306 *ResponseSize
= sizeof(uint32_t);
308 *((uint32_t*)ResponseData
) = CPU_TO_LE32(NDIS_HardwareStatus_Ready
);
311 case OID_GEN_MEDIA_SUPPORTED
:
312 case OID_GEN_MEDIA_IN_USE
:
313 *ResponseSize
= sizeof(uint32_t);
315 *((uint32_t*)ResponseData
) = CPU_TO_LE32(REMOTE_NDIS_MEDIUM_802_3
);
318 case OID_GEN_VENDOR_ID
:
319 *ResponseSize
= sizeof(uint32_t);
321 /* Vendor ID 0x0xFFFFFF is reserved for vendors who have not purchased a NDIS VID */
322 *((uint32_t*)ResponseData
) = CPU_TO_LE32(0x00FFFFFF);
325 case OID_GEN_MAXIMUM_FRAME_SIZE
:
326 case OID_GEN_TRANSMIT_BLOCK_SIZE
:
327 case OID_GEN_RECEIVE_BLOCK_SIZE
:
328 *ResponseSize
= sizeof(uint32_t);
330 *((uint32_t*)ResponseData
) = CPU_TO_LE32(ETHERNET_FRAME_SIZE_MAX
);
333 case OID_GEN_VENDOR_DESCRIPTION
:
334 *ResponseSize
= (strlen(RNDISInterfaceInfo
->Config
.AdapterVendorDescription
) + 1);
336 memcpy(ResponseData
, RNDISInterfaceInfo
->Config
.AdapterVendorDescription
, *ResponseSize
);
339 case OID_GEN_MEDIA_CONNECT_STATUS
:
340 *ResponseSize
= sizeof(uint32_t);
342 *((uint32_t*)ResponseData
) = CPU_TO_LE32(REMOTE_NDIS_MEDIA_STATE_CONNECTED
);
345 case OID_GEN_LINK_SPEED
:
346 *ResponseSize
= sizeof(uint32_t);
348 /* Indicate 10Mb/s link speed */
349 *((uint32_t*)ResponseData
) = CPU_TO_LE32(100000);
352 case OID_802_3_PERMANENT_ADDRESS
:
353 case OID_802_3_CURRENT_ADDRESS
:
354 *ResponseSize
= sizeof(MAC_Address_t
);
356 memcpy(ResponseData
, &RNDISInterfaceInfo
->Config
.AdapterMACAddress
, sizeof(MAC_Address_t
));
359 case OID_802_3_MAXIMUM_LIST_SIZE
:
360 *ResponseSize
= sizeof(uint32_t);
362 /* Indicate only one multicast address supported */
363 *((uint32_t*)ResponseData
) = CPU_TO_LE32(1);
366 case OID_GEN_CURRENT_PACKET_FILTER
:
367 *ResponseSize
= sizeof(uint32_t);
369 *((uint32_t*)ResponseData
) = cpu_to_le32(RNDISInterfaceInfo
->State
.CurrPacketFilter
);
372 case OID_GEN_XMIT_OK
:
374 case OID_GEN_XMIT_ERROR
:
375 case OID_GEN_RCV_ERROR
:
376 case OID_GEN_RCV_NO_BUFFER
:
377 case OID_802_3_RCV_ERROR_ALIGNMENT
:
378 case OID_802_3_XMIT_ONE_COLLISION
:
379 case OID_802_3_XMIT_MORE_COLLISIONS
:
380 *ResponseSize
= sizeof(uint32_t);
382 /* Unused statistic OIDs - always return 0 for each */
383 *((uint32_t*)ResponseData
) = CPU_TO_LE32(0);
386 case OID_GEN_MAXIMUM_TOTAL_SIZE
:
387 *ResponseSize
= sizeof(uint32_t);
389 /* Indicate maximum overall buffer (Ethernet frame and RNDIS header) the adapter can handle */
390 *((uint32_t*)ResponseData
) = CPU_TO_LE32(RNDIS_MESSAGE_BUFFER_SIZE
+ ETHERNET_FRAME_SIZE_MAX
);
398 static bool RNDIS_Device_ProcessNDISSet(USB_ClassInfo_RNDIS_Device_t
* const RNDISInterfaceInfo
,
401 const uint16_t SetSize
)
407 case OID_GEN_CURRENT_PACKET_FILTER
:
408 RNDISInterfaceInfo
->State
.CurrPacketFilter
= le32_to_cpu(*((uint32_t*)SetData
));
409 RNDISInterfaceInfo
->State
.CurrRNDISState
= (RNDISInterfaceInfo
->State
.CurrPacketFilter
) ? RNDIS_Data_Initialized
: RNDIS_Initialized
;
412 case OID_802_3_MULTICAST_LIST
:
413 /* Do nothing - throw away the value from the host as it is unused */
421 bool RNDIS_Device_IsPacketReceived(USB_ClassInfo_RNDIS_Device_t
* const RNDISInterfaceInfo
)
423 if ((USB_DeviceState
!= DEVICE_STATE_Configured
) ||
424 (RNDISInterfaceInfo
->State
.CurrRNDISState
!= RNDIS_Data_Initialized
))
429 Endpoint_SelectEndpoint(RNDISInterfaceInfo
->Config
.DataOUTEndpoint
.Address
);
430 return Endpoint_IsOUTReceived();
433 uint8_t RNDIS_Device_ReadPacket(USB_ClassInfo_RNDIS_Device_t
* const RNDISInterfaceInfo
,
435 uint16_t* const PacketLength
)
437 if ((USB_DeviceState
!= DEVICE_STATE_Configured
) ||
438 (RNDISInterfaceInfo
->State
.CurrRNDISState
!= RNDIS_Data_Initialized
))
440 return ENDPOINT_RWSTREAM_DeviceDisconnected
;
443 Endpoint_SelectEndpoint(RNDISInterfaceInfo
->Config
.DataOUTEndpoint
.Address
);
447 if (!(Endpoint_IsOUTReceived()))
448 return ENDPOINT_RWSTREAM_NoError
;
450 RNDIS_Packet_Message_t RNDISPacketHeader
;
451 Endpoint_Read_Stream_LE(&RNDISPacketHeader
, sizeof(RNDIS_Packet_Message_t
), NULL
);
453 if (le32_to_cpu(RNDISPacketHeader
.DataLength
) > ETHERNET_FRAME_SIZE_MAX
)
455 Endpoint_StallTransaction();
457 return RNDIS_ERROR_LOGICAL_CMD_FAILED
;
460 *PacketLength
= (uint16_t)le32_to_cpu(RNDISPacketHeader
.DataLength
);
462 Endpoint_Read_Stream_LE(Buffer
, *PacketLength
, NULL
);
465 return ENDPOINT_RWSTREAM_NoError
;
468 uint8_t RNDIS_Device_SendPacket(USB_ClassInfo_RNDIS_Device_t
* const RNDISInterfaceInfo
,
470 const uint16_t PacketLength
)
474 if ((USB_DeviceState
!= DEVICE_STATE_Configured
) ||
475 (RNDISInterfaceInfo
->State
.CurrRNDISState
!= RNDIS_Data_Initialized
))
477 return ENDPOINT_RWSTREAM_DeviceDisconnected
;
480 Endpoint_SelectEndpoint(RNDISInterfaceInfo
->Config
.DataINEndpoint
.Address
);
482 if ((ErrorCode
= Endpoint_WaitUntilReady()) != ENDPOINT_READYWAIT_NoError
)
485 RNDIS_Packet_Message_t RNDISPacketHeader
;
487 memset(&RNDISPacketHeader
, 0, sizeof(RNDIS_Packet_Message_t
));
489 RNDISPacketHeader
.MessageType
= CPU_TO_LE32(REMOTE_NDIS_PACKET_MSG
);
490 RNDISPacketHeader
.MessageLength
= cpu_to_le32(sizeof(RNDIS_Packet_Message_t
) + PacketLength
);
491 RNDISPacketHeader
.DataOffset
= CPU_TO_LE32(sizeof(RNDIS_Packet_Message_t
) - sizeof(RNDIS_Message_Header_t
));
492 RNDISPacketHeader
.DataLength
= cpu_to_le32(PacketLength
);
494 Endpoint_Write_Stream_LE(&RNDISPacketHeader
, sizeof(RNDIS_Packet_Message_t
), NULL
);
495 Endpoint_Write_Stream_LE(Buffer
, PacketLength
, NULL
);
498 return ENDPOINT_RWSTREAM_NoError
;