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