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