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