]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/MnpDxe/MnpIo.c
MdeModulePkg: Update MNP driver to recycle TX buffer asynchronously.
[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 - 2016, 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 Build the packet to transmit from the TxData passed in.
107
108 @param[in] MnpServiceData Pointer to the mnp service context data.
109 @param[in] TxData Pointer to the transmit data containing the information
110 to build the packet.
111 @param[out] PktBuf Pointer to record the address of the packet.
112 @param[out] PktLen Pointer to a UINT32 variable used to record the packet's
113 length.
114
115 @retval EFI_SUCCESS TxPackage is built.
116 @retval EFI_OUT_OF_RESOURCES The deliver fails due to lack of memory resource.
117
118 **/
119 EFI_STATUS
120 MnpBuildTxPacket (
121 IN MNP_SERVICE_DATA *MnpServiceData,
122 IN EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData,
123 OUT UINT8 **PktBuf,
124 OUT UINT32 *PktLen
125 )
126 {
127 EFI_SIMPLE_NETWORK_MODE *SnpMode;
128 UINT8 *DstPos;
129 UINT16 Index;
130 MNP_DEVICE_DATA *MnpDeviceData;
131 UINT8 *TxBuf;
132
133 MnpDeviceData = MnpServiceData->MnpDeviceData;
134
135 TxBuf = MnpAllocTxBuf (MnpDeviceData);
136 if (TxBuf == NULL) {
137 return EFI_OUT_OF_RESOURCES;
138 }
139
140 //
141 // Reserve space for vlan tag if needed.
142 //
143 if (MnpServiceData->VlanId != 0) {
144 *PktBuf = TxBuf + NET_VLAN_TAG_LEN;
145 } else {
146 *PktBuf = TxBuf;
147 }
148
149 if ((TxData->DestinationAddress == NULL) && (TxData->FragmentCount == 1)) {
150 CopyMem (
151 *PktBuf,
152 TxData->FragmentTable[0].FragmentBuffer,
153 TxData->FragmentTable[0].FragmentLength
154 );
155
156 *PktLen = TxData->FragmentTable[0].FragmentLength;
157 } else {
158 //
159 // Either media header isn't in FragmentTable or there is more than
160 // one fragment, copy the data into the packet buffer. Reserve the
161 // media header space if necessary.
162 //
163 SnpMode = MnpDeviceData->Snp->Mode;
164 DstPos = *PktBuf;
165 *PktLen = 0;
166 if (TxData->DestinationAddress != NULL) {
167 //
168 // If dest address is not NULL, move DstPos to reserve space for the
169 // media header. Add the media header length to buflen.
170 //
171 DstPos += SnpMode->MediaHeaderSize;
172 *PktLen += SnpMode->MediaHeaderSize;
173 }
174
175 for (Index = 0; Index < TxData->FragmentCount; Index++) {
176 //
177 // Copy the data.
178 //
179 CopyMem (
180 DstPos,
181 TxData->FragmentTable[Index].FragmentBuffer,
182 TxData->FragmentTable[Index].FragmentLength
183 );
184 DstPos += TxData->FragmentTable[Index].FragmentLength;
185 }
186
187 //
188 // Set the buffer length.
189 //
190 *PktLen += TxData->DataLength + TxData->HeaderLength;
191 }
192
193 return EFI_SUCCESS;
194 }
195
196
197 /**
198 Synchronously send out the packet.
199
200 This functon places the packet buffer to SNP driver's tansmit queue. The packet
201 can be considered successfully sent out once SNP acccetp the packet, while the
202 packet buffer recycle is deferred for better performance.
203
204 @param[in] MnpServiceData Pointer to the mnp service context data.
205 @param[in] Packet Pointer to the pakcet buffer.
206 @param[in] Length The length of the packet.
207 @param[in, out] Token Pointer to the token the packet generated from.
208
209 @retval EFI_SUCCESS The packet is sent out.
210 @retval EFI_TIMEOUT Time out occurs, the packet isn't sent.
211 @retval EFI_DEVICE_ERROR An unexpected network error occurs.
212
213 **/
214 EFI_STATUS
215 MnpSyncSendPacket (
216 IN MNP_SERVICE_DATA *MnpServiceData,
217 IN UINT8 *Packet,
218 IN UINT32 Length,
219 IN OUT EFI_MANAGED_NETWORK_COMPLETION_TOKEN *Token
220 )
221 {
222 EFI_STATUS Status;
223 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
224 EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData;
225 UINT32 HeaderSize;
226 MNP_DEVICE_DATA *MnpDeviceData;
227 UINT16 ProtocolType;
228
229 MnpDeviceData = MnpServiceData->MnpDeviceData;
230 Snp = MnpDeviceData->Snp;
231 TxData = Token->Packet.TxData;
232 Token->Status = EFI_SUCCESS;
233 HeaderSize = Snp->Mode->MediaHeaderSize - TxData->HeaderLength;
234
235 //
236 // Check media status before transmit packet.
237 // Note: media status will be updated by periodic timer MediaDetectTimer.
238 //
239 if (Snp->Mode->MediaPresentSupported && !Snp->Mode->MediaPresent) {
240 //
241 // Media not present, skip packet transmit and report EFI_NO_MEDIA
242 //
243 DEBUG ((EFI_D_WARN, "MnpSyncSendPacket: No network cable detected.\n"));
244 Token->Status = EFI_NO_MEDIA;
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 //
259 // Transmit the packet through SNP.
260 //
261 Status = Snp->Transmit (
262 Snp,
263 HeaderSize,
264 Length,
265 Packet,
266 TxData->SourceAddress,
267 TxData->DestinationAddress,
268 &ProtocolType
269 );
270 if (Status == EFI_NOT_READY) {
271 Status = MnpRecycleTxBuf (MnpDeviceData);
272 if (EFI_ERROR (Status)) {
273 Token->Status = EFI_DEVICE_ERROR;
274 goto SIGNAL_TOKEN;
275 }
276
277 Status = Snp->Transmit (
278 Snp,
279 HeaderSize,
280 Length,
281 Packet,
282 TxData->SourceAddress,
283 TxData->DestinationAddress,
284 &ProtocolType
285 );
286 }
287
288 if (EFI_ERROR (Status)) {
289 Token->Status = EFI_DEVICE_ERROR;
290 }
291
292 SIGNAL_TOKEN:
293
294 gBS->SignalEvent (Token->Event);
295
296 //
297 // Dispatch the DPC queued by the NotifyFunction of Token->Event.
298 //
299 DispatchDpc ();
300
301 return EFI_SUCCESS;
302 }
303
304
305 /**
306 Try to deliver the received packet to the instance.
307
308 @param[in, out] Instance Pointer to the mnp instance context data.
309
310 @retval EFI_SUCCESS The received packet is delivered, or there is no
311 packet to deliver, or there is no available receive
312 token.
313 @retval EFI_OUT_OF_RESOURCES The deliver fails due to lack of memory resource.
314
315 **/
316 EFI_STATUS
317 MnpInstanceDeliverPacket (
318 IN OUT MNP_INSTANCE_DATA *Instance
319 )
320 {
321 MNP_DEVICE_DATA *MnpDeviceData;
322 MNP_RXDATA_WRAP *RxDataWrap;
323 NET_BUF *DupNbuf;
324 EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData;
325 EFI_SIMPLE_NETWORK_MODE *SnpMode;
326 EFI_MANAGED_NETWORK_COMPLETION_TOKEN *RxToken;
327
328 MnpDeviceData = Instance->MnpServiceData->MnpDeviceData;
329 NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);
330
331 if (NetMapIsEmpty (&Instance->RxTokenMap) || IsListEmpty (&Instance->RcvdPacketQueue)) {
332 //
333 // No pending received data or no available receive token, return.
334 //
335 return EFI_SUCCESS;
336 }
337
338 ASSERT (Instance->RcvdPacketQueueSize != 0);
339
340 RxDataWrap = NET_LIST_HEAD (&Instance->RcvdPacketQueue, MNP_RXDATA_WRAP, WrapEntry);
341 if (RxDataWrap->Nbuf->RefCnt > 2) {
342 //
343 // There are other instances share this Nbuf, duplicate to get a
344 // copy to allow the instance to do R/W operations.
345 //
346 DupNbuf = MnpAllocNbuf (MnpDeviceData);
347 if (DupNbuf == NULL) {
348 DEBUG ((EFI_D_WARN, "MnpDeliverPacket: Failed to allocate a free Nbuf.\n"));
349
350 return EFI_OUT_OF_RESOURCES;
351 }
352
353 //
354 // Duplicate the net buffer.
355 //
356 NetbufDuplicate (RxDataWrap->Nbuf, DupNbuf, 0);
357 MnpFreeNbuf (MnpDeviceData, RxDataWrap->Nbuf);
358 RxDataWrap->Nbuf = DupNbuf;
359 }
360
361 //
362 // All resources are OK, remove the packet from the queue.
363 //
364 NetListRemoveHead (&Instance->RcvdPacketQueue);
365 Instance->RcvdPacketQueueSize--;
366
367 RxData = &RxDataWrap->RxData;
368 SnpMode = MnpDeviceData->Snp->Mode;
369
370 //
371 // Set all the buffer pointers.
372 //
373 RxData->MediaHeader = NetbufGetByte (RxDataWrap->Nbuf, 0, NULL);
374 RxData->DestinationAddress = RxData->MediaHeader;
375 RxData->SourceAddress = (UINT8 *) RxData->MediaHeader + SnpMode->HwAddressSize;
376 RxData->PacketData = (UINT8 *) RxData->MediaHeader + SnpMode->MediaHeaderSize;
377
378 //
379 // Insert this RxDataWrap into the delivered queue.
380 //
381 InsertTailList (&Instance->RxDeliveredPacketQueue, &RxDataWrap->WrapEntry);
382
383 //
384 // Get the receive token from the RxTokenMap.
385 //
386 RxToken = NetMapRemoveHead (&Instance->RxTokenMap, NULL);
387
388 //
389 // Signal this token's event.
390 //
391 RxToken->Packet.RxData = &RxDataWrap->RxData;
392 RxToken->Status = EFI_SUCCESS;
393 gBS->SignalEvent (RxToken->Event);
394
395 return EFI_SUCCESS;
396 }
397
398
399 /**
400 Deliver the received packet for the instances belonging to the MnpServiceData.
401
402 @param[in] MnpServiceData Pointer to the mnp service context data.
403
404 **/
405 VOID
406 MnpDeliverPacket (
407 IN MNP_SERVICE_DATA *MnpServiceData
408 )
409 {
410 LIST_ENTRY *Entry;
411 MNP_INSTANCE_DATA *Instance;
412
413 NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);
414
415 NET_LIST_FOR_EACH (Entry, &MnpServiceData->ChildrenList) {
416 Instance = NET_LIST_USER_STRUCT (Entry, MNP_INSTANCE_DATA, InstEntry);
417 NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);
418
419 //
420 // Try to deliver packet for this instance.
421 //
422 MnpInstanceDeliverPacket (Instance);
423 }
424 }
425
426
427 /**
428 Recycle the RxData and other resources used to hold and deliver the received
429 packet.
430
431 @param[in] Event The event this notify function registered to.
432 @param[in] Context Pointer to the context data registerd to the Event.
433
434 **/
435 VOID
436 EFIAPI
437 MnpRecycleRxData (
438 IN EFI_EVENT Event,
439 IN VOID *Context
440 )
441 {
442 MNP_RXDATA_WRAP *RxDataWrap;
443 MNP_DEVICE_DATA *MnpDeviceData;
444
445 ASSERT (Context != NULL);
446
447 RxDataWrap = (MNP_RXDATA_WRAP *) Context;
448 NET_CHECK_SIGNATURE (RxDataWrap->Instance, MNP_INSTANCE_DATA_SIGNATURE);
449
450 ASSERT (RxDataWrap->Nbuf != NULL);
451
452 MnpDeviceData = RxDataWrap->Instance->MnpServiceData->MnpDeviceData;
453 NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);
454
455 //
456 // Free this Nbuf.
457 //
458 MnpFreeNbuf (MnpDeviceData, RxDataWrap->Nbuf);
459 RxDataWrap->Nbuf = NULL;
460
461 //
462 // Close the recycle event.
463 //
464 gBS->CloseEvent (RxDataWrap->RxData.RecycleEvent);
465
466 //
467 // Remove this Wrap entry from the list.
468 //
469 RemoveEntryList (&RxDataWrap->WrapEntry);
470
471 FreePool (RxDataWrap);
472 }
473
474
475 /**
476 Queue the received packet into instance's receive queue.
477
478 @param[in, out] Instance Pointer to the mnp instance context data.
479 @param[in, out] RxDataWrap Pointer to the Wrap structure containing the
480 received data and other information.
481 **/
482 VOID
483 MnpQueueRcvdPacket (
484 IN OUT MNP_INSTANCE_DATA *Instance,
485 IN OUT MNP_RXDATA_WRAP *RxDataWrap
486 )
487 {
488 MNP_RXDATA_WRAP *OldRxDataWrap;
489
490 NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);
491
492 //
493 // Check the queue size. If it exceeds the limit, drop one packet
494 // from the head.
495 //
496 if (Instance->RcvdPacketQueueSize == MNP_MAX_RCVD_PACKET_QUE_SIZE) {
497
498 DEBUG ((EFI_D_WARN, "MnpQueueRcvdPacket: Drop one packet bcz queue size limit reached.\n"));
499
500 //
501 // Get the oldest packet.
502 //
503 OldRxDataWrap = NET_LIST_HEAD (
504 &Instance->RcvdPacketQueue,
505 MNP_RXDATA_WRAP,
506 WrapEntry
507 );
508
509 //
510 // Recycle this OldRxDataWrap, this entry will be removed by the callee.
511 //
512 MnpRecycleRxData (NULL, (VOID *) OldRxDataWrap);
513 Instance->RcvdPacketQueueSize--;
514 }
515
516 //
517 // Update the timeout tick using the configured parameter.
518 //
519 RxDataWrap->TimeoutTick = Instance->ConfigData.ReceivedQueueTimeoutValue;
520
521 //
522 // Insert this Wrap into the instance queue.
523 //
524 InsertTailList (&Instance->RcvdPacketQueue, &RxDataWrap->WrapEntry);
525 Instance->RcvdPacketQueueSize++;
526 }
527
528
529 /**
530 Match the received packet with the instance receive filters.
531
532 @param[in] Instance Pointer to the mnp instance context data.
533 @param[in] RxData Pointer to the EFI_MANAGED_NETWORK_RECEIVE_DATA.
534 @param[in] GroupAddress Pointer to the GroupAddress, the GroupAddress is
535 non-NULL and it contains the destination multicast
536 mac address of the received packet if the packet
537 destinated to a multicast mac address.
538 @param[in] PktAttr The received packets attribute.
539
540 @return The received packet matches the instance's receive filters or not.
541
542 **/
543 BOOLEAN
544 MnpMatchPacket (
545 IN MNP_INSTANCE_DATA *Instance,
546 IN EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData,
547 IN MNP_GROUP_ADDRESS *GroupAddress OPTIONAL,
548 IN UINT8 PktAttr
549 )
550 {
551 EFI_MANAGED_NETWORK_CONFIG_DATA *ConfigData;
552 LIST_ENTRY *Entry;
553 MNP_GROUP_CONTROL_BLOCK *GroupCtrlBlk;
554
555 NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);
556
557 ConfigData = &Instance->ConfigData;
558
559 //
560 // Check the protocol type.
561 //
562 if ((ConfigData->ProtocolTypeFilter != 0) && (ConfigData->ProtocolTypeFilter != RxData->ProtocolType)) {
563 return FALSE;
564 }
565
566 if (ConfigData->EnablePromiscuousReceive) {
567 //
568 // Always match if this instance is configured to be promiscuous.
569 //
570 return TRUE;
571 }
572
573 //
574 // The protocol type is matched, check receive filter, include unicast and broadcast.
575 //
576 if ((Instance->ReceiveFilter & PktAttr) != 0) {
577 return TRUE;
578 }
579
580 //
581 // Check multicast addresses.
582 //
583 if (ConfigData->EnableMulticastReceive && RxData->MulticastFlag) {
584
585 ASSERT (GroupAddress != NULL);
586
587 NET_LIST_FOR_EACH (Entry, &Instance->GroupCtrlBlkList) {
588
589 GroupCtrlBlk = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_CONTROL_BLOCK, CtrlBlkEntry);
590 if (GroupCtrlBlk->GroupAddress == GroupAddress) {
591 //
592 // The instance is configured to receiveing packets destinated to this
593 // multicast address.
594 //
595 return TRUE;
596 }
597 }
598 }
599
600 //
601 // No match.
602 //
603 return FALSE;
604 }
605
606
607 /**
608 Analyse the received packets.
609
610 @param[in] MnpServiceData Pointer to the mnp service context data.
611 @param[in] Nbuf Pointer to the net buffer holding the received
612 packet.
613 @param[in, out] RxData Pointer to the buffer used to save the analysed
614 result in EFI_MANAGED_NETWORK_RECEIVE_DATA.
615 @param[out] GroupAddress Pointer to pointer to a MNP_GROUP_ADDRESS used to
616 pass out the address of the multicast address the
617 received packet destinated to.
618 @param[out] PktAttr Pointer to the buffer used to save the analysed
619 packet attribute.
620
621 **/
622 VOID
623 MnpAnalysePacket (
624 IN MNP_SERVICE_DATA *MnpServiceData,
625 IN NET_BUF *Nbuf,
626 IN OUT EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData,
627 OUT MNP_GROUP_ADDRESS **GroupAddress,
628 OUT UINT8 *PktAttr
629 )
630 {
631 EFI_SIMPLE_NETWORK_MODE *SnpMode;
632 MNP_DEVICE_DATA *MnpDeviceData;
633 UINT8 *BufPtr;
634 LIST_ENTRY *Entry;
635
636 MnpDeviceData = MnpServiceData->MnpDeviceData;
637 SnpMode = MnpDeviceData->Snp->Mode;
638
639 //
640 // Get the packet buffer.
641 //
642 BufPtr = NetbufGetByte (Nbuf, 0, NULL);
643 ASSERT (BufPtr != NULL);
644
645 //
646 // Set the initial values.
647 //
648 RxData->BroadcastFlag = FALSE;
649 RxData->MulticastFlag = FALSE;
650 RxData->PromiscuousFlag = FALSE;
651 *PktAttr = UNICAST_PACKET;
652
653 if (!NET_MAC_EQUAL (&SnpMode->CurrentAddress, BufPtr, SnpMode->HwAddressSize)) {
654 //
655 // This packet isn't destinated to our current mac address, it't not unicast.
656 //
657 *PktAttr = 0;
658
659 if (NET_MAC_EQUAL (&SnpMode->BroadcastAddress, BufPtr, SnpMode->HwAddressSize)) {
660 //
661 // It's broadcast.
662 //
663 RxData->BroadcastFlag = TRUE;
664 *PktAttr = BROADCAST_PACKET;
665 } else if ((*BufPtr & 0x01) == 0x1) {
666 //
667 // It's multicast, try to match the multicast filters.
668 //
669 NET_LIST_FOR_EACH (Entry, &MnpDeviceData->GroupAddressList) {
670
671 *GroupAddress = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_ADDRESS, AddrEntry);
672 if (NET_MAC_EQUAL (BufPtr, &((*GroupAddress)->Address), SnpMode->HwAddressSize)) {
673 RxData->MulticastFlag = TRUE;
674 break;
675 }
676 }
677
678 if (!RxData->MulticastFlag) {
679 //
680 // No match, set GroupAddress to NULL. This multicast packet must
681 // be the result of PROMISUCOUS or PROMISUCOUS_MULTICAST flag is on.
682 //
683 *GroupAddress = NULL;
684 RxData->PromiscuousFlag = TRUE;
685
686 if (MnpDeviceData->PromiscuousCount == 0) {
687 //
688 // Skip the below code, there is no receiver of this packet.
689 //
690 return ;
691 }
692 }
693 } else {
694 RxData->PromiscuousFlag = TRUE;
695 }
696 }
697
698 ZeroMem (&RxData->Timestamp, sizeof (EFI_TIME));
699
700 //
701 // Fill the common parts of RxData.
702 //
703 RxData->PacketLength = Nbuf->TotalSize;
704 RxData->HeaderLength = SnpMode->MediaHeaderSize;
705 RxData->AddressLength = SnpMode->HwAddressSize;
706 RxData->DataLength = RxData->PacketLength - RxData->HeaderLength;
707 RxData->ProtocolType = NTOHS (*(UINT16 *) (BufPtr + 2 * SnpMode->HwAddressSize));
708 }
709
710
711 /**
712 Wrap the RxData.
713
714 @param[in] Instance Pointer to the mnp instance context data.
715 @param[in] RxData Pointer to the receive data to wrap.
716
717 @return Pointer to a MNP_RXDATA_WRAP which wraps the RxData.
718
719 **/
720 MNP_RXDATA_WRAP *
721 MnpWrapRxData (
722 IN MNP_INSTANCE_DATA *Instance,
723 IN EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData
724 )
725 {
726 EFI_STATUS Status;
727 MNP_RXDATA_WRAP *RxDataWrap;
728
729 //
730 // Allocate memory.
731 //
732 RxDataWrap = AllocatePool (sizeof (MNP_RXDATA_WRAP));
733 if (RxDataWrap == NULL) {
734 DEBUG ((EFI_D_ERROR, "MnpDispatchPacket: Failed to allocate a MNP_RXDATA_WRAP.\n"));
735 return NULL;
736 }
737
738 RxDataWrap->Instance = Instance;
739
740 //
741 // Fill the RxData in RxDataWrap,
742 //
743 CopyMem (&RxDataWrap->RxData, RxData, sizeof (RxDataWrap->RxData));
744
745 //
746 // Create the recycle event.
747 //
748 Status = gBS->CreateEvent (
749 EVT_NOTIFY_SIGNAL,
750 TPL_NOTIFY,
751 MnpRecycleRxData,
752 RxDataWrap,
753 &RxDataWrap->RxData.RecycleEvent
754 );
755 if (EFI_ERROR (Status)) {
756 DEBUG ((EFI_D_ERROR, "MnpDispatchPacket: gBS->CreateEvent failed, %r.\n", Status));
757
758 FreePool (RxDataWrap);
759 return NULL;
760 }
761
762 return RxDataWrap;
763 }
764
765
766 /**
767 Enqueue the received the packets to the instances belonging to the
768 MnpServiceData.
769
770 @param[in] MnpServiceData Pointer to the mnp service context data.
771 @param[in] Nbuf Pointer to the net buffer representing the received
772 packet.
773
774 **/
775 VOID
776 MnpEnqueuePacket (
777 IN MNP_SERVICE_DATA *MnpServiceData,
778 IN NET_BUF *Nbuf
779 )
780 {
781 LIST_ENTRY *Entry;
782 MNP_INSTANCE_DATA *Instance;
783 EFI_MANAGED_NETWORK_RECEIVE_DATA RxData;
784 UINT8 PktAttr;
785 MNP_GROUP_ADDRESS *GroupAddress;
786 MNP_RXDATA_WRAP *RxDataWrap;
787
788
789 GroupAddress = NULL;
790 //
791 // First, analyse the packet header.
792 //
793 MnpAnalysePacket (MnpServiceData, Nbuf, &RxData, &GroupAddress, &PktAttr);
794
795 if (RxData.PromiscuousFlag && (MnpServiceData->MnpDeviceData->PromiscuousCount == 0)) {
796 //
797 // No receivers, no more action need.
798 //
799 return ;
800 }
801
802 //
803 // Iterate the children to find match.
804 //
805 NET_LIST_FOR_EACH (Entry, &MnpServiceData->ChildrenList) {
806
807 Instance = NET_LIST_USER_STRUCT (Entry, MNP_INSTANCE_DATA, InstEntry);
808 NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);
809
810 if (!Instance->Configured) {
811 continue;
812 }
813
814 //
815 // Check the packet against the instance receive filters.
816 //
817 if (MnpMatchPacket (Instance, &RxData, GroupAddress, PktAttr)) {
818 //
819 // Wrap the RxData.
820 //
821 RxDataWrap = MnpWrapRxData (Instance, &RxData);
822 if (RxDataWrap == NULL) {
823 continue;
824 }
825
826 //
827 // Associate RxDataWrap with Nbuf and increase the RefCnt.
828 //
829 RxDataWrap->Nbuf = Nbuf;
830 NET_GET_REF (RxDataWrap->Nbuf);
831
832 //
833 // Queue the packet into the instance queue.
834 //
835 MnpQueueRcvdPacket (Instance, RxDataWrap);
836 }
837 }
838 }
839
840
841 /**
842 Try to receive a packet and deliver it.
843
844 @param[in, out] MnpDeviceData Pointer to the mnp device context data.
845
846 @retval EFI_SUCCESS add return value to function comment
847 @retval EFI_NOT_STARTED The simple network protocol is not started.
848 @retval EFI_NOT_READY No packet received.
849 @retval EFI_DEVICE_ERROR An unexpected error occurs.
850
851 **/
852 EFI_STATUS
853 MnpReceivePacket (
854 IN OUT MNP_DEVICE_DATA *MnpDeviceData
855 )
856 {
857 EFI_STATUS Status;
858 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
859 NET_BUF *Nbuf;
860 UINT8 *BufPtr;
861 UINTN BufLen;
862 UINTN HeaderSize;
863 UINT32 Trimmed;
864 MNP_SERVICE_DATA *MnpServiceData;
865 UINT16 VlanId;
866 BOOLEAN IsVlanPacket;
867
868 NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);
869
870 Snp = MnpDeviceData->Snp;
871 if (Snp->Mode->State != EfiSimpleNetworkInitialized) {
872 //
873 // The simple network protocol is not started.
874 //
875 return EFI_NOT_STARTED;
876 }
877
878 if (MnpDeviceData->RxNbufCache == NULL) {
879 //
880 // Try to get a new buffer as there may be buffers recycled.
881 //
882 MnpDeviceData->RxNbufCache = MnpAllocNbuf (MnpDeviceData);
883
884 if (MnpDeviceData->RxNbufCache == NULL) {
885 //
886 // No availabe buffer in the buffer pool.
887 //
888 return EFI_DEVICE_ERROR;
889 }
890
891 NetbufAllocSpace (
892 MnpDeviceData->RxNbufCache,
893 MnpDeviceData->BufferLength,
894 NET_BUF_TAIL
895 );
896 }
897
898 Nbuf = MnpDeviceData->RxNbufCache;
899 BufLen = Nbuf->TotalSize;
900 BufPtr = NetbufGetByte (Nbuf, 0, NULL);
901 ASSERT (BufPtr != NULL);
902
903 //
904 // Receive packet through Snp.
905 //
906 Status = Snp->Receive (Snp, &HeaderSize, &BufLen, BufPtr, NULL, NULL, NULL);
907 if (EFI_ERROR (Status)) {
908 DEBUG_CODE (
909 if (Status != EFI_NOT_READY) {
910 DEBUG ((EFI_D_WARN, "MnpReceivePacket: Snp->Receive() = %r.\n", Status));
911 }
912 );
913
914 return Status;
915 }
916
917 //
918 // Sanity check.
919 //
920 if ((HeaderSize != Snp->Mode->MediaHeaderSize) || (BufLen < HeaderSize)) {
921 DEBUG (
922 (EFI_D_WARN,
923 "MnpReceivePacket: Size error, HL:TL = %d:%d.\n",
924 HeaderSize,
925 BufLen)
926 );
927 return EFI_DEVICE_ERROR;
928 }
929
930 Trimmed = 0;
931 if (Nbuf->TotalSize != BufLen) {
932 //
933 // Trim the packet from tail.
934 //
935 Trimmed = NetbufTrim (Nbuf, Nbuf->TotalSize - (UINT32) BufLen, NET_BUF_TAIL);
936 ASSERT (Nbuf->TotalSize == BufLen);
937 }
938
939 VlanId = 0;
940 if (MnpDeviceData->NumberOfVlan != 0) {
941 //
942 // VLAN is configured, remove the VLAN tag if any
943 //
944 IsVlanPacket = MnpRemoveVlanTag (MnpDeviceData, Nbuf, &VlanId);
945 } else {
946 IsVlanPacket = FALSE;
947 }
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 }