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