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