Statistics
| Branch: | Tag: | Revision:

root / LUFA / Drivers / USB / Class / Host / RNDIS.c @ 978b99e5

History | View | Annotate | Download (17.4 KB)

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_HOST)
35

    
36
#define  __INCLUDE_FROM_RNDIS_DRIVER
37
#define  __INCLUDE_FROM_RNDIS_HOST_C
38
#include "RNDIS.h"
39

    
40
uint8_t RNDIS_Host_ConfigurePipes(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
41
                                  uint16_t ConfigDescriptorSize,
42
                                  void* ConfigDescriptorData)
43
{
44
        USB_Descriptor_Endpoint_t*  DataINEndpoint        = NULL;
45
        USB_Descriptor_Endpoint_t*  DataOUTEndpoint       = NULL;
46
        USB_Descriptor_Endpoint_t*  NotificationEndpoint  = NULL;
47
        USB_Descriptor_Interface_t* RNDISControlInterface = NULL;
48

    
49
        memset(&RNDISInterfaceInfo->State, 0x00, sizeof(RNDISInterfaceInfo->State));
50

    
51
        if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
52
          return RNDIS_ENUMERROR_InvalidConfigDescriptor;
53

    
54
        RNDISControlInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
55

    
56
        while (!(DataINEndpoint) || !(DataOUTEndpoint) || !(NotificationEndpoint))
57
        {
58
                if (!(RNDISControlInterface) ||
59
                    USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
60
                                              DCOMP_RNDIS_Host_NextRNDISInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
61
                {
62
                        if (NotificationEndpoint)
63
                        {
64
                                if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
65
                                                                                          DCOMP_RNDIS_Host_NextRNDISDataInterface) != DESCRIPTOR_SEARCH_COMP_Found)
66
                                {
67
                                        return RNDIS_ENUMERROR_NoCompatibleInterfaceFound;
68
                                }
69

    
70
                                DataINEndpoint  = NULL;
71
                                DataOUTEndpoint = NULL;
72
                        }
73
                        else
74
                        {
75
                                if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
76
                                                                                          DCOMP_RNDIS_Host_NextRNDISControlInterface) != DESCRIPTOR_SEARCH_COMP_Found)
77
                                {
78
                                        return RNDIS_ENUMERROR_NoCompatibleInterfaceFound;
79
                                }
80

    
81
                                RNDISControlInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
82

    
83
                                NotificationEndpoint = NULL;
84
                        }
85

    
86
                        continue;
87
                }
88

    
89
                USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);
90

    
91
                if ((EndpointData->EndpointAddress & ENDPOINT_DIR_MASK) == ENDPOINT_DIR_IN)
92
                {
93
                        if ((EndpointData->Attributes & EP_TYPE_MASK) == EP_TYPE_INTERRUPT)
94
                          NotificationEndpoint = EndpointData;
95
                        else
96
                          DataINEndpoint = EndpointData;
97
                }
98
                else
99
                {
100
                        DataOUTEndpoint = EndpointData;
101
                }
102
        }
103

    
104
        for (uint8_t PipeNum = 1; PipeNum < PIPE_TOTAL_PIPES; PipeNum++)
