Patch to remove STATIC modifier. This is on longer recommended by EFI Framework codin...
[mirror_edk2.git] / MdeModulePkg / Universal / Network / MnpDxe / MnpConfig.c
1 /** @file\r
2 \r
3 Copyright (c) 2005 - 2008, Intel Corporation\r
4 All rights reserved. This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution.  The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php\r
8 \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11 \r
12 Module Name:\r
13 \r
14   MnpConfig.c\r
15 \r
16 Abstract:\r
17 \r
18   Implementation of Managed Network Protocol private services.\r
19 \r
20 \r
21 **/\r
22 \r
23 \r
24 #include "MnpImpl.h"\r
25 \r
26 EFI_SERVICE_BINDING_PROTOCOL    mMnpServiceBindingProtocol = {\r
27   MnpServiceBindingCreateChild,\r
28   MnpServiceBindingDestroyChild\r
29 };\r
30 \r
31 EFI_MANAGED_NETWORK_PROTOCOL    mMnpProtocolTemplate = {\r
32   MnpGetModeData,\r
33   MnpConfigure,\r
34   MnpMcastIpToMac,\r
35   MnpGroups,\r
36   MnpTransmit,\r
37   MnpReceive,\r
38   MnpCancel,\r
39   MnpPoll\r
40 };\r
41 \r
42 EFI_MANAGED_NETWORK_CONFIG_DATA mMnpDefaultConfigData = {\r
43   10000,\r
44   10000,\r
45   0,\r
46   FALSE,\r
47   FALSE,\r
48   FALSE,\r
49   FALSE,\r
50   FALSE,\r
51   FALSE,\r
52   FALSE\r
53 };\r
54 \r
55 EFI_STATUS\r
56 MnpAddFreeNbuf (\r
57   IN MNP_SERVICE_DATA  *MnpServiceData,\r
58   IN UINTN             Count\r
59   );\r
60 \r
61 EFI_STATUS\r
62 MnpStartSnp (\r
63   IN EFI_SIMPLE_NETWORK_PROTOCOL  *Snp\r
64   );\r
65 \r
66 EFI_STATUS\r
67 MnpStopSnp (\r
68   IN EFI_SIMPLE_NETWORK_PROTOCOL  *Snp\r
69   );\r
70 \r
71 EFI_STATUS\r
72 MnpStart (\r
73   IN MNP_SERVICE_DATA  *MnpServiceData,\r
74   IN BOOLEAN           IsConfigUpdate,\r
75   IN BOOLEAN           EnableSystemPoll\r
76   );\r
77 \r
78 EFI_STATUS\r
79 MnpStop (\r
80   IN MNP_SERVICE_DATA  *MnpServiceData\r
81   );\r
82 \r
83 EFI_STATUS\r
84 MnpConfigReceiveFilters (\r
85   IN MNP_SERVICE_DATA  *MnpServiceData\r
86   );\r
87 \r
88 EFI_STATUS\r
89 MnpGroupOpAddCtrlBlk (\r
90   IN MNP_INSTANCE_DATA        *Instance,\r
91   IN MNP_GROUP_CONTROL_BLOCK  *CtrlBlk,\r
92   IN MNP_GROUP_ADDRESS        *GroupAddress OPTIONAL,\r
93   IN EFI_MAC_ADDRESS          *MacAddress,\r
94   IN UINT32                   HwAddressSize\r
95   );\r
96 \r
97 BOOLEAN\r
98 MnpGroupOpDelCtrlBlk (\r
99   IN MNP_INSTANCE_DATA        *Instance,\r
100   IN MNP_GROUP_CONTROL_BLOCK  *CtrlBlk\r
101   );\r
102 \r
103 \r
104 /**\r
105   Add some NET_BUF into MnpServiceData->FreeNbufQue. The buffer length of\r
106   the NET_BUF is specified by MnpServiceData->BufferLength.\r
107 \r
108   @param  MnpServiceData        Pointer to the MNP_SERVICE_DATA.\r
109   @param  Count                 Number of NET_BUFFERs to add.\r
110 \r
111   @retval EFI_SUCCESS           The specified amount of NET_BUFs are allocated and\r
112                                 added into MnpServiceData->FreeNbufQue.\r
113   @retval EFI_OUT_OF_RESOURCES  Failed to allocate a NET_BUF structure.\r
114 \r
115 **/\r
116 EFI_STATUS\r
117 MnpAddFreeNbuf (\r
118   IN MNP_SERVICE_DATA  *MnpServiceData,\r
119   IN UINTN             Count\r
120   )\r
121 {\r
122   EFI_STATUS  Status;\r
123   UINTN       Index;\r
124   NET_BUF     *Nbuf;\r
125 \r
126   NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
127   ASSERT ((Count > 0) && (MnpServiceData->BufferLength > 0));\r
128 \r
129   Status = EFI_SUCCESS;\r
130 \r
131   for (Index = 0; Index < Count; Index++) {\r
132 \r
133     Nbuf = NetbufAlloc (MnpServiceData->BufferLength + MnpServiceData->PaddingSize);\r
134     if (Nbuf == NULL) {\r
135 \r
136       DEBUG ((EFI_D_ERROR, "MnpAddFreeNbuf: NetBufAlloc failed.\n"));\r
137       Status = EFI_OUT_OF_RESOURCES;\r
138       break;\r
139     }\r
140 \r
141     if (MnpServiceData->PaddingSize > 0) {\r
142       //\r
143       // Pad padding bytes before the media header\r
144       //\r
145       NetbufAllocSpace (Nbuf, MnpServiceData->PaddingSize, NET_BUF_TAIL);\r
146       NetbufTrim (Nbuf, MnpServiceData->PaddingSize, NET_BUF_HEAD);\r
147     }\r
148 \r
149     NetbufQueAppend (&MnpServiceData->FreeNbufQue, Nbuf);\r
150   }\r
151 \r
152   MnpServiceData->NbufCnt += Index;\r
153 \r
154   return Status;\r
155 }\r
156 \r
157 \r
158 /**\r
159   Allocate a free NET_BUF from MnpServiceData->FreeNbufQue. If there is none\r
160   in the queue, first try to allocate some and add them into the queue, then\r
161   fetch the NET_BUF from the updated FreeNbufQue.\r
162 \r
163   @param  MnpServiceData        Pointer to the MNP_SERVICE_DATA.\r
164 \r
165   @return Pointer to the allocated free NET_BUF structure, if NULL the operation is failed.\r
166 \r
167 **/\r
168 NET_BUF *\r
169 MnpAllocNbuf (\r
170   IN MNP_SERVICE_DATA  *MnpServiceData\r
171   )\r
172 {\r
173   EFI_STATUS    Status;\r
174   NET_BUF_QUEUE *FreeNbufQue;\r
175   NET_BUF       *Nbuf;\r
176   EFI_TPL       OldTpl;\r
177 \r
178   NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
179 \r
180   FreeNbufQue = &MnpServiceData->FreeNbufQue;\r
181 \r
182   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
183 \r
184   //\r
185   // Check whether there are available buffers, or else try to add some.\r
186   //\r
187   if (FreeNbufQue->BufNum == 0) {\r
188 \r
189     if ((MnpServiceData->NbufCnt + MNP_NET_BUFFER_INCREASEMENT) > MNP_MAX_NET_BUFFER_NUM) {\r
190 \r
191       DEBUG (\r
192         (EFI_D_ERROR,\r
193         "MnpAllocNbuf: The maximum NET_BUF size is reached for MNP driver instance %p.\n",\r
194         MnpServiceData)\r
195         );\r
196 \r
197       Nbuf = NULL;\r
198       goto ON_EXIT;\r
199     }\r
200 \r
201     Status = MnpAddFreeNbuf (MnpServiceData, MNP_NET_BUFFER_INCREASEMENT);\r
202     if (EFI_ERROR (Status)) {\r
203 \r
204       DEBUG (\r
205         (EFI_D_ERROR,\r
206         "MnpAllocNbuf: Failed to add NET_BUFs into the FreeNbufQue, %r.\n",\r
207         Status)\r
208         );\r
209       //\r
210       // Don't return NULL, perhaps MnpAddFreeNbuf does add some NET_BUFs but\r
211       // the amount is less than MNP_NET_BUFFER_INCREASEMENT.\r
212       //\r
213     }\r
214   }\r
215 \r
216   Nbuf = NetbufQueRemove (FreeNbufQue);\r
217 \r
218   //\r
219   // Increase the RefCnt.\r
220   //\r
221   if (Nbuf != NULL) {\r
222     NET_GET_REF (Nbuf);\r
223   }\r
224 \r
225 ON_EXIT:\r
226   gBS->RestoreTPL (OldTpl);\r
227 \r
228   return Nbuf;\r
229 }\r
230 \r
231 \r
232 /**\r
233   Try to reclaim the Nbuf into the buffer pool.\r
234 \r
235   @param  MnpServiceData        Pointer to the mnp service context data.\r
236   @param  Nbuf                  Pointer to the NET_BUF to free.\r
237 \r
238   @return None.\r
239 \r
240 **/\r
241 VOID\r
242 MnpFreeNbuf (\r
243   IN MNP_SERVICE_DATA  *MnpServiceData,\r
244   IN NET_BUF           *Nbuf\r
245   )\r
246 {\r
247   EFI_TPL  OldTpl;\r
248 \r
249   NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
250   ASSERT (Nbuf->RefCnt > 1);\r
251 \r
252   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
253 \r
254   NET_PUT_REF (Nbuf);\r
255 \r
256   if (Nbuf->RefCnt == 1) {\r
257     //\r
258     // Trim all buffer contained in the Nbuf, then append it to the NbufQue.\r
259     //\r
260     NetbufTrim (Nbuf, Nbuf->TotalSize, NET_BUF_TAIL);\r
261     NetbufQueAppend (&MnpServiceData->FreeNbufQue, Nbuf);\r
262   }\r
263 \r
264   gBS->RestoreTPL (OldTpl);\r
265 }\r
266 \r
267 \r
268 /**\r
269   Initialize the mnp service context data.\r
270 \r
271   @param  MnpServiceData        Pointer to the mnp service context data.\r
272   @param  Snp                   Pointer to the simple network protocol.\r
273 \r
274   @retval EFI_SUCCESS           The mnp service context is initialized.\r
275   @retval Other                 Some error occurs.\r
276 \r
277 **/\r
278 EFI_STATUS\r
279 MnpInitializeServiceData (\r
280   IN MNP_SERVICE_DATA  *MnpServiceData,\r
281   IN EFI_HANDLE        ImageHandle,\r
282   IN EFI_HANDLE        ControllerHandle\r
283   )\r
284 {\r
285   EFI_STATUS                   Status;\r
286   EFI_SIMPLE_NETWORK_PROTOCOL  *Snp;\r
287   EFI_SIMPLE_NETWORK_MODE      *SnpMode;\r
288 \r
289   MnpServiceData->Signature = MNP_SERVICE_DATA_SIGNATURE;\r
290 \r
291   MnpServiceData->ControllerHandle = ControllerHandle;\r
292 \r
293   //\r
294   // Copy the ServiceBinding structure.\r
295   //\r
296   MnpServiceData->ServiceBinding = mMnpServiceBindingProtocol;\r
297 \r
298   //\r
299   // Open the Simple Network protocol.\r
300   //\r
301   Status = gBS->OpenProtocol (\r
302                   ControllerHandle,\r
303                   &gEfiSimpleNetworkProtocolGuid,\r
304                   (VOID **) &Snp,\r
305                   ImageHandle,\r
306                   ControllerHandle,\r
307                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
308                   );\r
309   if (EFI_ERROR (Status)) {\r
310     return EFI_UNSUPPORTED;\r
311   }\r
312 \r
313   //\r
314   // Get MTU from Snp.\r
315   //\r
316   SnpMode             = Snp->Mode;\r
317   MnpServiceData->Snp = Snp;\r
318   MnpServiceData->Mtu = SnpMode->MaxPacketSize;\r
319 \r
320   //\r
321   // Initialize the lists.\r
322   //\r
323   InitializeListHead (&MnpServiceData->GroupAddressList);\r
324   InitializeListHead (&MnpServiceData->ChildrenList);\r
325 \r
326   //\r
327   // Get the buffer length used to allocate NET_BUF to hold data received\r
328   // from SNP. Do this before fill the FreeNetBufQue.\r
329   //\r
330   MnpServiceData->BufferLength = MnpServiceData->Mtu + SnpMode->MediaHeaderSize + NET_ETHER_FCS_SIZE;\r
331 \r
332   //\r
333   // Make sure the protocol headers immediately following the media header\r
334   // 4-byte aligned\r
335   //\r
336   MnpServiceData->PaddingSize = (4 - SnpMode->MediaHeaderSize) & 0x3;\r
337 \r
338   //\r
339   // Initialize the FreeNetBufQue and pre-allocate some NET_BUFs.\r
340   //\r
341   NetbufQueInit (&MnpServiceData->FreeNbufQue);\r
342   Status = MnpAddFreeNbuf (MnpServiceData, MNP_INIT_NET_BUFFER_NUM);\r
343   if (EFI_ERROR (Status)) {\r
344 \r
345     DEBUG ((EFI_D_ERROR, "MnpInitializeServiceData: MnpAddFreeNbuf failed, %r.\n", Status));\r
346     goto ERROR;\r
347   }\r
348   //\r
349   // Get one NET_BUF from the FreeNbufQue for rx cache.\r
350   //\r
351   MnpServiceData->RxNbufCache = MnpAllocNbuf (MnpServiceData);\r
352   NetbufAllocSpace (\r
353     MnpServiceData->RxNbufCache,\r
354     MnpServiceData->BufferLength,\r
355     NET_BUF_TAIL\r
356     );\r
357 \r
358   //\r
359   // Allocate buffer pool for tx.\r
360   //\r
361   MnpServiceData->TxBuf = AllocatePool (MnpServiceData->Mtu + SnpMode->MediaHeaderSize);\r
362   if (MnpServiceData->TxBuf == NULL) {\r
363 \r
364     DEBUG ((EFI_D_ERROR, "MnpInitializeServiceData: AllocatePool failed.\n"));\r
365     Status = EFI_OUT_OF_RESOURCES;\r
366 \r
367     goto ERROR;\r
368   }\r
369 \r
370   //\r
371   // Create the system poll timer.\r
372   //\r
373   Status = gBS->CreateEvent (\r
374                   EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
375                   TPL_CALLBACK,\r
376                   MnpSystemPoll,\r
377                   MnpServiceData,\r
378                   &MnpServiceData->PollTimer\r
379                   );\r
380   if (EFI_ERROR (Status)) {\r
381 \r
382     DEBUG ((EFI_D_ERROR, "MnpInitializeServiceData: CreateEvent for poll timer failed.\n"));\r
383     goto ERROR;\r
384   }\r
385 \r
386   //\r
387   // Create the timer for packet timeout check.\r
388   //\r
389   Status = gBS->CreateEvent (\r
390                   EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
391                   TPL_CALLBACK,\r
392                   MnpCheckPacketTimeout,\r
393                   MnpServiceData,\r
394                   &MnpServiceData->TimeoutCheckTimer\r
395                   );\r
396   if (EFI_ERROR (Status)) {\r
397 \r
398     DEBUG ((EFI_D_ERROR, "MnpInitializeServiceData: CreateEvent for packet timeout check failed.\n"));\r
399     goto ERROR;\r
400   }\r
401 \r
402   //\r
403   // Create the timer for tx timeout check.\r
404   //\r
405   Status = gBS->CreateEvent (\r
406                   EVT_TIMER,\r
407                   TPL_CALLBACK,\r
408                   NULL,\r
409                   NULL,\r
410                   &MnpServiceData->TxTimeoutEvent\r
411                   );\r
412   if (EFI_ERROR (Status)) {\r
413 \r
414     DEBUG ((EFI_D_ERROR, "MnpInitializeServiceData: CreateEvent for tx timeout event failed.\n"));\r
415   }\r
416 \r
417 ERROR:\r
418 \r
419   if (EFI_ERROR (Status)) {\r
420     //\r
421     // Free the dynamic allocated resources if necessary.\r
422     //\r
423     if (MnpServiceData->TimeoutCheckTimer != NULL) {\r
424 \r
425       gBS->CloseEvent (MnpServiceData->TimeoutCheckTimer);\r
426     }\r
427 \r
428     if (MnpServiceData->PollTimer != NULL) {\r
429 \r
430       gBS->CloseEvent (MnpServiceData->PollTimer);\r
431     }\r
432 \r
433     if (MnpServiceData->TxBuf != NULL) {\r
434 \r
435       gBS->FreePool (MnpServiceData->TxBuf);\r
436     }\r
437 \r
438     if (MnpServiceData->RxNbufCache != NULL) {\r
439 \r
440       MnpFreeNbuf (MnpServiceData, MnpServiceData->RxNbufCache);\r
441     }\r
442 \r
443     if (MnpServiceData->FreeNbufQue.BufNum != 0) {\r
444 \r
445       NetbufQueFlush (&MnpServiceData->FreeNbufQue);\r
446     }\r
447   }\r
448 \r
449   return Status;\r
450 }\r
451 \r
452 \r
453 /**\r
454   Flush the mnp service context data.\r
455 \r
456   @param  MnpServiceData        Pointer to the mnp service context data.\r
457 \r
458   @return None.\r
459 \r
460 **/\r
461 VOID\r
462 MnpFlushServiceData (\r
463   IN MNP_SERVICE_DATA  *MnpServiceData,\r
464   IN EFI_HANDLE        ImageHandle\r
465   )\r
466 {\r
467   NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
468 \r
469   //\r
470   // The GroupAddressList must be empty.\r
471   //\r
472   ASSERT (IsListEmpty (&MnpServiceData->GroupAddressList));\r
473 \r
474   //\r
475   // Close the event.\r
476   //\r
477   gBS->CloseEvent (&MnpServiceData->TxTimeoutEvent);\r
478   gBS->CloseEvent (&MnpServiceData->TimeoutCheckTimer);\r
479   gBS->CloseEvent (&MnpServiceData->PollTimer);\r
480 \r
481   //\r
482   // Free the tx buffer.\r
483   //\r
484   gBS->FreePool (MnpServiceData->TxBuf);\r
485 \r
486   //\r
487   // Free the RxNbufCache.\r
488   //\r
489   MnpFreeNbuf (MnpServiceData, MnpServiceData->RxNbufCache);\r
490 \r
491   //\r
492   // Flush the FreeNbufQue.\r
493   //\r
494   MnpServiceData->NbufCnt -= MnpServiceData->FreeNbufQue.BufNum;\r
495   NetbufQueFlush (&MnpServiceData->FreeNbufQue);\r
496 \r
497   DEBUG_CODE (\r
498 \r
499   if (MnpServiceData->NbufCnt != 0) {\r
500 \r
501     DEBUG ((EFI_D_WARN, "MnpFlushServiceData: Memory leak, MnpServiceData->NbufCnt != 0.\n"));\r
502   }\r
503   );\r
504 \r
505   //\r
506   // Close the Simple Network Protocol.\r
507   //\r
508   gBS->CloseProtocol (\r
509         MnpServiceData->ControllerHandle,\r
510         &gEfiSimpleNetworkProtocolGuid,\r
511         ImageHandle,\r
512         MnpServiceData->ControllerHandle\r
513         );\r
514 }\r
515 \r
516 \r
517 /**\r
518   Initialize the mnp instance context data.\r
519 \r
520   @param  MnpServiceData        Pointer to the mnp service context data.\r
521   @param  Instance              Pointer to the mnp instance context data to\r
522                                 initialize.\r
523 \r
524   @return None.\r
525 \r
526 **/\r
527 VOID\r
528 MnpInitializeInstanceData (\r
529   IN MNP_SERVICE_DATA   *MnpServiceData,\r
530   IN MNP_INSTANCE_DATA  *Instance\r
531   )\r
532 {\r
533   NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
534   ASSERT (Instance != NULL);\r
535 \r
536   //\r
537   // Set the signature.\r
538   //\r
539   Instance->Signature = MNP_INSTANCE_DATA_SIGNATURE;\r
540 \r
541   //\r
542   // Copy the MNP Protocol interfaces from the template.\r
543   //\r
544   CopyMem (&Instance->ManagedNetwork, &mMnpProtocolTemplate, sizeof (Instance->ManagedNetwork));\r
545 \r
546   //\r
547   // Copy the default config data.\r
548   //\r
549   CopyMem (&Instance->ConfigData, &mMnpDefaultConfigData, sizeof (Instance->ConfigData));\r
550 \r
551   //\r
552   // Initialize the lists.\r
553   //\r
554   InitializeListHead (&Instance->GroupCtrlBlkList);\r
555   InitializeListHead (&Instance->RcvdPacketQueue);\r
556   InitializeListHead (&Instance->RxDeliveredPacketQueue);\r
557 \r
558   //\r
559   // Initialize the RxToken Map.\r
560   //\r
561   NetMapInit (&Instance->RxTokenMap);\r
562 \r
563   //\r
564   // Save the MnpServiceData info.\r
565   //\r
566   Instance->MnpServiceData = MnpServiceData;\r
567 }\r
568 \r
569 \r
570 /**\r
571   Check whether the token specified by Arg maches the token in Item.\r
572 \r
573   @param  Map                   Pointer to the NET_MAP.\r
574   @param  Item                  Pointer to the NET_MAP_ITEM\r
575   @param  Arg                   Pointer to the Arg, it's a pointer to the token to\r
576                                 check.\r
577 \r
578   @retval EFI_SUCCESS           The token specified by Arg is different from the\r
579                                 token in Item.\r
580   @retval EFI_ACCESS_DENIED     The token specified by Arg is the same as that in\r
581                                 Item.\r
582 \r
583 **/\r
584 EFI_STATUS\r
585 MnpTokenExist (\r
586   IN NET_MAP       *Map,\r
587   IN NET_MAP_ITEM  *Item,\r
588   IN VOID          *Arg\r
589   )\r
590 {\r
591   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *Token;\r
592   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *TokenInItem;\r
593 \r
594   Token       = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *) Arg;\r
595   TokenInItem = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *) Item->Key;\r
596 \r
597   if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {\r
598     //\r
599     // The token is the same either the two tokens equals or the Events in\r
600     // the two tokens are the same.\r
601     //\r
602     return EFI_ACCESS_DENIED;\r
603   }\r
604 \r
605   return EFI_SUCCESS;\r
606 }\r
607 \r
608 \r
609 /**\r
610   Cancel the token specified by Arg if it matches the token in Item.\r
611 \r
612   @param  Map                   Pointer to the NET_MAP.\r
613   @param  Item                  Pointer to the NET_MAP_ITEM\r
614   @param  Arg                   Pointer to the Arg, it's a pointer to the token to\r
615                                 cancel.\r
616 \r
617   @retval EFI_SUCCESS           The Arg is NULL, and the token in Item is\r
618                                 cancelled, or the Arg isn't NULL, and the token in\r
619                                 Item is different from the Arg.\r
620   @retval EFI_ABORTED           The Arg isn't NULL, the token in Item mathces the\r
621                                 Arg, and the token is cancelled.\r
622 \r
623 **/\r
624 EFI_STATUS\r
625 MnpCancelTokens (\r
626   IN NET_MAP       *Map,\r
627   IN NET_MAP_ITEM  *Item,\r
628   IN VOID          *Arg\r
629   )\r
630 {\r
631   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *TokenToCancel;\r
632 \r
633   if ((Arg != NULL) && (Item->Key != Arg)) {\r
634     //\r
635     // The token in Item is not the token specified by Arg.\r
636     //\r
637     return EFI_SUCCESS;\r
638   }\r
639 \r
640   TokenToCancel         = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *) Item->Key;\r
641 \r
642   //\r
643   // Remove the item from the map.\r
644   //\r
645   NetMapRemoveItem (Map, Item, NULL);\r
646 \r
647   //\r
648   // Cancel this token with status set to EFI_ABORTED.\r
649   //\r
650   TokenToCancel->Status = EFI_ABORTED;\r
651   gBS->SignalEvent (TokenToCancel->Event);\r
652 \r
653   if (Arg != NULL) {\r
654     //\r
655     // Only abort the token specified by Arg if Arg isn't NULL.\r
656     //\r
657     return EFI_ABORTED;\r
658   }\r
659 \r
660   return EFI_SUCCESS;\r
661 }\r
662 \r
663 \r
664 /**\r
665   Start and initialize the simple network.\r
666 \r
667   @param  Snp                   Pointer to the simple network protocol.\r
668 \r
669   @retval EFI_SUCCESS           The simple network protocol is started.\r
670   @retval Other                 Some error occurs.\r
671 \r
672 **/\r
673 EFI_STATUS\r
674 MnpStartSnp (\r
675   IN EFI_SIMPLE_NETWORK_PROTOCOL  *Snp\r
676   )\r
677 {\r
678   EFI_STATUS  Status;\r
679 \r
680   ASSERT (Snp != NULL);\r
681 \r
682   //\r
683   // Start the simple network.\r
684   //\r
685   Status = Snp->Start (Snp);\r
686 \r
687   if (!EFI_ERROR (Status)) {\r
688     //\r
689     // Initialize the simple network.\r
690     //\r
691     Status  = Snp->Initialize (Snp, 0, 0);\r
692   }\r
693 \r
694   return Status;\r
695 }\r
696 \r
697 \r
698 /**\r
699   Stop the simple network.\r
700 \r
701   @param  Snp                   Pointer to the simple network protocol.\r
702 \r
703   @retval EFI_SUCCESS           The simple network is stopped.\r
704   @retval Other                 Some error occurs.\r
705 \r
706 **/\r
707 EFI_STATUS\r
708 MnpStopSnp (\r
709   IN EFI_SIMPLE_NETWORK_PROTOCOL  *Snp\r
710   )\r
711 {\r
712   EFI_STATUS  Status;\r
713 \r
714   ASSERT (Snp != NULL);\r
715 \r
716   //\r
717   // Shut down the simple network.\r
718   //\r
719   Status = Snp->Shutdown (Snp);\r
720 \r
721   if (!EFI_ERROR (Status)) {\r
722     //\r
723     // Stop the simple network.\r
724     //\r
725     Status = Snp->Stop (Snp);\r
726   }\r
727 \r
728   return Status;\r
729 }\r
730 \r
731 \r
732 /**\r
733   Start the managed network, this function is called when one instance is configured\r
734   or reconfigured.\r
735 \r
736   @param  MnpServiceData        Pointer to the mnp service context data.\r
737   @param  IsConfigUpdate        The instance is reconfigured or it's the first time\r
738                                  the instanced is configured.\r
739   @param  EnableSystemPoll      Enable the system polling or not.\r
740 \r
741   @retval EFI_SUCCESS           The managed network is started and some\r
742                                 configuration is updated.\r
743   @retval Other                 Some error occurs.\r
744 \r
745 **/\r
746 EFI_STATUS\r
747 MnpStart (\r
748   IN MNP_SERVICE_DATA  *MnpServiceData,\r
749   IN BOOLEAN           IsConfigUpdate,\r
750   IN BOOLEAN           EnableSystemPoll\r
751   )\r
752 {\r
753   EFI_STATUS      Status;\r
754   EFI_TIMER_DELAY TimerOpType;\r
755 \r
756   NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
757 \r
758   Status = EFI_SUCCESS;\r
759 \r
760   if (!IsConfigUpdate) {\r
761     //\r
762     // If it's not a configuration update, increase the configured children number.\r
763     //\r
764     MnpServiceData->ConfiguredChildrenNumber++;\r
765 \r
766     if (MnpServiceData->ConfiguredChildrenNumber == 1) {\r
767       //\r
768       // It's the first configured child, start the simple network.\r
769       //\r
770       Status = MnpStartSnp (MnpServiceData->Snp);\r
771       if (EFI_ERROR (Status)) {\r
772 \r
773         DEBUG ((EFI_D_ERROR, "MnpStart: MnpStartSnp failed, %r.\n", Status));\r
774         goto ErrorExit;\r
775       }\r
776 \r
777       //\r
778       // Start the timeout timer.\r
779       //\r
780       Status = gBS->SetTimer (\r
781                       MnpServiceData->TimeoutCheckTimer,\r
782                       TimerPeriodic,\r
783                       MNP_TIMEOUT_CHECK_INTERVAL\r
784                       );\r
785       if (EFI_ERROR (Status)) {\r
786 \r
787         DEBUG (\r
788           (EFI_D_ERROR,\r
789           "MnpStart, gBS->SetTimer for TimeoutCheckTimer %r.\n",\r
790           Status)\r
791           );\r
792         goto ErrorExit;\r
793       }\r
794     }\r
795   }\r
796 \r
797   if (MnpServiceData->EnableSystemPoll ^ EnableSystemPoll) {\r
798     //\r
799     // The EnableSystemPoll differs with the current state, disable or enable\r
800     // the system poll.\r
801     //\r
802     TimerOpType = EnableSystemPoll ? TimerPeriodic : TimerCancel;\r
803 \r
804     Status      = gBS->SetTimer (MnpServiceData->PollTimer, TimerOpType, MNP_SYS_POLL_INTERVAL);\r
805     if (EFI_ERROR (Status)) {\r
806 \r
807       DEBUG ((EFI_D_ERROR, "MnpStart: gBS->SetTimer for PollTimer failed, %r.\n", Status));\r
808       goto ErrorExit;\r
809     }\r
810 \r
811     MnpServiceData->EnableSystemPoll = EnableSystemPoll;\r
812   }\r
813 \r
814   //\r
815   // Change the receive filters if need.\r
816   //\r
817   Status = MnpConfigReceiveFilters (MnpServiceData);\r
818 \r
819 ErrorExit:\r
820 \r
821   return Status;\r
822 }\r
823 \r
824 \r
825 /**\r
826   Stop the managed network.\r
827 \r
828   @param  MnpServiceData        Pointer to the mnp service context data.\r
829 \r
830   @retval EFI_SUCCESS           The managed network is stopped.\r
831   @retval Other                 Some error occurs.\r
832 \r
833 **/\r
834 EFI_STATUS\r
835 MnpStop (\r
836   IN MNP_SERVICE_DATA  *MnpServiceData\r
837   )\r
838 {\r
839   EFI_STATUS  Status;\r
840 \r
841   NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
842   ASSERT (MnpServiceData->ConfiguredChildrenNumber > 0);\r
843 \r
844   //\r
845   // Configure the receive filters.\r
846   //\r
847   MnpConfigReceiveFilters (MnpServiceData);\r
848 \r
849   //\r
850   // Decrease the children number.\r
851   //\r
852   MnpServiceData->ConfiguredChildrenNumber--;\r
853 \r
854   if (MnpServiceData->ConfiguredChildrenNumber > 0) {\r
855     //\r
856     // If there are other configured chilren, return and keep the timers and\r
857     // simple network unchanged.\r
858     //\r
859     return EFI_SUCCESS;\r
860   }\r
861 \r
862   //\r
863   // No configured children now.\r
864   //\r
865 \r
866   if (MnpServiceData->EnableSystemPoll) {\r
867     //\r
868     //  The system poll in on, cancel the poll timer.\r
869     //\r
870     Status  = gBS->SetTimer (MnpServiceData->PollTimer, TimerCancel, 0);\r
871     MnpServiceData->EnableSystemPoll = FALSE;\r
872   }\r
873 \r
874   //\r
875   // Cancel the timeout timer.\r
876   //\r
877   Status  = gBS->SetTimer (MnpServiceData->TimeoutCheckTimer, TimerCancel, 0);\r
878 \r
879   //\r
880   // Stop the simple network.\r
881   //\r
882   Status  = MnpStopSnp (MnpServiceData->Snp);\r
883 \r
884   return Status;\r
885 }\r
886 \r
887 \r
888 /**\r
889   Flush the instance's received data.\r
890 \r
891   @param  Instance              Pointer to the mnp instance context data.\r
892 \r
893   @return None.\r
894 \r
895 **/\r
896 VOID\r
897 MnpFlushRcvdDataQueue (\r
898   IN MNP_INSTANCE_DATA  *Instance\r
899   )\r
900 {\r
901   EFI_TPL          OldTpl;\r
902   MNP_RXDATA_WRAP *RxDataWrap;\r
903 \r
904   NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
905 \r
906   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
907 \r
908   while (!IsListEmpty (&Instance->RcvdPacketQueue)) {\r
909     //\r
910     // Remove all the Wraps.\r
911     //\r
912     RxDataWrap = NET_LIST_HEAD (&Instance->RcvdPacketQueue, MNP_RXDATA_WRAP, WrapEntry);\r
913 \r
914     //\r
915     // Recycle the RxDataWrap.\r
916     //\r
917     MnpRecycleRxData (NULL, (VOID *) RxDataWrap);\r
918     Instance->RcvdPacketQueueSize--;\r
919   }\r
920 \r
921   ASSERT (Instance->RcvdPacketQueueSize == 0);\r
922 \r
923   gBS->RestoreTPL (OldTpl);\r
924 }\r
925 \r
926 \r
927 /**\r
928   Configure the Instance using ConfigData.\r
929 \r
930   @param  Instance              Pointer to the mnp instance context data.\r
931   @param  ConfigData            Pointer to the configuration data used to configure\r
932                                 the isntance.\r
933 \r
934   @retval EFI_SUCCESS           The Instance is configured.\r
935   @retval EFI_UNSUPPORTED       EnableReceiveTimestamps is on and the\r
936                                 implementation doesn't support it.\r
937   @retval Other                 Some error occurs.\r
938 \r
939 **/\r
940 EFI_STATUS\r
941 MnpConfigureInstance (\r
942   IN MNP_INSTANCE_DATA                *Instance,\r
943   IN EFI_MANAGED_NETWORK_CONFIG_DATA  *ConfigData OPTIONAL\r
944   )\r
945 {\r
946   EFI_STATUS                      Status;\r
947   MNP_SERVICE_DATA                *MnpServiceData;\r
948   EFI_MANAGED_NETWORK_CONFIG_DATA *OldConfigData;\r
949   EFI_MANAGED_NETWORK_CONFIG_DATA *NewConfigData;\r
950   BOOLEAN                         IsConfigUpdate;\r
951 \r
952   NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
953 \r
954   if ((ConfigData != NULL) && ConfigData->EnableReceiveTimestamps) {\r
955     //\r
956     // Don't support timestamp.\r
957     //\r
958     return EFI_UNSUPPORTED;\r
959   }\r
960 \r
961   Status          = EFI_SUCCESS;\r
962 \r
963   MnpServiceData  = Instance->MnpServiceData;\r
964   NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
965 \r
966   IsConfigUpdate  = (BOOLEAN) ((Instance->Configured) && (ConfigData != NULL));\r
967 \r
968   OldConfigData   = &Instance->ConfigData;\r
969   NewConfigData   = ConfigData;\r
970   if (NewConfigData == NULL) {\r
971     //\r
972     // Restore back the default config data if a reset of this instance\r
973     // is required.\r
974     //\r
975     NewConfigData = &mMnpDefaultConfigData;\r
976   }\r
977 \r
978   //\r
979   // Reset the instance's receive filter.\r
980   //\r
981   Instance->ReceiveFilter = 0;\r
982 \r
983   //\r
984   // Clear the receive counters according to the old ConfigData.\r
985   //\r
986   if (OldConfigData->EnableUnicastReceive) {\r
987     MnpServiceData->UnicastCount--;\r
988   }\r
989 \r
990   if (OldConfigData->EnableMulticastReceive) {\r
991     MnpServiceData->MulticastCount--;\r
992   }\r
993 \r
994   if (OldConfigData->EnableBroadcastReceive) {\r
995     MnpServiceData->BroadcastCount--;\r
996   }\r
997 \r
998   if (OldConfigData->EnablePromiscuousReceive) {\r
999     MnpServiceData->PromiscuousCount--;\r
1000   }\r
1001 \r
1002   //\r
1003   // Set the receive filter counters and the receive filter of the\r
1004   // instance according to the new ConfigData.\r
1005   //\r
1006   if (NewConfigData->EnableUnicastReceive) {\r
1007     MnpServiceData->UnicastCount++;\r
1008     Instance->ReceiveFilter |= MNP_RECEIVE_UNICAST;\r
1009   }\r
1010 \r
1011   if (NewConfigData->EnableMulticastReceive) {\r
1012     MnpServiceData->MulticastCount++;\r
1013   }\r
1014 \r
1015   if (NewConfigData->EnableBroadcastReceive) {\r
1016     MnpServiceData->BroadcastCount++;\r
1017     Instance->ReceiveFilter |= MNP_RECEIVE_BROADCAST;\r
1018   }\r
1019 \r
1020   if (NewConfigData->EnablePromiscuousReceive) {\r
1021     MnpServiceData->PromiscuousCount++;\r
1022   }\r
1023 \r
1024   if (OldConfigData->FlushQueuesOnReset) {\r
1025 \r
1026     MnpFlushRcvdDataQueue (Instance);\r
1027   }\r
1028 \r
1029   if (ConfigData == NULL) {\r
1030 \r
1031     Instance->ManagedNetwork.Cancel (&Instance->ManagedNetwork, NULL);\r
1032   }\r
1033 \r
1034   if (!NewConfigData->EnableMulticastReceive) {\r
1035 \r
1036     MnpGroupOp (Instance, FALSE, NULL, NULL);\r
1037   }\r
1038 \r
1039   //\r
1040   // Save the new configuration data.\r
1041   //\r
1042   CopyMem (OldConfigData, NewConfigData, sizeof (*OldConfigData));\r
1043 \r
1044   Instance->Configured  = (BOOLEAN) (ConfigData != NULL);\r
1045 \r
1046   if (Instance->Configured) {\r
1047     //\r
1048     // The instance is configured, start the Mnp.\r
1049     //\r
1050     Status = MnpStart (\r
1051               MnpServiceData,\r
1052               IsConfigUpdate,\r
1053               (BOOLEAN) !NewConfigData->DisableBackgroundPolling\r
1054               );\r
1055   } else {\r
1056     //\r
1057     // The instance is changed to the unconfigured state, stop the Mnp.\r
1058     //\r
1059     Status = MnpStop (MnpServiceData);\r
1060   }\r
1061 \r
1062   return Status;\r
1063 }\r
1064 \r
1065 \r
1066 /**\r
1067   Configure the Snp receive filters according to the instances' receive filter\r
1068   settings.\r
1069 \r
1070   @param  MnpServiceData        Pointer to the mnp service context data.\r
1071 \r
1072   @retval EFI_SUCCESS           The receive filters is configured.\r
1073   @retval EFI_OUT_OF_RESOURCES  The receive filters can't be configured due to lack\r
1074                                 of memory resource.\r
1075 \r
1076 **/\r
1077 EFI_STATUS\r
1078 MnpConfigReceiveFilters (\r
1079   IN MNP_SERVICE_DATA  *MnpServiceData\r
1080   )\r
1081 {\r
1082   EFI_STATUS                  Status;\r
1083   EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
1084   EFI_MAC_ADDRESS             *MCastFilter;\r
1085   UINT32                      MCastFilterCnt;\r
1086   UINT32                      EnableFilterBits;\r
1087   UINT32                      DisableFilterBits;\r
1088   BOOLEAN                     ResetMCastFilters;\r
1089   LIST_ENTRY                  *Entry;\r
1090   UINT32                      Index;\r
1091   MNP_GROUP_ADDRESS           *GroupAddress;\r
1092 \r
1093   NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
1094 \r
1095   Snp = MnpServiceData->Snp;\r
1096 \r
1097   //\r
1098   // Initialize the enable filter and disable filter.\r
1099   //\r
1100   EnableFilterBits  = 0;\r
1101   DisableFilterBits = Snp->Mode->ReceiveFilterMask;\r
1102 \r
1103   if (MnpServiceData->UnicastCount != 0) {\r
1104     //\r
1105     // Enable unicast if any instance wants to receive unicast.\r
1106     //\r
1107     EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;\r
1108   }\r
1109 \r
1110   if (MnpServiceData->BroadcastCount != 0) {\r
1111     //\r
1112     // Enable broadcast if any instance wants to receive broadcast.\r
1113     //\r
1114     EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;\r
1115   }\r
1116 \r
1117   MCastFilter       = NULL;\r
1118   MCastFilterCnt    = 0;\r
1119   ResetMCastFilters = TRUE;\r
1120 \r
1121   if ((MnpServiceData->MulticastCount != 0) && (MnpServiceData->GroupAddressCount != 0)) {\r
1122     //\r
1123     // There are instances configured to receive multicast and already some group\r
1124     // addresses are joined.\r
1125     //\r
1126 \r
1127     ResetMCastFilters = FALSE;\r
1128 \r
1129     if (MnpServiceData->GroupAddressCount <= Snp->Mode->MaxMCastFilterCount) {\r
1130       //\r
1131       // The joind group address is less than simple network's maximum count.\r
1132       // Just configure the snp to do the multicast filtering.\r
1133       //\r
1134 \r
1135       EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;\r
1136 \r
1137       //\r
1138       // Allocate pool for the mulicast addresses.\r
1139       //\r
1140       MCastFilterCnt  = MnpServiceData->GroupAddressCount;\r
1141       MCastFilter     = AllocatePool (sizeof (EFI_MAC_ADDRESS) * MCastFilterCnt);\r
1142       if (MCastFilter == NULL) {\r
1143 \r
1144         DEBUG ((EFI_D_ERROR, "MnpConfigReceiveFilters: Failed to allocate memory resource for MCastFilter.\n"));\r
1145         return EFI_OUT_OF_RESOURCES;\r
1146       }\r
1147 \r
1148       //\r
1149       // Fill the multicast HW address buffer.\r
1150       //\r
1151       Index = 0;\r
1152       NET_LIST_FOR_EACH (Entry, &MnpServiceData->GroupAddressList) {\r
1153 \r
1154         GroupAddress            = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_ADDRESS, AddrEntry);\r
1155         CopyMem (MCastFilter + Index, &GroupAddress->Address, sizeof (*(MCastFilter + Index)));\r
1156         Index++;\r
1157 \r
1158         ASSERT (Index <= MCastFilterCnt);\r
1159       }\r
1160     } else {\r
1161       //\r
1162       // The maximum multicast is reached, set the filter to be promiscuous\r
1163       // multicast.\r
1164       //\r
1165 \r
1166       if (Snp->Mode->ReceiveFilterMask & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) {\r
1167         EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
1168       } else {\r
1169         //\r
1170         // Either MULTICAST or PROMISCUOUS_MULTICAST is not supported by Snp,\r
1171         // set the NIC to be promiscuous although this will tremendously degrade\r
1172         // the performance.\r
1173         //\r
1174         EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;\r
1175       }\r
1176     }\r
1177   }\r
1178 \r
1179   if (MnpServiceData->PromiscuousCount != 0) {\r
1180     //\r
1181     // Enable promiscuous if any instance wants to receive promiscuous.\r
1182     //\r
1183     EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;\r
1184   }\r
1185 \r
1186   //\r
1187   // Set the disable filter.\r
1188   //\r
1189   DisableFilterBits ^= EnableFilterBits;\r
1190 \r
1191   //\r
1192   // Configure the receive filters of SNP.\r
1193   //\r
1194   Status = Snp->ReceiveFilters (\r
1195                   Snp,\r
1196                   EnableFilterBits,\r
1197                   DisableFilterBits,\r
1198                   ResetMCastFilters,\r
1199                   MCastFilterCnt,\r
1200                   MCastFilter\r
1201                   );\r
1202   DEBUG_CODE (\r
1203     if (EFI_ERROR (Status)) {\r
1204 \r
1205     DEBUG (\r
1206       (EFI_D_ERROR,\r
1207       "MnpConfigReceiveFilters: Snp->ReceiveFilters failed, %r.\n",\r
1208       Status)\r
1209       );\r
1210   }\r
1211   );\r
1212 \r
1213   if (MCastFilter != NULL) {\r
1214     //\r
1215     // Free the buffer used to hold the group addresses.\r
1216     //\r
1217     gBS->FreePool (MCastFilter);\r
1218   }\r
1219 \r
1220   return Status;\r
1221 }\r
1222 \r
1223 \r
1224 /**\r
1225   Add a group address control block which controls the MacAddress for\r
1226   this instance.\r
1227 \r
1228   @param  Instance              Pointer to the mnp instance context data.\r
1229   @param  CtrlBlk               Pointer to the group address control block.\r
1230   @param  GroupAddress          Pointer to the group adress.\r
1231   @param  MacAddress            Pointer to the mac address.\r
1232   @param  HwAddressSize         The hardware address size.\r
1233 \r
1234   @retval EFI_SUCCESS           The group address control block is added.\r
1235   @retval EFI_OUT_OF_RESOURCE   Failed due to lack of memory resources.\r
1236 \r
1237 **/\r
1238 EFI_STATUS\r
1239 MnpGroupOpAddCtrlBlk (\r
1240   IN MNP_INSTANCE_DATA        *Instance,\r
1241   IN MNP_GROUP_CONTROL_BLOCK  *CtrlBlk,\r
1242   IN MNP_GROUP_ADDRESS        *GroupAddress OPTIONAL,\r
1243   IN EFI_MAC_ADDRESS          *MacAddress,\r
1244   IN UINT32                   HwAddressSize\r
1245   )\r
1246 {\r
1247   MNP_SERVICE_DATA  *MnpServiceData;\r
1248 \r
1249   NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
1250 \r
1251   MnpServiceData = Instance->MnpServiceData;\r
1252   NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
1253 \r
1254   if (GroupAddress == NULL) {\r
1255 \r
1256     ASSERT (MacAddress != NULL);\r
1257 \r
1258     //\r
1259     // Allocate a new GroupAddress to be added into MNP's GroupAddressList.\r
1260     //\r
1261     GroupAddress = AllocatePool (sizeof (MNP_GROUP_ADDRESS));\r
1262     if (GroupAddress == NULL) {\r
1263 \r
1264       DEBUG ((EFI_D_ERROR, "MnpGroupOpFormCtrlBlk: Failed to allocate memory resource.\n"));\r
1265 \r
1266       return EFI_OUT_OF_RESOURCES;\r
1267     }\r
1268 \r
1269     CopyMem (&GroupAddress->Address, MacAddress, sizeof (GroupAddress->Address));\r
1270     GroupAddress->RefCnt  = 0;\r
1271     InsertTailList (\r
1272       &MnpServiceData->GroupAddressList,\r
1273       &GroupAddress->AddrEntry\r
1274       );\r
1275     MnpServiceData->GroupAddressCount++;\r
1276   }\r
1277 \r
1278   //\r
1279   // Increase the RefCnt.\r
1280   //\r
1281   GroupAddress->RefCnt++;\r
1282 \r
1283   //\r
1284   // Add the CtrlBlk into the instance's GroupCtrlBlkList.\r
1285   //\r
1286   CtrlBlk->GroupAddress = GroupAddress;\r
1287   InsertTailList (&Instance->GroupCtrlBlkList, &CtrlBlk->CtrlBlkEntry);\r
1288 \r
1289   return EFI_SUCCESS;\r
1290 }\r
1291 \r
1292 \r
1293 /**\r
1294   Delete a group control block from the instance. If the controlled group address's\r
1295   reference count reaches zero, the group address is removed too.\r
1296 \r
1297   @param  Instance              Pointer to the instance context data.\r
1298   @param  CtrlBlk               Pointer to the group control block to delete.\r
1299 \r
1300   @return The group address controlled by the control block is no longer used or not.\r
1301 \r
1302 **/\r
1303 BOOLEAN\r
1304 MnpGroupOpDelCtrlBlk (\r
1305   IN MNP_INSTANCE_DATA        *Instance,\r
1306   IN MNP_GROUP_CONTROL_BLOCK  *CtrlBlk\r
1307   )\r
1308 {\r
1309   MNP_SERVICE_DATA  *MnpServiceData;\r
1310   MNP_GROUP_ADDRESS *GroupAddress;\r
1311 \r
1312   NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
1313 \r
1314   MnpServiceData = Instance->MnpServiceData;\r
1315   NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
1316 \r
1317   //\r
1318   // Remove and free the CtrlBlk.\r
1319   //\r
1320   GroupAddress = CtrlBlk->GroupAddress;\r
1321   RemoveEntryList (&CtrlBlk->CtrlBlkEntry);\r
1322   gBS->FreePool (CtrlBlk);\r
1323 \r
1324   ASSERT (GroupAddress->RefCnt > 0);\r
1325 \r
1326   //\r
1327   // Count down the RefCnt.\r
1328   //\r
1329   GroupAddress->RefCnt--;\r
1330 \r
1331   if (GroupAddress->RefCnt == 0) {\r
1332     //\r
1333     // Free this GroupAddress entry if no instance uses it.\r
1334     //\r
1335     MnpServiceData->GroupAddressCount--;\r
1336     RemoveEntryList (&GroupAddress->AddrEntry);\r
1337     gBS->FreePool (GroupAddress);\r
1338 \r
1339     return TRUE;\r
1340   }\r
1341 \r
1342   return FALSE;\r
1343 }\r
1344 \r
1345 \r
1346 /**\r
1347   Do the group operations for this instance.\r
1348 \r
1349   @param  Instance              Pointer to the instance context data.\r
1350   @param  JoinFlag              Set to TRUE to join a group. Set to TRUE to leave a\r
1351                                 group/groups.\r
1352   @param  MacAddress            Pointer to the group address to join or leave.\r
1353   @param  CtrlBlk               Pointer to the group control block if JoinFlag if\r
1354                                 FALSE.\r
1355 \r
1356   @retval EFI_SUCCESS           The group operation finished.\r
1357   @retval Other                 Some error occurs.\r
1358 \r
1359 **/\r
1360 EFI_STATUS\r
1361 MnpGroupOp (\r
1362   IN MNP_INSTANCE_DATA        *Instance,\r
1363   IN BOOLEAN                  JoinFlag,\r
1364   IN EFI_MAC_ADDRESS          *MacAddress OPTIONAL,\r
1365   IN MNP_GROUP_CONTROL_BLOCK  *CtrlBlk OPTIONAL\r
1366   )\r
1367 {\r
1368   MNP_SERVICE_DATA        *MnpServiceData;\r
1369   LIST_ENTRY              *Entry;\r
1370   LIST_ENTRY              *NextEntry;\r
1371   MNP_GROUP_ADDRESS       *GroupAddress;\r
1372   EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
1373   MNP_GROUP_CONTROL_BLOCK *NewCtrlBlk;\r
1374   EFI_STATUS              Status;\r
1375   BOOLEAN                 AddressExist;\r
1376   BOOLEAN                 NeedUpdate;\r
1377 \r
1378   NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
1379 \r
1380   MnpServiceData  = Instance->MnpServiceData;\r
1381   SnpMode         = MnpServiceData->Snp->Mode;\r
1382 \r
1383   if (JoinFlag) {\r
1384     //\r
1385     // A new gropu address is to be added.\r
1386     //\r
1387 \r
1388     GroupAddress  = NULL;\r
1389     AddressExist  = FALSE;\r
1390 \r
1391     //\r
1392     // Allocate memory for the control block.\r
1393     //\r
1394     NewCtrlBlk    = AllocatePool (sizeof (MNP_GROUP_CONTROL_BLOCK));\r
1395     if (NewCtrlBlk == NULL) {\r
1396 \r
1397       DEBUG ((EFI_D_ERROR, "MnpGroupOp: Failed to allocate memory resource.\n"));\r
1398       return EFI_OUT_OF_RESOURCES;\r
1399     }\r
1400 \r
1401     NET_LIST_FOR_EACH (Entry, &MnpServiceData->GroupAddressList) {\r
1402       //\r
1403       // Check whether the MacAddress is already joined by other instances.\r
1404       //\r
1405       GroupAddress = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_ADDRESS, AddrEntry);\r
1406       if (0 == CompareMem (\r
1407                 MacAddress,\r
1408                 &GroupAddress->Address,\r
1409                 SnpMode->HwAddressSize\r
1410                 )) {\r
1411 \r
1412         AddressExist = TRUE;\r
1413         break;\r
1414       }\r
1415     }\r
1416 \r
1417     if (!AddressExist) {\r
1418       GroupAddress = NULL;\r
1419     }\r
1420 \r
1421     //\r
1422     // Add the GroupAddress for this instance.\r
1423     //\r
1424     Status = MnpGroupOpAddCtrlBlk (\r
1425               Instance,\r
1426               NewCtrlBlk,\r
1427               GroupAddress,\r
1428               MacAddress,\r
1429               SnpMode->HwAddressSize\r
1430               );\r
1431     if (EFI_ERROR (Status)) {\r
1432 \r
1433       return Status;\r
1434     }\r
1435 \r
1436     NeedUpdate = TRUE;\r
1437   } else {\r
1438 \r
1439     if (MacAddress != NULL) {\r
1440 \r
1441       ASSERT (CtrlBlk != NULL);\r
1442 \r
1443       //\r
1444       // Leave the specific multicast mac address.\r
1445       //\r
1446       NeedUpdate = MnpGroupOpDelCtrlBlk (Instance, CtrlBlk);\r
1447     } else {\r
1448       //\r
1449       // Leave all multicast mac addresses.\r
1450       //\r
1451       NeedUpdate = FALSE;\r
1452 \r
1453       NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->GroupCtrlBlkList) {\r
1454 \r
1455         NewCtrlBlk = NET_LIST_USER_STRUCT (\r
1456                       Entry,\r
1457                       MNP_GROUP_CONTROL_BLOCK,\r
1458                       CtrlBlkEntry\r
1459                       );\r
1460         //\r
1461         // Update is required if the group address left is no longer used\r
1462         // by other instances.\r
1463         //\r
1464         NeedUpdate = MnpGroupOpDelCtrlBlk (Instance, NewCtrlBlk);\r
1465       }\r
1466     }\r
1467   }\r
1468 \r
1469   Status = EFI_SUCCESS;\r
1470 \r
1471   if (NeedUpdate) {\r
1472     //\r
1473     // Reconfigure the receive filters if necessary.\r
1474     //\r
1475     Status = MnpConfigReceiveFilters (MnpServiceData);\r
1476   }\r
1477 \r
1478   return Status;\r
1479 }\r