1/** @file
2  Implementation of Managed Network Protocol I/O functions.
3
4Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions
7of the BSD License which accompanies this distribution.  The full
8text of the license may be found at<BR>
9http://opensource.org/licenses/bsd-license.php
10
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12WITHOUT 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**/
28BOOLEAN
29MnpIsValidTxToken (
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**/
119EFI_STATUS
120MnpBuildTxPacket (
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**/
214EFI_STATUS
215MnpSyncSendPacket (
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
292SIGNAL_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**/
316EFI_STATUS
317MnpInstanceDeliverPacket (
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**/
405VOID
406MnpDeliverPacket (
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**/
435VOID
436EFIAPI
437MnpRecycleRxData (
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**/
482VOID
483MnpQueueRcvdPacket (
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**/
543BOOLEAN
544MnpMatchPacket (
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**/
622VOID
623MnpAnalysePacket (
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**/
720MNP_RXDATA_WRAP *
721MnpWrapRxData (
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**/
775VOID
776MnpEnqueuePacket (
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**/
852EFI_STATUS
853MnpReceivePacket (
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
1003EXIT:
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**/
1018VOID
1019EFIAPI
1020MnpCheckPacketTimeout (
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**/
1087VOID
1088EFIAPI
1089MnpCheckMediaStatus (
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**/
1119VOID
1120EFIAPI
1121MnpSystemPoll (
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}
1141