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