Patch to remove STATIC modifier. This is on longer recommended by EFI Framework codin...
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Ip4Dxe / Ip4If.c
1 /** @file\r
2 \r
3 Copyright (c) 2005 - 2007, Intel Corporation\r
4 All rights reserved. This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution.  The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php\r
8 \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11 \r
12 \r
13 Module Name:\r
14 \r
15   Ip4If.c\r
16 \r
17 Abstract:\r
18 \r
19   Implement IP4 pesudo interface.\r
20 \r
21 \r
22 **/\r
23 \r
24 #include "Ip4Impl.h"\r
25 \r
26 //\r
27 // Mac address with all zero, used to determine whethter the ARP\r
28 // resolve succeeded. Failed ARP requests zero the MAC address buffer.\r
29 //\r
30 EFI_MAC_ADDRESS  mZeroMacAddress;\r
31 \r
32 VOID\r
33 EFIAPI\r
34 Ip4OnFrameSentDpc (\r
35   IN VOID                   *Context\r
36   );\r
37 \r
38 VOID\r
39 EFIAPI\r
40 Ip4OnFrameSent (\r
41   IN EFI_EVENT              Event,\r
42   IN VOID                   *Context\r
43   );\r
44 \r
45 VOID\r
46 EFIAPI\r
47 Ip4OnArpResolvedDpc (\r
48   IN VOID                   *Context\r
49   );\r
50 \r
51 VOID\r
52 EFIAPI\r
53 Ip4OnArpResolved (\r
54   IN EFI_EVENT              Event,\r
55   IN VOID                   *Context\r
56   );\r
57 \r
58 VOID\r
59 EFIAPI\r
60 Ip4OnFrameReceivedDpc (\r
61   IN VOID                   *Context\r
62   );\r
63 \r
64 VOID\r
65 EFIAPI\r
66 Ip4OnFrameReceived (\r
67   IN EFI_EVENT              Event,\r
68   IN VOID                   *Context\r
69   );\r
70 \r
71 VOID\r
72 Ip4CancelFrameArp (\r
73   IN IP4_ARP_QUE            *ArpQue,\r
74   IN EFI_STATUS             IoStatus,\r
75   IN IP4_FRAME_TO_CANCEL    FrameToCancel, OPTIONAL\r
76   IN VOID                   *Context\r
77   );\r
78 \r
79 \r
80 /**\r
81   Wrap a transmit request into a newly allocated IP4_LINK_TX_TOKEN.\r
82 \r
83   @param  Interface             The interface to send out from\r
84   @param  IpInstance            The IpInstance that transmit the packet.  NULL if\r
85                                 the packet is sent by the IP4 driver itself.\r
86   @param  Packet                The packet to transmit\r
87   @param  CallBack              Call back function to execute if transmission\r
88                                 finished.\r
89   @param  Context               Opaque parameter to the call back.\r
90 \r
91   @return The wrapped token if succeed or NULL\r
92 \r
93 **/\r
94 IP4_LINK_TX_TOKEN *\r
95 Ip4WrapLinkTxToken (\r
96   IN IP4_INTERFACE          *Interface,\r
97   IN IP4_PROTOCOL           *IpInstance,    OPTIONAL\r
98   IN NET_BUF                *Packet,\r
99   IN IP4_FRAME_CALLBACK     CallBack,\r
100   IN VOID                   *Context\r
101   )\r
102 {\r
103   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *MnpToken;\r
104   EFI_MANAGED_NETWORK_TRANSMIT_DATA     *MnpTxData;\r
105   IP4_LINK_TX_TOKEN                     *Token;\r
106   EFI_STATUS                            Status;\r
107   UINT32                                Count;\r
108 \r
109   Token = AllocatePool (sizeof (IP4_LINK_TX_TOKEN) + \\r
110             (Packet->BlockOpNum - 1) * sizeof (EFI_MANAGED_NETWORK_FRAGMENT_DATA));\r
111 \r
112   if (Token == NULL) {\r
113     return NULL;\r
114   }\r
115 \r
116   Token->Signature = IP4_FRAME_TX_SIGNATURE;\r
117   InitializeListHead (&Token->Link);\r
118 \r
119   Token->Interface  = Interface;\r
120   Token->IpInstance = IpInstance;\r
121   Token->CallBack   = CallBack;\r
122   Token->Packet     = Packet;\r
123   Token->Context    = Context;\r
124   CopyMem (&Token->DstMac, &mZeroMacAddress, sizeof (Token->DstMac));\r
125   CopyMem (&Token->SrcMac, &Interface->Mac, sizeof (Token->SrcMac));\r
126 \r
127   MnpToken          = &(Token->MnpToken);\r
128   MnpToken->Status  = EFI_NOT_READY;\r
129 \r
130   Status = gBS->CreateEvent (\r
131                   EVT_NOTIFY_SIGNAL,\r
132                   TPL_NOTIFY,\r
133                   Ip4OnFrameSent,\r
134                   Token,\r
135                   &MnpToken->Event\r
136                   );\r
137 \r
138   if (EFI_ERROR (Status)) {\r
139     gBS->FreePool (Token);\r
140     return NULL;\r
141   }\r
142 \r
143   MnpTxData                     = &Token->MnpTxData;\r
144   MnpToken->Packet.TxData       = MnpTxData;\r
145 \r
146   MnpTxData->DestinationAddress = &Token->DstMac;\r
147   MnpTxData->SourceAddress      = &Token->SrcMac;\r
148   MnpTxData->ProtocolType       = IP4_ETHER_PROTO;\r
149   MnpTxData->DataLength         = Packet->TotalSize;\r
150   MnpTxData->HeaderLength       = 0;\r
151 \r
152   Count                         = Packet->BlockOpNum;\r
153 \r
154   NetbufBuildExt (Packet, (NET_FRAGMENT *) MnpTxData->FragmentTable, &Count);\r
155   MnpTxData->FragmentCount      = (UINT16)Count;\r
156 \r
157   return Token;\r
158 }\r
159 \r
160 \r
161 /**\r
162   Free the link layer transmit token. It will close the event\r
163   then free the memory used.\r
164 \r
165   @param  Token                 Token to free\r
166 \r
167   @return NONE\r
168 \r
169 **/\r
170 VOID\r
171 Ip4FreeLinkTxToken (\r
172   IN IP4_LINK_TX_TOKEN      *Token\r
173   )\r
174 {\r
175   NET_CHECK_SIGNATURE (Token, IP4_FRAME_TX_SIGNATURE);\r
176 \r
177   gBS->CloseEvent (Token->MnpToken.Event);\r
178   gBS->FreePool (Token);\r
179 }\r
180 \r
181 \r
182 /**\r
183   Create an IP_ARP_QUE structure to request ARP service.\r
184 \r
185   @param  Interface             The interface to send ARP from.\r
186   @param  DestIp                The destination IP (host byte order) to request MAC\r
187                                 for\r
188 \r
189   @return Point to newly created IP4_ARP_QUE if succeed, otherwise NULL.\r
190 \r
191 **/\r
192 IP4_ARP_QUE *\r
193 Ip4CreateArpQue (\r
194   IN IP4_INTERFACE          *Interface,\r
195   IN IP4_ADDR               DestIp\r
196   )\r
197 {\r
198   IP4_ARP_QUE               *ArpQue;\r
199   EFI_STATUS                Status;\r
200 \r
201   ArpQue = AllocatePool (sizeof (IP4_ARP_QUE));\r
202 \r
203   if (ArpQue == NULL) {\r
204     return NULL;\r
205   }\r
206 \r
207   ArpQue->Signature = IP4_FRAME_ARP_SIGNATURE;\r
208   InitializeListHead (&ArpQue->Link);\r
209 \r
210   InitializeListHead (&ArpQue->Frames);\r
211   ArpQue->Interface = Interface;\r
212 \r
213   Status = gBS->CreateEvent (\r
214                   EVT_NOTIFY_SIGNAL,\r
215                   TPL_NOTIFY,\r
216                   Ip4OnArpResolved,\r
217                   ArpQue,\r
218                   &ArpQue->OnResolved\r
219                   );\r
220 \r
221   if (EFI_ERROR (Status)) {\r
222     gBS->FreePool (ArpQue);\r
223     return NULL;\r
224   }\r
225 \r
226   ArpQue->Ip  = DestIp;\r
227   CopyMem (&ArpQue->Mac, &mZeroMacAddress, sizeof (ArpQue->Mac));\r
228 \r
229   return ArpQue;\r
230 }\r
231 \r
232 \r
233 /**\r
234   Remove all the transmit requests queued on the ARP queue, then free it.\r
235 \r
236   @param  ArpQue                Arp queue to free\r
237   @param  IoStatus              The transmit status returned to transmit requests'\r
238                                 callback.\r
239 \r
240   @return NONE\r
241 \r
242 **/\r
243 VOID\r
244 Ip4FreeArpQue (\r
245   IN IP4_ARP_QUE            *ArpQue,\r
246   IN EFI_STATUS             IoStatus\r
247   )\r
248 {\r
249   NET_CHECK_SIGNATURE (ArpQue, IP4_FRAME_ARP_SIGNATURE);\r
250 \r
251   //\r
252   // Remove all the frame waiting the ARP response\r
253   //\r
254   Ip4CancelFrameArp (ArpQue, IoStatus, NULL, NULL);\r
255 \r
256   gBS->CloseEvent (ArpQue->OnResolved);\r
257   gBS->FreePool (ArpQue);\r
258 }\r
259 \r
260 \r
261 /**\r
262   Create a link layer receive token to wrap the receive request\r
263 \r
264   @param  Interface             The interface to receive from\r
265   @param  IpInstance            The instance that request the receive (NULL for IP4\r
266                                 driver itself)\r
267   @param  CallBack              Call back function to execute when finished.\r
268   @param  Context               Opaque parameters to the callback\r
269 \r
270   @return Point to created IP4_LINK_RX_TOKEN if succeed, otherwise NULL.\r
271 \r
272 **/\r
273 IP4_LINK_RX_TOKEN *\r
274 Ip4CreateLinkRxToken (\r
275   IN IP4_INTERFACE          *Interface,\r
276   IN IP4_PROTOCOL           *IpInstance,\r
277   IN IP4_FRAME_CALLBACK     CallBack,\r
278   IN VOID                   *Context\r
279   )\r
280 {\r
281   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *MnpToken;\r
282   IP4_LINK_RX_TOKEN                     *Token;\r
283   EFI_STATUS                            Status;\r
284 \r
285   Token = AllocatePool (sizeof (IP4_LINK_RX_TOKEN));\r
286   if (Token == NULL) {\r
287     return NULL;\r
288   }\r
289 \r
290   Token->Signature  = IP4_FRAME_RX_SIGNATURE;\r
291   Token->Interface  = Interface;\r
292   Token->IpInstance = IpInstance;\r
293   Token->CallBack   = CallBack;\r
294   Token->Context    = Context;\r
295 \r
296   MnpToken          = &Token->MnpToken;\r
297   MnpToken->Status  = EFI_NOT_READY;\r
298 \r
299   Status = gBS->CreateEvent (\r
300                   EVT_NOTIFY_SIGNAL,\r
301                   TPL_NOTIFY,\r
302                   Ip4OnFrameReceived,\r
303                   Token,\r
304                   &MnpToken->Event\r
305                   );\r
306 \r
307   if (EFI_ERROR (Status)) {\r
308     gBS->FreePool (Token);\r
309     return NULL;\r
310   }\r
311 \r
312   MnpToken->Packet.RxData = NULL;\r
313   return Token;\r
314 }\r
315 \r
316 \r
317 /**\r
318   Free the link layer request token. It will close the event\r
319   then free the memory used.\r
320 \r
321   @param  Token                 Request token to free\r
322 \r
323   @return NONE\r
324 \r
325 **/\r
326 VOID\r
327 Ip4FreeFrameRxToken (\r
328   IN IP4_LINK_RX_TOKEN      *Token\r
329   )\r
330 {\r
331 \r
332   NET_CHECK_SIGNATURE (Token, IP4_FRAME_RX_SIGNATURE);\r
333 \r
334   gBS->CloseEvent (Token->MnpToken.Event);\r
335   gBS->FreePool (Token);\r
336 }\r
337 \r
338 \r
339 /**\r
340   Remove all the frames on the ARP queue that pass the FrameToCancel,\r
341   that is, either FrameToCancel is NULL or it returns true for the frame.\r
342 \r
343   @param  ArpQue                ARP frame to remove the frames from.\r
344   @param  IoStatus              The status returned to the cancelled frames'\r
345                                 callback function.\r
346   @param  FrameToCancel         Function to select which frame to cancel.\r
347   @param  Context               Opaque parameter to the FrameToCancel.\r
348 \r
349   @return NONE\r
350 \r
351 **/\r
352 VOID\r
353 Ip4CancelFrameArp (\r
354   IN IP4_ARP_QUE            *ArpQue,\r
355   IN EFI_STATUS             IoStatus,\r
356   IN IP4_FRAME_TO_CANCEL    FrameToCancel, OPTIONAL\r
357   IN VOID                   *Context\r
358   )\r
359 {\r
360   LIST_ENTRY                *Entry;\r
361   LIST_ENTRY                *Next;\r
362   IP4_LINK_TX_TOKEN         *Token;\r
363 \r
364   NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {\r
365     Token = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);\r
366 \r
367     if ((FrameToCancel == NULL) || FrameToCancel (Token, Context)) {\r
368       RemoveEntryList (Entry);\r
369 \r
370       Token->CallBack (Token->IpInstance, Token->Packet, IoStatus, 0, Token->Context);\r
371       Ip4FreeLinkTxToken (Token);\r
372     }\r
373   }\r
374 }\r
375 \r
376 \r
377 /**\r
378   Remove all the frames on the interface that pass the FrameToCancel,\r
379   either queued on ARP queues or that have already been delivered to\r
380   MNP and not yet recycled.\r
381 \r
382   @param  Interface             Interface to remove the frames from\r
383   @param  IoStatus              The transmit status returned to the frames'\r
384                                 callback\r
385   @param  FrameToCancel         Function to select the frame to cancel, NULL to\r
386                                 select all\r
387   @param  Context               Opaque parameters passed to FrameToCancel\r
388 \r
389   @return NONE\r
390 \r
391 **/\r
392 VOID\r
393 Ip4CancelFrames (\r
394   IN IP4_INTERFACE          *Interface,\r
395   IN EFI_STATUS             IoStatus,\r
396   IN IP4_FRAME_TO_CANCEL    FrameToCancel,   OPTIONAL\r
397   IN VOID                   *Context\r
398   )\r
399 {\r
400   LIST_ENTRY                *Entry;\r
401   LIST_ENTRY                *Next;\r
402   IP4_ARP_QUE               *ArpQue;\r
403   IP4_LINK_TX_TOKEN         *Token;\r
404 \r
405   //\r
406   // Cancel all the pending frames on ARP requests\r
407   //\r
408   NET_LIST_FOR_EACH_SAFE (Entry, Next, &Interface->ArpQues) {\r
409     ArpQue = NET_LIST_USER_STRUCT (Entry, IP4_ARP_QUE, Link);\r
410 \r
411     Ip4CancelFrameArp (ArpQue, IoStatus, FrameToCancel, Context);\r
412 \r
413     if (IsListEmpty (&ArpQue->Frames)) {\r
414       Interface->Arp->Cancel (Interface->Arp, &ArpQue->Ip, ArpQue->OnResolved);\r
415     }\r
416   }\r
417 \r
418   //\r
419   // Cancel all the frames that have been delivered to MNP\r
420   // but not yet recycled.\r
421   //\r
422   NET_LIST_FOR_EACH_SAFE (Entry, Next, &Interface->SentFrames) {\r
423     Token = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);\r
424 \r
425     if ((FrameToCancel == NULL) || FrameToCancel (Token, Context)) {\r
426       Interface->Mnp->Cancel (Interface->Mnp, &Token->MnpToken);\r
427     }\r
428   }\r
429 }\r
430 \r
431 \r
432 /**\r
433   Create an IP4_INTERFACE. Delay the creation of ARP instance until\r
434   the interface is configured.\r
435 \r
436   @param  Mnp                   The shared MNP child of this IP4 service binding\r
437                                 instance\r
438   @param  Controller            The controller this IP4 service binding instance\r
439                                 is installed. Most like the UNDI handle.\r
440   @param  ImageHandle           This driver's image handle\r
441 \r
442   @return Point to the created IP4_INTERFACE, otherwise NULL.\r
443 \r
444 **/\r
445 IP4_INTERFACE *\r
446 Ip4CreateInterface (\r
447   IN  EFI_MANAGED_NETWORK_PROTOCOL  *Mnp,\r
448   IN  EFI_HANDLE                    Controller,\r
449   IN  EFI_HANDLE                    ImageHandle\r
450   )\r
451 {\r
452   IP4_INTERFACE             *Interface;\r
453   EFI_SIMPLE_NETWORK_MODE   SnpMode;\r
454 \r
455   Interface = AllocatePool (sizeof (IP4_INTERFACE));\r
456 \r
457   if ((Interface == NULL) || (Mnp == NULL)) {\r
458     return NULL;\r
459   }\r
460 \r
461   Interface->Signature = IP4_INTERFACE_SIGNATURE;\r
462   InitializeListHead (&Interface->Link);\r
463   Interface->RefCnt     = 1;\r
464 \r
465   Interface->Ip         = IP4_ALLZERO_ADDRESS;\r
466   Interface->SubnetMask = IP4_ALLZERO_ADDRESS;\r
467   Interface->Configured = FALSE;\r
468 \r
469   Interface->Controller = Controller;\r
470   Interface->Image      = ImageHandle;\r
471   Interface->Mnp        = Mnp;\r
472   Interface->Arp        = NULL;\r
473   Interface->ArpHandle  = NULL;\r
474 \r
475   InitializeListHead (&Interface->ArpQues);\r
476   InitializeListHead (&Interface->SentFrames);\r
477 \r
478   Interface->RecvRequest = NULL;\r
479 \r
480   //\r
481   // Get the interface's Mac address and broadcast mac address from SNP\r
482   //\r
483   if (EFI_ERROR (Mnp->GetModeData (Mnp, NULL, &SnpMode))) {\r
484     gBS->FreePool (Interface);\r
485     return NULL;\r
486   }\r
487 \r
488   CopyMem (&Interface->Mac, &SnpMode.CurrentAddress, sizeof (Interface->Mac));\r
489   CopyMem (&Interface->BroadcastMac, &SnpMode.BroadcastAddress, sizeof (Interface->BroadcastMac));\r
490   Interface->HwaddrLen    = SnpMode.HwAddressSize;\r
491 \r
492   InitializeListHead (&Interface->IpInstances);\r
493   Interface->PromiscRecv = FALSE;\r
494 \r
495   return Interface;\r
496 }\r
497 \r
498 \r
499 /**\r
500   Set the interface's address, create and configure\r
501   the ARP child if necessary.\r
502 \r
503   @param  Interface             The interface to set the address\r
504   @param  IpAddr                The interface's IP address\r
505   @param  SubnetMask            The interface's netmask\r
506 \r
507   @retval EFI_SUCCESS           The interface is configured with Ip/netmask pair,\r
508                                 and a ARP is created for it.\r
509   @retval Others                Failed to set the interface's address.\r
510 \r
511 **/\r
512 EFI_STATUS\r
513 Ip4SetAddress (\r
514   IN  IP4_INTERFACE         *Interface,\r
515   IN  IP4_ADDR              IpAddr,\r
516   IN  IP4_ADDR              SubnetMask\r
517   )\r
518 {\r
519   EFI_ARP_CONFIG_DATA       ArpConfig;\r
520   EFI_STATUS                Status;\r
521   INTN                      Type;\r
522   INTN                      Len;\r
523   IP4_ADDR                  Netmask;\r
524 \r
525   NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);\r
526 \r
527   ASSERT (!Interface->Configured);\r
528 \r
529   //\r
530   // Set the ip/netmask, then compute the subnet broadcast\r
531   // and network broadcast for easy access. When computing\r
532   // nework broadcast, the subnet mask is most like longer\r
533   // than the default netmask (not subneted) as defined in\r
534   // RFC793. If that isn't the case, we are aggregating the\r
535   // networks, use the subnet's mask instead.\r
536   //\r
537   Interface->Ip             = IpAddr;\r
538   Interface->SubnetMask     = SubnetMask;\r
539   Interface->SubnetBrdcast  = (IpAddr | ~SubnetMask);\r
540 \r
541   Type                      = NetGetIpClass (IpAddr);\r
542   Len                       = NetGetMaskLength (SubnetMask);\r
543   Netmask                   = gIp4AllMasks[MIN (Len, Type << 3)];\r
544   Interface->NetBrdcast     = (IpAddr | ~Netmask);\r
545 \r
546   //\r
547   // If the address is NOT all zero, create then configure an ARP child.\r
548   // Pay attention: DHCP configures its station address as 0.0.0.0/0\r
549   //\r
550   Interface->Arp            = NULL;\r
551   Interface->ArpHandle      = NULL;\r
552 \r
553   if (IpAddr != IP4_ALLZERO_ADDRESS) {\r
554     Status = NetLibCreateServiceChild (\r
555                Interface->Controller,\r
556                Interface->Image,\r
557                &gEfiArpServiceBindingProtocolGuid,\r
558                &Interface->ArpHandle\r
559                );\r
560 \r
561     if (EFI_ERROR (Status)) {\r
562       return Status;;\r
563     }\r
564 \r
565     Status = gBS->OpenProtocol (\r
566                     Interface->ArpHandle,\r
567                     &gEfiArpProtocolGuid,\r
568                     (VOID **) &Interface->Arp,\r
569                     Interface->Image,\r
570                     Interface->Controller,\r
571                     EFI_OPEN_PROTOCOL_BY_DRIVER\r
572                     );\r
573 \r
574     if (EFI_ERROR (Status)) {\r
575       goto ON_ERROR;\r
576     }\r
577 \r
578     IpAddr                    = HTONL (IpAddr);\r
579     ArpConfig.SwAddressType   = IP4_ETHER_PROTO;\r
580     ArpConfig.SwAddressLength = 4;\r
581     ArpConfig.StationAddress  = &IpAddr;\r
582     ArpConfig.EntryTimeOut    = 0;\r
583     ArpConfig.RetryCount      = 0;\r
584     ArpConfig.RetryTimeOut    = 0;\r
585 \r
586     Status = Interface->Arp->Configure (Interface->Arp, &ArpConfig);\r
587 \r
588     if (EFI_ERROR (Status)) {\r
589       gBS->CloseProtocol (\r
590             Interface->ArpHandle,\r
591             &gEfiArpProtocolGuid,\r
592             Interface->Image,\r
593             Interface->Controller\r
594             );\r
595 \r
596       goto ON_ERROR;\r
597     }\r
598   }\r
599 \r
600   Interface->Configured = TRUE;\r
601   return EFI_SUCCESS;\r
602 \r
603 ON_ERROR:\r
604   NetLibDestroyServiceChild (\r
605     Interface->Controller,\r
606     Interface->Image,\r
607     &gEfiArpServiceBindingProtocolGuid,\r
608     &Interface->ArpHandle\r
609     );\r
610 \r
611   return Status;\r
612 }\r
613 \r
614 \r
615 /**\r
616   Fileter function to cancel all the frame related to an IP instance.\r
617 \r
618   @param  Frame                 The transmit request to test whether to cancel\r
619   @param  Context               The context which is the Ip instance that issued\r
620                                 the transmit.\r
621 \r
622   @retval TRUE                  The frame belongs to this instance and is to be\r
623                                 removed\r
624   @retval FALSE                 The frame doesn't belong to this instance.\r
625 \r
626 **/\r
627 BOOLEAN\r
628 Ip4CancelInstanceFrame (\r
629   IN IP4_LINK_TX_TOKEN *Frame,\r
630   IN VOID              *Context\r
631   )\r
632 {\r
633   if (Frame->IpInstance == (IP4_PROTOCOL *) Context) {\r
634     return TRUE;\r
635   }\r
636 \r
637   return FALSE;\r
638 }\r
639 \r
640 \r
641 \r
642 /**\r
643   If there is a pending receive request, cancel it. Don't call\r
644   the receive request's callback because this function can be only\r
645   called if the instance or driver is tearing itself down. It\r
646   doesn't make sense to call it back. But it is necessary to call\r
647   the transmit token's callback to give it a chance to free the\r
648   packet and update the upper layer's transmit request status, say\r
649   that from the UDP.\r
650 \r
651   @param  Interface             The interface used by the IpInstance\r
652 \r
653   @return None\r
654 \r
655 **/\r
656 VOID\r
657 Ip4CancelReceive (\r
658   IN IP4_INTERFACE          *Interface\r
659   )\r
660 {\r
661   EFI_TPL                   OldTpl;\r
662   IP4_LINK_RX_TOKEN         *Token;\r
663 \r
664   if ((Token = Interface->RecvRequest) != NULL) {\r
665     OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
666 \r
667     Interface->RecvRequest = NULL;\r
668     Interface->Mnp->Cancel (Interface->Mnp, &Token->MnpToken);\r
669 \r
670     gBS->RestoreTPL (OldTpl);\r
671   }\r
672 }\r
673 \r
674 \r
675 /**\r
676   Free the interface used by IpInstance. All the IP instance with\r
677   the same Ip/Netmask pair share the same interface. It is reference\r
678   counted. All the frames haven't been sent will be cancelled.\r
679   Because the IpInstance is optional, the caller must remove\r
680   IpInstance from the interface's instance list itself.\r
681 \r
682   @param  Interface             The interface used by the IpInstance\r
683   @param  IpInstance            The Ip instance that free the interface. NULL if\r
684                                 the  Ip driver is releasing the default interface.\r
685 \r
686   @retval EFI_SUCCESS           The interface use IpInstance is freed.\r
687 \r
688 **/\r
689 EFI_STATUS\r
690 Ip4FreeInterface (\r
691   IN  IP4_INTERFACE         *Interface,\r
692   IN  IP4_PROTOCOL          *IpInstance           OPTIONAL\r
693   )\r
694 {\r
695   NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);\r
696   ASSERT (Interface->RefCnt > 0);\r
697 \r
698   //\r
699   // Remove all the pending transmit token related to this IP instance.\r
700   //\r
701   Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, IpInstance);\r
702 \r
703   if (--Interface->RefCnt > 0) {\r
704     return EFI_SUCCESS;\r
705   }\r
706 \r
707   //\r
708   // Destory the interface if this is the last IP instance that\r
709   // has the address. Remove all the system transmitted packets\r
710   // from this interface, cancel the receive request if there is\r
711   // one, and destory the ARP requests.\r
712   //\r
713   Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, NULL);\r
714   Ip4CancelReceive (Interface);\r
715 \r
716   ASSERT (IsListEmpty (&Interface->IpInstances));\r
717   ASSERT (IsListEmpty (&Interface->ArpQues));\r
718   ASSERT (IsListEmpty (&Interface->SentFrames));\r
719 \r
720   if (Interface->Arp != NULL) {\r
721     gBS->CloseProtocol (\r
722           Interface->ArpHandle,\r
723           &gEfiArpProtocolGuid,\r
724           Interface->Image,\r
725           Interface->Controller\r
726           );\r
727 \r
728     NetLibDestroyServiceChild (\r
729       Interface->Controller,\r
730       Interface->Image,\r
731       &gEfiArpServiceBindingProtocolGuid,\r
732       Interface->ArpHandle\r
733       );\r
734   }\r
735 \r
736   RemoveEntryList (&Interface->Link);\r
737   gBS->FreePool (Interface);\r
738 \r
739   return EFI_SUCCESS;\r
740 }\r
741 \r
742 \r
743 /**\r
744   Callback function when ARP request are finished. It will cancelled\r
745   all the queued frame if the ARP requests failed. Or transmit them\r
746   if the request succeed.\r
747 \r
748   @param  Context               The context of the callback, a point to the ARP\r
749                                 queue\r
750 \r
751   @return None\r
752 \r
753 **/\r
754 VOID\r
755 EFIAPI\r
756 Ip4OnArpResolvedDpc (\r
757   IN VOID                   *Context\r
758   )\r
759 {\r
760   LIST_ENTRY                *Entry;\r
761   LIST_ENTRY                *Next;\r
762   IP4_ARP_QUE               *ArpQue;\r
763   IP4_INTERFACE             *Interface;\r
764   IP4_LINK_TX_TOKEN         *Token;\r
765   EFI_STATUS                Status;\r
766 \r
767   ArpQue = (IP4_ARP_QUE *) Context;\r
768   NET_CHECK_SIGNATURE (ArpQue, IP4_FRAME_ARP_SIGNATURE);\r
769 \r
770   RemoveEntryList (&ArpQue->Link);\r
771 \r
772   //\r
773   // ARP resolve failed for some reason. Release all the frame\r
774   // and ARP queue itself. Ip4FreeArpQue will call the frame's\r
775   // owner back.\r
776   //\r
777   if (NET_MAC_EQUAL (&ArpQue->Mac, &mZeroMacAddress, ArpQue->Interface->HwaddrLen)) {\r
778     Ip4FreeArpQue (ArpQue, EFI_NO_MAPPING);\r
779 \r
780     return ;\r
781   }\r
782 \r
783   //\r
784   // ARP resolve succeeded, Transmit all the frame. Release the ARP\r
785   // queue. It isn't necessary for us to cache the ARP binding because\r
786   // we always check the ARP cache first before transmit.\r
787   //\r
788   Interface = ArpQue->Interface;\r
789 \r
790   NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {\r
791     RemoveEntryList (Entry);\r
792 \r
793     Token         = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);\r
794     CopyMem (&Token->DstMac, &ArpQue->Mac, sizeof (Token->DstMac));\r
795 \r
796     //\r
797     // Insert the tx token before transmitting it via MNP as the FrameSentDpc\r
798     // may be called before Mnp->Transmit returns which will remove this tx\r
799     // token from the SentFrames list. Remove it from the list if the returned\r
800     // Status of Mnp->Transmit is not EFI_SUCCESS as in this case the\r
801     // FrameSentDpc won't be queued.\r
802     //\r
803     InsertTailList (&Interface->SentFrames, &Token->Link);\r
804 \r
805     Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);\r
806     if (EFI_ERROR (Status)) {\r
807       RemoveEntryList (Entry);\r
808       Token->CallBack (Token->IpInstance, Token->Packet, Status, 0, Token->Context);\r
809 \r
810       Ip4FreeLinkTxToken (Token);\r
811       continue;\r
812     }\r
813   }\r
814 \r
815   Ip4FreeArpQue (ArpQue, EFI_SUCCESS);\r
816 }\r
817 \r
818 VOID\r
819 EFIAPI\r
820 Ip4OnArpResolved (\r
821   IN EFI_EVENT              Event,\r
822   IN VOID                   *Context\r
823   )\r
824 /*++\r
825 \r
826 Routine Description:\r
827 \r
828   Request Ip4OnArpResolvedDpc as a DPC at TPL_CALLBACK\r
829 \r
830 Arguments:\r
831 \r
832   Event   - The Arp request event\r
833   Context - The context of the callback, a point to the ARP queue\r
834 \r
835 Returns:\r
836 \r
837   None\r
838 \r
839 --*/\r
840 {\r
841   //\r
842   // Request Ip4OnArpResolvedDpc as a DPC at TPL_CALLBACK\r
843   //\r
844   NetLibQueueDpc (TPL_CALLBACK, Ip4OnArpResolvedDpc, Context);\r
845 }\r
846 \r
847 \r
848 \r
849 /**\r
850   Callback funtion when frame transmission is finished. It will\r
851   call the frame owner's callback function to tell it the result.\r
852 \r
853   @param  Context               Context which is point to the token.\r
854 \r
855   @return None.\r
856 \r
857 **/\r
858 VOID\r
859 EFIAPI\r
860 Ip4OnFrameSentDpc (\r
861   IN VOID                    *Context\r
862   )\r
863 {\r
864   IP4_LINK_TX_TOKEN         *Token;\r
865 \r
866   Token = (IP4_LINK_TX_TOKEN *) Context;\r
867   NET_CHECK_SIGNATURE (Token, IP4_FRAME_TX_SIGNATURE);\r
868 \r
869   RemoveEntryList (&Token->Link);\r
870 \r
871   Token->CallBack (\r
872           Token->IpInstance,\r
873           Token->Packet,\r
874           Token->MnpToken.Status,\r
875           0,\r
876           Token->Context\r
877           );\r
878 \r
879   Ip4FreeLinkTxToken (Token);\r
880 }\r
881 \r
882 VOID\r
883 EFIAPI\r
884 Ip4OnFrameSent (\r
885   IN EFI_EVENT               Event,\r
886   IN VOID                    *Context\r
887   )\r
888 /*++\r
889 \r
890 Routine Description:\r
891 \r
892   Request Ip4OnFrameSentDpc as a DPC at TPL_CALLBACK\r
893 \r
894 Arguments:\r
895 \r
896   Event   - The transmit token's event\r
897   Context - Context which is point to the token.\r
898 \r
899 Returns:\r
900 \r
901   None.\r
902 \r
903 --*/\r
904 {\r
905   //\r
906   // Request Ip4OnFrameSentDpc as a DPC at TPL_CALLBACK\r
907   //\r
908   NetLibQueueDpc (TPL_CALLBACK, Ip4OnFrameSentDpc, Context);\r
909 }\r
910 \r
911 \r
912 \r
913 /**\r
914   Send a frame from the interface. If the next hop is broadcast or\r
915   multicast address, it is transmitted immediately. If the next hop\r
916   is a unicast, it will consult ARP to resolve the NextHop's MAC.\r
917   If some error happened, the CallBack won't be called. So, the caller\r
918   must test the return value, and take action when there is an error.\r
919 \r
920   @param  Interface             The interface to send the frame from\r
921   @param  IpInstance            The IP child that request the transmission.  NULL\r
922                                 if it is the IP4 driver itself.\r
923   @param  Packet                The packet to transmit.\r
924   @param  NextHop               The immediate destination to transmit the packet\r
925                                 to.\r
926   @param  CallBack              Function to call back when transmit finished.\r
927   @param  Context               Opaque parameter to the call back.\r
928 \r
929   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to send the frame\r
930   @retval EFI_NO_MAPPING        Can't resolve the MAC for the nexthop\r
931   @retval EFI_SUCCESS           The packet is successfully transmitted.\r
932 \r
933 **/\r
934 EFI_STATUS\r
935 Ip4SendFrame (\r
936   IN  IP4_INTERFACE         *Interface,\r
937   IN  IP4_PROTOCOL          *IpInstance,      OPTIONAL\r
938   IN  NET_BUF               *Packet,\r
939   IN  IP4_ADDR              NextHop,\r
940   IN  IP4_FRAME_CALLBACK    CallBack,\r
941   IN  VOID                  *Context\r
942   )\r
943 {\r
944   IP4_LINK_TX_TOKEN         *Token;\r
945   LIST_ENTRY                *Entry;\r
946   IP4_ARP_QUE               *ArpQue;\r
947   EFI_ARP_PROTOCOL          *Arp;\r
948   EFI_STATUS                Status;\r
949 \r
950   ASSERT (Interface->Configured);\r
951 \r
952   Token = Ip4WrapLinkTxToken (Interface, IpInstance, Packet, CallBack, Context);\r
953 \r
954   if (Token == NULL) {\r
955     return EFI_OUT_OF_RESOURCES;\r
956   }\r
957 \r
958   //\r
959   // Get the destination MAC address for multicast and broadcasts.\r
960   // Don't depend on ARP to solve the address since there maybe no\r
961   // ARP at all. Ip4Output has set NextHop to 255.255.255.255 for\r
962   // all the broadcasts.\r
963   //\r
964   if (NextHop == IP4_ALLONE_ADDRESS) {\r
965     CopyMem (&Token->DstMac, &Interface->BroadcastMac, sizeof (Token->DstMac));\r
966     goto SEND_NOW;\r
967 \r
968   } else if (IP4_IS_MULTICAST (NextHop)) {\r
969 \r
970     Status = Ip4GetMulticastMac (Interface->Mnp, NextHop, &Token->DstMac);\r
971 \r
972     if (EFI_ERROR (Status)) {\r
973       goto ON_ERROR;\r
974     }\r
975 \r
976     goto SEND_NOW;\r
977   }\r
978 \r
979   //\r
980   // Can only send out multicast/broadcast if the IP address is zero\r
981   //\r
982   if ((Arp = Interface->Arp) == NULL) {\r
983     Status = EFI_NO_MAPPING;\r
984     goto ON_ERROR;\r
985   }\r
986 \r
987   //\r
988   // First check whether this binding is in the ARP cache.\r
989   //\r
990   NextHop = HTONL (NextHop);\r
991   Status  = Arp->Request (Arp, &NextHop, NULL, &Token->DstMac);\r
992 \r
993   if (Status == EFI_SUCCESS) {\r
994     goto SEND_NOW;\r
995 \r
996   } else if (Status != EFI_NOT_READY) {\r
997     goto ON_ERROR;\r
998   }\r
999 \r
1000   //\r
1001   // Have to do asynchronous ARP resolution. First check\r
1002   // whether there is already a pending request.\r
1003   //\r
1004   ArpQue = NULL;\r
1005 \r
1006   NET_LIST_FOR_EACH (Entry, &Interface->ArpQues) {\r
1007     ArpQue = NET_LIST_USER_STRUCT (Entry, IP4_ARP_QUE, Link);\r
1008 \r
1009     if (ArpQue->Ip == NextHop) {\r
1010       break;\r
1011     }\r
1012   }\r
1013 \r
1014   //\r
1015   // Found a pending ARP request, enqueue the frame then return\r
1016   //\r
1017   if (Entry != &Interface->ArpQues) {\r
1018     InsertTailList (&ArpQue->Frames, &Token->Link);\r
1019     return EFI_SUCCESS;\r
1020   }\r
1021 \r
1022   //\r
1023   // First frame to NextHop, issue an asynchronous ARP requests\r
1024   //\r
1025   ArpQue = Ip4CreateArpQue (Interface, NextHop);\r
1026 \r
1027   if (ArpQue == NULL) {\r
1028     Status = EFI_OUT_OF_RESOURCES;\r
1029     goto ON_ERROR;\r
1030   }\r
1031 \r
1032   Status = Arp->Request (Arp, &ArpQue->Ip, ArpQue->OnResolved, ArpQue->Mac.Addr);\r
1033 \r
1034   if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {\r
1035     Ip4FreeArpQue (ArpQue, EFI_NO_MAPPING);\r
1036     goto ON_ERROR;\r
1037   }\r
1038 \r
1039   InsertHeadList (&ArpQue->Frames, &Token->Link);\r
1040   InsertHeadList (&Interface->ArpQues, &ArpQue->Link);\r
1041   return EFI_SUCCESS;\r
1042 \r
1043 SEND_NOW:\r
1044   //\r
1045   // Insert the tx token into the SentFrames list before calling Mnp->Transmit.\r
1046   // Remove it if the returned status is not EFI_SUCCESS.\r
1047   //\r
1048   InsertTailList (&Interface->SentFrames, &Token->Link);\r
1049   Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);\r
1050   if (EFI_ERROR (Status)) {\r
1051     RemoveEntryList (&Interface->SentFrames);\r
1052     goto ON_ERROR;\r
1053   }\r
1054 \r
1055   return EFI_SUCCESS;\r
1056 \r
1057 ON_ERROR:\r
1058   Ip4FreeLinkTxToken (Token);\r
1059   return Status;\r
1060 }\r
1061 \r
1062 \r
1063 /**\r
1064   Call back function when the received packet is freed.\r
1065   Check Ip4OnFrameReceived for information.\r
1066 \r
1067   @param  Context               Context, which is the IP4_LINK_RX_TOKEN.\r
1068 \r
1069   @return None.\r
1070 \r
1071 **/\r
1072 VOID\r
1073 Ip4RecycleFrame (\r
1074   IN VOID                   *Context\r
1075   )\r
1076 {\r
1077   IP4_LINK_RX_TOKEN         *Frame;\r
1078 \r
1079   Frame = (IP4_LINK_RX_TOKEN *) Context;\r
1080   NET_CHECK_SIGNATURE (Frame, IP4_FRAME_RX_SIGNATURE);\r
1081 \r
1082   gBS->SignalEvent (Frame->MnpToken.Packet.RxData->RecycleEvent);\r
1083   Ip4FreeFrameRxToken (Frame);\r
1084 }\r
1085 \r
1086 \r
1087 /**\r
1088   Received a frame from MNP, wrap it in net buffer then deliver\r
1089   it to IP's input function. The ownship of the packet also\r
1090   transferred to IP. When Ip is finished with this packet, it\r
1091   will call NetbufFree to release the packet, NetbufFree will\r
1092   again call the Ip4RecycleFrame to signal MNP's event and free\r
1093   the token used.\r
1094 \r
1095   @param  Context               Context for the callback.\r
1096 \r
1097   @return None.\r
1098 \r
1099 **/\r
1100 VOID\r
1101 EFIAPI\r
1102 Ip4OnFrameReceivedDpc (\r
1103   IN VOID                     *Context\r
1104   )\r
1105 {\r
1106   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *MnpToken;\r
1107   EFI_MANAGED_NETWORK_RECEIVE_DATA      *MnpRxData;\r
1108   IP4_LINK_RX_TOKEN                     *Token;\r
1109   NET_FRAGMENT                          Netfrag;\r
1110   NET_BUF                               *Packet;\r
1111   UINT32                                Flag;\r
1112 \r
1113   Token = (IP4_LINK_RX_TOKEN *) Context;\r
1114   NET_CHECK_SIGNATURE (Token, IP4_FRAME_RX_SIGNATURE);\r
1115 \r
1116   //\r
1117   // First clear the interface's receive request in case the\r
1118   // caller wants to call Ip4ReceiveFrame in the callback.\r
1119   //\r
1120   Token->Interface->RecvRequest = NULL;\r
1121 \r
1122   MnpToken  = &Token->MnpToken;\r
1123   MnpRxData = MnpToken->Packet.RxData;\r
1124 \r
1125   if (EFI_ERROR (MnpToken->Status) || (MnpRxData == NULL)) {\r
1126     Token->CallBack (Token->IpInstance, NULL, MnpToken->Status, 0, Token->Context);\r
1127     Ip4FreeFrameRxToken (Token);\r
1128 \r
1129     return ;\r
1130   }\r
1131 \r
1132   //\r
1133   // Wrap the frame in a net buffer then deliever it to IP input.\r
1134   // IP will reassemble the packet, and deliver it to upper layer\r
1135   //\r
1136   Netfrag.Len  = MnpRxData->DataLength;\r
1137   Netfrag.Bulk = MnpRxData->PacketData;\r
1138 \r
1139   Packet = NetbufFromExt (&Netfrag, 1, 0, IP4_MAX_HEADLEN, Ip4RecycleFrame, Token);\r
1140 \r
1141   if (Packet == NULL) {\r
1142     gBS->SignalEvent (MnpRxData->RecycleEvent);\r
1143 \r
1144     Token->CallBack (Token->IpInstance, NULL, EFI_OUT_OF_RESOURCES, 0, Token->Context);\r
1145     Ip4FreeFrameRxToken (Token);\r
1146 \r
1147     return ;\r
1148   }\r
1149 \r
1150   Flag  = (MnpRxData->BroadcastFlag ? IP4_LINK_BROADCAST : 0);\r
1151   Flag |= (MnpRxData->MulticastFlag ? IP4_LINK_MULTICAST : 0);\r
1152   Flag |= (MnpRxData->PromiscuousFlag ? IP4_LINK_PROMISC : 0);\r
1153 \r
1154   Token->CallBack (Token->IpInstance, Packet, EFI_SUCCESS, Flag, Token->Context);\r
1155 }\r
1156 \r
1157 VOID\r
1158 EFIAPI\r
1159 Ip4OnFrameReceived (\r
1160   IN EFI_EVENT                Event,\r
1161   IN VOID                     *Context\r
1162   )\r
1163 /*++\r
1164 \r
1165 Routine Description:\r
1166 \r
1167   Request Ip4OnFrameReceivedDpc as a DPC at TPL_CALLBACK\r
1168 \r
1169 Arguments:\r
1170 \r
1171   Event   - The receive event delivered to MNP for receive.\r
1172   Context - Context for the callback.\r
1173 \r
1174 Returns:\r
1175 \r
1176   None.\r
1177 \r
1178 --*/\r
1179 {\r
1180   //\r
1181   // Request Ip4OnFrameReceivedDpc as a DPC at TPL_CALLBACK\r
1182   //\r
1183   NetLibQueueDpc (TPL_CALLBACK, Ip4OnFrameReceivedDpc, Context);\r
1184 }\r
1185 \r
1186 \r
1187 /**\r
1188   Request to receive the packet from the interface.\r
1189 \r
1190   @param  Interface             The interface to receive the frames from\r
1191   @param  IpInstance            The instance that requests the receive. NULL for\r
1192                                 the driver itself.\r
1193   @param  CallBack              Function to call when receive finished.\r
1194   @param  Context               Opaque parameter to the callback\r
1195 \r
1196   @retval EFI_ALREADY_STARTED   There is already a pending receive request.\r
1197   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to receive\r
1198   @retval EFI_SUCCESS           The recieve request has been started.\r
1199 \r
1200 **/\r
1201 EFI_STATUS\r
1202 Ip4ReceiveFrame (\r
1203   IN  IP4_INTERFACE         *Interface,\r
1204   IN  IP4_PROTOCOL          *IpInstance,      OPTIONAL\r
1205   IN  IP4_FRAME_CALLBACK    CallBack,\r
1206   IN  VOID                  *Context\r
1207   )\r
1208 {\r
1209   IP4_LINK_RX_TOKEN *Token;\r
1210   EFI_STATUS        Status;\r
1211 \r
1212   NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);\r
1213 \r
1214   if (Interface->RecvRequest != NULL) {\r
1215     return EFI_ALREADY_STARTED;\r
1216   }\r
1217 \r
1218   Token = Ip4CreateLinkRxToken (Interface, IpInstance, CallBack, Context);\r
1219 \r
1220   if (Token == NULL) {\r
1221     return EFI_OUT_OF_RESOURCES;\r
1222   }\r
1223 \r
1224   Interface->RecvRequest = Token;\r
1225   Status = Interface->Mnp->Receive (Interface->Mnp, &Token->MnpToken);\r
1226   if (EFI_ERROR (Status)) {\r
1227     Interface->RecvRequest = NULL;\r
1228     Ip4FreeFrameRxToken (Token);\r
1229     return Status;\r
1230   }\r
1231   return EFI_SUCCESS;\r
1232 }\r