1 /** @file
2   Implement IP4 pesudo interface.
3 
4 Copyright (c) 2005 - 2014, 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                      Type;
564   INTN                      Len;
565   IP4_ADDR                  Netmask;
566 
567   NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);
568 
569   ASSERT (!Interface->Configured);
570 
571   //
572   // Set the ip/netmask, then compute the subnet broadcast
573   // and network broadcast for easy access. When computing
574   // nework broadcast, the subnet mask is most like longer
575   // than the default netmask (not subneted) as defined in
576   // RFC793. If that isn't the case, we are aggregating the
577   // networks, use the subnet's mask instead.
578   //
579   Interface->Ip             = IpAddr;
580   Interface->SubnetMask     = SubnetMask;
581   Interface->SubnetBrdcast  = (IpAddr | ~SubnetMask);
582 
583   Type                      = NetGetIpClass (IpAddr);
584   ASSERT (Type <= IP4_ADDR_CLASSC);
585   Len                       = NetGetMaskLength (SubnetMask);
586   ASSERT (Len < IP4_MASK_NUM);
587   Netmask                   = gIp4AllMasks[MIN (Len, Type << 3)];
588   Interface->NetBrdcast     = (IpAddr | ~Netmask);
589 
590   //
591   // If the address is NOT all zero, create then configure an ARP child.
592   // Pay attention: DHCP configures its station address as 0.0.0.0/0
593   //
594   Interface->Arp            = NULL;
595   Interface->ArpHandle      = NULL;
596 
597   if (IpAddr != IP4_ALLZERO_ADDRESS) {
598     Status = NetLibCreateServiceChild (
599                Interface->Controller,
600                Interface->Image,
601                &gEfiArpServiceBindingProtocolGuid,
602                &Interface->ArpHandle
603                );
604 
605     if (EFI_ERROR (Status)) {
606       return Status;;
607     }
608 
609     Status = gBS->OpenProtocol (
610                     Interface->ArpHandle,
611                     &gEfiArpProtocolGuid,
612                     (VOID **) &Interface->Arp,
613                     Interface->Image,
614                     Interface->Controller,
615                     EFI_OPEN_PROTOCOL_BY_DRIVER
616                     );
617 
618     if (EFI_ERROR (Status)) {
619       goto ON_ERROR;
620     }
621 
622     IpAddr                    = HTONL (IpAddr);
623     ArpConfig.SwAddressType   = IP4_ETHER_PROTO;
624     ArpConfig.SwAddressLength = 4;
625     ArpConfig.StationAddress  = &IpAddr;
626     ArpConfig.EntryTimeOut    = 0;
627     ArpConfig.RetryCount      = 0;
628     ArpConfig.RetryTimeOut    = 0;
629 
630     Status = Interface->Arp->Configure (Interface->Arp, &ArpConfig);
631 
632     if (EFI_ERROR (Status)) {
633       gBS->CloseProtocol (
634             Interface->ArpHandle,
635             &gEfiArpProtocolGuid,
636             Interface->Image,
637             Interface->Controller
638             );
639 
640       goto ON_ERROR;
641     }
642   }
643 
644   Interface->Configured = TRUE;
645   return EFI_SUCCESS;
646 
647 ON_ERROR:
648   NetLibDestroyServiceChild (
649     Interface->Controller,
650     Interface->Image,
651     &gEfiArpServiceBindingProtocolGuid,
652     &Interface->ArpHandle
653     );
654 
655   return Status;
656 }
657 
658 
659 /**
660   Filter function to cancel all the frame related to an IP instance.
661 
662   @param[in]  Frame             The transmit request to test whether to cancel
663   @param[in]  Context           The context which is the Ip instance that issued
664                                 the transmit.
665 
666   @retval TRUE                  The frame belongs to this instance and is to be
667                                 removed
668   @retval FALSE                 The frame doesn't belong to this instance.
669 
670 **/
671 BOOLEAN
Ip4CancelInstanceFrame(IN IP4_LINK_TX_TOKEN * Frame,IN VOID * Context)672 Ip4CancelInstanceFrame (
673   IN IP4_LINK_TX_TOKEN *Frame,
674   IN VOID              *Context
675   )
676 {
677   if (Frame->IpInstance == (IP4_PROTOCOL *) Context) {
678     return TRUE;
679   }
680 
681   return FALSE;
682 }
683 
684 
685 
686 /**
687   If there is a pending receive request, cancel it. Don't call
688   the receive request's callback because this function can be only
689   called if the instance or driver is tearing itself down. It
690   doesn't make sense to call it back. But it is necessary to call
691   the transmit token's callback to give it a chance to free the
692   packet and update the upper layer's transmit request status, say
693   that from the UDP.
694 
695   @param[in]  Interface         The interface used by the IpInstance
696 
697 **/
698 VOID
Ip4CancelReceive(IN IP4_INTERFACE * Interface)699 Ip4CancelReceive (
700   IN IP4_INTERFACE          *Interface
701   )
702 {
703   EFI_TPL                   OldTpl;
704   IP4_LINK_RX_TOKEN         *Token;
705 
706   if ((Token = Interface->RecvRequest) != NULL) {
707     OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
708 
709     Interface->RecvRequest = NULL;
710     Interface->Mnp->Cancel (Interface->Mnp, &Token->MnpToken);
711 
712     gBS->RestoreTPL (OldTpl);
713   }
714 }
715 
716 
717 /**
718   Free the interface used by IpInstance. All the IP instance with
719   the same Ip/Netmask pair share the same interface. It is reference
720   counted. All the frames haven't been sent will be cancelled.
721   Because the IpInstance is optional, the caller must remove
722   IpInstance from the interface's instance list itself.
723 
724   @param[in]  Interface         The interface used by the IpInstance
725   @param[in]  IpInstance        The Ip instance that free the interface. NULL if
726                                 the Ip driver is releasing the default interface.
727 
728   @retval EFI_SUCCESS           The interface use IpInstance is freed.
729 
730 **/
731 EFI_STATUS
Ip4FreeInterface(IN IP4_INTERFACE * Interface,IN IP4_PROTOCOL * IpInstance OPTIONAL)732 Ip4FreeInterface (
733   IN  IP4_INTERFACE         *Interface,
734   IN  IP4_PROTOCOL          *IpInstance           OPTIONAL
735   )
736 {
737   NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);
738   ASSERT (Interface->RefCnt > 0);
739 
740   //
741   // Remove all the pending transmit token related to this IP instance.
742   //
743   Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, IpInstance);
744 
745   if (--Interface->RefCnt > 0) {
746     return EFI_SUCCESS;
747   }
748 
749   //
750   // Destroy the interface if this is the last IP instance that
751   // has the address. Remove all the system transmitted packets
752   // from this interface, cancel the receive request if there is
753   // one, and destroy the ARP requests.
754   //
755   Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, NULL);
756   Ip4CancelReceive (Interface);
757 
758   ASSERT (IsListEmpty (&Interface->IpInstances));
759   ASSERT (IsListEmpty (&Interface->ArpQues));
760   ASSERT (IsListEmpty (&Interface->SentFrames));
761 
762   if (Interface->Arp != NULL) {
763     gBS->CloseProtocol (
764           Interface->ArpHandle,
765           &gEfiArpProtocolGuid,
766           Interface->Image,
767           Interface->Controller
768           );
769 
770     NetLibDestroyServiceChild (
771       Interface->Controller,
772       Interface->Image,
773       &gEfiArpServiceBindingProtocolGuid,
774       Interface->ArpHandle
775       );
776   }
777 
778   RemoveEntryList (&Interface->Link);
779   FreePool (Interface);
780 
781   return EFI_SUCCESS;
782 }
783 
784 
785 /**
786   Callback function when ARP request are finished. It will cancelled
787   all the queued frame if the ARP requests failed. Or transmit them
788   if the request succeed.
789 
790   @param[in]  Context           The context of the callback, a point to the ARP
791                                 queue
792 
793 **/
794 VOID
795 EFIAPI
Ip4OnArpResolvedDpc(IN VOID * Context)796 Ip4OnArpResolvedDpc (
797   IN VOID                   *Context
798   )
799 {
800   LIST_ENTRY                *Entry;
801   LIST_ENTRY                *Next;
802   IP4_ARP_QUE               *ArpQue;
803   IP4_INTERFACE             *Interface;
804   IP4_LINK_TX_TOKEN         *Token;
805   EFI_STATUS                Status;
806 
807   ArpQue = (IP4_ARP_QUE *) Context;
808   NET_CHECK_SIGNATURE (ArpQue, IP4_FRAME_ARP_SIGNATURE);
809 
810   RemoveEntryList (&ArpQue->Link);
811 
812   //
813   // ARP resolve failed for some reason. Release all the frame
814   // and ARP queue itself. Ip4FreeArpQue will call the frame's
815   // owner back.
816   //
817   if (NET_MAC_EQUAL (&ArpQue->Mac, &mZeroMacAddress, ArpQue->Interface->HwaddrLen)) {
818     Ip4FreeArpQue (ArpQue, EFI_NO_MAPPING);
819 
820     return ;
821   }
822 
823   //
824   // ARP resolve succeeded, Transmit all the frame. Release the ARP
825   // queue. It isn't necessary for us to cache the ARP binding because
826   // we always check the ARP cache first before transmit.
827   //
828   Interface = ArpQue->Interface;
829 
830   NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {
831     RemoveEntryList (Entry);
832 
833     Token         = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);
834     CopyMem (&Token->DstMac, &ArpQue->Mac, sizeof (Token->DstMac));
835 
836     //
837     // Insert the tx token before transmitting it via MNP as the FrameSentDpc
838     // may be called before Mnp->Transmit returns which will remove this tx
839     // token from the SentFrames list. Remove it from the list if the returned
840     // Status of Mnp->Transmit is not EFI_SUCCESS as in this case the
841     // FrameSentDpc won't be queued.
842     //
843     InsertTailList (&Interface->SentFrames, &Token->Link);
844 
845     Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);
846     if (EFI_ERROR (Status)) {
847       RemoveEntryList (Entry);
848       Token->CallBack (Token->IpInstance, Token->Packet, Status, 0, Token->Context);
849 
850       Ip4FreeLinkTxToken (Token);
851       continue;
852     }
853   }
854 
855   Ip4FreeArpQue (ArpQue, EFI_SUCCESS);
856 }
857 
858 /**
859   Request Ip4OnArpResolvedDpc as a DPC at TPL_CALLBACK.
860 
861   @param  Event             The Arp request event.
862   @param  Context           The context of the callback, a point to the ARP
863                             queue.
864 
865 **/
866 VOID
867 EFIAPI
Ip4OnArpResolved(IN EFI_EVENT Event,IN VOID * Context)868 Ip4OnArpResolved (
869   IN EFI_EVENT              Event,
870   IN VOID                   *Context
871   )
872 {
873   //
874   // Request Ip4OnArpResolvedDpc as a DPC at TPL_CALLBACK
875   //
876   QueueDpc (TPL_CALLBACK, Ip4OnArpResolvedDpc, Context);
877 }
878 
879 
880 
881 /**
882   Callback funtion when frame transmission is finished. It will
883   call the frame owner's callback function to tell it the result.
884 
885   @param[in]  Context            Context which is point to the token.
886 
887 **/
888 VOID
889 EFIAPI
Ip4OnFrameSentDpc(IN VOID * Context)890 Ip4OnFrameSentDpc (
891   IN VOID                    *Context
892   )
893 {
894   IP4_LINK_TX_TOKEN         *Token;
895 
896   Token = (IP4_LINK_TX_TOKEN *) Context;
897   NET_CHECK_SIGNATURE (Token, IP4_FRAME_TX_SIGNATURE);
898 
899   RemoveEntryList (&Token->Link);
900 
901   Token->CallBack (
902           Token->IpInstance,
903           Token->Packet,
904           Token->MnpToken.Status,
905           0,
906           Token->Context
907           );
908 
909   Ip4FreeLinkTxToken (Token);
910 }
911 
912 /**
913   Request Ip4OnFrameSentDpc as a DPC at TPL_CALLBACK.
914 
915   @param[in]  Event              The transmit token's event.
916   @param[in]  Context            Context which is point to the token.
917 
918 **/
919 VOID
920 EFIAPI
Ip4OnFrameSent(IN EFI_EVENT Event,IN VOID * Context)921 Ip4OnFrameSent (
922   IN EFI_EVENT               Event,
923   IN VOID                    *Context
924   )
925 {
926   //
927   // Request Ip4OnFrameSentDpc as a DPC at TPL_CALLBACK
928   //
929   QueueDpc (TPL_CALLBACK, Ip4OnFrameSentDpc, Context);
930 }
931 
932 
933 
934 /**
935   Send a frame from the interface. If the next hop is broadcast or
936   multicast address, it is transmitted immediately. If the next hop
937   is a unicast, it will consult ARP to resolve the NextHop's MAC.
938   If some error happened, the CallBack won't be called. So, the caller
939   must test the return value, and take action when there is an error.
940 
941   @param[in]  Interface         The interface to send the frame from
942   @param[in]  IpInstance        The IP child that request the transmission.  NULL
943                                 if it is the IP4 driver itself.
944   @param[in]  Packet            The packet to transmit.
945   @param[in]  NextHop           The immediate destination to transmit the packet
946                                 to.
947   @param[in]  CallBack          Function to call back when transmit finished.
948   @param[in]  Context           Opaque parameter to the call back.
949 
950   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to send the frame
951   @retval EFI_NO_MAPPING        Can't resolve the MAC for the nexthop
952   @retval EFI_SUCCESS           The packet is successfully transmitted.
953   @retval other                 Other error occurs.
954 
955 **/
956 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)957 Ip4SendFrame (
958   IN  IP4_INTERFACE         *Interface,
959   IN  IP4_PROTOCOL          *IpInstance       OPTIONAL,
960   IN  NET_BUF               *Packet,
961   IN  IP4_ADDR              NextHop,
962   IN  IP4_FRAME_CALLBACK    CallBack,
963   IN  VOID                  *Context
964   )
965 {
966   IP4_LINK_TX_TOKEN         *Token;
967   LIST_ENTRY                *Entry;
968   IP4_ARP_QUE               *ArpQue;
969   EFI_ARP_PROTOCOL          *Arp;
970   EFI_STATUS                Status;
971 
972   ASSERT (Interface->Configured);
973 
974   Token = Ip4WrapLinkTxToken (Interface, IpInstance, Packet, CallBack, Context);
975 
976   if (Token == NULL) {
977     return EFI_OUT_OF_RESOURCES;
978   }
979 
980   //
981   // Get the destination MAC address for multicast and broadcasts.
982   // Don't depend on ARP to solve the address since there maybe no
983   // ARP at all. Ip4Output has set NextHop to 255.255.255.255 for
984   // all the broadcasts.
985   //
986   if (NextHop == IP4_ALLONE_ADDRESS) {
987     CopyMem (&Token->DstMac, &Interface->BroadcastMac, sizeof (Token->DstMac));
988     goto SEND_NOW;
989 
990   } else if (IP4_IS_MULTICAST (NextHop)) {
991 
992     Status = Ip4GetMulticastMac (Interface->Mnp, NextHop, &Token->DstMac);
993 
994     if (EFI_ERROR (Status)) {
995       goto ON_ERROR;
996     }
997 
998     goto SEND_NOW;
999   }
1000 
1001   //
1002   // Can only send out multicast/broadcast if the IP address is zero
1003   //
1004   if ((Arp = Interface->Arp) == NULL) {
1005     Status = EFI_NO_MAPPING;
1006     goto ON_ERROR;
1007   }
1008 
1009   //
1010   // First check whether this binding is in the ARP cache.
1011   //
1012   NextHop = HTONL (NextHop);
1013   Status  = Arp->Request (Arp, &NextHop, NULL, &Token->DstMac);
1014 
1015   if (Status == EFI_SUCCESS) {
1016     goto SEND_NOW;
1017 
1018   } else if (Status != EFI_NOT_READY) {
1019     goto ON_ERROR;
1020   }
1021 
1022   //
1023   // Have to do asynchronous ARP resolution. First check
1024   // whether there is already a pending request.
1025   //
1026   ArpQue = NULL;
1027 
1028   NET_LIST_FOR_EACH (Entry, &Interface->ArpQues) {
1029     ArpQue = NET_LIST_USER_STRUCT (Entry, IP4_ARP_QUE, Link);
1030 
1031     if (ArpQue->Ip == NextHop) {
1032       break;
1033     }
1034   }
1035 
1036   //
1037   // Found a pending ARP request, enqueue the frame then return
1038   //
1039   if (Entry != &Interface->ArpQues) {
1040     InsertTailList (&ArpQue->Frames, &Token->Link);
1041     return EFI_SUCCESS;
1042   }
1043 
1044   //
1045   // First frame to NextHop, issue an asynchronous ARP requests
1046   //
1047   ArpQue = Ip4CreateArpQue (Interface, NextHop);
1048 
1049   if (ArpQue == NULL) {
1050     Status = EFI_OUT_OF_RESOURCES;
1051     goto ON_ERROR;
1052   }
1053 
1054   Status = Arp->Request (Arp, &ArpQue->Ip, ArpQue->OnResolved, ArpQue->Mac.Addr);
1055 
1056   if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {
1057     Ip4FreeArpQue (ArpQue, EFI_NO_MAPPING);
1058     goto ON_ERROR;
1059   }
1060 
1061   InsertHeadList (&ArpQue->Frames, &Token->Link);
1062   InsertHeadList (&Interface->ArpQues, &ArpQue->Link);
1063   return EFI_SUCCESS;
1064 
1065 SEND_NOW:
1066   //
1067   // Insert the tx token into the SentFrames list before calling Mnp->Transmit.
1068   // Remove it if the returned status is not EFI_SUCCESS.
1069   //
1070   InsertTailList (&Interface->SentFrames, &Token->Link);
1071   Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);
1072   if (EFI_ERROR (Status)) {
1073     RemoveEntryList (&Interface->SentFrames);
1074     goto ON_ERROR;
1075   }
1076 
1077   return EFI_SUCCESS;
1078 
1079 ON_ERROR:
1080   Ip4FreeLinkTxToken (Token);
1081   return Status;
1082 }
1083 
1084 
1085 /**
1086   Call back function when the received packet is freed.
1087   Check Ip4OnFrameReceived for information.
1088 
1089   @param  Context          Context, which is the IP4_LINK_RX_TOKEN.
1090 
1091 **/
1092 VOID
1093 EFIAPI
Ip4RecycleFrame(IN VOID * Context)1094 Ip4RecycleFrame (
1095   IN VOID                   *Context
1096   )
1097 {
1098   IP4_LINK_RX_TOKEN         *Frame;
1099 
1100   Frame = (IP4_LINK_RX_TOKEN *) Context;
1101   NET_CHECK_SIGNATURE (Frame, IP4_FRAME_RX_SIGNATURE);
1102 
1103   gBS->SignalEvent (Frame->MnpToken.Packet.RxData->RecycleEvent);
1104   Ip4FreeFrameRxToken (Frame);
1105 }
1106 
1107 
1108 /**
1109   Received a frame from MNP, wrap it in net buffer then deliver
1110   it to IP's input function. The ownship of the packet also
1111   transferred to IP. When Ip is finished with this packet, it
1112   will call NetbufFree to release the packet, NetbufFree will
1113   again call the Ip4RecycleFrame to signal MNP's event and free
1114   the token used.
1115 
1116   @param  Context               Context for the callback.
1117 
1118 **/
1119 VOID
1120 EFIAPI
Ip4OnFrameReceivedDpc(IN VOID * Context)1121 Ip4OnFrameReceivedDpc (
1122   IN VOID                     *Context
1123   )
1124 {
1125   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *MnpToken;
1126   EFI_MANAGED_NETWORK_RECEIVE_DATA      *MnpRxData;
1127   IP4_LINK_RX_TOKEN                     *Token;
1128   NET_FRAGMENT                          Netfrag;
1129   NET_BUF                               *Packet;
1130   UINT32                                Flag;
1131 
1132   Token = (IP4_LINK_RX_TOKEN *) Context;
1133   NET_CHECK_SIGNATURE (Token, IP4_FRAME_RX_SIGNATURE);
1134 
1135   //
1136   // First clear the interface's receive request in case the
1137   // caller wants to call Ip4ReceiveFrame in the callback.
1138   //
1139   Token->Interface->RecvRequest = NULL;
1140 
1141   MnpToken  = &Token->MnpToken;
1142   MnpRxData = MnpToken->Packet.RxData;
1143 
1144   if (EFI_ERROR (MnpToken->Status) || (MnpRxData == NULL)) {
1145     Token->CallBack (Token->IpInstance, NULL, MnpToken->Status, 0, Token->Context);
1146     Ip4FreeFrameRxToken (Token);
1147 
1148     return ;
1149   }
1150 
1151   //
1152   // Wrap the frame in a net buffer then deliever it to IP input.
1153   // IP will reassemble the packet, and deliver it to upper layer
1154   //
1155   Netfrag.Len  = MnpRxData->DataLength;
1156   Netfrag.Bulk = MnpRxData->PacketData;
1157 
1158   Packet = NetbufFromExt (&Netfrag, 1, 0, IP4_MAX_HEADLEN, Ip4RecycleFrame, Token);
1159 
1160   if (Packet == NULL) {
1161     gBS->SignalEvent (MnpRxData->RecycleEvent);
1162 
1163     Token->CallBack (Token->IpInstance, NULL, EFI_OUT_OF_RESOURCES, 0, Token->Context);
1164     Ip4FreeFrameRxToken (Token);
1165 
1166     return ;
1167   }
1168 
1169   Flag  = (MnpRxData->BroadcastFlag ? IP4_LINK_BROADCAST : 0);
1170   Flag |= (MnpRxData->MulticastFlag ? IP4_LINK_MULTICAST : 0);
1171   Flag |= (MnpRxData->PromiscuousFlag ? IP4_LINK_PROMISC : 0);
1172 
1173   Token->CallBack (Token->IpInstance, Packet, EFI_SUCCESS, Flag, Token->Context);
1174 }
1175 
1176 /**
1177   Request Ip4OnFrameReceivedDpc as a DPC at TPL_CALLBACK.
1178 
1179   @param Event      The receive event delivered to MNP for receive.
1180   @param Context    Context for the callback.
1181 
1182 **/
1183 VOID
1184 EFIAPI
Ip4OnFrameReceived(IN EFI_EVENT Event,IN VOID * Context)1185 Ip4OnFrameReceived (
1186   IN EFI_EVENT                Event,
1187   IN VOID                     *Context
1188   )
1189 {
1190   //
1191   // Request Ip4OnFrameReceivedDpc as a DPC at TPL_CALLBACK
1192   //
1193   QueueDpc (TPL_CALLBACK, Ip4OnFrameReceivedDpc, Context);
1194 }
1195 
1196 
1197 /**
1198   Request to receive the packet from the interface.
1199 
1200   @param[in]  Interface         The interface to receive the frames from
1201   @param[in]  IpInstance        The instance that requests the receive. NULL for
1202                                 the driver itself.
1203   @param[in]  CallBack          Function to call when receive finished.
1204   @param[in]  Context           Opaque parameter to the callback
1205 
1206   @retval EFI_ALREADY_STARTED   There is already a pending receive request.
1207   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to receive
1208   @retval EFI_SUCCESS           The recieve request has been started.
1209   @retval other                 Other error occurs.
1210 
1211 **/
1212 EFI_STATUS
Ip4ReceiveFrame(IN IP4_INTERFACE * Interface,IN IP4_PROTOCOL * IpInstance OPTIONAL,IN IP4_FRAME_CALLBACK CallBack,IN VOID * Context)1213 Ip4ReceiveFrame (
1214   IN  IP4_INTERFACE         *Interface,
1215   IN  IP4_PROTOCOL          *IpInstance       OPTIONAL,
1216   IN  IP4_FRAME_CALLBACK    CallBack,
1217   IN  VOID                  *Context
1218   )
1219 {
1220   IP4_LINK_RX_TOKEN *Token;
1221   EFI_STATUS        Status;
1222 
1223   NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);
1224 
1225   if (Interface->RecvRequest != NULL) {
1226     return EFI_ALREADY_STARTED;
1227   }
1228 
1229   Token = Ip4CreateLinkRxToken (Interface, IpInstance, CallBack, Context);
1230 
1231   if (Token == NULL) {
1232     return EFI_OUT_OF_RESOURCES;
1233   }
1234 
1235   Interface->RecvRequest = Token;
1236   Status = Interface->Mnp->Receive (Interface->Mnp, &Token->MnpToken);
1237   if (EFI_ERROR (Status)) {
1238     Interface->RecvRequest = NULL;
1239     Ip4FreeFrameRxToken (Token);
1240     return Status;
1241   }
1242   return EFI_SUCCESS;
1243 }
1244