BaseTools:Change the path of the file that Binary Cache
[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 - 2018, Intel Corporation. All rights reserved.<BR>\r
5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
6 \r
7 **/\r
8 \r
9 #include "MnpImpl.h"\r
10 #include "MnpVlan.h"\r
11 \r
12 EFI_SERVICE_BINDING_PROTOCOL    mMnpServiceBindingProtocol = {\r
13   MnpServiceBindingCreateChild,\r
14   MnpServiceBindingDestroyChild\r
15 };\r
16 \r
17 EFI_MANAGED_NETWORK_PROTOCOL    mMnpProtocolTemplate = {\r
18   MnpGetModeData,\r
19   MnpConfigure,\r
20   MnpMcastIpToMac,\r
21   MnpGroups,\r
22   MnpTransmit,\r
23   MnpReceive,\r
24   MnpCancel,\r
25   MnpPoll\r
26 };\r
27 \r
28 EFI_MANAGED_NETWORK_CONFIG_DATA mMnpDefaultConfigData = {\r
29   10000000,\r
30   10000000,\r
31   0,\r
32   FALSE,\r
33   FALSE,\r
34   FALSE,\r
35   FALSE,\r
36   FALSE,\r
37   FALSE,\r
38   FALSE\r
39 };\r
40 \r
41 /**\r
42   Add Count of net buffers to MnpDeviceData->FreeNbufQue. The length of the net\r
43   buffer is specified by MnpDeviceData->BufferLength.\r
44 \r
45   @param[in, out]  MnpDeviceData         Pointer to the MNP_DEVICE_DATA.\r
46   @param[in]       Count                 Number of NET_BUFFERs to add.\r
47 \r
48   @retval EFI_SUCCESS           The specified amount of NET_BUFs are allocated\r
49                                 and added to MnpDeviceData->FreeNbufQue.\r
50   @retval EFI_OUT_OF_RESOURCES  Failed to allocate a NET_BUF structure.\r
51 \r
52 **/\r
53 EFI_STATUS\r
54 MnpAddFreeNbuf (\r
55   IN OUT MNP_DEVICE_DATA   *MnpDeviceData,\r
56   IN     UINTN             Count\r
57   )\r
58 {\r
59   EFI_STATUS  Status;\r
60   UINTN       Index;\r
61   NET_BUF     *Nbuf;\r
62 \r
63   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);\r
64   ASSERT ((Count > 0) && (MnpDeviceData->BufferLength > 0));\r
65 \r
66   Status = EFI_SUCCESS;\r
67   for (Index = 0; Index < Count; Index++) {\r
68     Nbuf = NetbufAlloc (MnpDeviceData->BufferLength + MnpDeviceData->PaddingSize);\r
69     if (Nbuf == NULL) {\r
70       DEBUG ((EFI_D_ERROR, "MnpAddFreeNbuf: NetBufAlloc failed.\n"));\r
71 \r
72       Status = EFI_OUT_OF_RESOURCES;\r
73       break;\r
74     }\r
75 \r
76     if (MnpDeviceData->PaddingSize > 0) {\r
77       //\r
78       // Pad padding bytes before the media header\r
79       //\r
80       NetbufAllocSpace (Nbuf, MnpDeviceData->PaddingSize, NET_BUF_TAIL);\r
81       NetbufTrim (Nbuf, MnpDeviceData->PaddingSize, NET_BUF_HEAD);\r
82     }\r
83 \r
84     NetbufQueAppend (&MnpDeviceData->FreeNbufQue, Nbuf);\r
85   }\r
86 \r
87   MnpDeviceData->NbufCnt += Index;\r
88   return Status;\r
89 }\r
90 \r
91 \r
92 /**\r
93   Allocate a free NET_BUF from MnpDeviceData->FreeNbufQue. If there is none\r
94   in the queue, first try to allocate some and add them into the queue, then\r
95   fetch the NET_BUF from the updated FreeNbufQue.\r
96 \r
97   @param[in, out]  MnpDeviceData        Pointer to the MNP_DEVICE_DATA.\r
98 \r
99   @return     Pointer to the allocated free NET_BUF structure, if NULL the\r
100               operation is failed.\r
101 \r
102 **/\r
103 NET_BUF *\r
104 MnpAllocNbuf (\r
105   IN OUT MNP_DEVICE_DATA   *MnpDeviceData\r
106   )\r
107 {\r
108   EFI_STATUS    Status;\r
109   NET_BUF_QUEUE *FreeNbufQue;\r
110   NET_BUF       *Nbuf;\r
111   EFI_TPL       OldTpl;\r
112 \r
113   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);\r
114 \r
115   FreeNbufQue = &MnpDeviceData->FreeNbufQue;\r
116   OldTpl      = gBS->RaiseTPL (TPL_NOTIFY);\r
117 \r
118   //\r
119   // Check whether there are available buffers, or else try to add some.\r
120   //\r
121   if (FreeNbufQue->BufNum == 0) {\r
122     if ((MnpDeviceData->NbufCnt + MNP_NET_BUFFER_INCREASEMENT) > MNP_MAX_NET_BUFFER_NUM) {\r
123       DEBUG (\r
124         (EFI_D_ERROR,\r
125         "MnpAllocNbuf: The maximum NET_BUF size is reached for MNP driver instance %p.\n",\r
126         MnpDeviceData)\r
127         );\r
128 \r
129       Nbuf = NULL;\r
130       goto ON_EXIT;\r
131     }\r
132 \r
133     Status = MnpAddFreeNbuf (MnpDeviceData, MNP_NET_BUFFER_INCREASEMENT);\r
134     if (EFI_ERROR (Status)) {\r
135       DEBUG (\r
136         (EFI_D_ERROR,\r
137         "MnpAllocNbuf: Failed to add NET_BUFs into the FreeNbufQue, %r.\n",\r
138         Status)\r
139         );\r
140 \r
141       //\r
142       // Don't return NULL, perhaps MnpAddFreeNbuf does add some NET_BUFs but\r
143       // the amount is less than MNP_NET_BUFFER_INCREASEMENT.\r
144       //\r
145     }\r
146   }\r
147 \r
148   Nbuf = NetbufQueRemove (FreeNbufQue);\r
149 \r
150   //\r
151   // Increase the RefCnt.\r
152   //\r
153   if (Nbuf != NULL) {\r
154     NET_GET_REF (Nbuf);\r
155   }\r
156 \r
157 ON_EXIT:\r
158   gBS->RestoreTPL (OldTpl);\r
159 \r
160   return Nbuf;\r
161 }\r
162 \r
163 \r
164 /**\r
165   Try to reclaim the Nbuf into the buffer pool.\r
166 \r
167   @param[in, out]  MnpDeviceData         Pointer to the mnp device context data.\r
168   @param[in, out]  Nbuf                  Pointer to the NET_BUF to free.\r
169 \r
170 **/\r
171 VOID\r
172 MnpFreeNbuf (\r
173   IN OUT MNP_DEVICE_DATA   *MnpDeviceData,\r
174   IN OUT NET_BUF           *Nbuf\r
175   )\r
176 {\r
177   EFI_TPL  OldTpl;\r
178 \r
179   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);\r
180   ASSERT (Nbuf->RefCnt > 1);\r
181 \r
182   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
183 \r
184   NET_PUT_REF (Nbuf);\r
185 \r
186   if (Nbuf->RefCnt == 1) {\r
187     //\r
188     // Trim all buffer contained in the Nbuf, then append it to the NbufQue.\r
189     //\r
190     NetbufTrim (Nbuf, Nbuf->TotalSize, NET_BUF_TAIL);\r
191 \r
192     if (NetbufAllocSpace (Nbuf, NET_VLAN_TAG_LEN, NET_BUF_HEAD) != NULL) {\r
193       //\r
194       // There is space reserved for vlan tag in the head, reclaim it\r
195       //\r
196       NetbufTrim (Nbuf, NET_VLAN_TAG_LEN, NET_BUF_TAIL);\r
197     }\r
198 \r
199     NetbufQueAppend (&MnpDeviceData->FreeNbufQue, Nbuf);\r
200   }\r
201 \r
202   gBS->RestoreTPL (OldTpl);\r
203 }\r
204 \r
205 /**\r
206   Add Count of TX buffers to MnpDeviceData->AllTxBufList and MnpDeviceData->FreeTxBufList.\r
207   The length of the buffer is specified by MnpDeviceData->BufferLength.\r
208 \r
209   @param[in, out]  MnpDeviceData         Pointer to the MNP_DEVICE_DATA.\r
210   @param[in]       Count                 Number of TX buffers to add.\r
211 \r
212   @retval EFI_SUCCESS           The specified amount of TX buffers are allocated.\r
213   @retval EFI_OUT_OF_RESOURCES  Failed to allocate a TX buffer.\r
214 \r
215 **/\r
216 EFI_STATUS\r
217 MnpAddFreeTxBuf (\r
218   IN OUT MNP_DEVICE_DATA   *MnpDeviceData,\r
219   IN     UINTN             Count\r
220   )\r
221 {\r
222   EFI_STATUS        Status;\r
223   UINT32            Index;\r
224   MNP_TX_BUF_WRAP   *TxBufWrap;\r
225 \r
226   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);\r
227   ASSERT ((Count > 0) && (MnpDeviceData->BufferLength > 0));\r
228 \r
229   Status = EFI_SUCCESS;\r
230   for (Index = 0; Index < Count; Index++) {\r
231     TxBufWrap = (MNP_TX_BUF_WRAP*) AllocatePool (OFFSET_OF (MNP_TX_BUF_WRAP, TxBuf) + MnpDeviceData->BufferLength );\r
232     if (TxBufWrap == NULL) {\r
233       DEBUG ((EFI_D_ERROR, "MnpAddFreeTxBuf: TxBuf Alloc failed.\n"));\r
234 \r
235       Status = EFI_OUT_OF_RESOURCES;\r
236       break;\r
237     }\r
238     DEBUG ((EFI_D_INFO, "MnpAddFreeTxBuf: Add TxBufWrap %p, TxBuf %p\n", TxBufWrap, TxBufWrap->TxBuf));\r
239     TxBufWrap->Signature = MNP_TX_BUF_WRAP_SIGNATURE;\r
240     TxBufWrap->InUse     = FALSE;\r
241     InsertTailList (&MnpDeviceData->FreeTxBufList, &TxBufWrap->WrapEntry);\r
242     InsertTailList (&MnpDeviceData->AllTxBufList, &TxBufWrap->AllEntry);\r
243   }\r
244 \r
245   MnpDeviceData->TxBufCount += Index;\r
246   return Status;\r
247 }\r
248 \r
249 /**\r
250   Allocate a free TX buffer from MnpDeviceData->FreeTxBufList. If there is none\r
251   in the queue, first try to recycle some from SNP, then try to allocate some and add\r
252   them into the queue, then fetch the NET_BUF from the updated FreeTxBufList.\r
253 \r
254   @param[in, out]  MnpDeviceData        Pointer to the MNP_DEVICE_DATA.\r
255 \r
256   @return     Pointer to the allocated free NET_BUF structure, if NULL the\r
257               operation is failed.\r
258 \r
259 **/\r
260 UINT8 *\r
261 MnpAllocTxBuf (\r
262   IN OUT MNP_DEVICE_DATA   *MnpDeviceData\r
263   )\r
264 {\r
265   EFI_TPL           OldTpl;\r
266   UINT8             *TxBuf;\r
267   EFI_STATUS        Status;\r
268   LIST_ENTRY        *Entry;\r
269   MNP_TX_BUF_WRAP   *TxBufWrap;\r
270 \r
271   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);\r
272 \r
273   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
274 \r
275   if (IsListEmpty (&MnpDeviceData->FreeTxBufList)) {\r
276     //\r
277     // First try to recycle some TX buffer from SNP\r
278     //\r
279     Status = MnpRecycleTxBuf (MnpDeviceData);\r
280     if (EFI_ERROR (Status)) {\r
281       TxBuf = NULL;\r
282       goto ON_EXIT;\r
283     }\r
284 \r
285     //\r
286     // If still no free TX buffer, allocate more.\r
287     //\r
288     if (IsListEmpty (&MnpDeviceData->FreeTxBufList)) {\r
289       if ((MnpDeviceData->TxBufCount + MNP_TX_BUFFER_INCREASEMENT) > MNP_MAX_TX_BUFFER_NUM) {\r
290         DEBUG (\r
291           (EFI_D_ERROR,\r
292           "MnpAllocTxBuf: The maximum TxBuf size is reached for MNP driver instance %p.\n",\r
293           MnpDeviceData)\r
294           );\r
295 \r
296         TxBuf = NULL;\r
297         goto ON_EXIT;\r
298       }\r
299 \r
300       Status = MnpAddFreeTxBuf (MnpDeviceData, MNP_TX_BUFFER_INCREASEMENT);\r
301       if (IsListEmpty (&MnpDeviceData->FreeTxBufList)) {\r
302         DEBUG (\r
303           (EFI_D_ERROR,\r
304           "MnpAllocNbuf: Failed to add TxBuf into the FreeTxBufList, %r.\n",\r
305           Status)\r
306           );\r
307 \r
308         TxBuf = NULL;\r
309         goto ON_EXIT;\r
310       }\r
311     }\r
312   }\r
313 \r
314   ASSERT (!IsListEmpty (&MnpDeviceData->FreeTxBufList));\r
315   Entry = MnpDeviceData->FreeTxBufList.ForwardLink;\r
316   RemoveEntryList (MnpDeviceData->FreeTxBufList.ForwardLink);\r
317   TxBufWrap = NET_LIST_USER_STRUCT_S (Entry, MNP_TX_BUF_WRAP, WrapEntry, MNP_TX_BUF_WRAP_SIGNATURE);\r
318   TxBufWrap->InUse = TRUE;\r
319   TxBuf = TxBufWrap->TxBuf;\r
320 \r
321 ON_EXIT:\r
322   gBS->RestoreTPL (OldTpl);\r
323 \r
324   return TxBuf;\r
325 }\r
326 \r
327 /**\r
328   Try to reclaim the TX buffer into the buffer pool.\r
329 \r
330   @param[in, out]  MnpDeviceData         Pointer to the mnp device context data.\r
331   @param[in, out]  TxBuf                 Pointer to the TX buffer to free.\r
332 \r
333 **/\r
334 VOID\r
335 MnpFreeTxBuf (\r
336   IN OUT MNP_DEVICE_DATA   *MnpDeviceData,\r
337   IN OUT UINT8             *TxBuf\r
338   )\r
339 {\r
340   MNP_TX_BUF_WRAP   *TxBufWrap;\r
341   EFI_TPL           OldTpl;\r
342 \r
343   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);\r
344 \r
345   if (TxBuf == NULL) {\r
346     return;\r
347   }\r
348 \r
349   TxBufWrap = NET_LIST_USER_STRUCT (TxBuf, MNP_TX_BUF_WRAP, TxBuf);\r
350   if (TxBufWrap->Signature != MNP_TX_BUF_WRAP_SIGNATURE) {\r
351     DEBUG (\r
352       (EFI_D_ERROR,\r
353       "MnpFreeTxBuf: Signature check failed in MnpFreeTxBuf.\n")\r
354       );\r
355     return;\r
356   }\r
357 \r
358   if (!TxBufWrap->InUse) {\r
359     DEBUG (\r
360       (EFI_D_WARN,\r
361       "MnpFreeTxBuf: Duplicated recycle report from SNP.\n")\r
362       );\r
363     return;\r
364   }\r
365 \r
366   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
367   InsertTailList (&MnpDeviceData->FreeTxBufList, &TxBufWrap->WrapEntry);\r
368   TxBufWrap->InUse = FALSE;\r
369   gBS->RestoreTPL (OldTpl);\r
370 }\r
371 \r
372 /**\r
373   Try to recycle all the transmitted buffer address from SNP.\r
374 \r
375   @param[in, out]  MnpDeviceData     Pointer to the mnp device context data.\r
376 \r
377   @retval EFI_SUCCESS             Successed to recyclethe transmitted buffer address.\r
378   @retval Others                  Failed to recyclethe transmitted buffer address.\r
379 \r
380 **/\r
381 EFI_STATUS\r
382 MnpRecycleTxBuf (\r
383   IN OUT MNP_DEVICE_DATA   *MnpDeviceData\r
384   )\r
385 {\r
386   UINT8                         *TxBuf;\r
387   EFI_SIMPLE_NETWORK_PROTOCOL   *Snp;\r
388   EFI_STATUS                    Status;\r
389 \r
390   Snp = MnpDeviceData->Snp;\r
391   ASSERT (Snp != NULL);\r
392 \r
393   do {\r
394     TxBuf = NULL;\r
395     Status = Snp->GetStatus (Snp, NULL, (VOID **) &TxBuf);\r
396     if (EFI_ERROR (Status)) {\r
397       return Status;\r
398     }\r
399 \r
400     if (TxBuf != NULL) {\r
401       MnpFreeTxBuf (MnpDeviceData, TxBuf);\r
402     }\r
403   } while (TxBuf != NULL);\r
404 \r
405   return EFI_SUCCESS;\r
406 }\r
407 \r
408 /**\r
409   Initialize the mnp device context data.\r
410 \r
411   @param[in, out]  MnpDeviceData      Pointer to the mnp device context data.\r
412   @param[in]       ImageHandle        The driver image handle.\r
413   @param[in]       ControllerHandle   Handle of device to bind driver to.\r
414 \r
415   @retval EFI_SUCCESS           The mnp service context is initialized.\r
416   @retval EFI_UNSUPPORTED       ControllerHandle does not support Simple Network Protocol.\r
417   @retval Others                Other errors as indicated.\r
418 \r
419 **/\r
420 EFI_STATUS\r
421 MnpInitializeDeviceData (\r
422   IN OUT MNP_DEVICE_DATA   *MnpDeviceData,\r
423   IN     EFI_HANDLE        ImageHandle,\r
424   IN     EFI_HANDLE        ControllerHandle\r
425   )\r
426 {\r
427   EFI_STATUS                  Status;\r
428   EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
429   EFI_SIMPLE_NETWORK_MODE     *SnpMode;\r
430 \r
431   MnpDeviceData->Signature        = MNP_DEVICE_DATA_SIGNATURE;\r
432   MnpDeviceData->ImageHandle      = ImageHandle;\r
433   MnpDeviceData->ControllerHandle = ControllerHandle;\r
434 \r
435   //\r
436   // Copy the MNP Protocol interfaces from the template.\r
437   //\r
438   CopyMem (&MnpDeviceData->VlanConfig, &mVlanConfigProtocolTemplate, sizeof (EFI_VLAN_CONFIG_PROTOCOL));\r
439 \r
440   //\r
441   // Open the Simple Network protocol.\r
442   //\r
443   Status = gBS->OpenProtocol (\r
444                   ControllerHandle,\r
445                   &gEfiSimpleNetworkProtocolGuid,\r
446                   (VOID **) &Snp,\r
447                   ImageHandle,\r
448                   ControllerHandle,\r
449                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
450                   );\r
451   if (EFI_ERROR (Status)) {\r
452     return EFI_UNSUPPORTED;\r
453   }\r
454 \r
455   //\r
456   // Get MTU from Snp.\r
457   //\r
458   SnpMode            = Snp->Mode;\r
459   MnpDeviceData->Snp = Snp;\r
460 \r
461   //\r
462   // Initialize the lists.\r
463   //\r
464   InitializeListHead (&MnpDeviceData->ServiceList);\r
465   InitializeListHead (&MnpDeviceData->GroupAddressList);\r
466 \r
467   //\r
468   // Get the buffer length used to allocate NET_BUF to hold data received\r
469   // from SNP. Do this before fill the FreeNetBufQue.\r
470   //\r
471   //\r
472   MnpDeviceData->BufferLength = SnpMode->MediaHeaderSize + NET_VLAN_TAG_LEN + SnpMode->MaxPacketSize + NET_ETHER_FCS_SIZE;\r
473 \r
474   //\r
475   // Make sure the protocol headers immediately following the media header\r
476   // 4-byte aligned, and also preserve additional space for VLAN tag\r
477   //\r
478   MnpDeviceData->PaddingSize = ((4 - SnpMode->MediaHeaderSize) & 0x3) + NET_VLAN_TAG_LEN;\r
479 \r
480   //\r
481   // Initialize MAC string which will be used as VLAN configuration variable name\r
482   //\r
483   Status = NetLibGetMacString (ControllerHandle, ImageHandle, &MnpDeviceData->MacString);\r
484   if (EFI_ERROR (Status)) {\r
485     goto ERROR;\r
486   }\r
487 \r
488   //\r
489   // Initialize the FreeNetBufQue and pre-allocate some NET_BUFs.\r
490   //\r
491   NetbufQueInit (&MnpDeviceData->FreeNbufQue);\r
492   Status = MnpAddFreeNbuf (MnpDeviceData, MNP_INIT_NET_BUFFER_NUM);\r
493   if (EFI_ERROR (Status)) {\r
494     DEBUG ((EFI_D_ERROR, "MnpInitializeDeviceData: MnpAddFreeNbuf failed, %r.\n", Status));\r
495 \r
496     goto ERROR;\r
497   }\r
498 \r
499   //\r
500   // Get one NET_BUF from the FreeNbufQue for rx cache.\r
501   //\r
502   MnpDeviceData->RxNbufCache = MnpAllocNbuf (MnpDeviceData);\r
503   NetbufAllocSpace (\r
504     MnpDeviceData->RxNbufCache,\r
505     MnpDeviceData->BufferLength,\r
506     NET_BUF_TAIL\r
507     );\r
508 \r
509   //\r
510   // Allocate buffer pool for tx.\r
511   //\r
512   InitializeListHead (&MnpDeviceData->FreeTxBufList);\r
513   InitializeListHead (&MnpDeviceData->AllTxBufList);\r
514   MnpDeviceData->TxBufCount = 0;\r
515 \r
516   //\r
517   // Create the system poll timer.\r
518   //\r
519   Status = gBS->CreateEvent (\r
520                   EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
521                   TPL_CALLBACK,\r
522                   MnpSystemPoll,\r
523                   MnpDeviceData,\r
524                   &MnpDeviceData->PollTimer\r
525                   );\r
526   if (EFI_ERROR (Status)) {\r
527     DEBUG ((EFI_D_ERROR, "MnpInitializeDeviceData: CreateEvent for poll timer failed.\n"));\r
528 \r
529     goto ERROR;\r
530   }\r
531 \r
532   //\r
533   // Create the timer for packet timeout check.\r
534   //\r
535   Status = gBS->CreateEvent (\r
536                   EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
537                   TPL_CALLBACK,\r
538                   MnpCheckPacketTimeout,\r
539                   MnpDeviceData,\r
540                   &MnpDeviceData->TimeoutCheckTimer\r
541                   );\r
542   if (EFI_ERROR (Status)) {\r
543     DEBUG ((EFI_D_ERROR, "MnpInitializeDeviceData: CreateEvent for packet timeout check failed.\n"));\r
544 \r
545     goto ERROR;\r
546   }\r
547 \r
548   //\r
549   // Create the timer for media detection.\r
550   //\r
551   Status = gBS->CreateEvent (\r
552                   EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
553                   TPL_CALLBACK,\r
554                   MnpCheckMediaStatus,\r
555                   MnpDeviceData,\r
556                   &MnpDeviceData->MediaDetectTimer\r
557                   );\r
558   if (EFI_ERROR (Status)) {\r
559     DEBUG ((EFI_D_ERROR, "MnpInitializeDeviceData: CreateEvent for media detection failed.\n"));\r
560 \r
561     goto ERROR;\r
562   }\r
563 \r
564 ERROR:\r
565   if (EFI_ERROR (Status)) {\r
566     //\r
567     // Free the dynamic allocated resources if necessary.\r
568     //\r
569     if (MnpDeviceData->MacString != NULL) {\r
570       FreePool (MnpDeviceData->MacString);\r
571     }\r
572 \r
573     if (MnpDeviceData->TimeoutCheckTimer != NULL) {\r
574       gBS->CloseEvent (MnpDeviceData->TimeoutCheckTimer);\r
575     }\r
576 \r
577     if (MnpDeviceData->MediaDetectTimer != NULL) {\r
578       gBS->CloseEvent (MnpDeviceData->MediaDetectTimer);\r
579     }\r
580 \r
581     if (MnpDeviceData->PollTimer != NULL) {\r
582       gBS->CloseEvent (MnpDeviceData->PollTimer);\r
583     }\r
584 \r
585     if (MnpDeviceData->RxNbufCache != NULL) {\r
586       MnpFreeNbuf (MnpDeviceData, MnpDeviceData->RxNbufCache);\r
587     }\r
588 \r
589     if (MnpDeviceData->FreeNbufQue.BufNum != 0) {\r
590       NetbufQueFlush (&MnpDeviceData->FreeNbufQue);\r
591     }\r
592 \r
593     //\r
594     // Close the Simple Network Protocol.\r
595     //\r
596     gBS->CloseProtocol (\r
597           ControllerHandle,\r
598           &gEfiSimpleNetworkProtocolGuid,\r
599           ImageHandle,\r
600           ControllerHandle\r
601           );\r
602   }\r
603 \r
604   return Status;\r
605 }\r
606 \r
607 \r
608 /**\r
609   Destroy the MNP device context data.\r
610 \r
611   @param[in, out]  MnpDeviceData      Pointer to the mnp device context data.\r
612   @param[in]       ImageHandle        The driver image handle.\r
613 \r
614 **/\r
615 VOID\r
616 MnpDestroyDeviceData (\r
617   IN OUT MNP_DEVICE_DATA   *MnpDeviceData,\r
618   IN     EFI_HANDLE        ImageHandle\r
619   )\r
620 {\r
621   LIST_ENTRY         *Entry;\r
622   LIST_ENTRY         *NextEntry;\r
623   MNP_TX_BUF_WRAP    *TxBufWrap;\r
624 \r
625   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);\r
626 \r
627   //\r
628   // Free Vlan Config variable name string\r
629   //\r
630   if (MnpDeviceData->MacString != NULL) {\r
631     FreePool (MnpDeviceData->MacString);\r
632   }\r
633 \r
634   //\r
635   // The GroupAddressList must be empty.\r
636   //\r
637   ASSERT (IsListEmpty (&MnpDeviceData->GroupAddressList));\r
638 \r
639   //\r
640   // Close the event.\r
641   //\r
642   gBS->CloseEvent (MnpDeviceData->TimeoutCheckTimer);\r
643   gBS->CloseEvent (MnpDeviceData->MediaDetectTimer);\r
644   gBS->CloseEvent (MnpDeviceData->PollTimer);\r
645 \r
646   //\r
647   // Free the Tx buffer pool.\r
648   //\r
649   NET_LIST_FOR_EACH_SAFE(Entry, NextEntry, &MnpDeviceData->AllTxBufList) {\r
650     TxBufWrap = NET_LIST_USER_STRUCT (Entry, MNP_TX_BUF_WRAP, AllEntry);\r
651     RemoveEntryList (Entry);\r
652     FreePool (TxBufWrap);\r
653     MnpDeviceData->TxBufCount--;\r
654   }\r
655   ASSERT (IsListEmpty (&MnpDeviceData->AllTxBufList));\r
656   ASSERT (MnpDeviceData->TxBufCount == 0);\r
657 \r
658   //\r
659   // Free the RxNbufCache.\r
660   //\r
661   MnpFreeNbuf (MnpDeviceData, MnpDeviceData->RxNbufCache);\r
662 \r
663   //\r
664   // Flush the FreeNbufQue.\r
665   //\r
666   MnpDeviceData->NbufCnt -= MnpDeviceData->FreeNbufQue.BufNum;\r
667   NetbufQueFlush (&MnpDeviceData->FreeNbufQue);\r
668 \r
669   //\r
670   // Close the Simple Network Protocol.\r
671   //\r
672   gBS->CloseProtocol (\r
673          MnpDeviceData->ControllerHandle,\r
674          &gEfiSimpleNetworkProtocolGuid,\r
675          ImageHandle,\r
676          MnpDeviceData->ControllerHandle\r
677          );\r
678 }\r
679 \r
680 \r
681 /**\r
682   Create mnp service context data.\r
683 \r
684   @param[in]       MnpDeviceData      Pointer to the mnp device context data.\r
685   @param[in]       VlanId             The VLAN ID.\r
686   @param[in]       Priority           The VLAN priority. If VlanId is 0,\r
687                                       Priority is ignored.\r
688 \r
689   @return A pointer to MNP_SERVICE_DATA or NULL if failed to create MNP service context.\r
690 \r
691 **/\r
692 MNP_SERVICE_DATA *\r
693 MnpCreateServiceData (\r
694   IN MNP_DEVICE_DATA     *MnpDeviceData,\r
695   IN UINT16              VlanId,\r
696   IN UINT8                Priority OPTIONAL\r
697   )\r
698 {\r
699   EFI_HANDLE                MnpServiceHandle;\r
700   MNP_SERVICE_DATA          *MnpServiceData;\r
701   EFI_STATUS                Status;\r
702   EFI_SIMPLE_NETWORK_MODE   *SnpMode;\r
703   EFI_VLAN_CONFIG_PROTOCOL  *VlanConfig;\r
704 \r
705   //\r
706   // Initialize the Mnp Service Data.\r
707   //\r
708   MnpServiceData = AllocateZeroPool (sizeof (MNP_SERVICE_DATA));\r
709   if (MnpServiceData == NULL) {\r
710     DEBUG ((EFI_D_ERROR, "MnpCreateServiceData: Faild to allocate memory for the new Mnp Service Data.\n"));\r
711 \r
712     return NULL;\r
713   }\r
714 \r
715   //\r
716   // Add to MNP service list\r
717   //\r
718   InsertTailList (&MnpDeviceData->ServiceList, &MnpServiceData->Link);\r
719 \r
720   MnpServiceData->Signature     = MNP_SERVICE_DATA_SIGNATURE;\r
721   MnpServiceData->MnpDeviceData = MnpDeviceData;\r
722 \r
723   //\r
724   // Copy the ServiceBinding structure.\r
725   //\r
726   CopyMem (&MnpServiceData->ServiceBinding, &mMnpServiceBindingProtocol, sizeof (EFI_SERVICE_BINDING_PROTOCOL));\r
727 \r
728   //\r
729   // Initialize the lists.\r
730   //\r
731   InitializeListHead (&MnpServiceData->ChildrenList);\r
732 \r
733   SnpMode = MnpDeviceData->Snp->Mode;\r
734   if (VlanId != 0) {\r
735     //\r
736     // Create VLAN child handle\r
737     //\r
738     MnpServiceHandle = MnpCreateVlanChild (\r
739                          MnpDeviceData->ImageHandle,\r
740                          MnpDeviceData->ControllerHandle,\r
741                          VlanId,\r
742                          &MnpServiceData->DevicePath\r
743                          );\r
744     if (MnpServiceHandle == NULL) {\r
745       DEBUG ((EFI_D_ERROR, "MnpCreateServiceData: Faild to create child handle.\n"));\r
746 \r
747       return NULL;\r
748     }\r
749 \r
750     //\r
751     // Open VLAN Config Protocol by child\r
752     //\r
753     Status = gBS->OpenProtocol (\r
754                     MnpDeviceData->ControllerHandle,\r
755                     &gEfiVlanConfigProtocolGuid,\r
756                     (VOID **) &VlanConfig,\r
757                     MnpDeviceData->ImageHandle,\r
758                     MnpServiceHandle,\r
759                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
760                     );\r
761     if (EFI_ERROR (Status)) {\r
762       goto Exit;\r
763     }\r
764 \r
765     //\r
766     // Reduce MTU for VLAN device\r
767     //\r
768     MnpServiceData->Mtu = SnpMode->MaxPacketSize - NET_VLAN_TAG_LEN;\r
769   } else {\r
770     //\r
771     // VlanId set to 0 means rx/tx untagged frame\r
772     //\r
773     MnpServiceHandle    = MnpDeviceData->ControllerHandle;\r
774     MnpServiceData->Mtu = SnpMode->MaxPacketSize;\r
775   }\r
776 \r
777   MnpServiceData->ServiceHandle = MnpServiceHandle;\r
778   MnpServiceData->VlanId        = VlanId;\r
779   MnpServiceData->Priority      = Priority;\r
780 \r
781   //\r
782   // Install the MNP Service Binding Protocol\r
783   //\r
784   Status = gBS->InstallMultipleProtocolInterfaces (\r
785                   &MnpServiceHandle,\r
786                   &gEfiManagedNetworkServiceBindingProtocolGuid,\r
787                   &MnpServiceData->ServiceBinding,\r
788                   NULL\r
789                   );\r
790 \r
791 Exit:\r
792   if (EFI_ERROR (Status)) {\r
793     MnpDestroyServiceData (MnpServiceData);\r
794     MnpServiceData = NULL;\r
795   }\r
796 \r
797   return MnpServiceData;\r
798 }\r
799 \r
800 /**\r
801   Destroy the MNP service context data.\r
802 \r
803   @param[in, out]  MnpServiceData    Pointer to the mnp service context data.\r
804 \r
805   @retval EFI_SUCCESS           The mnp service context is destroyed.\r
806   @retval Others                Errors as indicated.\r
807 \r
808 **/\r
809 EFI_STATUS\r
810 MnpDestroyServiceData (\r
811   IN OUT MNP_SERVICE_DATA    *MnpServiceData\r
812   )\r
813 {\r
814   EFI_STATUS  Status;\r
815 \r
816   //\r
817   // Uninstall the MNP Service Binding Protocol\r
818   //\r
819   Status = gBS->UninstallMultipleProtocolInterfaces (\r
820                   MnpServiceData->ServiceHandle,\r
821                   &gEfiManagedNetworkServiceBindingProtocolGuid,\r
822                   &MnpServiceData->ServiceBinding,\r
823                   NULL\r
824                   );\r
825   if (EFI_ERROR (Status)) {\r
826     return Status;\r
827   }\r
828 \r
829   if (MnpServiceData->VlanId != 0) {\r
830     //\r
831     // Close VlanConfig Protocol opened by VLAN child handle\r
832     //\r
833     Status = gBS->CloseProtocol (\r
834                     MnpServiceData->MnpDeviceData->ControllerHandle,\r
835                     &gEfiVlanConfigProtocolGuid,\r
836                     MnpServiceData->MnpDeviceData->ImageHandle,\r
837                     MnpServiceData->ServiceHandle\r
838                     );\r
839     if (EFI_ERROR (Status)) {\r
840       return Status;\r
841     }\r
842 \r
843     //\r
844     // Uninstall Device Path Protocol to destroy the VLAN child handle\r
845     //\r
846     Status = gBS->UninstallMultipleProtocolInterfaces (\r
847                     MnpServiceData->ServiceHandle,\r
848                     &gEfiDevicePathProtocolGuid,\r
849                     MnpServiceData->DevicePath,\r
850                     NULL\r
851                     );\r
852     if (EFI_ERROR (Status)) {\r
853       return Status;\r
854     }\r
855 \r
856     if (MnpServiceData->DevicePath != NULL) {\r
857       FreePool (MnpServiceData->DevicePath);\r
858     }\r
859   }\r
860 \r
861   //\r
862   // Remove from MnpDeviceData service list\r
863   //\r
864   RemoveEntryList (&MnpServiceData->Link);\r
865 \r
866   FreePool (MnpServiceData);\r
867 \r
868   return Status;\r
869 }\r
870 \r
871 /**\r
872   Callback function which provided by user to remove one node in NetDestroyLinkList process.\r
873 \r
874   @param[in]    Entry           The entry to be removed.\r
875   @param[in]    Context         Pointer to the callback context corresponds to the Context in NetDestroyLinkList.\r
876 \r
877   @retval EFI_SUCCESS           The entry has been removed successfully.\r
878   @retval Others                Fail to remove the entry.\r
879 \r
880 **/\r
881 EFI_STATUS\r
882 EFIAPI\r
883 MnpDestoryChildEntry (\r
884   IN LIST_ENTRY         *Entry,\r
885   IN VOID               *Context\r
886   )\r
887 {\r
888   MNP_INSTANCE_DATA             *Instance;\r
889   EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;\r
890 \r
891   ServiceBinding = (EFI_SERVICE_BINDING_PROTOCOL *) Context;\r
892   Instance = CR (Entry, MNP_INSTANCE_DATA, InstEntry, MNP_INSTANCE_DATA_SIGNATURE);\r
893   return ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);\r
894 }\r
895 \r
896 /**\r
897   Destroy all child of the MNP service data.\r
898 \r
899   @param[in, out]  MnpServiceData    Pointer to the mnp service context data.\r
900 \r
901   @retval EFI_SUCCESS           All child are destroyed.\r
902   @retval Others                Failed to destroy all child.\r
903 \r
904 **/\r
905 EFI_STATUS\r
906 MnpDestroyServiceChild (\r
907   IN OUT MNP_SERVICE_DATA    *MnpServiceData\r
908   )\r
909 {\r
910   LIST_ENTRY                         *List;\r
911   EFI_STATUS                         Status;\r
912   UINTN                              ListLength;\r
913 \r
914   List = &MnpServiceData->ChildrenList;\r
915 \r
916   Status = NetDestroyLinkList (\r
917              List,\r
918              MnpDestoryChildEntry,\r
919              &MnpServiceData->ServiceBinding,\r
920              &ListLength\r
921              );\r
922   if (EFI_ERROR (Status) || ListLength != 0) {\r
923     return EFI_DEVICE_ERROR;\r
924   }\r
925 \r
926   return EFI_SUCCESS;\r
927 }\r
928 \r
929 /**\r
930   Find the MNP Service Data for given VLAN ID.\r
931 \r
932   @param[in]  MnpDeviceData      Pointer to the mnp device context data.\r
933   @param[in]  VlanId             The VLAN ID.\r
934 \r
935   @return A pointer to MNP_SERVICE_DATA or NULL if not found.\r
936 \r
937 **/\r
938 MNP_SERVICE_DATA *\r
939 MnpFindServiceData (\r
940   IN MNP_DEVICE_DATA     *MnpDeviceData,\r
941   IN UINT16              VlanId\r
942   )\r
943 {\r
944   LIST_ENTRY        *Entry;\r
945   MNP_SERVICE_DATA  *MnpServiceData;\r
946 \r
947   NET_LIST_FOR_EACH (Entry, &MnpDeviceData->ServiceList) {\r
948     //\r
949     // Check VLAN ID of each Mnp Service Data\r
950     //\r
951     MnpServiceData = MNP_SERVICE_DATA_FROM_LINK (Entry);\r
952     if (MnpServiceData->VlanId == VlanId) {\r
953       return MnpServiceData;\r
954     }\r
955   }\r
956 \r
957   return NULL;\r
958 }\r
959 \r
960 /**\r
961   Initialize the mnp instance context data.\r
962 \r
963   @param[in]       MnpServiceData   Pointer to the mnp service context data.\r
964   @param[in, out]  Instance         Pointer to the mnp instance context data\r
965                                     to initialize.\r
966 \r
967 **/\r
968 VOID\r
969 MnpInitializeInstanceData (\r
970   IN     MNP_SERVICE_DATA    *MnpServiceData,\r
971   IN OUT MNP_INSTANCE_DATA   *Instance\r
972   )\r
973 {\r
974   NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
975   ASSERT (Instance != NULL);\r
976 \r
977   //\r
978   // Set the signature.\r
979   //\r
980   Instance->Signature = MNP_INSTANCE_DATA_SIGNATURE;\r
981 \r
982   //\r
983   // Copy the MNP Protocol interfaces from the template.\r
984   //\r
985   CopyMem (&Instance->ManagedNetwork, &mMnpProtocolTemplate, sizeof (Instance->ManagedNetwork));\r
986 \r
987   //\r
988   // Copy the default config data.\r
989   //\r
990   CopyMem (&Instance->ConfigData, &mMnpDefaultConfigData, sizeof (Instance->ConfigData));\r
991 \r
992   //\r
993   // Initialize the lists.\r
994   //\r
995   InitializeListHead (&Instance->GroupCtrlBlkList);\r
996   InitializeListHead (&Instance->RcvdPacketQueue);\r
997   InitializeListHead (&Instance->RxDeliveredPacketQueue);\r
998 \r
999   //\r
1000   // Initialize the RxToken Map.\r
1001   //\r
1002   NetMapInit (&Instance->RxTokenMap);\r
1003 \r
1004   //\r
1005   // Save the MnpServiceData info.\r
1006   //\r
1007   Instance->MnpServiceData = MnpServiceData;\r
1008 }\r
1009 \r
1010 \r
1011 /**\r
1012   Check whether the token specified by Arg matches the token in Item.\r
1013 \r
1014   @param[in]  Map               Pointer to the NET_MAP.\r
1015   @param[in]  Item              Pointer to the NET_MAP_ITEM.\r
1016   @param[in]  Arg               Pointer to the Arg, it's a pointer to the token to\r
1017                                 check.\r
1018 \r
1019   @retval EFI_SUCCESS           The token specified by Arg is different from the\r
1020                                 token in Item.\r
1021   @retval EFI_ACCESS_DENIED     The token specified by Arg is the same as that in\r
1022                                 Item.\r
1023 \r
1024 **/\r
1025 EFI_STATUS\r
1026 EFIAPI\r
1027 MnpTokenExist (\r
1028   IN NET_MAP         *Map,\r
1029   IN NET_MAP_ITEM    *Item,\r
1030   IN VOID            *Arg\r
1031   )\r
1032 {\r
1033   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *Token;\r
1034   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *TokenInItem;\r
1035 \r
1036   Token       = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *) Arg;\r
1037   TokenInItem = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *) Item->Key;\r
1038 \r
1039   if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {\r
1040     //\r
1041     // The token is the same either the two tokens equals or the Events in\r
1042     // the two tokens are the same.\r
1043     //\r
1044     return EFI_ACCESS_DENIED;\r
1045   }\r
1046 \r
1047   return EFI_SUCCESS;\r
1048 }\r
1049 \r
1050 /**\r
1051   Cancel the token specified by Arg if it matches the token in Item.\r
1052 \r
1053   @param[in, out]  Map               Pointer to the NET_MAP.\r
1054   @param[in, out]  Item              Pointer to the NET_MAP_ITEM.\r
1055   @param[in]       Arg               Pointer to the Arg, it's a pointer to the\r
1056                                      token to cancel.\r
1057 \r
1058   @retval EFI_SUCCESS       The Arg is NULL, and the token in Item is cancelled,\r
1059                             or the Arg isn't NULL, and the token in Item is\r
1060                             different from the Arg.\r
1061   @retval EFI_ABORTED       The Arg isn't NULL, the token in Item mathces the\r
1062                             Arg, and the token is cancelled.\r
1063 \r
1064 **/\r
1065 EFI_STATUS\r
1066 EFIAPI\r
1067 MnpCancelTokens (\r
1068   IN OUT NET_MAP         *Map,\r
1069   IN OUT NET_MAP_ITEM    *Item,\r
1070   IN     VOID            *Arg\r
1071   )\r
1072 {\r
1073   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *TokenToCancel;\r
1074 \r
1075   if ((Arg != NULL) && (Item->Key != Arg)) {\r
1076     //\r
1077     // The token in Item is not the token specified by Arg.\r
1078     //\r
1079     return EFI_SUCCESS;\r
1080   }\r
1081 \r
1082   TokenToCancel = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *) Item->Key;\r
1083 \r
1084   //\r
1085   // Remove the item from the map.\r
1086   //\r
1087   NetMapRemoveItem (Map, Item, NULL);\r
1088 \r
1089   //\r
1090   // Cancel this token with status set to EFI_ABORTED.\r
1091   //\r
1092   TokenToCancel->Status = EFI_ABORTED;\r
1093   gBS->SignalEvent (TokenToCancel->Event);\r
1094 \r
1095   if (Arg != NULL) {\r
1096     //\r
1097     // Only abort the token specified by Arg if Arg isn't NULL.\r
1098     //\r
1099     return EFI_ABORTED;\r
1100   }\r
1101 \r
1102   return EFI_SUCCESS;\r
1103 }\r
1104 \r
1105 \r
1106 /**\r
1107   Start and initialize the simple network.\r
1108 \r
1109   @param[in]  Snp               Pointer to the simple network protocol.\r
1110 \r
1111   @retval EFI_SUCCESS           The simple network protocol is started.\r
1112   @retval Others                Other errors as indicated.\r
1113 \r
1114 **/\r
1115 EFI_STATUS\r
1116 MnpStartSnp (\r
1117   IN EFI_SIMPLE_NETWORK_PROTOCOL     *Snp\r
1118   )\r
1119 {\r
1120   EFI_STATUS  Status;\r
1121 \r
1122   ASSERT (Snp != NULL);\r
1123 \r
1124   //\r
1125   // Start the simple network.\r
1126   //\r
1127   Status = Snp->Start (Snp);\r
1128 \r
1129   if (!EFI_ERROR (Status)) {\r
1130     //\r
1131     // Initialize the simple network.\r
1132     //\r
1133     Status = Snp->Initialize (Snp, 0, 0);\r
1134   }\r
1135 \r
1136   return Status;\r
1137 }\r
1138 \r
1139 \r
1140 /**\r
1141   Stop the simple network.\r
1142 \r
1143   @param[in]  MnpDeviceData     Pointer to the MNP_DEVICE_DATA.\r
1144 \r
1145   @retval EFI_SUCCESS           The simple network is stopped.\r
1146   @retval Others                Other errors as indicated.\r
1147 \r
1148 **/\r
1149 EFI_STATUS\r
1150 MnpStopSnp (\r
1151   IN  MNP_DEVICE_DATA   *MnpDeviceData\r
1152   )\r
1153 {\r
1154   EFI_STATUS  Status;\r
1155   EFI_SIMPLE_NETWORK_PROTOCOL     *Snp;\r
1156 \r
1157   Snp = MnpDeviceData->Snp;\r
1158   ASSERT (Snp != NULL);\r
1159 \r
1160   //\r
1161   // Recycle all the transmit buffer from SNP.\r
1162   //\r
1163   Status = MnpRecycleTxBuf (MnpDeviceData);\r
1164   if (EFI_ERROR (Status)) {\r
1165     return Status;\r
1166   }\r
1167 \r
1168   //\r
1169   // Shut down the simple network.\r
1170   //\r
1171   Status  = Snp->Shutdown (Snp);\r
1172   if (!EFI_ERROR (Status)) {\r
1173     //\r
1174     // Stop the simple network.\r
1175     //\r
1176     Status = Snp->Stop (Snp);\r
1177   }\r
1178 \r
1179   return Status;\r
1180 }\r
1181 \r
1182 \r
1183 /**\r
1184   Start the managed network, this function is called when one instance is configured\r
1185   or reconfigured.\r
1186 \r
1187   @param[in, out]  MnpServiceData       Pointer to the mnp service context data.\r
1188   @param[in]       IsConfigUpdate       The instance is reconfigured or it's the first\r
1189                                         time the instanced is configured.\r
1190   @param[in]       EnableSystemPoll     Enable the system polling or not.\r
1191 \r
1192   @retval EFI_SUCCESS                   The managed network is started and some\r
1193                                         configuration is updated.\r
1194   @retval Others                        Other errors as indicated.\r
1195 \r
1196 **/\r
1197 EFI_STATUS\r
1198 MnpStart (\r
1199   IN OUT MNP_SERVICE_DATA    *MnpServiceData,\r
1200   IN     BOOLEAN             IsConfigUpdate,\r
1201   IN     BOOLEAN             EnableSystemPoll\r
1202   )\r
1203 {\r
1204   EFI_STATUS      Status;\r
1205   EFI_TIMER_DELAY TimerOpType;\r
1206   MNP_DEVICE_DATA *MnpDeviceData;\r
1207 \r
1208   NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
1209 \r
1210   Status        = EFI_SUCCESS;\r
1211   MnpDeviceData = MnpServiceData->MnpDeviceData;\r
1212 \r
1213   if (!IsConfigUpdate) {\r
1214     //\r
1215     // If it's not a configuration update, increase the configured children number.\r
1216     //\r
1217     MnpDeviceData->ConfiguredChildrenNumber++;\r
1218 \r
1219     if (MnpDeviceData->ConfiguredChildrenNumber == 1) {\r
1220       //\r
1221       // It's the first configured child, start the simple network.\r
1222       //\r
1223       Status = MnpStartSnp (MnpDeviceData->Snp);\r
1224       if (EFI_ERROR (Status)) {\r
1225         DEBUG ((EFI_D_ERROR, "MnpStart: MnpStartSnp failed, %r.\n", Status));\r
1226 \r
1227         goto ErrorExit;\r
1228       }\r
1229 \r
1230       //\r
1231       // Start the timeout timer.\r
1232       //\r
1233       Status = gBS->SetTimer (\r
1234                       MnpDeviceData->TimeoutCheckTimer,\r
1235                       TimerPeriodic,\r
1236                       MNP_TIMEOUT_CHECK_INTERVAL\r
1237                       );\r
1238       if (EFI_ERROR (Status)) {\r
1239         DEBUG (\r
1240           (EFI_D_ERROR,\r
1241           "MnpStart, gBS->SetTimer for TimeoutCheckTimer %r.\n",\r
1242           Status)\r
1243           );\r
1244 \r
1245         goto ErrorExit;\r
1246       }\r
1247 \r
1248       //\r
1249       // Start the media detection timer.\r
1250       //\r
1251       Status = gBS->SetTimer (\r
1252                       MnpDeviceData->MediaDetectTimer,\r
1253                       TimerPeriodic,\r
1254                       MNP_MEDIA_DETECT_INTERVAL\r
1255                       );\r
1256       if (EFI_ERROR (Status)) {\r
1257         DEBUG (\r
1258           (EFI_D_ERROR,\r
1259           "MnpStart, gBS->SetTimer for MediaDetectTimer %r.\n",\r
1260           Status)\r
1261           );\r
1262 \r
1263         goto ErrorExit;\r
1264       }\r
1265     }\r
1266   }\r
1267 \r
1268   if (MnpDeviceData->EnableSystemPoll ^ EnableSystemPoll) {\r
1269     //\r
1270     // The EnableSystemPoll differs with the current state, disable or enable\r
1271     // the system poll.\r
1272     //\r
1273     TimerOpType = EnableSystemPoll ? TimerPeriodic : TimerCancel;\r
1274 \r
1275     Status      = gBS->SetTimer (MnpDeviceData->PollTimer, TimerOpType, MNP_SYS_POLL_INTERVAL);\r
1276     if (EFI_ERROR (Status)) {\r
1277       DEBUG ((EFI_D_ERROR, "MnpStart: gBS->SetTimer for PollTimer failed, %r.\n", Status));\r
1278 \r
1279       goto ErrorExit;\r
1280     }\r
1281 \r
1282     MnpDeviceData->EnableSystemPoll = EnableSystemPoll;\r
1283   }\r
1284 \r
1285   //\r
1286   // Change the receive filters if need.\r
1287   //\r
1288   Status = MnpConfigReceiveFilters (MnpDeviceData);\r
1289 \r
1290 ErrorExit:\r
1291   return Status;\r
1292 }\r
1293 \r
1294 \r
1295 /**\r
1296   Stop the managed network.\r
1297 \r
1298   @param[in, out]  MnpServiceData    Pointer to the mnp service context data.\r
1299 \r
1300   @retval EFI_SUCCESS                The managed network is stopped.\r
1301   @retval Others                     Other errors as indicated.\r
1302 \r
1303 **/\r
1304 EFI_STATUS\r
1305 MnpStop (\r
1306   IN OUT MNP_SERVICE_DATA    *MnpServiceData\r
1307   )\r
1308 {\r
1309   EFI_STATUS      Status;\r
1310   MNP_DEVICE_DATA *MnpDeviceData;\r
1311 \r
1312   NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
1313   MnpDeviceData = MnpServiceData->MnpDeviceData;\r
1314   ASSERT (MnpDeviceData->ConfiguredChildrenNumber > 0);\r
1315 \r
1316   //\r
1317   // Configure the receive filters.\r
1318   //\r
1319   MnpConfigReceiveFilters (MnpDeviceData);\r
1320 \r
1321   //\r
1322   // Decrease the children number.\r
1323   //\r
1324   MnpDeviceData->ConfiguredChildrenNumber--;\r
1325 \r
1326   if (MnpDeviceData->ConfiguredChildrenNumber > 0) {\r
1327     //\r
1328     // If there are other configured chilren, return and keep the timers and\r
1329     // simple network unchanged.\r
1330     //\r
1331     return EFI_SUCCESS;\r
1332   }\r
1333 \r
1334   //\r
1335   // No configured children now.\r
1336   //\r
1337   if (MnpDeviceData->EnableSystemPoll) {\r
1338     //\r
1339     //  The system poll in on, cancel the poll timer.\r
1340     //\r
1341     Status  = gBS->SetTimer (MnpDeviceData->PollTimer, TimerCancel, 0);\r
1342     MnpDeviceData->EnableSystemPoll = FALSE;\r
1343   }\r
1344 \r
1345   //\r
1346   // Cancel the timeout timer.\r
1347   //\r
1348   Status = gBS->SetTimer (MnpDeviceData->TimeoutCheckTimer, TimerCancel, 0);\r
1349 \r
1350   //\r
1351   // Cancel the media detect timer.\r
1352   //\r
1353   Status = gBS->SetTimer (MnpDeviceData->MediaDetectTimer, TimerCancel, 0);\r
1354 \r
1355   //\r
1356   // Stop the simple network.\r
1357   //\r
1358   Status = MnpStopSnp (MnpDeviceData);\r
1359   return Status;\r
1360 }\r
1361 \r
1362 \r
1363 /**\r
1364   Flush the instance's received data.\r
1365 \r
1366   @param[in, out]  Instance              Pointer to the mnp instance context data.\r
1367 \r
1368 **/\r
1369 VOID\r
1370 MnpFlushRcvdDataQueue (\r
1371   IN OUT MNP_INSTANCE_DATA   *Instance\r
1372   )\r
1373 {\r
1374   EFI_TPL         OldTpl;\r
1375   MNP_RXDATA_WRAP *RxDataWrap;\r
1376 \r
1377   NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
1378 \r
1379   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
1380 \r
1381   while (!IsListEmpty (&Instance->RcvdPacketQueue)) {\r
1382     //\r
1383     // Remove all the Wraps.\r
1384     //\r
1385     RxDataWrap = NET_LIST_HEAD (&Instance->RcvdPacketQueue, MNP_RXDATA_WRAP, WrapEntry);\r
1386 \r
1387     //\r
1388     // Recycle the RxDataWrap.\r
1389     //\r
1390     MnpRecycleRxData (NULL, (VOID *) RxDataWrap);\r
1391     Instance->RcvdPacketQueueSize--;\r
1392   }\r
1393 \r
1394   ASSERT (Instance->RcvdPacketQueueSize == 0);\r
1395 \r
1396   gBS->RestoreTPL (OldTpl);\r
1397 }\r
1398 \r
1399 \r
1400 /**\r
1401   Configure the Instance using ConfigData.\r
1402 \r
1403   @param[in, out]  Instance     Pointer to the mnp instance context data.\r
1404   @param[in]       ConfigData   Pointer to the configuration data used to configure\r
1405                                 the isntance.\r
1406 \r
1407   @retval EFI_SUCCESS           The Instance is configured.\r
1408   @retval EFI_UNSUPPORTED       EnableReceiveTimestamps is on and the\r
1409                                 implementation doesn't support it.\r
1410   @retval Others                Other errors as indicated.\r
1411 \r
1412 **/\r
1413 EFI_STATUS\r
1414 MnpConfigureInstance (\r
1415   IN OUT MNP_INSTANCE_DATA                 *Instance,\r
1416   IN     EFI_MANAGED_NETWORK_CONFIG_DATA   *ConfigData OPTIONAL\r
1417   )\r
1418 {\r
1419   EFI_STATUS                      Status;\r
1420   MNP_SERVICE_DATA                *MnpServiceData;\r
1421   MNP_DEVICE_DATA                 *MnpDeviceData;\r
1422   EFI_MANAGED_NETWORK_CONFIG_DATA *OldConfigData;\r
1423   EFI_MANAGED_NETWORK_CONFIG_DATA *NewConfigData;\r
1424   BOOLEAN                         IsConfigUpdate;\r
1425 \r
1426   NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
1427 \r
1428   if ((ConfigData != NULL) && ConfigData->EnableReceiveTimestamps) {\r
1429     //\r
1430     // Don't support timestamp.\r
1431     //\r
1432     return EFI_UNSUPPORTED;\r
1433   }\r
1434 \r
1435   Status          = EFI_SUCCESS;\r
1436 \r
1437   MnpServiceData  = Instance->MnpServiceData;\r
1438   MnpDeviceData   = MnpServiceData->MnpDeviceData;\r
1439   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);\r
1440 \r
1441   IsConfigUpdate  = (BOOLEAN) ((Instance->Configured) && (ConfigData != NULL));\r
1442 \r
1443   OldConfigData   = &Instance->ConfigData;\r
1444   NewConfigData   = ConfigData;\r
1445   if (NewConfigData == NULL) {\r
1446     //\r
1447     // Restore back the default config data if a reset of this instance\r
1448     // is required.\r
1449     //\r
1450     NewConfigData = &mMnpDefaultConfigData;\r
1451   }\r
1452 \r
1453   //\r
1454   // Reset the instance's receive filter.\r
1455   //\r
1456   Instance->ReceiveFilter = 0;\r
1457 \r
1458   //\r
1459   // Clear the receive counters according to the old ConfigData.\r
1460   //\r
1461   if (OldConfigData->EnableUnicastReceive) {\r
1462     MnpDeviceData->UnicastCount--;\r
1463   }\r
1464 \r
1465   if (OldConfigData->EnableMulticastReceive) {\r
1466     MnpDeviceData->MulticastCount--;\r
1467   }\r
1468 \r
1469   if (OldConfigData->EnableBroadcastReceive) {\r
1470     MnpDeviceData->BroadcastCount--;\r
1471   }\r
1472 \r
1473   if (OldConfigData->EnablePromiscuousReceive) {\r
1474     MnpDeviceData->PromiscuousCount--;\r
1475   }\r
1476 \r
1477   //\r
1478   // Set the receive filter counters and the receive filter of the\r
1479   // instance according to the new ConfigData.\r
1480   //\r
1481   if (NewConfigData->EnableUnicastReceive) {\r
1482     MnpDeviceData->UnicastCount++;\r
1483     Instance->ReceiveFilter |= MNP_RECEIVE_UNICAST;\r
1484   }\r
1485 \r
1486   if (NewConfigData->EnableMulticastReceive) {\r
1487     MnpDeviceData->MulticastCount++;\r
1488   }\r
1489 \r
1490   if (NewConfigData->EnableBroadcastReceive) {\r
1491     MnpDeviceData->BroadcastCount++;\r
1492     Instance->ReceiveFilter |= MNP_RECEIVE_BROADCAST;\r
1493   }\r
1494 \r
1495   if (NewConfigData->EnablePromiscuousReceive) {\r
1496     MnpDeviceData->PromiscuousCount++;\r
1497   }\r
1498 \r
1499   if (OldConfigData->FlushQueuesOnReset) {\r
1500     MnpFlushRcvdDataQueue (Instance);\r
1501   }\r
1502 \r
1503   if (ConfigData == NULL) {\r
1504     Instance->ManagedNetwork.Cancel (&Instance->ManagedNetwork, NULL);\r
1505   }\r
1506 \r
1507   if (!NewConfigData->EnableMulticastReceive) {\r
1508     MnpGroupOp (Instance, FALSE, NULL, NULL);\r
1509   }\r
1510 \r
1511   //\r
1512   // Save the new configuration data.\r
1513   //\r
1514   CopyMem (OldConfigData, NewConfigData, sizeof (*OldConfigData));\r
1515 \r
1516   Instance->Configured = (BOOLEAN) (ConfigData != NULL);\r
1517   if (Instance->Configured) {\r
1518     //\r
1519     // The instance is configured, start the Mnp.\r
1520     //\r
1521     Status = MnpStart (\r
1522               MnpServiceData,\r
1523               IsConfigUpdate,\r
1524               (BOOLEAN) !NewConfigData->DisableBackgroundPolling\r
1525               );\r
1526   } else {\r
1527     //\r
1528     // The instance is changed to the unconfigured state, stop the Mnp.\r
1529     //\r
1530     Status = MnpStop (MnpServiceData);\r
1531   }\r
1532 \r
1533   return Status;\r
1534 }\r
1535 \r
1536 /**\r
1537   Configure the Snp receive filters according to the instances' receive filter\r
1538   settings.\r
1539 \r
1540   @param[in]  MnpDeviceData         Pointer to the mnp device context data.\r
1541 \r
1542   @retval     EFI_SUCCESS           The receive filters is configured.\r
1543   @retval     EFI_OUT_OF_RESOURCES  The receive filters can't be configured due\r
1544                                     to lack of memory resource.\r
1545 \r
1546 **/\r
1547 EFI_STATUS\r
1548 MnpConfigReceiveFilters (\r
1549   IN MNP_DEVICE_DATA     *MnpDeviceData\r
1550   )\r
1551 {\r
1552   EFI_STATUS                  Status;\r
1553   EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
1554   EFI_MAC_ADDRESS             *MCastFilter;\r
1555   UINT32                      MCastFilterCnt;\r
1556   UINT32                      EnableFilterBits;\r
1557   UINT32                      DisableFilterBits;\r
1558   BOOLEAN                     ResetMCastFilters;\r
1559   LIST_ENTRY                  *Entry;\r
1560   UINT32                      Index;\r
1561   MNP_GROUP_ADDRESS           *GroupAddress;\r
1562 \r
1563   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);\r
1564 \r
1565   Snp = MnpDeviceData->Snp;\r
1566 \r
1567   //\r
1568   // Initialize the enable filter and disable filter.\r
1569   //\r
1570   EnableFilterBits  = 0;\r
1571   DisableFilterBits = Snp->Mode->ReceiveFilterMask;\r
1572 \r
1573   if (MnpDeviceData->UnicastCount != 0) {\r
1574     //\r
1575     // Enable unicast if any instance wants to receive unicast.\r
1576     //\r
1577     EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;\r
1578   }\r
1579 \r
1580   if (MnpDeviceData->BroadcastCount != 0) {\r
1581     //\r
1582     // Enable broadcast if any instance wants to receive broadcast.\r
1583     //\r
1584     EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;\r
1585   }\r
1586 \r
1587   MCastFilter       = NULL;\r
1588   MCastFilterCnt    = 0;\r
1589   ResetMCastFilters = TRUE;\r
1590 \r
1591   if ((MnpDeviceData->MulticastCount != 0) && (MnpDeviceData->GroupAddressCount != 0)) {\r
1592     //\r
1593     // There are instances configured to receive multicast and already some group\r
1594     // addresses are joined.\r
1595     //\r
1596 \r
1597     ResetMCastFilters = FALSE;\r
1598 \r
1599     if (MnpDeviceData->GroupAddressCount <= Snp->Mode->MaxMCastFilterCount) {\r
1600       //\r
1601       // The joind group address is less than simple network's maximum count.\r
1602       // Just configure the snp to do the multicast filtering.\r
1603       //\r
1604 \r
1605       EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;\r
1606 \r
1607       //\r
1608       // Allocate pool for the mulicast addresses.\r
1609       //\r
1610       MCastFilterCnt  = MnpDeviceData->GroupAddressCount;\r
1611       MCastFilter     = AllocatePool (sizeof (EFI_MAC_ADDRESS) * MCastFilterCnt);\r
1612       if (MCastFilter == NULL) {\r
1613         DEBUG ((EFI_D_ERROR, "MnpConfigReceiveFilters: Failed to allocate memory resource for MCastFilter.\n"));\r
1614 \r
1615         return EFI_OUT_OF_RESOURCES;\r
1616       }\r
1617 \r
1618       //\r
1619       // Fill the multicast HW address buffer.\r
1620       //\r
1621       Index = 0;\r
1622       NET_LIST_FOR_EACH (Entry, &MnpDeviceData->GroupAddressList) {\r
1623 \r
1624         GroupAddress = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_ADDRESS, AddrEntry);\r
1625         CopyMem (MCastFilter + Index, &GroupAddress->Address, sizeof (*(MCastFilter + Index)));\r
1626         Index++;\r
1627 \r
1628         ASSERT (Index <= MCastFilterCnt);\r
1629       }\r
1630     } else {\r
1631       //\r
1632       // The maximum multicast is reached, set the filter to be promiscuous\r
1633       // multicast.\r
1634       //\r
1635 \r
1636       if ((Snp->Mode->ReceiveFilterMask & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {\r
1637         EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
1638       } else {\r
1639         //\r
1640         // Either MULTICAST or PROMISCUOUS_MULTICAST is not supported by Snp,\r
1641         // set the NIC to be promiscuous although this will tremendously degrade\r
1642         // the performance.\r
1643         //\r
1644         EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;\r
1645       }\r
1646     }\r
1647   }\r
1648 \r
1649   if (MnpDeviceData->PromiscuousCount != 0) {\r
1650     //\r
1651     // Enable promiscuous if any instance wants to receive promiscuous.\r
1652     //\r
1653     EnableFilterBits |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;\r
1654   }\r
1655 \r
1656   //\r
1657   // Set the disable filter.\r
1658   //\r
1659   DisableFilterBits ^= EnableFilterBits;\r
1660 \r
1661   //\r
1662   // Configure the receive filters of SNP.\r
1663   //\r
1664   Status = Snp->ReceiveFilters (\r
1665                   Snp,\r
1666                   EnableFilterBits,\r
1667                   DisableFilterBits,\r
1668                   ResetMCastFilters,\r
1669                   MCastFilterCnt,\r
1670                   MCastFilter\r
1671                   );\r
1672   DEBUG_CODE (\r
1673     if (EFI_ERROR (Status)) {\r
1674       DEBUG (\r
1675         (EFI_D_ERROR,\r
1676         "MnpConfigReceiveFilters: Snp->ReceiveFilters failed, %r.\n",\r
1677         Status)\r
1678         );\r
1679     }\r
1680   );\r
1681 \r
1682   if (MCastFilter != NULL) {\r
1683     //\r
1684     // Free the buffer used to hold the group addresses.\r
1685     //\r
1686     FreePool (MCastFilter);\r
1687   }\r
1688 \r
1689   return Status;\r
1690 }\r
1691 \r
1692 \r
1693 /**\r
1694   Add a group address control block which controls the MacAddress for\r
1695   this instance.\r
1696 \r
1697   @param[in, out]  Instance        Pointer to the mnp instance context data.\r
1698   @param[in, out]  CtrlBlk         Pointer to the group address control block.\r
1699   @param[in, out]  GroupAddress    Pointer to the group adress.\r
1700   @param[in]       MacAddress      Pointer to the mac address.\r
1701   @param[in]       HwAddressSize   The hardware address size.\r
1702 \r
1703   @retval EFI_SUCCESS              The group address control block is added.\r
1704   @retval EFI_OUT_OF_RESOURCES     Failed due to lack of memory resources.\r
1705 \r
1706 **/\r
1707 EFI_STATUS\r
1708 MnpGroupOpAddCtrlBlk (\r
1709   IN OUT MNP_INSTANCE_DATA         *Instance,\r
1710   IN OUT MNP_GROUP_CONTROL_BLOCK   *CtrlBlk,\r
1711   IN OUT MNP_GROUP_ADDRESS         *GroupAddress OPTIONAL,\r
1712   IN     EFI_MAC_ADDRESS           *MacAddress,\r
1713   IN     UINT32                    HwAddressSize\r
1714   )\r
1715 {\r
1716   MNP_DEVICE_DATA  *MnpDeviceData;\r
1717 \r
1718   NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
1719 \r
1720   MnpDeviceData = Instance->MnpServiceData->MnpDeviceData;\r
1721   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);\r
1722 \r
1723   if (GroupAddress == NULL) {\r
1724     ASSERT (MacAddress != NULL);\r
1725 \r
1726     //\r
1727     // Allocate a new GroupAddress to be added into MNP's GroupAddressList.\r
1728     //\r
1729     GroupAddress = AllocatePool (sizeof (MNP_GROUP_ADDRESS));\r
1730     if (GroupAddress == NULL) {\r
1731 \r
1732       DEBUG ((EFI_D_ERROR, "MnpGroupOpFormCtrlBlk: Failed to allocate memory resource.\n"));\r
1733 \r
1734       return EFI_OUT_OF_RESOURCES;\r
1735     }\r
1736 \r
1737     CopyMem (&GroupAddress->Address, MacAddress, sizeof (GroupAddress->Address));\r
1738     GroupAddress->RefCnt = 0;\r
1739     InsertTailList (\r
1740       &MnpDeviceData->GroupAddressList,\r
1741       &GroupAddress->AddrEntry\r
1742       );\r
1743     MnpDeviceData->GroupAddressCount++;\r
1744   }\r
1745 \r
1746   //\r
1747   // Increase the RefCnt.\r
1748   //\r
1749   GroupAddress->RefCnt++;\r
1750 \r
1751   //\r
1752   // Add the CtrlBlk into the instance's GroupCtrlBlkList.\r
1753   //\r
1754   CtrlBlk->GroupAddress = GroupAddress;\r
1755   InsertTailList (&Instance->GroupCtrlBlkList, &CtrlBlk->CtrlBlkEntry);\r
1756 \r
1757   return EFI_SUCCESS;\r
1758 }\r
1759 \r
1760 \r
1761 /**\r
1762   Delete a group control block from the instance. If the controlled group address's\r
1763   reference count reaches zero, the group address is removed too.\r
1764 \r
1765   @param[in]  Instance              Pointer to the instance context data.\r
1766   @param[in]  CtrlBlk               Pointer to the group control block to delete.\r
1767 \r
1768   @return The group address controlled by the control block is no longer used or not.\r
1769 \r
1770 **/\r
1771 BOOLEAN\r
1772 MnpGroupOpDelCtrlBlk (\r
1773   IN MNP_INSTANCE_DATA           *Instance,\r
1774   IN MNP_GROUP_CONTROL_BLOCK     *CtrlBlk\r
1775   )\r
1776 {\r
1777   MNP_DEVICE_DATA   *MnpDeviceData;\r
1778   MNP_GROUP_ADDRESS *GroupAddress;\r
1779 \r
1780   NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
1781 \r
1782   MnpDeviceData = Instance->MnpServiceData->MnpDeviceData;\r
1783   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);\r
1784 \r
1785   //\r
1786   // Remove and free the CtrlBlk.\r
1787   //\r
1788   GroupAddress = CtrlBlk->GroupAddress;\r
1789   RemoveEntryList (&CtrlBlk->CtrlBlkEntry);\r
1790   FreePool (CtrlBlk);\r
1791 \r
1792   ASSERT (GroupAddress->RefCnt > 0);\r
1793 \r
1794   //\r
1795   // Count down the RefCnt.\r
1796   //\r
1797   GroupAddress->RefCnt--;\r
1798 \r
1799   if (GroupAddress->RefCnt == 0) {\r
1800     //\r
1801     // Free this GroupAddress entry if no instance uses it.\r
1802     //\r
1803     MnpDeviceData->GroupAddressCount--;\r
1804     RemoveEntryList (&GroupAddress->AddrEntry);\r
1805     FreePool (GroupAddress);\r
1806 \r
1807     return TRUE;\r
1808   }\r
1809 \r
1810   return FALSE;\r
1811 }\r
1812 \r
1813 \r
1814 /**\r
1815   Do the group operations for this instance.\r
1816 \r
1817   @param[in, out]  Instance        Pointer to the instance context data.\r
1818   @param[in]       JoinFlag        Set to TRUE to join a group. Set to TRUE to\r
1819                                    leave a group/groups.\r
1820   @param[in]       MacAddress      Pointer to the group address to join or leave.\r
1821   @param[in]       CtrlBlk         Pointer to the group control block if JoinFlag\r
1822                                    is FALSE.\r
1823 \r
1824   @retval EFI_SUCCESS              The group operation finished.\r
1825   @retval EFI_OUT_OF_RESOURCES     Failed due to lack of memory resources.\r
1826   @retval Others                   Other errors as indicated.\r
1827 \r
1828 **/\r
1829 EFI_STATUS\r
1830 MnpGroupOp (\r
1831   IN OUT MNP_INSTANCE_DATA         *Instance,\r
1832   IN     BOOLEAN                   JoinFlag,\r
1833   IN     EFI_MAC_ADDRESS           *MacAddress OPTIONAL,\r
1834   IN     MNP_GROUP_CONTROL_BLOCK   *CtrlBlk OPTIONAL\r
1835   )\r
1836 {\r
1837   MNP_DEVICE_DATA         *MnpDeviceData;\r
1838   LIST_ENTRY              *Entry;\r
1839   LIST_ENTRY              *NextEntry;\r
1840   MNP_GROUP_ADDRESS       *GroupAddress;\r
1841   EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
1842   MNP_GROUP_CONTROL_BLOCK *NewCtrlBlk;\r
1843   EFI_STATUS              Status;\r
1844   BOOLEAN                 AddressExist;\r
1845   BOOLEAN                 NeedUpdate;\r
1846 \r
1847   NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
1848 \r
1849   MnpDeviceData = Instance->MnpServiceData->MnpDeviceData;\r
1850   SnpMode       = MnpDeviceData->Snp->Mode;\r
1851 \r
1852   if (JoinFlag) {\r
1853     //\r
1854     // A new gropu address is to be added.\r
1855     //\r
1856     GroupAddress  = NULL;\r
1857     AddressExist  = FALSE;\r
1858 \r
1859     //\r
1860     // Allocate memory for the control block.\r
1861     //\r
1862     NewCtrlBlk = AllocatePool (sizeof (MNP_GROUP_CONTROL_BLOCK));\r
1863     if (NewCtrlBlk == NULL) {\r
1864       DEBUG ((EFI_D_ERROR, "MnpGroupOp: Failed to allocate memory resource.\n"));\r
1865 \r
1866       return EFI_OUT_OF_RESOURCES;\r
1867     }\r
1868 \r
1869     NET_LIST_FOR_EACH (Entry, &MnpDeviceData->GroupAddressList) {\r
1870       //\r
1871       // Check whether the MacAddress is already joined by other instances.\r
1872       //\r
1873       GroupAddress = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_ADDRESS, AddrEntry);\r
1874       if (CompareMem (MacAddress, &GroupAddress->Address, SnpMode->HwAddressSize) == 0) {\r
1875         AddressExist = TRUE;\r
1876         break;\r
1877       }\r
1878     }\r
1879 \r
1880     if (!AddressExist) {\r
1881       GroupAddress = NULL;\r
1882     }\r
1883 \r
1884     //\r
1885     // Add the GroupAddress for this instance.\r
1886     //\r
1887     Status = MnpGroupOpAddCtrlBlk (\r
1888               Instance,\r
1889               NewCtrlBlk,\r
1890               GroupAddress,\r
1891               MacAddress,\r
1892               SnpMode->HwAddressSize\r
1893               );\r
1894     if (EFI_ERROR (Status)) {\r
1895       return Status;\r
1896     }\r
1897 \r
1898     NeedUpdate = TRUE;\r
1899   } else {\r
1900     if (MacAddress != NULL) {\r
1901       ASSERT (CtrlBlk != NULL);\r
1902 \r
1903       //\r
1904       // Leave the specific multicast mac address.\r
1905       //\r
1906       NeedUpdate = MnpGroupOpDelCtrlBlk (Instance, CtrlBlk);\r
1907     } else {\r
1908       //\r
1909       // Leave all multicast mac addresses.\r
1910       //\r
1911       NeedUpdate = FALSE;\r
1912 \r
1913       NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->GroupCtrlBlkList) {\r
1914 \r
1915         NewCtrlBlk = NET_LIST_USER_STRUCT (\r
1916                       Entry,\r
1917                       MNP_GROUP_CONTROL_BLOCK,\r
1918                       CtrlBlkEntry\r
1919                       );\r
1920         //\r
1921         // Update is required if the group address left is no longer used\r
1922         // by other instances.\r
1923         //\r
1924         NeedUpdate = MnpGroupOpDelCtrlBlk (Instance, NewCtrlBlk);\r
1925       }\r
1926     }\r
1927   }\r
1928 \r
1929   Status = EFI_SUCCESS;\r
1930 \r
1931   if (NeedUpdate) {\r
1932     //\r
1933     // Reconfigure the receive filters if necessary.\r
1934     //\r
1935     Status = MnpConfigReceiveFilters (MnpDeviceData);\r
1936   }\r
1937 \r
1938   return Status;\r
1939 }\r