]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/MnpDxe/MnpIo.c
code scrub fix
[mirror_edk2.git] / MdeModulePkg / Universal / Network / MnpDxe / MnpIo.c
1 /** @file
2 Implementation of Managed Network Protocol I/O functions.
3
4 Copyright (c) 2005 - 2007, Intel Corporation.<BR>
5
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "MnpImpl.h"
17 #include <Library/NetLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/BaseLib.h>
20 #include <Library/MemoryAllocationLib.h>
21
22
23 /**
24 Validates the Mnp transmit token.
25
26 @param[in] Instance Pointer to the Mnp instance context data.
27 @param[in] Token Pointer to the transmit token to check.
28
29 @return The Token is valid or not.
30
31 **/
32 BOOLEAN
33 MnpIsValidTxToken (
34 IN MNP_INSTANCE_DATA *Instance,
35 IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN *Token
36 )
37 {
38 MNP_SERVICE_DATA *MnpServiceData;
39 EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData;
40 UINT32 Index;
41 UINT32 TotalLength;
42 EFI_MANAGED_NETWORK_FRAGMENT_DATA *FragmentTable;
43
44 MnpServiceData = Instance->MnpServiceData;
45 NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);
46
47 TxData = Token->Packet.TxData;
48
49 if ((Token->Event == NULL) || (TxData == NULL) || (TxData->FragmentCount == 0)) {
50 //
51 // The token is invalid if the Event is NULL, or the TxData is NULL, or
52 // the fragment count is zero.
53 //
54 DEBUG ((EFI_D_WARN, "MnpIsValidTxToken: Invalid Token.\n"));
55 return FALSE;
56 }
57
58 if ((TxData->DestinationAddress != NULL) && (TxData->HeaderLength != 0)) {
59 //
60 // The token is invalid if the HeaderLength isn't zero while the DestinationAddress
61 // is NULL (The destination address is already put into the packet).
62 //
63 DEBUG ((EFI_D_WARN, "MnpIsValidTxToken: DestinationAddress isn't NULL, HeaderLength must be 0.\n"));
64 return FALSE;
65 }
66
67 TotalLength = 0;
68 FragmentTable = TxData->FragmentTable;
69 for (Index = 0; Index < TxData->FragmentCount; Index++) {
70
71 if ((FragmentTable[Index].FragmentLength == 0) || (FragmentTable[Index].FragmentBuffer == NULL)) {
72 //
73 // The token is invalid if any FragmentLength is zero or any FragmentBuffer is NULL.
74 //
75 DEBUG ((EFI_D_WARN, "MnpIsValidTxToken: Invalid FragmentLength or FragmentBuffer.\n"));
76 return FALSE;
77 }
78
79 TotalLength += FragmentTable[Index].FragmentLength;
80 }
81
82 if ((TxData->DestinationAddress == NULL) && (FragmentTable[0].FragmentLength < TxData->HeaderLength)) {
83 //
84 // Media header is split between fragments.
85 //
86 return FALSE;
87 }
88
89 if (TotalLength != (TxData->DataLength + TxData->HeaderLength)) {
90 //
91 // The length calculated from the fragment information doesn't equal to the
92 // sum of the DataLength and the HeaderLength.
93 //
94 DEBUG ((EFI_D_WARN, "MnpIsValidTxData: Invalid Datalength compared with the sum of fragment length.\n"));
95 return FALSE;
96 }
97
98 if (TxData->DataLength > MnpServiceData->Mtu) {
99 //
100 // The total length is larger than the MTU.
101 //
102 DEBUG ((EFI_D_WARN, "MnpIsValidTxData: TxData->DataLength exceeds Mtu.\n"));
103 return FALSE;
104 }
105
106 return TRUE;
107 }
108
109
110 /**
111 Build the packet to transmit from the TxData passed in.
112
113 @param MnpServiceData Pointer to the mnp service context data.
114 @param TxData Pointer to the transmit data containing the
115 information to build the packet.
116 @param PktBuf Pointer to record the address of the packet.
117 @param PktLen Pointer to a UINT32 variable used to record the
118 packet's length.
119
120 **/
121 VOID
122 MnpBuildTxPacket (
123 IN MNP_SERVICE_DATA *MnpServiceData,
124 IN EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData,
125 OUT UINT8 **PktBuf,
126 OUT UINT32 *PktLen
127 )
128 {
129 EFI_SIMPLE_NETWORK_MODE *SnpMode;
130 UINT8 *DstPos;
131 UINT16 Index;
132
133 if ((TxData->DestinationAddress == NULL) && (TxData->FragmentCount == 1)) {
134 //
135 // Media header is in FragmentTable and there is only one fragment,
136 // use fragment buffer directly.
137 //
138 *PktBuf = TxData->FragmentTable[0].FragmentBuffer;
139 *PktLen = TxData->FragmentTable[0].FragmentLength;
140 } else {
141 //
142 // Either media header isn't in FragmentTable or there is more than
143 // one fragment, copy the data into the packet buffer. Reserve the
144 // media header space if necessary.
145 //
146 SnpMode = MnpServiceData->Snp->Mode;
147 DstPos = MnpServiceData->TxBuf;
148
149 *PktLen = 0;
150 if (TxData->DestinationAddress != NULL) {
151 //
152 // If dest address is not NULL, move DstPos to reserve space for the
153 // media header. Add the media header length to buflen.
154 //
155 DstPos += SnpMode->MediaHeaderSize;
156 *PktLen += SnpMode->MediaHeaderSize;
157 }
158
159 for (Index = 0; Index < TxData->FragmentCount; Index++) {
160 //
161 // Copy the data.
162 //
163 CopyMem (
164 DstPos,
165 TxData->FragmentTable[Index].FragmentBuffer,
166 TxData->FragmentTable[Index].FragmentLength
167 );
168 DstPos += TxData->FragmentTable[Index].FragmentLength;
169 }
170
171 //
172 // Set the buffer pointer and the buffer length.
173 //
174 *PktBuf = MnpServiceData->TxBuf;
175 *PktLen += TxData->DataLength + TxData->HeaderLength;
176 }
177 }
178
179
180 /**
181 Synchronously send out the packet.
182
183 @param[in] MnpServiceData Pointer to the mnp service context data.
184 @param[in] Packet Pointer to the pakcet buffer.
185 @param[in] Length The length of the packet.
186 @param[in] Token Pointer to the token the packet generated from.
187
188 @retval EFI_SUCCESS The packet is sent out.
189 @retval EFI_TIMEOUT Time out occurs, the packet isn't sent.
190 @retval EFI_DEVICE_ERROR An unexpected network error occurs.
191
192 **/
193 EFI_STATUS
194 MnpSyncSendPacket (
195 IN MNP_SERVICE_DATA *MnpServiceData,
196 IN UINT8 *Packet,
197 IN UINT32 Length,
198 IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN *Token
199 )
200 {
201 EFI_STATUS Status;
202 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
203 EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData;
204 UINT32 HeaderSize;
205 UINT8 *TxBuf;
206
207 Snp = MnpServiceData->Snp;
208 TxData = Token->Packet.TxData;
209
210 HeaderSize = Snp->Mode->MediaHeaderSize - TxData->HeaderLength;
211
212 //
213 // Start the timeout event.
214 //
215 Status = gBS->SetTimer (
216 MnpServiceData->TxTimeoutEvent,
217 TimerRelative,
218 MNP_TX_TIMEOUT_TIME
219 );
220 if (EFI_ERROR (Status)) {
221
222 goto SIGNAL_TOKEN;
223 }
224
225 for (;;) {
226 //
227 // Transmit the packet through SNP.
228 //
229 Status = Snp->Transmit (
230 Snp,
231 HeaderSize,
232 Length,
233 Packet,
234 TxData->SourceAddress,
235 TxData->DestinationAddress,
236 &TxData->ProtocolType
237 );
238 if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_READY)) {
239
240 Status = EFI_DEVICE_ERROR;
241 break;
242 }
243
244 //
245 // If Status is EFI_SUCCESS, the packet is put in the transmit queue.
246 // if Status is EFI_NOT_READY, the transmit engine of the network interface is busy.
247 // Both need to sync SNP.
248 //
249 TxBuf = NULL;
250 do {
251 //
252 // Get the recycled transmit buffer status.
253 //
254 Snp->GetStatus (Snp, NULL, (VOID **) &TxBuf);
255
256 if (!EFI_ERROR (gBS->CheckEvent (MnpServiceData->TxTimeoutEvent))) {
257
258 Status = EFI_TIMEOUT;
259 break;
260 }
261 } while (TxBuf == NULL);
262
263 if ((Status == EFI_SUCCESS) || (Status == EFI_TIMEOUT)) {
264
265 break;
266 } else {
267 //
268 // Status is EFI_NOT_READY. Restart the timer event and call Snp->Transmit again.
269 //
270 gBS->SetTimer (
271 MnpServiceData->TxTimeoutEvent,
272 TimerRelative,
273 MNP_TX_TIMEOUT_TIME
274 );
275 }
276 }
277
278 //
279 // Cancel the timer event.
280 //
281 gBS->SetTimer (MnpServiceData->TxTimeoutEvent, TimerCancel, 0);
282
283 SIGNAL_TOKEN:
284
285 Token->Status = Status;
286 gBS->SignalEvent (Token->Event);
287
288 //
289 // Dispatch the DPC queued by the NotifyFunction of Token->Event.
290 //
291 NetLibDispatchDpc ();
292
293 return EFI_SUCCESS;
294 }
295
296
297 /**
298 Try to deliver the received packet to the instance.
299
300 @param[in] Instance Pointer to the mnp instance context data.
301
302 @retval EFI_SUCCESS The received packet is delivered, or there is no
303 packet to deliver, or there is no available receive
304 token.
305 @retval EFI_OUT_OF_RESOURCES The deliver fails due to lack of memory resource.
306
307 **/
308 EFI_STATUS
309 MnpInstanceDeliverPacket (
310 IN MNP_INSTANCE_DATA *Instance
311 )
312 {
313 MNP_SERVICE_DATA *MnpServiceData;
314 MNP_RXDATA_WRAP *RxDataWrap;
315 NET_BUF *DupNbuf;
316 EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData;
317 EFI_SIMPLE_NETWORK_MODE *SnpMode;
318 EFI_MANAGED_NETWORK_COMPLETION_TOKEN *RxToken;
319
320 MnpServiceData = Instance->MnpServiceData;
321 NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);
322
323 if (NetMapIsEmpty (&Instance->RxTokenMap) || IsListEmpty (&Instance->RcvdPacketQueue)) {
324 //
325 // No pending received data or no available receive token, return.
326 //
327 return EFI_SUCCESS;
328 }
329
330 ASSERT (Instance->RcvdPacketQueueSize != 0);
331
332 RxDataWrap = NET_LIST_HEAD (&Instance->RcvdPacketQueue, MNP_RXDATA_WRAP, WrapEntry);
333 if (RxDataWrap->Nbuf->RefCnt > 2) {
334 //
335 // There are other instances share this Nbuf, duplicate to get a
336 // copy to allow the instance to do R/W operations.
337 //
338 DupNbuf = MnpAllocNbuf (MnpServiceData);
339 if (DupNbuf == NULL) {
340 DEBUG ((EFI_D_WARN, "MnpDeliverPacket: Failed to allocate a free Nbuf.\n"));
341
342 return EFI_OUT_OF_RESOURCES;
343 }
344
345 //
346 // Duplicate the net buffer.
347 //
348 NetbufDuplicate (RxDataWrap->Nbuf, DupNbuf, 0);
349 MnpFreeNbuf (MnpServiceData, RxDataWrap->Nbuf);
350 RxDataWrap->Nbuf = DupNbuf;
351 }
352
353 //
354 // All resources are OK, remove the packet from the queue.
355 //
356 NetListRemoveHead (&Instance->RcvdPacketQueue);
357 Instance->RcvdPacketQueueSize--;
358
359 RxData = &RxDataWrap->RxData;
360 SnpMode = MnpServiceData->Snp->Mode;
361
362 //
363 // Set all the buffer pointers.
364 //
365 RxData->MediaHeader = NetbufGetByte (RxDataWrap->Nbuf, 0, NULL);
366 RxData->DestinationAddress = RxData->MediaHeader;
367 RxData->SourceAddress = (UINT8 *) RxData->MediaHeader + SnpMode->HwAddressSize;
368 RxData->PacketData = (UINT8 *) RxData->MediaHeader + SnpMode->MediaHeaderSize;
369
370 //
371 // Insert this RxDataWrap into the delivered queue.
372 //
373 InsertTailList (&Instance->RxDeliveredPacketQueue, &RxDataWrap->WrapEntry);
374
375 //
376 // Get the receive token from the RxTokenMap.
377 //
378 RxToken = NetMapRemoveHead (&Instance->RxTokenMap, NULL);
379
380 //
381 // Signal this token's event.
382 //
383 RxToken->Packet.RxData = &RxDataWrap->RxData;
384 RxToken->Status = EFI_SUCCESS;
385 gBS->SignalEvent (RxToken->Event);
386
387 return EFI_SUCCESS;
388 }
389
390
391 /**
392 Deliver the received packet for the instances belonging to the MnpServiceData.
393
394 @param MnpServiceData Pointer to the mnp service context data.
395
396 **/
397 VOID
398 MnpDeliverPacket (
399 IN MNP_SERVICE_DATA *MnpServiceData
400 )
401 {
402 LIST_ENTRY *Entry;
403 MNP_INSTANCE_DATA *Instance;
404
405 NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);
406
407 NET_LIST_FOR_EACH (Entry, &MnpServiceData->ChildrenList) {
408 Instance = NET_LIST_USER_STRUCT (Entry, MNP_INSTANCE_DATA, InstEntry);
409 NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);
410
411 //
412 // Try to deliver packet for this instance.
413 //
414 MnpInstanceDeliverPacket (Instance);
415 }
416 }
417
418
419 /**
420 Recycle the RxData and other resources used to hold and deliver the received
421 packet.
422
423 @param Event The event this notify function registered to.
424 @param Context Pointer to the context data registerd to the Event.
425
426 **/
427 VOID
428 EFIAPI
429 MnpRecycleRxData (
430 IN EFI_EVENT Event,
431 IN VOID *Context
432 )
433 {
434 MNP_RXDATA_WRAP *RxDataWrap;
435 MNP_SERVICE_DATA *MnpServiceData;
436
437 ASSERT (Context != NULL);
438
439 RxDataWrap = (MNP_RXDATA_WRAP *) Context;
440 NET_CHECK_SIGNATURE (RxDataWrap->Instance, MNP_INSTANCE_DATA_SIGNATURE);
441
442 ASSERT (RxDataWrap->Nbuf != NULL);
443
444 MnpServiceData = RxDataWrap->Instance->MnpServiceData;
445 NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);
446
447 //
448 // Free this Nbuf.
449 //
450 MnpFreeNbuf (MnpServiceData, RxDataWrap->Nbuf);
451 RxDataWrap->Nbuf = NULL;
452
453 //
454 // Close the recycle event.
455 //
456 gBS->CloseEvent (RxDataWrap->RxData.RecycleEvent);
457
458 //
459 // Remove this Wrap entry from the list.
460 //
461 RemoveEntryList (&RxDataWrap->WrapEntry);
462
463 gBS->FreePool (RxDataWrap);
464 }
465
466
467 /**
468 Queue the received packet into instance's receive queue.
469
470 @param Instance Pointer to the mnp instance context data.
471 @param RxDataWrap Pointer to the Wrap structure containing the
472 received data and other information.
473
474 **/
475 VOID
476 MnpQueueRcvdPacket (
477 IN MNP_INSTANCE_DATA *Instance,
478 IN MNP_RXDATA_WRAP *RxDataWrap
479 )
480 {
481 MNP_RXDATA_WRAP *OldRxDataWrap;
482
483 NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);
484
485 //
486 // Check the queue size. If it exceeds the limit, drop one packet
487 // from the head.
488 //
489 if (Instance->RcvdPacketQueueSize == MNP_MAX_RCVD_PACKET_QUE_SIZE) {
490
491 DEBUG ((EFI_D_WARN, "MnpQueueRcvdPacket: Drop one packet bcz queue size limit reached.\n"));
492
493 //
494 // Get the oldest packet.
495 //
496 OldRxDataWrap = NET_LIST_HEAD (
497 &Instance->RcvdPacketQueue,
498 MNP_RXDATA_WRAP,
499 WrapEntry
500 );
501
502 //
503 // Recycle this OldRxDataWrap, this entry will be removed by the callee.
504 //
505 MnpRecycleRxData (NULL, (VOID *) OldRxDataWrap);
506 Instance->RcvdPacketQueueSize--;
507 }
508
509 //
510 // Update the timeout tick using the configured parameter.
511 //
512 RxDataWrap->TimeoutTick = Instance->ConfigData.ReceivedQueueTimeoutValue;
513
514 //
515 // Insert this Wrap into the instance queue.
516 //
517 InsertTailList (&Instance->RcvdPacketQueue, &RxDataWrap->WrapEntry);
518 Instance->RcvdPacketQueueSize++;
519 }
520
521
522 /**
523 Match the received packet with the instance receive filters.
524
525 @param[in] Instance Pointer to the mnp instance context data.
526 @param[in] RxData Pointer to the EFI_MANAGED_NETWORK_RECEIVE_DATA.
527 @param[in] GroupAddress Pointer to the GroupAddress, the GroupAddress is
528 non-NULL and it contains the destination multicast
529 mac address of the received packet if the packet
530 destinated to a multicast mac address.
531 @param[in] PktAttr The received packets attribute.
532
533 @return The received packet matches the instance's receive filters or not.
534
535 **/
536 BOOLEAN
537 MnpMatchPacket (
538 IN MNP_INSTANCE_DATA *Instance,
539 IN EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData,
540 IN MNP_GROUP_ADDRESS *GroupAddress OPTIONAL,
541 IN UINT8 PktAttr
542 )
543 {
544 EFI_MANAGED_NETWORK_CONFIG_DATA *ConfigData;
545 LIST_ENTRY *Entry;
546 MNP_GROUP_CONTROL_BLOCK *GroupCtrlBlk;
547
548 NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);
549
550 ConfigData = &Instance->ConfigData;
551
552 //
553 // Check the protocol type.
554 //
555 if ((ConfigData->ProtocolTypeFilter != 0) && (ConfigData->ProtocolTypeFilter != RxData->ProtocolType)) {
556 return FALSE;
557 }
558
559 if (ConfigData->EnablePromiscuousReceive) {
560 //
561 // Always match if this instance is configured to be promiscuous.
562 //
563 return TRUE;
564 }
565
566 //
567 // The protocol type is matched, check receive filter, include unicast and broadcast.
568 //
569 if ((Instance->ReceiveFilter & PktAttr) != 0) {
570 return TRUE;
571 }
572
573 //
574 // Check multicast addresses.
575 //
576 if (ConfigData->EnableMulticastReceive && RxData->MulticastFlag) {
577
578 ASSERT (GroupAddress != NULL);
579
580 NET_LIST_FOR_EACH (Entry, &Instance->GroupCtrlBlkList) {
581
582 GroupCtrlBlk = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_CONTROL_BLOCK, CtrlBlkEntry);
583 if (GroupCtrlBlk->GroupAddress == GroupAddress) {
584 //
585 // The instance is configured to receiveing packets destinated to this
586 // multicast address.
587 //
588 return TRUE;
589 }
590 }
591 }
592
593 //
594 // No match.
595 //
596 return FALSE;
597 }
598
599
600 /**
601 Analyse the received packets.
602
603 @param MnpServiceData Pointer to the mnp service context data.
604 @param Nbuf Pointer to the net buffer holding the received
605 packet.
606 @param RxData Pointer to the buffer used to save the analysed
607 result in EFI_MANAGED_NETWORK_RECEIVE_DATA.
608 @param GroupAddress Pointer to pointer to a MNP_GROUP_ADDRESS used to
609 pass out the address of the multicast address the
610 received packet destinated to.
611 @param PktAttr Pointer to the buffer used to save the analysed
612 packet attribute.
613
614 **/
615 VOID
616 MnpAnalysePacket (
617 IN MNP_SERVICE_DATA *MnpServiceData,
618 IN NET_BUF *Nbuf,
619 IN EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData,
620 OUT MNP_GROUP_ADDRESS **GroupAddress,
621 OUT UINT8 *PktAttr
622 )
623 {
624 EFI_SIMPLE_NETWORK_MODE *SnpMode;
625 UINT8 *BufPtr;
626 LIST_ENTRY *Entry;
627
628 SnpMode = MnpServiceData->Snp->Mode;
629
630 //
631 // Get the packet buffer.
632 //
633 BufPtr = NetbufGetByte (Nbuf, 0, NULL);
634 ASSERT (BufPtr != NULL);
635
636 //
637 // Set the initial values.
638 //
639 RxData->BroadcastFlag = FALSE;
640 RxData->MulticastFlag = FALSE;
641 RxData->PromiscuousFlag = FALSE;
642 *PktAttr = UNICAST_PACKET;
643
644 if (!NET_MAC_EQUAL (&SnpMode->CurrentAddress, BufPtr, SnpMode->HwAddressSize)) {
645 //
646 // This packet isn't destinated to our current mac address, it't not unicast.
647 //
648 *PktAttr = 0;
649
650 if (NET_MAC_EQUAL (&SnpMode->BroadcastAddress, BufPtr, SnpMode->HwAddressSize)) {
651 //
652 // It's broadcast.
653 //
654 RxData->BroadcastFlag = TRUE;
655 *PktAttr = BROADCAST_PACKET;
656 } else if ((*BufPtr & 0x01) == 0x1) {
657 //
658 // It's multicast, try to match the multicast filters.
659 //
660 NET_LIST_FOR_EACH (Entry, &MnpServiceData->GroupAddressList) {
661
662 *GroupAddress = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_ADDRESS, AddrEntry);
663 if (NET_MAC_EQUAL (BufPtr, &((*GroupAddress)->Address), SnpMode->HwAddressSize)) {
664 RxData->MulticastFlag = TRUE;
665 break;
666 }
667 }
668
669 if (!RxData->MulticastFlag) {
670 //
671 // No match, set GroupAddress to NULL. This multicast packet must
672 // be the result of PROMISUCOUS or PROMISUCOUS_MULTICAST flag is on.
673 //
674 *GroupAddress = NULL;
675 RxData->PromiscuousFlag = TRUE;
676
677 if (MnpServiceData->PromiscuousCount == 0) {
678 //
679 // Skip the below code, there is no receiver of this packet.
680 //
681 return ;
682 }
683 }
684 } else {
685 RxData->PromiscuousFlag = TRUE;
686 }
687 }
688
689 ZeroMem (&RxData->Timestamp, sizeof (EFI_TIME));
690
691 //
692 // Fill the common parts of RxData.
693 //
694 RxData->PacketLength = Nbuf->TotalSize;
695 RxData->HeaderLength = SnpMode->MediaHeaderSize;
696 RxData->AddressLength = SnpMode->HwAddressSize;
697 RxData->DataLength = RxData->PacketLength - RxData->HeaderLength;
698 RxData->ProtocolType = NTOHS (*(UINT16 *) (BufPtr + 2 * SnpMode->HwAddressSize));
699 }
700
701
702 /**
703 Wrap the RxData.
704
705 @param[in] Instance Pointer to the mnp instance context data.
706 @param[in] RxData Pointer to the receive data to wrap.
707
708 @return Pointer to a MNP_RXDATA_WRAP which wraps the RxData.
709
710 **/
711 MNP_RXDATA_WRAP *
712 MnpWrapRxData (
713 IN MNP_INSTANCE_DATA *Instance,
714 IN EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData
715 )
716 {
717 EFI_STATUS Status;
718 MNP_RXDATA_WRAP *RxDataWrap;
719
720 //
721 // Allocate memory.
722 //
723 RxDataWrap = AllocatePool (sizeof (MNP_RXDATA_WRAP));
724 if (RxDataWrap == NULL) {
725 DEBUG ((EFI_D_ERROR, "MnpDispatchPacket: Failed to allocate a MNP_RXDATA_WRAP.\n"));
726 return NULL;
727 }
728
729 RxDataWrap->Instance = Instance;
730
731 //
732 // Fill the RxData in RxDataWrap,
733 //
734 CopyMem (&RxDataWrap->RxData, RxData, sizeof (RxDataWrap->RxData));
735
736 //
737 // Create the recycle event.
738 //
739 Status = gBS->CreateEvent (
740 EVT_NOTIFY_SIGNAL,
741 TPL_NOTIFY,
742 MnpRecycleRxData,
743 RxDataWrap,
744 &RxDataWrap->RxData.RecycleEvent
745 );
746 if (EFI_ERROR (Status)) {
747
748 DEBUG ((EFI_D_ERROR, "MnpDispatchPacket: gBS->CreateEvent failed, %r.\n", Status));
749 gBS->FreePool (RxDataWrap);
750 return NULL;
751 }
752
753 return RxDataWrap;
754 }
755
756
757 /**
758 Enqueue the received the packets to the instances belonging to the
759 MnpServiceData.
760
761 @param MnpServiceData Pointer to the mnp service context data.
762 @param Nbuf Pointer to the net buffer representing the received
763 packet.
764
765 **/
766 VOID
767 MnpEnqueuePacket (
768 IN MNP_SERVICE_DATA *MnpServiceData,
769 IN NET_BUF *Nbuf
770 )
771 {
772 LIST_ENTRY *Entry;
773 MNP_INSTANCE_DATA *Instance;
774 EFI_MANAGED_NETWORK_RECEIVE_DATA RxData;
775 UINT8 PktAttr;
776 MNP_GROUP_ADDRESS *GroupAddress;
777 MNP_RXDATA_WRAP *RxDataWrap;
778
779
780 GroupAddress = NULL;
781 //
782 // First, analyse the packet header.
783 //
784 MnpAnalysePacket (MnpServiceData, Nbuf, &RxData, &GroupAddress, &PktAttr);
785
786 if (RxData.PromiscuousFlag && (MnpServiceData->PromiscuousCount == 0)) {
787 //
788 // No receivers, no more action need.
789 //
790 return ;
791 }
792
793 //
794 // Iterate the children to find match.
795 //
796 NET_LIST_FOR_EACH (Entry, &MnpServiceData->ChildrenList) {
797
798 Instance = NET_LIST_USER_STRUCT (Entry, MNP_INSTANCE_DATA, InstEntry);
799 NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);
800
801 if (!Instance->Configured) {
802 continue;
803 }
804
805 //
806 // Check the packet against the instance receive filters.
807 //
808 if (MnpMatchPacket (Instance, &RxData, GroupAddress, PktAttr)) {
809
810 //
811 // Wrap the RxData.
812 //
813 RxDataWrap = MnpWrapRxData (Instance, &RxData);
814 if (RxDataWrap == NULL) {
815 continue;
816 }
817
818 //
819 // Associate RxDataWrap with Nbuf and increase the RefCnt.
820 //
821 RxDataWrap->Nbuf = Nbuf;
822 NET_GET_REF (RxDataWrap->Nbuf);
823
824 //
825 // Queue the packet into the instance queue.
826 //
827 MnpQueueRcvdPacket (Instance, RxDataWrap);
828 }
829 }
830 }
831
832
833 /**
834 Try to receive a packet and deliver it.
835
836 @param[in] MnpServiceData Pointer to the mnp service context data.
837
838 @retval EFI_SUCCESS add return value to function comment
839 @retval EFI_NOT_STARTED The simple network protocol is not started.
840 @retval EFI_NOT_READY No packet received.
841 @retval EFI_DEVICE_ERROR An unexpected error occurs.
842
843 **/
844 EFI_STATUS
845 MnpReceivePacket (
846 IN MNP_SERVICE_DATA *MnpServiceData
847 )
848 {
849 EFI_STATUS Status;
850 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
851 NET_BUF *Nbuf;
852 UINT8 *BufPtr;
853 UINTN BufLen;
854 UINTN HeaderSize;
855 UINT32 Trimmed;
856
857 NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);
858
859 Snp = MnpServiceData->Snp;
860 if (Snp->Mode->State != EfiSimpleNetworkInitialized) {
861 //
862 // The simple network protocol is not started.
863 //
864 return EFI_NOT_STARTED;
865 }
866
867 if (IsListEmpty (&MnpServiceData->ChildrenList)) {
868 //
869 // There is no child, no need to receive packets.
870 //
871 return EFI_SUCCESS;
872 }
873
874 if (MnpServiceData->RxNbufCache == NULL) {
875 //
876 // Try to get a new buffer as there may be buffers recycled.
877 //
878 MnpServiceData->RxNbufCache = MnpAllocNbuf (MnpServiceData);
879
880 if (MnpServiceData->RxNbufCache == NULL) {
881 //
882 // No availabe buffer in the buffer pool.
883 //
884 return EFI_DEVICE_ERROR;
885 }
886
887 NetbufAllocSpace (
888 MnpServiceData->RxNbufCache,
889 MnpServiceData->BufferLength,
890 NET_BUF_TAIL
891 );
892 }
893
894 Nbuf = MnpServiceData->RxNbufCache;
895 BufLen = Nbuf->TotalSize;
896 BufPtr = NetbufGetByte (Nbuf, 0, NULL);
897 ASSERT (BufPtr != NULL);
898
899 //
900 // Receive packet through Snp.
901 //
902 Status = Snp->Receive (Snp, &HeaderSize, &BufLen, BufPtr, NULL, NULL, NULL);
903 if (EFI_ERROR (Status)) {
904
905 DEBUG_CODE (
906 if (Status != EFI_NOT_READY) {
907 DEBUG ((EFI_D_WARN, "MnpReceivePacket: Snp->Receive() = %r.\n", Status));
908 }
909 );
910
911 return Status;
912 }
913
914 //
915 // Sanity check.
916 //
917 if ((HeaderSize != Snp->Mode->MediaHeaderSize) || (BufLen < HeaderSize)) {
918
919 DEBUG (
920 (EFI_D_WARN,
921 "MnpReceivePacket: Size error, HL:TL = %d:%d.\n",
922 HeaderSize,
923 BufLen)
924 );
925 return EFI_DEVICE_ERROR;
926 }
927
928 Trimmed = 0;
929 if (Nbuf->TotalSize != BufLen) {
930 //
931 // Trim the packet from tail.
932 //
933 Trimmed = NetbufTrim (Nbuf, Nbuf->TotalSize - (UINT32) BufLen, NET_BUF_TAIL);
934 ASSERT (Nbuf->TotalSize == BufLen);
935 }
936
937 //
938 // Enqueue the packet to the matched instances.
939 //
940 MnpEnqueuePacket (MnpServiceData, Nbuf);
941
942 if (Nbuf->RefCnt > 2) {
943 //
944 // RefCnt > 2 indicates there is at least one receiver of this packet.
945 // Free the current RxNbufCache and allocate a new one.
946 //
947 MnpFreeNbuf (MnpServiceData, Nbuf);
948
949 Nbuf = MnpAllocNbuf (MnpServiceData);
950 MnpServiceData->RxNbufCache = Nbuf;
951 if (Nbuf == NULL) {
952 DEBUG ((EFI_D_ERROR, "MnpReceivePacket: Alloc packet for receiving cache failed.\n"));
953 return EFI_DEVICE_ERROR;
954 }
955
956 NetbufAllocSpace (Nbuf, MnpServiceData->BufferLength, NET_BUF_TAIL);
957 } else {
958 //
959 // No receiver for this packet.
960 //
961 if (Trimmed > 0) {
962 NetbufAllocSpace (Nbuf, Trimmed, NET_BUF_TAIL);
963 }
964
965 goto EXIT;
966 }
967 //
968 // Deliver the queued packets.
969 //
970 MnpDeliverPacket (MnpServiceData);
971
972 //
973 // Dispatch the DPC queued by the NotifyFunction of rx token's events.
974 //
975 NetLibDispatchDpc ();
976
977 EXIT:
978
979 ASSERT (Nbuf->TotalSize == MnpServiceData->BufferLength);
980
981 return Status;
982 }
983
984
985 /**
986 Remove the received packets if timeout occurs.
987
988 @param Event The event this notify function registered to.
989 @param Context Pointer to the context data registered to the
990 event.
991
992 **/
993 VOID
994 EFIAPI
995 MnpCheckPacketTimeout (
996 IN EFI_EVENT Event,
997 IN VOID *Context
998 )
999 {
1000 MNP_SERVICE_DATA *MnpServiceData;
1001 LIST_ENTRY *Entry;
1002 LIST_ENTRY *RxEntry;
1003 LIST_ENTRY *NextEntry;
1004 MNP_INSTANCE_DATA *Instance;
1005 MNP_RXDATA_WRAP *RxDataWrap;
1006 EFI_TPL OldTpl;
1007
1008 MnpServiceData = (MNP_SERVICE_DATA *) Context;
1009 NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);
1010
1011 NET_LIST_FOR_EACH (Entry, &MnpServiceData->ChildrenList) {
1012
1013 Instance = NET_LIST_USER_STRUCT (Entry, MNP_INSTANCE_DATA, InstEntry);
1014 NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);
1015
1016 if (!Instance->Configured || (Instance->ConfigData.ReceivedQueueTimeoutValue == 0)) {
1017 //
1018 // This instance is not configured or there is no receive time out,
1019 // just skip to the next instance.
1020 //
1021 continue;
1022 }
1023
1024 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1025
1026 NET_LIST_FOR_EACH_SAFE (RxEntry, NextEntry, &Instance->RcvdPacketQueue) {
1027
1028 RxDataWrap = NET_LIST_USER_STRUCT (RxEntry, MNP_RXDATA_WRAP, WrapEntry);
1029
1030 //
1031 // TimeoutTick unit is ms, MNP_TIMEOUT_CHECK_INTERVAL unit is 100ns.
1032 //
1033 if (RxDataWrap->TimeoutTick >= (MNP_TIMEOUT_CHECK_INTERVAL / 10)) {
1034
1035 RxDataWrap->TimeoutTick -= (MNP_TIMEOUT_CHECK_INTERVAL / 10);
1036 } else {
1037 //
1038 // Drop the timeout packet.
1039 //
1040 DEBUG ((EFI_D_WARN, "MnpCheckPacketTimeout: Received packet timeout.\n"));
1041 MnpRecycleRxData (NULL, RxDataWrap);
1042 Instance->RcvdPacketQueueSize--;
1043 }
1044 }
1045
1046 gBS->RestoreTPL (OldTpl);
1047 }
1048 }
1049
1050
1051 /**
1052 Poll to receive the packets from Snp. This function is either called by upperlayer
1053 protocols/applications or the system poll timer notify mechanism.
1054
1055 @param Event The event this notify function registered to.
1056 @param Context Pointer to the context data registered to the
1057 event.
1058
1059 **/
1060 VOID
1061 EFIAPI
1062 MnpSystemPoll (
1063 IN EFI_EVENT Event,
1064 IN VOID *Context
1065 )
1066 {
1067 MNP_SERVICE_DATA *MnpServiceData;
1068
1069 MnpServiceData = (MNP_SERVICE_DATA *) Context;
1070 NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);
1071
1072 //
1073 // Try to receive packets from Snp.
1074 //
1075 MnpReceivePacket (MnpServiceData);
1076
1077 NetLibDispatchDpc ();
1078 }