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