105
        {
106
                uint16_t Size;
107
                uint8_t  Type;
108
                uint8_t  Token;
109
                uint8_t  EndpointAddress;
110
                uint8_t  InterruptPeriod;
111
                bool     DoubleBanked;
112

    
113
                if (PipeNum == RNDISInterfaceInfo->Config.DataINPipeNumber)
114
                {
115
                        Size            = le16_to_cpu(DataINEndpoint->EndpointSize);
116
                        EndpointAddress = DataINEndpoint->EndpointAddress;
117
                        Token           = PIPE_TOKEN_IN;
118
                        Type            = EP_TYPE_BULK;
119
                        DoubleBanked    = RNDISInterfaceInfo->Config.DataINPipeDoubleBank;
120
                        InterruptPeriod = 0;
121

    
122
                        RNDISInterfaceInfo->State.DataINPipeSize = DataINEndpoint->EndpointSize;
123
                }
124
                else if (PipeNum == RNDISInterfaceInfo->Config.DataOUTPipeNumber)
125
                {
126
                        Size            = le16_to_cpu(DataOUTEndpoint->EndpointSize);
127
                        EndpointAddress = DataOUTEndpoint->EndpointAddress;
128
                        Token           = PIPE_TOKEN_OUT;
129
                        Type            = EP_TYPE_BULK;
130
                        DoubleBanked    = RNDISInterfaceInfo->Config.DataOUTPipeDoubleBank;
131
                        InterruptPeriod = 0;
132

    
133
                        RNDISInterfaceInfo->State.DataOUTPipeSize = DataOUTEndpoint->EndpointSize;
134
                }
135
                else if (PipeNum == RNDISInterfaceInfo->Config.NotificationPipeNumber)
136
                {
137
                        Size            = le16_to_cpu(NotificationEndpoint->EndpointSize);
138
                        EndpointAddress = NotificationEndpoint->EndpointAddress;
139
                        Token           = PIPE_TOKEN_IN;
140
                        Type            = EP_TYPE_INTERRUPT;
141
                        DoubleBanked    = RNDISInterfaceInfo->Config.NotificationPipeDoubleBank;
142
                        InterruptPeriod = NotificationEndpoint->PollingIntervalMS;
143

    
144
                        RNDISInterfaceInfo->State.NotificationPipeSize = NotificationEndpoint->EndpointSize;
145
                }
146
                else
147
                {
148
                        continue;
149
                }
150
                
151
                if (!(Pipe_ConfigurePipe(PipeNum, Type, Token, EndpointAddress, Size,
152
                                         DoubleBanked ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE)))
153
                {
154
                        return CDC_ENUMERROR_PipeConfigurationFailed;
155
                }
156
                
157
                if (InterruptPeriod)
158
                  Pipe_SetInterruptPeriod(InterruptPeriod);
159
        }
160

    
161
        RNDISInterfaceInfo->State.ControlInterfaceNumber = RNDISControlInterface->InterfaceNumber;
162
        RNDISInterfaceInfo->State.IsActive = true;
163

    
164
        return RNDIS_ENUMERROR_NoError;
165
}
166

    
167
static uint8_t DCOMP_RNDIS_Host_NextRNDISControlInterface(void* const CurrentDescriptor)
168
{
169
        USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
170

    
171
        if (Header->Type == DTYPE_Interface)
172
        {
173
                USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
174

    
175
                if ((Interface->Class    == CDC_CSCP_CDCClass)    &&
176
                    (Interface->SubClass == CDC_CSCP_ACMSubclass) &&
177
                    (Interface->Protocol == CDC_CSCP_VendorSpecificProtocol))
178
                {
179
                        return DESCRIPTOR_SEARCH_Found;
180
                }
181
        }
182

    
183
        return DESCRIPTOR_SEARCH_NotFound;
184
}
185

    
186
static uint8_t DCOMP_RNDIS_Host_NextRNDISDataInterface(void* const CurrentDescriptor)
187
{
188
        USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
189

    
190
        if (Header->Type == DTYPE_Interface)
191
        {
192
                USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor,
193
                                                                         USB_Descriptor_Interface_t);
194

    
195
                if ((Interface->Class    == CDC_CSCP_CDCDataClass)   &&
196
                    (Interface->SubClass == CDC_CSCP_NoDataSubclass) &&
197
                    (Interface->Protocol == CDC_CSCP_NoDataProtocol))
198
                {
199
                        return DESCRIPTOR_SEARCH_Found;
200
                }
201
        }
202

    
203
        return DESCRIPTOR_SEARCH_NotFound;
204
}
205

    
206
static uint8_t DCOMP_RNDIS_Host_NextRNDISInterfaceEndpoint(void* const CurrentDescriptor)
207
{
208
        USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
209

    
210
        if (Header->Type == DTYPE_Endpoint)
211
        {
212
                USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);
213

    
214
                uint8_t EndpointType = (Endpoint->Attributes & EP_TYPE_MASK);
215

    
216
                if (((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT)) &&
217
                    !(Pipe_IsEndpointBound(Endpoint->EndpointAddress)))
218
                {
219
                        return DESCRIPTOR_SEARCH_Found;
220
                }
221
        }
222
        else if (Header->Type == DTYPE_Interface)
223
        {
224
                return DESCRIPTOR_SEARCH_Fail;
225
        }
226

    
227
        return DESCRIPTOR_SEARCH_NotFound;
228
}
229

    
230
static uint8_t RNDIS_SendEncapsulatedCommand(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
231
                                             void* Buffer,
232
                                             const uint16_t Length)
233
{
234
        USB_ControlRequest = (USB_Request_Header_t)
235
                {
236
                        .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
237
                        .bRequest      = RNDIS_REQ_SendEncapsulatedCommand,
238
                        .wValue        = 0,
239
                        .wIndex        = RNDISInterfaceInfo->State.ControlInterfaceNumber,
240
                        .wLength       = Length,
241
                };
242

    
243
        Pipe_SelectPipe(PIPE_CONTROLPIPE);
244
        
245
        return USB_Host_SendControlRequest(Buffer);
246
}
247

    
248
static uint8_t RNDIS_GetEncapsulatedResponse(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
249
                                             void* Buffer,
250
                                             const uint16_t Length)
