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