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