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