This commit was manufactured by cvs2svn to create branch 'captive'.
[reactos.git] / drivers / net / ndis / ndis / protocol.c
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS NDIS library
4  * FILE:        ndis/protocol.c
5  * PURPOSE:     Routines used by NDIS protocol drivers
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  * REVISIONS:
8  *   CSH 01/08-2000 Created
9  */
10 #include <ndissys.h>
11 #include <miniport.h>
12 #include <protocol.h>
13 #include <buffer.h>
14
15
16 LIST_ENTRY ProtocolListHead;
17 KSPIN_LOCK ProtocolListLock;
18
19
20 NDIS_STATUS
21 ProIndicatePacket(
22     PLOGICAL_ADAPTER Adapter,
23     PNDIS_PACKET Packet)
24 /*
25  * FUNCTION: Indicates a packet to bound protocols
26  * ARGUMENTS:
27  *     Adapter = Pointer to logical adapter
28  *     Packet  = Pointer to packet to indicate
29  * RETURNS:
30  *     Status of operation
31  */
32 {
33     KIRQL OldIrql;
34     UINT Length;
35     UINT Total;
36
37     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
38
39 #ifdef DBG
40     MiniDisplayPacket(Packet);
41 #endif
42
43     NdisQueryPacket(Packet, NULL, NULL, NULL, &Total);
44
45     KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
46
47     Adapter->LoopPacket = Packet;
48
49     Length = CopyPacketToBuffer(
50         Adapter->LookaheadBuffer,
51         Packet,
52         0,
53         Adapter->CurLookaheadLength);
54
55     KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
56
57     if (Length > Adapter->MediumHeaderSize) {
58         MiniIndicateData(Adapter,
59                          NULL,
60                          Adapter->LookaheadBuffer,
61                          Adapter->MediumHeaderSize,
62                          &Adapter->LookaheadBuffer[Adapter->MediumHeaderSize],
63                          Length - Adapter->MediumHeaderSize,
64                          Total - Adapter->MediumHeaderSize);
65     } else {
66         MiniIndicateData(Adapter,
67                          NULL,
68                          Adapter->LookaheadBuffer,
69                          Adapter->MediumHeaderSize,
70                          NULL,
71                          0,
72                          0);
73     }
74
75     KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
76
77     Adapter->LoopPacket = NULL;
78
79     KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
80
81     return STATUS_SUCCESS;
82 }
83
84
85 NDIS_STATUS
86 ProRequest(
87     IN  NDIS_HANDLE     MacBindingHandle,
88     IN  PNDIS_REQUEST   NdisRequest)
89 /*
90  * FUNCTION: Forwards a request to an NDIS miniport
91  * ARGUMENTS:
92  *     MacBindingHandle = Adapter binding handle
93  *     NdisRequest      = Pointer to request to perform
94  * RETURNS:
95  *     Status of operation
96  */
97 {
98     KIRQL OldIrql;
99     BOOLEAN Queue;
100     NDIS_STATUS NdisStatus;
101     PADAPTER_BINDING AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle);
102     PLOGICAL_ADAPTER Adapter        = AdapterBinding->Adapter;
103
104     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
105
106     KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
107     Queue = Adapter->MiniportBusy;
108     if (Queue) {
109         MiniQueueWorkItem(Adapter,
110                           NdisWorkItemRequest,
111                           (PVOID)NdisRequest,
112                           (NDIS_HANDLE)AdapterBinding);
113     } else {
114         Adapter->MiniportBusy = TRUE;
115     }
116     KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
117
118     if (!Queue) {
119         KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
120         NdisStatus = MiniDoRequest(Adapter, NdisRequest);
121         KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
122         Adapter->MiniportBusy = FALSE;
123         if (Adapter->WorkQueueHead)
124             KeInsertQueueDpc(&Adapter->MiniportDpc, NULL, NULL);
125         KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
126         KeLowerIrql(OldIrql);
127     } else {
128         NdisStatus = NDIS_STATUS_PENDING;
129     }
130     return NdisStatus;
131 }
132
133
134 NDIS_STATUS
135 ProReset(
136     IN  NDIS_HANDLE MacBindingHandle)
137 {
138     UNIMPLEMENTED
139
140     return NDIS_STATUS_FAILURE;
141 }
142
143
144 NDIS_STATUS
145 ProSend(
146     IN  NDIS_HANDLE     MacBindingHandle,
147     IN  PNDIS_PACKET    Packet)
148 /*
149  * FUNCTION: Forwards a request to send a packet to an NDIS miniport
150  * ARGUMENTS:
151  *     MacBindingHandle = Adapter binding handle
152  *     Packet           = Pointer to NDIS packet descriptor
153  */
154 {
155     KIRQL OldIrql;
156     BOOLEAN Queue;
157     NDIS_STATUS NdisStatus;
158     PADAPTER_BINDING AdapterBinding  = GET_ADAPTER_BINDING(MacBindingHandle);
159     PLOGICAL_ADAPTER Adapter         = AdapterBinding->Adapter;
160
161     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
162
163     /* FIXME: Should queue packet if miniport returns NDIS_STATUS_RESOURCES */
164
165     Packet->Reserved[0] = (ULONG_PTR)MacBindingHandle;
166
167     KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
168     Queue = Adapter->MiniportBusy;
169
170     /* We may have to loop this packet if miniport cannot */
171     if (Adapter->NdisMiniportBlock.MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) {
172         if (MiniAdapterHasAddress(Adapter, Packet)) {
173             /* Do software loopback because miniport does not support it */
174
175             NDIS_DbgPrint(MIN_TRACE, ("Looping packet.\n"));
176
177             if (Queue) {
178
179                 /* FIXME: Packets should properbly be queued directly on the adapter instead */
180
181                 MiniQueueWorkItem(Adapter,
182                                   NdisWorkItemSendLoopback,
183                                   (PVOID)Packet,
184                                   (NDIS_HANDLE)AdapterBinding);
185             } else {
186                 Adapter->MiniportBusy = TRUE;
187             }
188             KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
189
190             if (!Queue) {
191                 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
192                 NdisStatus = ProIndicatePacket(Adapter, Packet);
193                 KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
194                 Adapter->MiniportBusy = FALSE;
195                 if (Adapter->WorkQueueHead)
196                     KeInsertQueueDpc(&Adapter->MiniportDpc, NULL, NULL);
197                 KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
198                 KeLowerIrql(OldIrql);
199                 return NdisStatus;
200             } else {
201                 return NDIS_STATUS_PENDING;
202             }
203         }
204     }
205
206     if (Queue) {
207
208         /* FIXME: Packets should properbly be queued directly on the adapter instead */
209
210         MiniQueueWorkItem(Adapter,
211                           NdisWorkItemSend,
212                           (PVOID)Packet,
213                           (NDIS_HANDLE)AdapterBinding);
214     } else {
215         Adapter->MiniportBusy = TRUE;
216     }
217     KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
218
219     if (!Queue) {
220         KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
221         NdisStatus = (*Adapter->Miniport->Chars.u1.SendHandler)(
222             Adapter->NdisMiniportBlock.MiniportAdapterContext,
223             Packet,
224             0);
225         KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
226         Adapter->MiniportBusy = FALSE;
227         if (Adapter->WorkQueueHead)
228             KeInsertQueueDpc(&Adapter->MiniportDpc, NULL, NULL);
229         KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
230         KeLowerIrql(OldIrql);
231     } else {
232         NdisStatus = NDIS_STATUS_PENDING;
233     }
234     return NdisStatus;
235 }
236
237
238 VOID
239 ProSendPackets(
240     IN  NDIS_HANDLE     NdisBindingHandle,
241     IN  PPNDIS_PACKET   PacketArray,
242     IN  UINT            NumberOfPackets)
243 {
244     UNIMPLEMENTED
245 }
246
247
248 NDIS_STATUS
249 ProTransferData(
250     IN  NDIS_HANDLE         MacBindingHandle,
251     IN  NDIS_HANDLE         MacReceiveContext,
252     IN  UINT                ByteOffset,
253     IN  UINT                BytesToTransfer,
254     IN  OUT     PNDIS_PACKET    Packet,
255     OUT PUINT               BytesTransferred)
256 /*
257  * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
258  * ARGUMENTS:
259  *     MacBindingHandle  = Adapter binding handle
260  *     MacReceiveContext = MAC receive context
261  *     ByteOffset        = Offset in packet to place data
262  *     BytesToTransfer   = Number of bytes to copy into packet
263  *     Packet            = Pointer to NDIS packet descriptor
264  *     BytesTransferred  = Address of buffer to place number of bytes copied
265  */
266 {
267     PADAPTER_BINDING AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle);
268     PLOGICAL_ADAPTER Adapter        = AdapterBinding->Adapter;
269
270     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
271
272     /* FIXME: Interrupts must be disabled for adapter */
273
274     if (Packet == Adapter->LoopPacket) {
275         /* NDIS is responsible for looping this packet */
276         NdisCopyFromPacketToPacket(Packet,
277                                    ByteOffset,
278                                    BytesToTransfer,
279                                    Adapter->LoopPacket,
280                                    0,
281                                    BytesTransferred);
282         return NDIS_STATUS_SUCCESS;
283     }
284
285     return (*Adapter->Miniport->Chars.u2.TransferDataHandler)(
286         Packet,
287         BytesTransferred,
288         Adapter->NdisMiniportBlock.MiniportAdapterContext,
289         MacReceiveContext,
290         ByteOffset,
291         BytesToTransfer);
292 }
293
294
295
296 VOID
297 EXPORT
298 NdisCloseAdapter(
299     OUT PNDIS_STATUS    Status,
300     IN  NDIS_HANDLE     NdisBindingHandle)
301 /*
302  * FUNCTION: Closes an adapter opened with NdisOpenAdapter
303  * ARGUMENTS:
304  *     Status            = Address of buffer for status information
305  *     NdisBindingHandle = Handle returned by NdisOpenAdapter
306  */
307 {
308     KIRQL OldIrql;
309     PADAPTER_BINDING AdapterBinding = GET_ADAPTER_BINDING(NdisBindingHandle);
310
311     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
312
313     /* Remove from protocol's bound adapters list */
314     KeAcquireSpinLock(&AdapterBinding->ProtocolBinding->Lock, &OldIrql);
315     RemoveEntryList(&AdapterBinding->ProtocolListEntry);
316     KeReleaseSpinLock(&AdapterBinding->ProtocolBinding->Lock, OldIrql);
317
318     /* Remove protocol from adapter's bound protocols list */
319     KeAcquireSpinLock(&AdapterBinding->Adapter->NdisMiniportBlock.Lock, &OldIrql);
320     RemoveEntryList(&AdapterBinding->AdapterListEntry);
321     KeReleaseSpinLock(&AdapterBinding->Adapter->NdisMiniportBlock.Lock, OldIrql);
322
323     ExFreePool(AdapterBinding);
324
325     *Status = NDIS_STATUS_SUCCESS;
326 }
327
328
329 VOID
330 EXPORT
331 NdisDeregisterProtocol(
332     OUT PNDIS_STATUS    Status,
333     IN NDIS_HANDLE      NdisProtocolHandle)
334 /*
335  * FUNCTION: Releases the resources allocated by NdisRegisterProtocol
336  * ARGUMENTS:
337  *     Status             = Address of buffer for status information
338  *     NdisProtocolHandle = Handle returned by NdisRegisterProtocol
339  */
340 {
341     KIRQL OldIrql;
342     PPROTOCOL_BINDING Protocol = GET_PROTOCOL_BINDING(NdisProtocolHandle);
343
344     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
345
346     /* FIXME: Make sure no adapter bindings exist */
347
348     /* Remove protocol from global list */
349     KeAcquireSpinLock(&ProtocolListLock, &OldIrql);
350     RemoveEntryList(&Protocol->ListEntry);
351     KeReleaseSpinLock(&ProtocolListLock, OldIrql);
352
353     ExFreePool(Protocol);
354
355     *Status = NDIS_STATUS_SUCCESS;
356 }
357
358
359 VOID
360 EXPORT
361 NdisOpenAdapter(
362     OUT PNDIS_STATUS    Status,
363     OUT PNDIS_STATUS    OpenErrorStatus,
364     OUT PNDIS_HANDLE    NdisBindingHandle,
365     OUT PUINT           SelectedMediumIndex,
366     IN  PNDIS_MEDIUM    MediumArray,
367     IN  UINT            MediumArraySize,
368     IN  NDIS_HANDLE     NdisProtocolHandle,
369     IN  NDIS_HANDLE     ProtocolBindingContext,
370     IN  PNDIS_STRING    AdapterName,
371     IN  UINT            OpenOptions,
372     IN  PSTRING         AddressingInformation   OPTIONAL)
373 /*
374  * FUNCTION: Opens an adapter for communication
375  * ARGUMENTS:
376  *     Status                 = Address of buffer for status information
377  *     OpenErrorStatus        = Address of buffer for secondary error code
378  *     NdisBindingHandle      = Address of buffer for adapter binding handle
379  *     SelectedMediumIndex    = Address of buffer for selected medium
380  *     MediumArray            = Pointer to an array of NDIS_MEDIUMs called can support
381  *     MediumArraySize        = Number of elements in MediumArray
382  *     NdisProtocolHandle     = Handle returned by NdisRegisterProtocol
383  *     ProtocolBindingContext = Pointer to caller suplied context area
384  *     AdapterName            = Pointer to buffer with name of adapter
385  *     OpenOptions            = Bitmask with flags passed to next-lower driver
386  *     AddressingInformation  = Optional pointer to buffer with NIC specific information
387  */
388 {
389     UINT i;
390     BOOLEAN Found;
391     PLOGICAL_ADAPTER Adapter;
392     PADAPTER_BINDING AdapterBinding;
393     PPROTOCOL_BINDING Protocol = GET_PROTOCOL_BINDING(NdisProtocolHandle);
394
395     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
396
397     Adapter = MiniLocateDevice(AdapterName);
398     if (!Adapter) {
399         NDIS_DbgPrint(MIN_TRACE, ("Adapter not found.\n"));
400         *Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
401         return;
402     }
403
404     /* Find the media type in the list provided by the protocol driver */
405     Found = FALSE;
406     for (i = 0; i < MediumArraySize; i++) {
407         if (Adapter->NdisMiniportBlock.MediaType == MediumArray[i]) {
408             *SelectedMediumIndex = i;
409             Found = TRUE;
410             break;
411         }
412     }
413
414     if (!Found) {
415         NDIS_DbgPrint(MIN_TRACE, ("Medium is not supported.\n"));
416         *Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
417         return;
418     }
419
420     AdapterBinding = ExAllocatePool(NonPagedPool, sizeof(ADAPTER_BINDING));
421     if (!AdapterBinding) {
422         NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
423         *Status = NDIS_STATUS_RESOURCES;
424         return;
425     }
426
427     RtlZeroMemory(AdapterBinding, sizeof(ADAPTER_BINDING));
428
429     AdapterBinding->ProtocolBinding        = Protocol;
430     AdapterBinding->Adapter                = Adapter;
431     AdapterBinding->NdisOpenBlock.ProtocolBindingContext = ProtocolBindingContext;
432
433     /* Set fields required by some NDIS macros */
434     AdapterBinding->NdisOpenBlock.MacBindingHandle = (NDIS_HANDLE)AdapterBinding;
435     
436     /* Set handlers (some NDIS macros require these) */
437
438     AdapterBinding->NdisOpenBlock.RequestHandler      = ProRequest;
439     AdapterBinding->NdisOpenBlock.ResetHandler        = ProReset;
440     AdapterBinding->NdisOpenBlock.u1.SendHandler      = ProSend;
441     AdapterBinding->NdisOpenBlock.SendPacketsHandler  = ProSendPackets;
442     AdapterBinding->NdisOpenBlock.TransferDataHandler = ProTransferData;
443
444     /* Put on protocol's bound adapters list */
445     ExInterlockedInsertTailList(&Protocol->AdapterListHead,
446                                 &AdapterBinding->ProtocolListEntry,
447                                 &Protocol->Lock);
448
449     /* Put protocol on adapter's bound protocols list */
450     ExInterlockedInsertTailList(&Adapter->ProtocolListHead,
451                                 &AdapterBinding->AdapterListEntry,
452                                 &Adapter->NdisMiniportBlock.Lock);
453
454     *NdisBindingHandle = (NDIS_HANDLE)AdapterBinding;
455
456     *Status = NDIS_STATUS_SUCCESS;
457 }
458
459
460 VOID
461 EXPORT
462 NdisRegisterProtocol(
463     OUT PNDIS_STATUS                    Status,
464     OUT PNDIS_HANDLE                    NdisProtocolHandle,
465     IN  PNDIS_PROTOCOL_CHARACTERISTICS  ProtocolCharacteristics,
466     IN  UINT                            CharacteristicsLength)
467 /*
468  * FUNCTION: Registers an NDIS driver's ProtocolXxx entry points
469  * ARGUMENTS:
470  *     Status                  = Address of buffer for status information
471  *     NdisProtocolHandle      = Address of buffer for handle used to identify the driver
472  *     ProtocolCharacteristics = Pointer to NDIS_PROTOCOL_CHARACTERISTICS structure
473  *     CharacteristicsLength   = Size of structure which ProtocolCharacteristics targets
474  */
475 {
476     PPROTOCOL_BINDING Protocol;
477     NTSTATUS NtStatus;
478     UINT MinSize;
479
480     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
481
482     switch (ProtocolCharacteristics->MajorNdisVersion) {
483     case 0x03:
484         MinSize = sizeof(NDIS30_PROTOCOL_CHARACTERISTICS_S);
485         break;
486
487     case 0x04:
488         MinSize = sizeof(NDIS40_PROTOCOL_CHARACTERISTICS_S);
489         break;
490
491     case 0x05:
492         MinSize = sizeof(NDIS50_PROTOCOL_CHARACTERISTICS_S);
493         break;
494
495     default:
496         *Status = NDIS_STATUS_BAD_VERSION;
497         return;
498     }
499
500     if (CharacteristicsLength < MinSize) {
501         NDIS_DbgPrint(DEBUG_PROTOCOL, ("Bad protocol characteristics.\n"));
502         *Status = NDIS_STATUS_BAD_CHARACTERISTICS;
503         return;
504     }
505
506     Protocol = ExAllocatePool(NonPagedPool, sizeof(PROTOCOL_BINDING));
507     if (!Protocol) {
508         NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
509         *Status = NDIS_STATUS_RESOURCES;
510         return;
511     }
512
513     RtlZeroMemory(Protocol, sizeof(PROTOCOL_BINDING));
514     RtlCopyMemory(&Protocol->Chars, ProtocolCharacteristics, MinSize);
515
516     NtStatus = RtlUpcaseUnicodeString(&Protocol->Chars.Name,
517                                       &ProtocolCharacteristics->Name,
518                                       TRUE);
519     if (!NT_SUCCESS(NtStatus)) {
520         NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
521         ExFreePool(Protocol);
522         *Status = NDIS_STATUS_RESOURCES;
523         return;
524     }
525
526     KeInitializeSpinLock(&Protocol->Lock);
527
528     Protocol->RefCount = 1;
529
530     InitializeListHead(&Protocol->AdapterListHead);
531
532     /* Put protocol binding on global list */
533     ExInterlockedInsertTailList(&ProtocolListHead,
534                                 &Protocol->ListEntry,
535                                 &ProtocolListLock);
536
537     *NdisProtocolHandle = Protocol;
538     *Status             = NDIS_STATUS_SUCCESS;
539 }
540
541
542 VOID
543 EXPORT
544 NdisRequest(
545     OUT PNDIS_STATUS    Status,
546     IN  NDIS_HANDLE     NdisBindingHandle,
547     IN  PNDIS_REQUEST   NdisRequest)
548 /*
549  * FUNCTION: Forwards a request to an NDIS driver
550  * ARGUMENTS:
551  *     Status            = Address of buffer for status information
552  *     NdisBindingHandle = Adapter binding handle
553  *     NdisRequest       = Pointer to request to perform
554  */
555 {
556     *Status = ProRequest(NdisBindingHandle, NdisRequest);
557 }
558
559
560 VOID
561 EXPORT
562 NdisReset(
563     OUT PNDIS_STATUS    Status,
564     IN  NDIS_HANDLE     NdisBindingHandle)
565 {
566     *Status = ProReset(NdisBindingHandle);
567 }
568
569
570 VOID
571 EXPORT
572 NdisSend(
573     OUT PNDIS_STATUS    Status,
574     IN  NDIS_HANDLE     NdisBindingHandle,
575     IN  PNDIS_PACKET    Packet)
576 /*
577  * FUNCTION: Forwards a request to send a packet
578  * ARGUMENTS:
579  *     Status             = Address of buffer for status information
580  *     NdisBindingHandle  = Adapter binding handle
581  *     Packet             = Pointer to NDIS packet descriptor
582  */
583 {
584     *Status = ProSend(NdisBindingHandle, Packet);
585 }
586
587
588 VOID
589 EXPORT
590 NdisSendPackets(
591     IN  NDIS_HANDLE     NdisBindingHandle,
592     IN  PPNDIS_PACKET   PacketArray,
593     IN  UINT            NumberOfPackets)
594 {
595     ProSendPackets(NdisBindingHandle, PacketArray, NumberOfPackets);
596 }
597
598
599 VOID
600 EXPORT
601 NdisTransferData(
602     OUT     PNDIS_STATUS    Status,
603     IN      NDIS_HANDLE     NdisBindingHandle,
604     IN      NDIS_HANDLE     MacReceiveContext,
605     IN      UINT            ByteOffset,
606     IN      UINT            BytesToTransfer,
607     IN OUT      PNDIS_PACKET    Packet,
608     OUT     PUINT           BytesTransferred)
609 /*
610  * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
611  * ARGUMENTS:
612  *     Status            = Address of buffer for status information
613  *     NdisBindingHandle = Adapter binding handle
614  *     MacReceiveContext = MAC receive context
615  *     ByteOffset        = Offset in packet to place data
616  *     BytesToTransfer   = Number of bytes to copy into packet
617  *     Packet            = Pointer to NDIS packet descriptor
618  *     BytesTransferred  = Address of buffer to place number of bytes copied
619  */
620 {
621     *Status = ProTransferData(NdisBindingHandle,
622                               MacReceiveContext,
623                               ByteOffset,
624                               BytesToTransfer,
625                               Packet,
626                               BytesTransferred);
627 }
628
629 /* EOF */