]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Ip4Dxe/Ip4If.c
1. Add DPC protocol and DpcLib library in MdeModulePkg.
[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
684 Ip4FreeFrameRxToken (Token);\r
685\r
686 NET_RESTORE_TPL (OldTpl);\r
687 }\r
688}\r
689\r
690\r
691/**\r
692 Free the interface used by IpInstance. All the IP instance with\r
693 the same Ip/Netmask pair share the same interface. It is reference\r
694 counted. All the frames haven't been sent will be cancelled.\r
695 Because the IpInstance is optional, the caller must remove\r
696 IpInstance from the interface's instance list itself.\r
697\r
698 @param Interface The interface used by the IpInstance\r
699 @param IpInstance The Ip instance that free the interface. NULL if\r
700 the Ip driver is releasing the default interface.\r
701\r
702 @retval EFI_SUCCESS The interface use IpInstance is freed.\r
703\r
704**/\r
705EFI_STATUS\r
706Ip4FreeInterface (\r
707 IN IP4_INTERFACE *Interface,\r
708 IN IP4_PROTOCOL *IpInstance OPTIONAL\r
709 )\r
710{\r
711 NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);\r
712 ASSERT (Interface->RefCnt > 0);\r
713\r
714 //\r
715 // Remove all the pending transmit token related to this IP instance.\r
716 //\r
717 Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, IpInstance);\r
718\r
719 if (--Interface->RefCnt > 0) {\r
720 return EFI_SUCCESS;\r
721 }\r
722\r
723 //\r
724 // Destory the interface if this is the last IP instance that\r
725 // has the address. Remove all the system transmitted packets\r
726 // from this interface, cancel the receive request if there is\r
727 // one, and destory the ARP requests.\r
728 //\r
729 Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, NULL);\r
730 Ip4CancelReceive (Interface);\r
731\r
732 ASSERT (NetListIsEmpty (&Interface->IpInstances));\r
733 ASSERT (NetListIsEmpty (&Interface->ArpQues));\r
734 ASSERT (NetListIsEmpty (&Interface->SentFrames));\r
735\r
736 if (Interface->Arp != NULL) {\r
737 gBS->CloseProtocol (\r
738 Interface->ArpHandle,\r
739 &gEfiArpProtocolGuid,\r
740 Interface->Image,\r
741 Interface->Controller\r
742 );\r
743\r
744 NetLibDestroyServiceChild (\r
745 Interface->Controller,\r
746 Interface->Image,\r
747 &gEfiArpServiceBindingProtocolGuid,\r
748 Interface->ArpHandle\r
749 );\r
750 }\r
751\r
752 NetListRemoveEntry (&Interface->Link);\r
753 NetFreePool (Interface);\r
754\r
755 return EFI_SUCCESS;\r
756}\r
757\r
758\r
759/**\r
760 Callback function when ARP request are finished. It will cancelled\r
761 all the queued frame if the ARP requests failed. Or transmit them\r
762 if the request succeed.\r
763\r
772db4bb 764 @param Context The context of the callback, a point to the ARP\r
765 queue\r
766\r
767 @return None\r
768\r
769**/\r
770STATIC\r
771VOID\r
772EFIAPI\r
36ee91ca 773Ip4OnArpResolvedDpc (\r
772db4bb 774 IN VOID *Context\r
775 )\r
776{\r
777 NET_LIST_ENTRY *Entry;\r
778 NET_LIST_ENTRY *Next;\r
779 IP4_ARP_QUE *ArpQue;\r
780 IP4_INTERFACE *Interface;\r
781 IP4_LINK_TX_TOKEN *Token;\r
782 EFI_STATUS Status;\r
783\r
784 ArpQue = (IP4_ARP_QUE *) Context;\r
785 NET_CHECK_SIGNATURE (ArpQue, IP4_FRAME_ARP_SIGNATURE);\r
786\r
787 NetListRemoveEntry (&ArpQue->Link);\r
788\r
789 //\r
790 // ARP resolve failed for some reason. Release all the frame\r
791 // and ARP queue itself. Ip4FreeArpQue will call the frame's\r
792 // owner back.\r
793 //\r
794 if (NET_MAC_EQUAL (&ArpQue->Mac, &mZeroMacAddress, ArpQue->Interface->HwaddrLen)) {\r
795 Ip4FreeArpQue (ArpQue, EFI_NO_MAPPING);\r
796\r
797 return ;\r
798 }\r
799\r
800 //\r
801 // ARP resolve succeeded, Transmit all the frame. Release the ARP\r
802 // queue. It isn't necessary for us to cache the ARP binding because\r
803 // we always check the ARP cache first before transmit.\r
804 //\r
805 Interface = ArpQue->Interface;\r
806\r
807 NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {\r
808 NetListRemoveEntry (Entry);\r
809\r
810 Token = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);\r
687a2e5f 811 CopyMem (&Token->DstMac, &ArpQue->Mac, sizeof (Token->DstMac));\r
772db4bb 812\r
36ee91ca 813 //\r
814 // Insert the tx token before transmitting it via MNP as the FrameSentDpc\r
815 // may be called before Mnp->Transmit returns which will remove this tx\r
816 // token from the SentFrames list. Remove it from the list if the returned\r
817 // Status of Mnp->Transmit is not EFI_SUCCESS as in this case the\r
818 // FrameSentDpc won't be queued.\r
819 //\r
820 NetListInsertTail (&Interface->SentFrames, &Token->Link);\r
772db4bb 821\r
36ee91ca 822 Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);\r
772db4bb 823 if (EFI_ERROR (Status)) {\r
36ee91ca 824 NetListRemoveEntry (Entry);\r
772db4bb 825 Token->CallBack (Token->IpInstance, Token->Packet, Status, 0, Token->Context);\r
826\r
827 Ip4FreeLinkTxToken (Token);\r
828 continue;\r
829 }\r
772db4bb 830 }\r
831\r
832 Ip4FreeArpQue (ArpQue, EFI_SUCCESS);\r
833}\r
834\r
36ee91ca 835STATIC\r
836VOID\r
837EFIAPI\r
838Ip4OnArpResolved (\r
839 IN EFI_EVENT Event,\r
840 IN VOID *Context\r
841 )\r
842/*++\r
843\r
844Routine Description:\r
845\r
846 Request Ip4OnArpResolvedDpc as a DPC at TPL_CALLBACK\r
847\r
848Arguments:\r
849\r
850 Event - The Arp request event\r
851 Context - The context of the callback, a point to the ARP queue\r
852\r
853Returns:\r
854\r
855 None\r
856\r
857--*/\r
858{\r
859 //\r
860 // Request Ip4OnArpResolvedDpc as a DPC at TPL_CALLBACK\r
861 //\r
862 NetLibQueueDpc (TPL_CALLBACK, Ip4OnArpResolvedDpc, Context);\r
863}\r
864\r
865\r
772db4bb 866\r
867/**\r
868 Callback funtion when frame transmission is finished. It will\r
869 call the frame owner's callback function to tell it the result.\r
870\r
772db4bb 871 @param Context Context which is point to the token.\r
872\r
873 @return None.\r
874\r
875**/\r
876STATIC\r
877VOID\r
878EFIAPI\r
36ee91ca 879Ip4OnFrameSentDpc (\r
772db4bb 880 IN VOID *Context\r
881 )\r
882{\r
883 IP4_LINK_TX_TOKEN *Token;\r
884\r
885 Token = (IP4_LINK_TX_TOKEN *) Context;\r
886 NET_CHECK_SIGNATURE (Token, IP4_FRAME_TX_SIGNATURE);\r
887\r
888 NetListRemoveEntry (&Token->Link);\r
889\r
890 Token->CallBack (\r
891 Token->IpInstance,\r
892 Token->Packet,\r
893 Token->MnpToken.Status,\r
894 0,\r
895 Token->Context\r
896 );\r
897\r
898 Ip4FreeLinkTxToken (Token);\r
899}\r
900\r
36ee91ca 901STATIC\r
902VOID\r
903EFIAPI\r
904Ip4OnFrameSent (\r
905 IN EFI_EVENT Event,\r
906 IN VOID *Context\r
907 )\r
908/*++\r
909\r
910Routine Description:\r
911\r
912 Request Ip4OnFrameSentDpc as a DPC at TPL_CALLBACK\r
913\r
914Arguments:\r
915\r
916 Event - The transmit token's event\r
917 Context - Context which is point to the token.\r
918\r
919Returns:\r
920\r
921 None.\r
922\r
923--*/\r
924{\r
925 //\r
926 // Request Ip4OnFrameSentDpc as a DPC at TPL_CALLBACK\r
927 //\r
928 NetLibQueueDpc (TPL_CALLBACK, Ip4OnFrameSentDpc, Context);\r
929}\r
930\r
772db4bb 931\r
932\r
933/**\r
934 Send a frame from the interface. If the next hop is broadcast or\r
935 multicast address, it is transmitted immediately. If the next hop\r
936 is a unicast, it will consult ARP to resolve the NextHop's MAC.\r
937 If some error happened, the CallBack won't be called. So, the caller\r
938 must test the return value, and take action when there is an error.\r
939\r
940 @param Interface The interface to send the frame from\r
941 @param IpInstance The IP child that request the transmission. NULL\r
942 if it is the IP4 driver itself.\r
943 @param Packet The packet to transmit.\r
944 @param NextHop The immediate destination to transmit the packet\r
945 to.\r
946 @param CallBack Function to call back when transmit finished.\r
947 @param Context Opaque parameter to the call back.\r
948\r
949 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to send the frame\r
950 @retval EFI_NO_MAPPING Can't resolve the MAC for the nexthop\r
951 @retval EFI_SUCCESS The packet is successfully transmitted.\r
952\r
953**/\r
954EFI_STATUS\r
955Ip4SendFrame (\r
956 IN IP4_INTERFACE *Interface,\r
957 IN IP4_PROTOCOL *IpInstance, OPTIONAL\r
958 IN NET_BUF *Packet,\r
959 IN IP4_ADDR NextHop,\r
960 IN IP4_FRAME_CALLBACK CallBack,\r
961 IN VOID *Context\r
962 )\r
963{\r
964 IP4_LINK_TX_TOKEN *Token;\r
965 NET_LIST_ENTRY *Entry;\r
966 IP4_ARP_QUE *ArpQue;\r
967 EFI_ARP_PROTOCOL *Arp;\r
968 EFI_STATUS Status;\r
969\r
970 ASSERT (Interface->Configured);\r
971\r
972 Token = Ip4WrapLinkTxToken (Interface, IpInstance, Packet, CallBack, Context);\r
973\r
974 if (Token == NULL) {\r
975 return EFI_OUT_OF_RESOURCES;\r
976 }\r
977\r
978 //\r
979 // Get the destination MAC address for multicast and broadcasts.\r
980 // Don't depend on ARP to solve the address since there maybe no\r
981 // ARP at all. Ip4Output has set NextHop to 255.255.255.255 for\r
982 // all the broadcasts.\r
983 //\r
984 if (NextHop == IP4_ALLONE_ADDRESS) {\r
687a2e5f 985 CopyMem (&Token->DstMac, &Interface->BroadcastMac, sizeof (Token->DstMac));\r
772db4bb 986 goto SEND_NOW;\r
987\r
988 } else if (IP4_IS_MULTICAST (NextHop)) {\r
989\r
990 Status = Ip4GetMulticastMac (Interface->Mnp, NextHop, &Token->DstMac);\r
991\r
992 if (EFI_ERROR (Status)) {\r
993 goto ON_ERROR;\r
994 }\r
995\r
996 goto SEND_NOW;\r
997 }\r
998\r
999 //\r
1000 // Can only send out multicast/broadcast if the IP address is zero\r
1001 //\r
1002 if ((Arp = Interface->Arp) == NULL) {\r
1003 Status = EFI_NO_MAPPING;\r
1004 goto ON_ERROR;\r
1005 }\r
1006\r
1007 //\r
1008 // First check whether this binding is in the ARP cache.\r
1009 //\r
1010 NextHop = HTONL (NextHop);\r
1011 Status = Arp->Request (Arp, &NextHop, NULL, &Token->DstMac);\r
1012\r
1013 if (Status == EFI_SUCCESS) {\r
1014 goto SEND_NOW;\r
1015\r
1016 } else if (Status != EFI_NOT_READY) {\r
1017 goto ON_ERROR;\r
1018 }\r
1019\r
1020 //\r
1021 // Have to do asynchronous ARP resolution. First check\r
1022 // whether there is already a pending request.\r
1023 //\r
1024 ArpQue = NULL;\r
1025\r
1026 NET_LIST_FOR_EACH (Entry, &Interface->ArpQues) {\r
1027 ArpQue = NET_LIST_USER_STRUCT (Entry, IP4_ARP_QUE, Link);\r
1028\r
1029 if (ArpQue->Ip == NextHop) {\r
1030 break;\r
1031 }\r
1032 }\r
1033\r
1034 //\r
1035 // Found a pending ARP request, enqueue the frame then return\r
1036 //\r
1037 if (Entry != &Interface->ArpQues) {\r
1038 NetListInsertTail (&ArpQue->Frames, &Token->Link);\r
1039 return EFI_SUCCESS;\r
1040 }\r
1041\r
1042 //\r
1043 // First frame to NextHop, issue an asynchronous ARP requests\r
1044 //\r
1045 ArpQue = Ip4CreateArpQue (Interface, NextHop);\r
1046\r
1047 if (ArpQue == NULL) {\r
1048 Status = EFI_OUT_OF_RESOURCES;\r
1049 goto ON_ERROR;\r
1050 }\r
1051\r
1052 Status = Arp->Request (Arp, &ArpQue->Ip, ArpQue->OnResolved, ArpQue->Mac.Addr);\r
1053\r
1054 if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {\r
1055 Ip4FreeArpQue (ArpQue, EFI_NO_MAPPING);\r
1056 goto ON_ERROR;\r
1057 }\r
1058\r
1059 NetListInsertHead (&ArpQue->Frames, &Token->Link);\r
1060 NetListInsertHead (&Interface->ArpQues, &ArpQue->Link);\r
1061 return EFI_SUCCESS;\r
1062\r
1063SEND_NOW:\r
36ee91ca 1064 //\r
1065 // Insert the tx token into the SentFrames list before calling Mnp->Transmit.\r
1066 // Remove it if the returned status is not EFI_SUCCESS.\r
1067 //\r
1068 NetListInsertTail (&Interface->SentFrames, &Token->Link);\r
772db4bb 1069 Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);\r
772db4bb 1070 if (EFI_ERROR (Status)) {\r
36ee91ca 1071 NetListRemoveEntry (&Interface->SentFrames);\r
772db4bb 1072 goto ON_ERROR;\r
1073 }\r
1074\r
772db4bb 1075 return EFI_SUCCESS;\r
1076\r
1077ON_ERROR:\r
1078 Ip4FreeLinkTxToken (Token);\r
1079 return Status;\r
1080}\r
1081\r
1082\r
1083/**\r
1084 Call back function when the received packet is freed.\r
1085 Check Ip4OnFrameReceived for information.\r
1086\r
1087 @param Context Context, which is the IP4_LINK_RX_TOKEN.\r
1088\r
1089 @return None.\r
1090\r
1091**/\r
1092STATIC\r
1093VOID\r
1094Ip4RecycleFrame (\r
1095 IN VOID *Context\r
1096 )\r
1097{\r
1098 IP4_LINK_RX_TOKEN *Frame;\r
1099\r
1100 Frame = (IP4_LINK_RX_TOKEN *) Context;\r
1101 NET_CHECK_SIGNATURE (Frame, IP4_FRAME_RX_SIGNATURE);\r
1102\r
1103 gBS->SignalEvent (Frame->MnpToken.Packet.RxData->RecycleEvent);\r
1104 Ip4FreeFrameRxToken (Frame);\r
1105}\r
1106\r
1107\r
1108/**\r
1109 Received a frame from MNP, wrap it in net buffer then deliver\r
1110 it to IP's input function. The ownship of the packet also\r
1111 transferred to IP. When Ip is finished with this packet, it\r
1112 will call NetbufFree to release the packet, NetbufFree will\r
1113 again call the Ip4RecycleFrame to signal MNP's event and free\r
1114 the token used.\r
1115\r
772db4bb 1116 @param Context Context for the callback.\r
1117\r
1118 @return None.\r
1119\r
1120**/\r
1121STATIC\r
1122VOID\r
1123EFIAPI\r
36ee91ca 1124Ip4OnFrameReceivedDpc (\r
772db4bb 1125 IN VOID *Context\r
1126 )\r
1127{\r
1128 EFI_MANAGED_NETWORK_COMPLETION_TOKEN *MnpToken;\r
1129 EFI_MANAGED_NETWORK_RECEIVE_DATA *MnpRxData;\r
1130 IP4_LINK_RX_TOKEN *Token;\r
1131 NET_FRAGMENT Netfrag;\r
1132 NET_BUF *Packet;\r
1133 UINT32 Flag;\r
1134\r
1135 Token = (IP4_LINK_RX_TOKEN *) Context;\r
1136 NET_CHECK_SIGNATURE (Token, IP4_FRAME_RX_SIGNATURE);\r
1137\r
1138 //\r
1139 // First clear the interface's receive request in case the\r
1140 // caller wants to call Ip4ReceiveFrame in the callback.\r
1141 //\r
1142 Token->Interface->RecvRequest = NULL;\r
1143\r
1144 MnpToken = &Token->MnpToken;\r
1145 MnpRxData = MnpToken->Packet.RxData;\r
1146\r
1147 if (EFI_ERROR (MnpToken->Status) || (MnpRxData == NULL)) {\r
1148 Token->CallBack (Token->IpInstance, NULL, MnpToken->Status, 0, Token->Context);\r
1149 Ip4FreeFrameRxToken (Token);\r
1150\r
1151 return ;\r
1152 }\r
1153\r
1154 //\r
1155 // Wrap the frame in a net buffer then deliever it to IP input.\r
1156 // IP will reassemble the packet, and deliver it to upper layer\r
1157 //\r
1158 Netfrag.Len = MnpRxData->DataLength;\r
1159 Netfrag.Bulk = MnpRxData->PacketData;\r
1160\r
1161 Packet = NetbufFromExt (&Netfrag, 1, 0, IP4_MAX_HEADLEN, Ip4RecycleFrame, Token);\r
1162\r
1163 if (Packet == NULL) {\r
1164 gBS->SignalEvent (MnpRxData->RecycleEvent);\r
1165\r
1166 Token->CallBack (Token->IpInstance, NULL, EFI_OUT_OF_RESOURCES, 0, Token->Context);\r
1167 Ip4FreeFrameRxToken (Token);\r
1168\r
1169 return ;\r
1170 }\r
1171\r
1172 Flag = (MnpRxData->BroadcastFlag ? IP4_LINK_BROADCAST : 0);\r
1173 Flag |= (MnpRxData->MulticastFlag ? IP4_LINK_MULTICAST : 0);\r
1174 Flag |= (MnpRxData->PromiscuousFlag ? IP4_LINK_PROMISC : 0);\r
1175\r
1176 Token->CallBack (Token->IpInstance, Packet, EFI_SUCCESS, Flag, Token->Context);\r
1177}\r
1178\r
36ee91ca 1179STATIC\r
1180VOID\r
1181EFIAPI\r
1182Ip4OnFrameReceived (\r
1183 IN EFI_EVENT Event,\r
1184 IN VOID *Context\r
1185 )\r
1186/*++\r
1187\r
1188Routine Description:\r
1189\r
1190 Request Ip4OnFrameReceivedDpc as a DPC at TPL_CALLBACK\r
1191\r
1192Arguments:\r
1193\r
1194 Event - The receive event delivered to MNP for receive.\r
1195 Context - Context for the callback.\r
1196\r
1197Returns:\r
1198\r
1199 None.\r
1200\r
1201--*/\r
1202{\r
1203 //\r
1204 // Request Ip4OnFrameReceivedDpc as a DPC at TPL_CALLBACK\r
1205 //\r
1206 NetLibQueueDpc (TPL_CALLBACK, Ip4OnFrameReceivedDpc, Context);\r
1207}\r
1208\r
772db4bb 1209\r
1210/**\r
1211 Request to receive the packet from the interface.\r
1212\r
1213 @param Interface The interface to receive the frames from\r
1214 @param IpInstance The instance that requests the receive. NULL for\r
1215 the driver itself.\r
1216 @param CallBack Function to call when receive finished.\r
1217 @param Context Opaque parameter to the callback\r
1218\r
1219 @retval EFI_ALREADY_STARTED There is already a pending receive request.\r
1220 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to receive\r
1221 @retval EFI_SUCCESS The recieve request has been started.\r
1222\r
1223**/\r
1224EFI_STATUS\r
1225Ip4ReceiveFrame (\r
1226 IN IP4_INTERFACE *Interface,\r
1227 IN IP4_PROTOCOL *IpInstance, OPTIONAL\r
1228 IN IP4_FRAME_CALLBACK CallBack,\r
1229 IN VOID *Context\r
1230 )\r
1231{\r
1232 IP4_LINK_RX_TOKEN *Token;\r
1233 EFI_STATUS Status;\r
1234\r
1235 NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);\r
1236\r
1237 if (Interface->RecvRequest != NULL) {\r
1238 return EFI_ALREADY_STARTED;\r
1239 }\r
1240\r
1241 Token = Ip4CreateLinkRxToken (Interface, IpInstance, CallBack, Context);\r
1242\r
1243 if (Token == NULL) {\r
1244 return EFI_OUT_OF_RESOURCES;\r
1245 }\r
1246\r
36ee91ca 1247 Interface->RecvRequest = Token;\r
772db4bb 1248 Status = Interface->Mnp->Receive (Interface->Mnp, &Token->MnpToken);\r
772db4bb 1249 if (EFI_ERROR (Status)) {\r
36ee91ca 1250 Interface->RecvRequest = NULL;\r
772db4bb 1251 Ip4FreeFrameRxToken (Token);\r
1252 return Status;\r
1253 }\r
772db4bb 1254 return EFI_SUCCESS;\r
1255}\r