251
{
252
        USB_ControlRequest = (USB_Request_Header_t)
253
                {
254
                        .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
255
                        .bRequest      = RNDIS_REQ_GetEncapsulatedResponse,
256
                        .wValue        = 0,
257
                        .wIndex        = RNDISInterfaceInfo->State.ControlInterfaceNumber,
258
                        .wLength       = Length,
259
                };
260

    
261
        Pipe_SelectPipe(PIPE_CONTROLPIPE);
262
        
263
        return USB_Host_SendControlRequest(Buffer);
264
}
265

    
266
uint8_t RNDIS_Host_SendKeepAlive(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo)
267
{
268
        uint8_t ErrorCode;
269

    
270
        RNDIS_KeepAlive_Message_t  KeepAliveMessage;
271
        RNDIS_KeepAlive_Complete_t KeepAliveMessageResponse;
272

    
273
        KeepAliveMessage.MessageType     = CPU_TO_LE32(REMOTE_NDIS_KEEPALIVE_MSG);
274
        KeepAliveMessage.MessageLength   = CPU_TO_LE32(sizeof(RNDIS_KeepAlive_Message_t));
275
        KeepAliveMessage.RequestId       = cpu_to_le32(RNDISInterfaceInfo->State.RequestID++);
276

    
277
        if ((ErrorCode = RNDIS_SendEncapsulatedCommand(RNDISInterfaceInfo, &KeepAliveMessage,
278
                                                       sizeof(RNDIS_KeepAlive_Message_t))) != HOST_SENDCONTROL_Successful)
279
        {
280
                return ErrorCode;
281
        }
282

    
283
        if ((ErrorCode = RNDIS_GetEncapsulatedResponse(RNDISInterfaceInfo, &KeepAliveMessageResponse,
284
                                                       sizeof(RNDIS_KeepAlive_Complete_t))) != HOST_SENDCONTROL_Successful)
285
        {
286
                return ErrorCode;
287
        }
288

    
289
        return HOST_SENDCONTROL_Successful;
290
}
291

    
292
uint8_t RNDIS_Host_InitializeDevice(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo)
293
{
294
        uint8_t ErrorCode;
295

    
296
        RNDIS_Initialize_Message_t  InitMessage;
297
        RNDIS_Initialize_Complete_t InitMessageResponse;
298

    
299
        InitMessage.MessageType     = CPU_TO_LE32(REMOTE_NDIS_INITIALIZE_MSG);
300
        InitMessage.MessageLength   = CPU_TO_LE32(sizeof(RNDIS_Initialize_Message_t));
301
        InitMessage.RequestId       = cpu_to_le32(RNDISInterfaceInfo->State.RequestID++);
302

    
303
        InitMessage.MajorVersion    = CPU_TO_LE32(REMOTE_NDIS_VERSION_MAJOR);
304
        InitMessage.MinorVersion    = CPU_TO_LE32(REMOTE_NDIS_VERSION_MINOR);
305
        InitMessage.MaxTransferSize = cpu_to_le32(RNDISInterfaceInfo->Config.HostMaxPacketSize);
306

    
307
        if ((ErrorCode = RNDIS_SendEncapsulatedCommand(RNDISInterfaceInfo, &InitMessage,
308
                                                       sizeof(RNDIS_Initialize_Message_t))) != HOST_SENDCONTROL_Successful)
309
        {
310
                return ErrorCode;
311
        }
312

    
313
        if ((ErrorCode = RNDIS_GetEncapsulatedResponse(RNDISInterfaceInfo, &InitMessageResponse,
314
                                                       sizeof(RNDIS_Initialize_Complete_t))) != HOST_SENDCONTROL_Successful)
315
        {
316
                return ErrorCode;
317
        }
318

    
319
        if (InitMessageResponse.Status != CPU_TO_LE32(REMOTE_NDIS_STATUS_SUCCESS))
320
          return RNDIS_ERROR_LOGICAL_CMD_FAILED;
321

    
322
        RNDISInterfaceInfo->State.DeviceMaxPacketSize = le32_to_cpu(InitMessageResponse.MaxTransferSize);
323

    
324
        return HOST_SENDCONTROL_Successful;
325
}
326

    
327
uint8_t RNDIS_Host_SetRNDISProperty(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
328
                                    const uint32_t Oid,
329
                                    void* Buffer,
330
                                    const uint16_t Length)
