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