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