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