331
{
332
        uint8_t ErrorCode;
333

    
334
        struct
335
        {
336
                RNDIS_Set_Message_t SetMessage;
337
                uint8_t             ContiguousBuffer[Length];
338
        } SetMessageData;
339

    
340
        RNDIS_Set_Complete_t SetMessageResponse;
341

    
342
        SetMessageData.SetMessage.MessageType    = CPU_TO_LE32(REMOTE_NDIS_SET_MSG);
343
        SetMessageData.SetMessage.MessageLength  = cpu_to_le32(sizeof(RNDIS_Set_Message_t) + Length);
344
        SetMessageData.SetMessage.RequestId      = cpu_to_le32(RNDISInterfaceInfo->State.RequestID++);
345

    
346
        SetMessageData.SetMessage.Oid            = cpu_to_le32(Oid);
347
        SetMessageData.SetMessage.InformationBufferLength = cpu_to_le32(Length);
348
        SetMessageData.SetMessage.InformationBufferOffset = CPU_TO_LE32(sizeof(RNDIS_Set_Message_t) - sizeof(RNDIS_Message_Header_t));
349
        SetMessageData.SetMessage.DeviceVcHandle = CPU_TO_LE32(0);
350

    
351
        memcpy(&SetMessageData.ContiguousBuffer, Buffer, Length);
352

    
353
        if ((ErrorCode = RNDIS_SendEncapsulatedCommand(RNDISInterfaceInfo, &SetMessageData,
354
                                                       SetMessageData.SetMessage.MessageLength)) != HOST_SENDCONTROL_Successful)
355
        {
356
                return ErrorCode;
357
        }
358

    
359
        if ((ErrorCode = RNDIS_GetEncapsulatedResponse(RNDISInterfaceInfo, &SetMessageResponse,
360
                                                       sizeof(RNDIS_Set_Complete_t))) != HOST_SENDCONTROL_Successful)
361
        {
362
                return ErrorCode;
363
        }
364

    
365
        if (SetMessageResponse.Status != CPU_TO_LE32(REMOTE_NDIS_STATUS_SUCCESS))
366
          return RNDIS_ERROR_LOGICAL_CMD_FAILED;
367

    
368
        return HOST_SENDCONTROL_Successful;
369
}
370

    
371
uint8_t RNDIS_Host_QueryRNDISProperty(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
372
                                      const uint32_t Oid,
373
                                      void* Buffer,
374
                                      const uint16_t MaxLength)
375
{
376
        uint8_t ErrorCode;
377

    
378
        RNDIS_Query_Message_t QueryMessage;
379

    
380
        struct
381
        {
382
                RNDIS_Query_Complete_t QueryMessageResponse;
383
                uint8_t                ContiguousBuffer[MaxLength];
384
        } QueryMessageResponseData;
385

    
386
        QueryMessage.MessageType    = CPU_TO_LE32(REMOTE_NDIS_QUERY_MSG);
387
        QueryMessage.MessageLength  = CPU_TO_LE32(sizeof(RNDIS_Query_Message_t));
388
        QueryMessage.RequestId      = cpu_to_le32(RNDISInterfaceInfo->State.RequestID++);
389

    
390
        QueryMessage.Oid            = cpu_to_le32(Oid);
391
        QueryMessage.InformationBufferLength = CPU_TO_LE32(0);
392
        QueryMessage.InformationBufferOffset = CPU_TO_LE32(0);
393
        QueryMessage.DeviceVcHandle = CPU_TO_LE32(0);
394

    
395
        if ((ErrorCode = RNDIS_SendEncapsulatedCommand(RNDISInterfaceInfo, &QueryMessage,
396
                                                       sizeof(RNDIS_Query_Message_t))) != HOST_SENDCONTROL_Successful)
397
        {
398
                return ErrorCode;
399
        }
400

    
401
        if ((ErrorCode = RNDIS_GetEncapsulatedResponse(RNDISInterfaceInfo, &QueryMessageResponseData,
402
                                                       sizeof(QueryMessageResponseData))) != HOST_SENDCONTROL_Successful)
403
        {
404
                return ErrorCode;
405
        }
406

    
407
        if (QueryMessageResponseData.QueryMessageResponse.Status != CPU_TO_LE32(REMOTE_NDIS_STATUS_SUCCESS))
408
          return RNDIS_ERROR_LOGICAL_CMD_FAILED;
409

    
410
        memcpy(Buffer, &QueryMessageResponseData.ContiguousBuffer, MaxLength);
411

    
412
        return HOST_SENDCONTROL_Successful;
413
}
414

    
415
bool RNDIS_Host_IsPacketReceived(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo)
416
{
417
        bool PacketWaiting;
418

    
419
        if ((USB_HostState != HOST_STATE_Configured) || !(RNDISInterfaceInfo->State.IsActive))
420
          return false;
421

    
422
        Pipe_SelectPipe(RNDISInterfaceInfo->Config.DataINPipeNumber);
423

    
424
        Pipe_Unfreeze();
425
        PacketWaiting = Pipe_IsINReceived();
426
        Pipe_Freeze();
427

    
428
        return PacketWaiting;
429
}
430

    
431
uint8_t RNDIS_Host_ReadPacket(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
432
                              void* Buffer,
433
                              uint16_t* const PacketLength)
