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