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