• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
MnpIsValidTxToken(IN MNP_INSTANCE_DATA * Instance,IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN * Token)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
MnpBuildTxPacket(IN MNP_SERVICE_DATA * MnpServiceData,IN EFI_MANAGED_NETWORK_TRANSMIT_DATA * TxData,OUT UINT8 ** PktBuf,OUT UINT32 * PktLen)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
MnpSyncSendPacket(IN MNP_SERVICE_DATA * MnpServiceData,IN UINT8 * Packet,IN UINT32 Length,IN OUT EFI_MANAGED_NETWORK_COMPLETION_TOKEN * Token)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
MnpInstanceDeliverPacket(IN OUT MNP_INSTANCE_DATA * Instance)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
MnpDeliverPacket(IN MNP_SERVICE_DATA * MnpServiceData)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
MnpRecycleRxData(IN EFI_EVENT Event,IN VOID * Context)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
MnpQueueRcvdPacket(IN OUT MNP_INSTANCE_DATA * Instance,IN OUT MNP_RXDATA_WRAP * RxDataWrap)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
MnpMatchPacket(IN MNP_INSTANCE_DATA * Instance,IN EFI_MANAGED_NETWORK_RECEIVE_DATA * RxData,IN MNP_GROUP_ADDRESS * GroupAddress OPTIONAL,IN UINT8 PktAttr)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
MnpAnalysePacket(IN MNP_SERVICE_DATA * MnpServiceData,IN NET_BUF * Nbuf,IN OUT EFI_MANAGED_NETWORK_RECEIVE_DATA * RxData,OUT MNP_GROUP_ADDRESS ** GroupAddress,OUT UINT8 * PktAttr)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 *
MnpWrapRxData(IN MNP_INSTANCE_DATA * Instance,IN EFI_MANAGED_NETWORK_RECEIVE_DATA * RxData)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
MnpEnqueuePacket(IN MNP_SERVICE_DATA * MnpServiceData,IN NET_BUF * Nbuf)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
MnpReceivePacket(IN OUT MNP_DEVICE_DATA * MnpDeviceData)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 available 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
MnpCheckPacketTimeout(IN EFI_EVENT Event,IN VOID * Context)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
MnpCheckMediaStatus(IN EFI_EVENT Event,IN VOID * Context)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
MnpSystemPoll(IN EFI_EVENT Event,IN VOID * Context)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 }
1141