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