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