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