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