1 /** @file
2 Implement IP4 pesudo interface.
3
4 Copyright (c) 2005 - 2015, 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 *
Ip4WrapLinkTxToken(IN IP4_INTERFACE * Interface,IN IP4_PROTOCOL * IpInstance OPTIONAL,IN NET_BUF * Packet,IN IP4_FRAME_CALLBACK CallBack,IN VOID * Context)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
Ip4FreeLinkTxToken(IN IP4_LINK_TX_TOKEN * Token)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 *
Ip4CreateArpQue(IN IP4_INTERFACE * Interface,IN IP4_ADDR DestIp)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
Ip4FreeArpQue(IN IP4_ARP_QUE * ArpQue,IN EFI_STATUS IoStatus)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 *
Ip4CreateLinkRxToken(IN IP4_INTERFACE * Interface,IN IP4_PROTOCOL * IpInstance,IN IP4_FRAME_CALLBACK CallBack,IN VOID * Context)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
Ip4FreeFrameRxToken(IN IP4_LINK_RX_TOKEN * Token)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
Ip4CancelFrameArp(IN IP4_ARP_QUE * ArpQue,IN EFI_STATUS IoStatus,IN IP4_FRAME_TO_CANCEL FrameToCancel OPTIONAL,IN VOID * Context)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
Ip4CancelFrames(IN IP4_INTERFACE * Interface,IN EFI_STATUS IoStatus,IN IP4_FRAME_TO_CANCEL FrameToCancel OPTIONAL,IN VOID * Context)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 *
Ip4CreateInterface(IN EFI_MANAGED_NETWORK_PROTOCOL * Mnp,IN EFI_HANDLE Controller,IN EFI_HANDLE ImageHandle)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
Ip4SetAddress(IN OUT IP4_INTERFACE * Interface,IN IP4_ADDR IpAddr,IN IP4_ADDR SubnetMask)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 //
570 // Set the ip/netmask, then compute the subnet broadcast
571 // and network broadcast for easy access. When computing
572 // nework broadcast, the subnet mask is most like longer
573 // than the default netmask (not subneted) as defined in
574 // RFC793. If that isn't the case, we are aggregating the
575 // networks, use the subnet's mask instead.
576 //
577 Interface->Ip = IpAddr;
578 Interface->SubnetMask = SubnetMask;
579 Interface->SubnetBrdcast = (IpAddr | ~SubnetMask);
580
581 Type = NetGetIpClass (IpAddr);
582 ASSERT (Type <= IP4_ADDR_CLASSC);
583 Len = NetGetMaskLength (SubnetMask);
584 ASSERT (Len < IP4_MASK_NUM);
585 Netmask = gIp4AllMasks[MIN (Len, Type << 3)];
586 Interface->NetBrdcast = (IpAddr | ~Netmask);
587
588 //
589 // Do clean up for Arp child
590 //
591 if (Interface->ArpHandle != NULL) {
592 if (Interface->Arp != NULL) {
593 gBS->CloseProtocol (
594 Interface->ArpHandle,
595 &gEfiArpProtocolGuid,
596 Interface->Image,
597 Interface->Controller
598 );
599
600 Interface->Arp = NULL;
601 }
602
603 NetLibDestroyServiceChild (
604 Interface->Controller,
605 Interface->Image,
606 &gEfiArpServiceBindingProtocolGuid,
607 &Interface->ArpHandle
608 );
609
610 Interface->ArpHandle = NULL;
611 }
612
613 //
614 // If the address is NOT all zero, create then configure an ARP child.
615 // Pay attention: DHCP configures its station address as 0.0.0.0/0
616 //
617 if (IpAddr != IP4_ALLZERO_ADDRESS) {
618 Status = NetLibCreateServiceChild (
619 Interface->Controller,
620 Interface->Image,
621 &gEfiArpServiceBindingProtocolGuid,
622 &Interface->ArpHandle
623 );
624
625 if (EFI_ERROR (Status)) {
626 return Status;
627 }
628
629 Status = gBS->OpenProtocol (
630 Interface->ArpHandle,
631 &gEfiArpProtocolGuid,
632 (VOID **) &Interface->Arp,
633 Interface->Image,
634 Interface->Controller,
635 EFI_OPEN_PROTOCOL_BY_DRIVER
636 );
637
638 if (EFI_ERROR (Status)) {
639 goto ON_ERROR;
640 }
641
642 IpAddr = HTONL (IpAddr);
643 ArpConfig.SwAddressType = IP4_ETHER_PROTO;
644 ArpConfig.SwAddressLength = 4;
645 ArpConfig.StationAddress = &IpAddr;
646 ArpConfig.EntryTimeOut = 0;
647 ArpConfig.RetryCount = 0;
648 ArpConfig.RetryTimeOut = 0;
649
650 Status = Interface->Arp->Configure (Interface->Arp, &ArpConfig);
651
652 if (EFI_ERROR (Status)) {
653 gBS->CloseProtocol (
654 Interface->ArpHandle,
655 &gEfiArpProtocolGuid,
656 Interface->Image,
657 Interface->Controller
658 );
659
660 goto ON_ERROR;
661 }
662 }
663
664 Interface->Configured = TRUE;
665 return EFI_SUCCESS;
666
667 ON_ERROR:
668 NetLibDestroyServiceChild (
669 Interface->Controller,
670 Interface->Image,
671 &gEfiArpServiceBindingProtocolGuid,
672 &Interface->ArpHandle
673 );
674
675 return Status;
676 }
677
678
679 /**
680 Filter function to cancel all the frame related to an IP instance.
681
682 @param[in] Frame The transmit request to test whether to cancel
683 @param[in] Context The context which is the Ip instance that issued
684 the transmit.
685
686 @retval TRUE The frame belongs to this instance and is to be
687 removed
688 @retval FALSE The frame doesn't belong to this instance.
689
690 **/
691 BOOLEAN
Ip4CancelInstanceFrame(IN IP4_LINK_TX_TOKEN * Frame,IN VOID * Context)692 Ip4CancelInstanceFrame (
693 IN IP4_LINK_TX_TOKEN *Frame,
694 IN VOID *Context
695 )
696 {
697 if (Frame->IpInstance == (IP4_PROTOCOL *) Context) {
698 return TRUE;
699 }
700
701 return FALSE;
702 }
703
704
705
706 /**
707 If there is a pending receive request, cancel it. Don't call
708 the receive request's callback because this function can be only
709 called if the instance or driver is tearing itself down. It
710 doesn't make sense to call it back. But it is necessary to call
711 the transmit token's callback to give it a chance to free the
712 packet and update the upper layer's transmit request status, say
713 that from the UDP.
714
715 @param[in] Interface The interface used by the IpInstance
716
717 **/
718 VOID
Ip4CancelReceive(IN IP4_INTERFACE * Interface)719 Ip4CancelReceive (
720 IN IP4_INTERFACE *Interface
721 )
722 {
723 EFI_TPL OldTpl;
724 IP4_LINK_RX_TOKEN *Token;
725
726 if ((Token = Interface->RecvRequest) != NULL) {
727 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
728
729 Interface->RecvRequest = NULL;
730 Interface->Mnp->Cancel (Interface->Mnp, &Token->MnpToken);
731
732 gBS->RestoreTPL (OldTpl);
733 }
734 }
735
736
737 /**
738 Free the interface used by IpInstance. All the IP instance with
739 the same Ip/Netmask pair share the same interface. It is reference
740 counted. All the frames haven't been sent will be cancelled.
741 Because the IpInstance is optional, the caller must remove
742 IpInstance from the interface's instance list itself.
743
744 @param[in] Interface The interface used by the IpInstance.
745 @param[in] IpInstance The Ip instance that free the interface. NULL if
746 the Ip driver is releasing the default interface.
747
748 @retval EFI_SUCCESS The interface use IpInstance is freed.
749
750 **/
751 EFI_STATUS
Ip4FreeInterface(IN IP4_INTERFACE * Interface,IN IP4_PROTOCOL * IpInstance OPTIONAL)752 Ip4FreeInterface (
753 IN IP4_INTERFACE *Interface,
754 IN IP4_PROTOCOL *IpInstance OPTIONAL
755 )
756 {
757 NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);
758 ASSERT (Interface->RefCnt > 0);
759
760 //
761 // Remove all the pending transmit token related to this IP instance.
762 //
763 Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, IpInstance);
764
765 if (--Interface->RefCnt > 0) {
766 return EFI_SUCCESS;
767 }
768
769 //
770 // Destroy the interface if this is the last IP instance that
771 // has the address. Remove all the system transmitted packets
772 // from this interface, cancel the receive request if there is
773 // one, and destroy the ARP requests.
774 //
775 Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, NULL);
776 Ip4CancelReceive (Interface);
777
778 ASSERT (IsListEmpty (&Interface->IpInstances));
779 ASSERT (IsListEmpty (&Interface->ArpQues));
780 ASSERT (IsListEmpty (&Interface->SentFrames));
781
782 if (Interface->Arp != NULL) {
783 gBS->CloseProtocol (
784 Interface->ArpHandle,
785 &gEfiArpProtocolGuid,
786 Interface->Image,
787 Interface->Controller
788 );
789
790 NetLibDestroyServiceChild (
791 Interface->Controller,
792 Interface->Image,
793 &gEfiArpServiceBindingProtocolGuid,
794 Interface->ArpHandle
795 );
796 }
797
798 RemoveEntryList (&Interface->Link);
799 FreePool (Interface);
800
801 return EFI_SUCCESS;
802 }
803
804
805 /**
806 Callback function when ARP request are finished. It will cancelled
807 all the queued frame if the ARP requests failed. Or transmit them
808 if the request succeed.
809
810 @param[in] Context The context of the callback, a point to the ARP
811 queue
812
813 **/
814 VOID
815 EFIAPI
Ip4OnArpResolvedDpc(IN VOID * Context)816 Ip4OnArpResolvedDpc (
817 IN VOID *Context
818 )
819 {
820 LIST_ENTRY *Entry;
821 LIST_ENTRY *Next;
822 IP4_ARP_QUE *ArpQue;
823 IP4_INTERFACE *Interface;
824 IP4_LINK_TX_TOKEN *Token;
825 EFI_STATUS Status;
826
827 ArpQue = (IP4_ARP_QUE *) Context;
828 NET_CHECK_SIGNATURE (ArpQue, IP4_FRAME_ARP_SIGNATURE);
829
830 RemoveEntryList (&ArpQue->Link);
831
832 //
833 // ARP resolve failed for some reason. Release all the frame
834 // and ARP queue itself. Ip4FreeArpQue will call the frame's
835 // owner back.
836 //
837 if (NET_MAC_EQUAL (&ArpQue->Mac, &mZeroMacAddress, ArpQue->Interface->HwaddrLen)) {
838 Ip4FreeArpQue (ArpQue, EFI_NO_MAPPING);
839
840 return ;
841 }
842
843 //
844 // ARP resolve succeeded, Transmit all the frame. Release the ARP
845 // queue. It isn't necessary for us to cache the ARP binding because
846 // we always check the ARP cache first before transmit.
847 //
848 Interface = ArpQue->Interface;
849
850 NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {
851 RemoveEntryList (Entry);
852
853 Token = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);
854 CopyMem (&Token->DstMac, &ArpQue->Mac, sizeof (Token->DstMac));
855
856 //
857 // Insert the tx token before transmitting it via MNP as the FrameSentDpc
858 // may be called before Mnp->Transmit returns which will remove this tx
859 // token from the SentFrames list. Remove it from the list if the returned
860 // Status of Mnp->Transmit is not EFI_SUCCESS as in this case the
861 // FrameSentDpc won't be queued.
862 //
863 InsertTailList (&Interface->SentFrames, &Token->Link);
864
865 Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);
866 if (EFI_ERROR (Status)) {
867 RemoveEntryList (Entry);
868 Token->CallBack (Token->IpInstance, Token->Packet, Status, 0, Token->Context);
869
870 Ip4FreeLinkTxToken (Token);
871 continue;
872 }
873 }
874
875 Ip4FreeArpQue (ArpQue, EFI_SUCCESS);
876 }
877
878 /**
879 Request Ip4OnArpResolvedDpc as a DPC at TPL_CALLBACK.
880
881 @param Event The Arp request event.
882 @param Context The context of the callback, a point to the ARP
883 queue.
884
885 **/
886 VOID
887 EFIAPI
Ip4OnArpResolved(IN EFI_EVENT Event,IN VOID * Context)888 Ip4OnArpResolved (
889 IN EFI_EVENT Event,
890 IN VOID *Context
891 )
892 {
893 //
894 // Request Ip4OnArpResolvedDpc as a DPC at TPL_CALLBACK
895 //
896 QueueDpc (TPL_CALLBACK, Ip4OnArpResolvedDpc, Context);
897 }
898
899
900
901 /**
902 Callback funtion when frame transmission is finished. It will
903 call the frame owner's callback function to tell it the result.
904
905 @param[in] Context Context which is point to the token.
906
907 **/
908 VOID
909 EFIAPI
Ip4OnFrameSentDpc(IN VOID * Context)910 Ip4OnFrameSentDpc (
911 IN VOID *Context
912 )
913 {
914 IP4_LINK_TX_TOKEN *Token;
915
916 Token = (IP4_LINK_TX_TOKEN *) Context;
917 NET_CHECK_SIGNATURE (Token, IP4_FRAME_TX_SIGNATURE);
918
919 RemoveEntryList (&Token->Link);
920
921 Token->CallBack (
922 Token->IpInstance,
923 Token->Packet,
924 Token->MnpToken.Status,
925 0,
926 Token->Context
927 );
928
929 Ip4FreeLinkTxToken (Token);
930 }
931
932 /**
933 Request Ip4OnFrameSentDpc as a DPC at TPL_CALLBACK.
934
935 @param[in] Event The transmit token's event.
936 @param[in] Context Context which is point to the token.
937
938 **/
939 VOID
940 EFIAPI
Ip4OnFrameSent(IN EFI_EVENT Event,IN VOID * Context)941 Ip4OnFrameSent (
942 IN EFI_EVENT Event,
943 IN VOID *Context
944 )
945 {
946 //
947 // Request Ip4OnFrameSentDpc as a DPC at TPL_CALLBACK
948 //
949 QueueDpc (TPL_CALLBACK, Ip4OnFrameSentDpc, Context);
950 }
951
952
953
954 /**
955 Send a frame from the interface. If the next hop is broadcast or
956 multicast address, it is transmitted immediately. If the next hop
957 is a unicast, it will consult ARP to resolve the NextHop's MAC.
958 If some error happened, the CallBack won't be called. So, the caller
959 must test the return value, and take action when there is an error.
960
961 @param[in] Interface The interface to send the frame from
962 @param[in] IpInstance The IP child that request the transmission. NULL
963 if it is the IP4 driver itself.
964 @param[in] Packet The packet to transmit.
965 @param[in] NextHop The immediate destination to transmit the packet
966 to.
967 @param[in] CallBack Function to call back when transmit finished.
968 @param[in] Context Opaque parameter to the call back.
969
970 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to send the frame
971 @retval EFI_NO_MAPPING Can't resolve the MAC for the nexthop
972 @retval EFI_SUCCESS The packet is successfully transmitted.
973 @retval other Other error occurs.
974
975 **/
976 EFI_STATUS
Ip4SendFrame(IN IP4_INTERFACE * Interface,IN IP4_PROTOCOL * IpInstance OPTIONAL,IN NET_BUF * Packet,IN IP4_ADDR NextHop,IN IP4_FRAME_CALLBACK CallBack,IN VOID * Context)977 Ip4SendFrame (
978 IN IP4_INTERFACE *Interface,
979 IN IP4_PROTOCOL *IpInstance OPTIONAL,
980 IN NET_BUF *Packet,
981 IN IP4_ADDR NextHop,
982 IN IP4_FRAME_CALLBACK CallBack,
983 IN VOID *Context
984 )
985 {
986 IP4_LINK_TX_TOKEN *Token;
987 LIST_ENTRY *Entry;
988 IP4_ARP_QUE *ArpQue;
989 EFI_ARP_PROTOCOL *Arp;
990 EFI_STATUS Status;
991
992 ASSERT (Interface->Configured);
993
994 Token = Ip4WrapLinkTxToken (Interface, IpInstance, Packet, CallBack, Context);
995
996 if (Token == NULL) {
997 return EFI_OUT_OF_RESOURCES;
998 }
999
1000 //
1001 // Get the destination MAC address for multicast and broadcasts.
1002 // Don't depend on ARP to solve the address since there maybe no
1003 // ARP at all. Ip4Output has set NextHop to 255.255.255.255 for
1004 // all the broadcasts.
1005 //
1006 if (NextHop == IP4_ALLONE_ADDRESS) {
1007 CopyMem (&Token->DstMac, &Interface->BroadcastMac, sizeof (Token->DstMac));
1008 goto SEND_NOW;
1009
1010 } else if (IP4_IS_MULTICAST (NextHop)) {
1011
1012 Status = Ip4GetMulticastMac (Interface->Mnp, NextHop, &Token->DstMac);
1013
1014 if (EFI_ERROR (Status)) {
1015 goto ON_ERROR;
1016 }
1017
1018 goto SEND_NOW;
1019 }
1020
1021 //
1022 // Can only send out multicast/broadcast if the IP address is zero
1023 //
1024 if ((Arp = Interface->Arp) == NULL) {
1025 Status = EFI_NO_MAPPING;
1026 goto ON_ERROR;
1027 }
1028
1029 //
1030 // First check whether this binding is in the ARP cache.
1031 //
1032 NextHop = HTONL (NextHop);
1033 Status = Arp->Request (Arp, &NextHop, NULL, &Token->DstMac);
1034
1035 if (Status == EFI_SUCCESS) {
1036 goto SEND_NOW;
1037
1038 } else if (Status != EFI_NOT_READY) {
1039 goto ON_ERROR;
1040 }
1041
1042 //
1043 // Have to do asynchronous ARP resolution. First check
1044 // whether there is already a pending request.
1045 //
1046 ArpQue = NULL;
1047
1048 NET_LIST_FOR_EACH (Entry, &Interface->ArpQues) {
1049 ArpQue = NET_LIST_USER_STRUCT (Entry, IP4_ARP_QUE, Link);
1050
1051 if (ArpQue->Ip == NextHop) {
1052 break;
1053 }
1054 }
1055
1056 //
1057 // Found a pending ARP request, enqueue the frame then return
1058 //
1059 if (Entry != &Interface->ArpQues) {
1060 InsertTailList (&ArpQue->Frames, &Token->Link);
1061 return EFI_SUCCESS;
1062 }
1063
1064 //
1065 // First frame to NextHop, issue an asynchronous ARP requests
1066 //
1067 ArpQue = Ip4CreateArpQue (Interface, NextHop);
1068
1069 if (ArpQue == NULL) {
1070 Status = EFI_OUT_OF_RESOURCES;
1071 goto ON_ERROR;
1072 }
1073
1074 Status = Arp->Request (Arp, &ArpQue->Ip, ArpQue->OnResolved, ArpQue->Mac.Addr);
1075
1076 if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {
1077 Ip4FreeArpQue (ArpQue, EFI_NO_MAPPING);
1078 goto ON_ERROR;
1079 }
1080
1081 InsertHeadList (&ArpQue->Frames, &Token->Link);
1082 InsertHeadList (&Interface->ArpQues, &ArpQue->Link);
1083 return EFI_SUCCESS;
1084
1085 SEND_NOW:
1086 //
1087 // Insert the tx token into the SentFrames list before calling Mnp->Transmit.
1088 // Remove it if the returned status is not EFI_SUCCESS.
1089 //
1090 InsertTailList (&Interface->SentFrames, &Token->Link);
1091 Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);
1092 if (EFI_ERROR (Status)) {
1093 RemoveEntryList (&Interface->SentFrames);
1094 goto ON_ERROR;
1095 }
1096
1097 return EFI_SUCCESS;
1098
1099 ON_ERROR:
1100 Ip4FreeLinkTxToken (Token);
1101 return Status;
1102 }
1103
1104
1105 /**
1106 Call back function when the received packet is freed.
1107 Check Ip4OnFrameReceived for information.
1108
1109 @param Context Context, which is the IP4_LINK_RX_TOKEN.
1110
1111 **/
1112 VOID
1113 EFIAPI
Ip4RecycleFrame(IN VOID * Context)1114 Ip4RecycleFrame (
1115 IN VOID *Context
1116 )
1117 {
1118 IP4_LINK_RX_TOKEN *Frame;
1119
1120 Frame = (IP4_LINK_RX_TOKEN *) Context;
1121 NET_CHECK_SIGNATURE (Frame, IP4_FRAME_RX_SIGNATURE);
1122
1123 gBS->SignalEvent (Frame->MnpToken.Packet.RxData->RecycleEvent);
1124 Ip4FreeFrameRxToken (Frame);
1125 }
1126
1127
1128 /**
1129 Received a frame from MNP, wrap it in net buffer then deliver
1130 it to IP's input function. The ownship of the packet also
1131 transferred to IP. When Ip is finished with this packet, it
1132 will call NetbufFree to release the packet, NetbufFree will
1133 again call the Ip4RecycleFrame to signal MNP's event and free
1134 the token used.
1135
1136 @param Context Context for the callback.
1137
1138 **/
1139 VOID
1140 EFIAPI
Ip4OnFrameReceivedDpc(IN VOID * Context)1141 Ip4OnFrameReceivedDpc (
1142 IN VOID *Context
1143 )
1144 {
1145 EFI_MANAGED_NETWORK_COMPLETION_TOKEN *MnpToken;
1146 EFI_MANAGED_NETWORK_RECEIVE_DATA *MnpRxData;
1147 IP4_LINK_RX_TOKEN *Token;
1148 NET_FRAGMENT Netfrag;
1149 NET_BUF *Packet;
1150 UINT32 Flag;
1151
1152 Token = (IP4_LINK_RX_TOKEN *) Context;
1153 NET_CHECK_SIGNATURE (Token, IP4_FRAME_RX_SIGNATURE);
1154
1155 //
1156 // First clear the interface's receive request in case the
1157 // caller wants to call Ip4ReceiveFrame in the callback.
1158 //
1159 Token->Interface->RecvRequest = NULL;
1160
1161 MnpToken = &Token->MnpToken;
1162 MnpRxData = MnpToken->Packet.RxData;
1163
1164 if (EFI_ERROR (MnpToken->Status) || (MnpRxData == NULL)) {
1165 Token->CallBack (Token->IpInstance, NULL, MnpToken->Status, 0, Token->Context);
1166 Ip4FreeFrameRxToken (Token);
1167
1168 return ;
1169 }
1170
1171 //
1172 // Wrap the frame in a net buffer then deliever it to IP input.
1173 // IP will reassemble the packet, and deliver it to upper layer
1174 //
1175 Netfrag.Len = MnpRxData->DataLength;
1176 Netfrag.Bulk = MnpRxData->PacketData;
1177
1178 Packet = NetbufFromExt (&Netfrag, 1, 0, IP4_MAX_HEADLEN, Ip4RecycleFrame, Token);
1179
1180 if (Packet == NULL) {
1181 gBS->SignalEvent (MnpRxData->RecycleEvent);
1182
1183 Token->CallBack (Token->IpInstance, NULL, EFI_OUT_OF_RESOURCES, 0, Token->Context);
1184 Ip4FreeFrameRxToken (Token);
1185
1186 return ;
1187 }
1188
1189 Flag = (MnpRxData->BroadcastFlag ? IP4_LINK_BROADCAST : 0);
1190 Flag |= (MnpRxData->MulticastFlag ? IP4_LINK_MULTICAST : 0);
1191 Flag |= (MnpRxData->PromiscuousFlag ? IP4_LINK_PROMISC : 0);
1192
1193 Token->CallBack (Token->IpInstance, Packet, EFI_SUCCESS, Flag, Token->Context);
1194 }
1195
1196 /**
1197 Request Ip4OnFrameReceivedDpc as a DPC at TPL_CALLBACK.
1198
1199 @param Event The receive event delivered to MNP for receive.
1200 @param Context Context for the callback.
1201
1202 **/
1203 VOID
1204 EFIAPI
Ip4OnFrameReceived(IN EFI_EVENT Event,IN VOID * Context)1205 Ip4OnFrameReceived (
1206 IN EFI_EVENT Event,
1207 IN VOID *Context
1208 )
1209 {
1210 //
1211 // Request Ip4OnFrameReceivedDpc as a DPC at TPL_CALLBACK
1212 //
1213 QueueDpc (TPL_CALLBACK, Ip4OnFrameReceivedDpc, Context);
1214 }
1215
1216
1217 /**
1218 Request to receive the packet from the interface.
1219
1220 @param[in] Interface The interface to receive the frames from.
1221 @param[in] IpInstance The instance that requests the receive. NULL for
1222 the driver itself.
1223 @param[in] CallBack Function to call when receive finished.
1224 @param[in] Context Opaque parameter to the callback.
1225
1226 @retval EFI_ALREADY_STARTED There is already a pending receive request.
1227 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to receive.
1228 @retval EFI_SUCCESS The recieve request has been started.
1229 @retval other Other error occurs.
1230
1231 **/
1232 EFI_STATUS
Ip4ReceiveFrame(IN IP4_INTERFACE * Interface,IN IP4_PROTOCOL * IpInstance OPTIONAL,IN IP4_FRAME_CALLBACK CallBack,IN VOID * Context)1233 Ip4ReceiveFrame (
1234 IN IP4_INTERFACE *Interface,
1235 IN IP4_PROTOCOL *IpInstance OPTIONAL,
1236 IN IP4_FRAME_CALLBACK CallBack,
1237 IN VOID *Context
1238 )
1239 {
1240 IP4_LINK_RX_TOKEN *Token;
1241 EFI_STATUS Status;
1242
1243 NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);
1244
1245 if (Interface->RecvRequest != NULL) {
1246 return EFI_ALREADY_STARTED;
1247 }
1248
1249 Token = Ip4CreateLinkRxToken (Interface, IpInstance, CallBack, Context);
1250
1251 if (Token == NULL) {
1252 return EFI_OUT_OF_RESOURCES;
1253 }
1254
1255 Interface->RecvRequest = Token;
1256 Status = Interface->Mnp->Receive (Interface->Mnp, &Token->MnpToken);
1257 if (EFI_ERROR (Status)) {
1258 Interface->RecvRequest = NULL;
1259 Ip4FreeFrameRxToken (Token);
1260 return Status;
1261 }
1262 return EFI_SUCCESS;
1263 }
1264