434
{
435
        uint8_t ErrorCode;
436

    
437
        if ((USB_HostState != HOST_STATE_Configured) || !(RNDISInterfaceInfo->State.IsActive))
438
          return PIPE_READYWAIT_DeviceDisconnected;
439

    
440
        Pipe_SelectPipe(RNDISInterfaceInfo->Config.DataINPipeNumber);
441
        Pipe_Unfreeze();
442

    
443
        if (!(Pipe_IsReadWriteAllowed()))
444
        {
445
                if (Pipe_IsINReceived())
446
                  Pipe_ClearIN();
447

    
448
                *PacketLength = 0;
449
                Pipe_Freeze();
450
                return PIPE_RWSTREAM_NoError;
451
        }
452

    
453
        RNDIS_Packet_Message_t DeviceMessage;
454

    
455
        if ((ErrorCode = Pipe_Read_Stream_LE(&DeviceMessage, sizeof(RNDIS_Packet_Message_t),
456
                                             NULL)) != PIPE_RWSTREAM_NoError)
457
        {
458
                return ErrorCode;
459
        }
460

    
461
        *PacketLength = (uint16_t)le32_to_cpu(DeviceMessage.DataLength);
462

    
463
        Pipe_Discard_Stream(DeviceMessage.DataOffset -
464
                            (sizeof(RNDIS_Packet_Message_t) - sizeof(RNDIS_Message_Header_t)),
465
                            NULL);
466

    
467
        Pipe_Read_Stream_LE(Buffer, *PacketLength, NULL);
468

    
469
        if (!(Pipe_BytesInPipe()))
470
          Pipe_ClearIN();
471

    
472
        Pipe_Freeze();
473

    
474
        return PIPE_RWSTREAM_NoError;
475
}
476

    
477
uint8_t RNDIS_Host_SendPacket(USB_ClassInfo_RNDIS_Host_t* const RNDISInterfaceInfo,
478
                              void* Buffer,
479
                              const uint16_t PacketLength)
480
{
481
        uint8_t ErrorCode;
482

    
483
        if ((USB_HostState != HOST_STATE_Configured) || !(RNDISInterfaceInfo->State.IsActive))
484
          return PIPE_READYWAIT_DeviceDisconnected;
485

    
486
        RNDIS_Packet_Message_t DeviceMessage;
487

    
488
        memset(&DeviceMessage, 0, sizeof(RNDIS_Packet_Message_t));
489
        DeviceMessage.MessageType   = CPU_TO_LE32(REMOTE_NDIS_PACKET_MSG);
490
        DeviceMessage.MessageLength = CPU_TO_LE32(sizeof(RNDIS_Packet_Message_t) + PacketLength);
491
        DeviceMessage.DataOffset    = CPU_TO_LE32(sizeof(RNDIS_Packet_Message_t) - sizeof(RNDIS_Message_Header_t));
492
        DeviceMessage.DataLength    = cpu_to_le32(PacketLength);
493

    
494
        Pipe_SelectPipe(RNDISInterfaceInfo->Config.DataOUTPipeNumber);
495
        Pipe_Unfreeze();
496

    
497
        if ((ErrorCode = Pipe_Write_Stream_LE(&DeviceMessage, sizeof(RNDIS_Packet_Message_t),
498
                                              NULL)) != PIPE_RWSTREAM_NoError)
499
        {
500
                return ErrorCode;
501
        }
502

    
503
        Pipe_Write_Stream_LE(Buffer, PacketLength, NULL);
504
        Pipe_ClearOUT();
505

    
506
        Pipe_Freeze();
507

    
508
        return PIPE_RWSTREAM_NoError;
509
}
510

    
511
#endif
512