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