]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/Ip6Dxe/Ip6If.c
NetworkPkg/Ip6Dxe: Fix various typos
[mirror_edk2.git] / NetworkPkg / Ip6Dxe / Ip6If.c
CommitLineData
a3bcde70 1/** @file\r
7de8045a 2 Implement IP6 pseudo interface.\r
a3bcde70 3\r
f75a7f56 4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
a3bcde70 5\r
ecf98fbc 6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
a3bcde70
HT
7\r
8**/\r
9\r
10#include "Ip6Impl.h"\r
11\r
12/**\r
13 Request Ip6OnFrameSentDpc as a DPC at TPL_CALLBACK.\r
14\r
15 @param[in] Event The transmit token's event.\r
16 @param[in] Context The Context which is pointed to the token.\r
17\r
18**/\r
19VOID\r
20EFIAPI\r
21Ip6OnFrameSent (\r
22 IN EFI_EVENT Event,\r
23 IN VOID *Context\r
24 );\r
25\r
26/**\r
27 Fileter function to cancel all the frame related to an IP instance.\r
28\r
29 @param[in] Frame The transmit request to test whether to cancel.\r
30 @param[in] Context The context which is the Ip instance that issued\r
31 the transmit.\r
32\r
33 @retval TRUE The frame belongs to this instance and is to be\r
34 removed.\r
35 @retval FALSE The frame doesn't belong to this instance.\r
36\r
37**/\r
38BOOLEAN\r
39Ip6CancelInstanceFrame (\r
40 IN IP6_LINK_TX_TOKEN *Frame,\r
41 IN VOID *Context\r
42 )\r
43{\r
44 if (Frame->IpInstance == (IP6_PROTOCOL *) Context) {\r
45 return TRUE;\r
46 }\r
47\r
48 return FALSE;\r
49}\r
50\r
51/**\r
52 Set the interface's address. This will trigger the DAD process for the\r
53 address to set. To set an already set address, the lifetimes wil be\r
54 updated to the new value passed in.\r
55\r
56 @param[in] Interface The interface to set the address.\r
57 @param[in] Ip6Addr The interface's to be assigned IPv6 address.\r
58 @param[in] IsAnycast If TRUE, the unicast IPv6 address is anycast.\r
59 Otherwise, it is not anycast.\r
60 @param[in] PrefixLength The prefix length of the Ip6Addr.\r
61 @param[in] ValidLifetime The valid lifetime for this address.\r
62 @param[in] PreferredLifetime The preferred lifetime for this address.\r
63 @param[in] DadCallback The caller's callback to trigger when DAD finishes.\r
64 This is an optional parameter that may be NULL.\r
65 @param[in] Context The context that will be passed to DadCallback.\r
66 This is an optional parameter that may be NULL.\r
67\r
68 @retval EFI_SUCCESS The interface is scheduled to be configured with\r
69 the specified address.\r
70 @retval EFI_OUT_OF_RESOURCES Failed to set the interface's address due to\r
71 lack of resources.\r
72\r
73**/\r
74EFI_STATUS\r
75Ip6SetAddress (\r
76 IN IP6_INTERFACE *Interface,\r
77 IN EFI_IPv6_ADDRESS *Ip6Addr,\r
78 IN BOOLEAN IsAnycast,\r
79 IN UINT8 PrefixLength,\r
80 IN UINT32 ValidLifetime,\r
81 IN UINT32 PreferredLifetime,\r
82 IN IP6_DAD_CALLBACK DadCallback OPTIONAL,\r
83 IN VOID *Context OPTIONAL\r
84 )\r
85{\r
86 IP6_SERVICE *IpSb;\r
87 IP6_ADDRESS_INFO *AddressInfo;\r
88 LIST_ENTRY *Entry;\r
89 IP6_PREFIX_LIST_ENTRY *PrefixEntry;\r
90 UINT64 Delay;\r
91 IP6_DELAY_JOIN_LIST *DelayNode;\r
92\r
93 NET_CHECK_SIGNATURE (Interface, IP6_INTERFACE_SIGNATURE);\r
94\r
95 IpSb = Interface->Service;\r
96\r
97 if (Ip6IsOneOfSetAddress (IpSb, Ip6Addr, NULL, &AddressInfo)) {\r
98 ASSERT (AddressInfo != NULL);\r
99 //\r
100 // Update the lifetime.\r
101 //\r
102 AddressInfo->ValidLifetime = ValidLifetime;\r
103 AddressInfo->PreferredLifetime = PreferredLifetime;\r
104\r
105 if (DadCallback != NULL) {\r
106 DadCallback (TRUE, Ip6Addr, Context);\r
107 }\r
108\r
109 return EFI_SUCCESS;\r
110 }\r
111\r
112 AddressInfo = (IP6_ADDRESS_INFO *) AllocatePool (sizeof (IP6_ADDRESS_INFO));\r
113 if (AddressInfo == NULL) {\r
114 return EFI_OUT_OF_RESOURCES;\r
115 }\r
116\r
117 AddressInfo->Signature = IP6_ADDR_INFO_SIGNATURE;\r
118 IP6_COPY_ADDRESS (&AddressInfo->Address, Ip6Addr);\r
119 AddressInfo->IsAnycast = IsAnycast;\r
120 AddressInfo->PrefixLength = PrefixLength;\r
121 AddressInfo->ValidLifetime = ValidLifetime;\r
122 AddressInfo->PreferredLifetime = PreferredLifetime;\r
123\r
124 if (AddressInfo->PrefixLength == 0) {\r
125 //\r
126 // Find an appropriate prefix from on-link prefixes and update the prefixlength.\r
127 // Longest prefix match is used here.\r
128 //\r
129 NET_LIST_FOR_EACH (Entry, &IpSb->OnlinkPrefix) {\r
130 PrefixEntry = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);\r
131\r
132 if (NetIp6IsNetEqual (&PrefixEntry->Prefix, &AddressInfo->Address, PrefixEntry->PrefixLength)) {\r
133 AddressInfo->PrefixLength = PrefixEntry->PrefixLength;\r
134 break;\r
135 }\r
136 }\r
137 }\r
138\r
139 if (AddressInfo->PrefixLength == 0) {\r
140 //\r
141 // If the prefix length is still zero, try the autonomous prefixes.\r
142 // Longest prefix match is used here.\r
143 //\r
144 NET_LIST_FOR_EACH (Entry, &IpSb->AutonomousPrefix) {\r
145 PrefixEntry = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);\r
146\r
147 if (NetIp6IsNetEqual (&PrefixEntry->Prefix, &AddressInfo->Address, PrefixEntry->PrefixLength)) {\r
148 AddressInfo->PrefixLength = PrefixEntry->PrefixLength;\r
149 break;\r
150 }\r
151 }\r
152 }\r
153\r
154 if (AddressInfo->PrefixLength == 0) {\r
155 //\r
156 // BUGBUG: Stil fail, use 64 as the default prefix length.\r
157 //\r
158 AddressInfo->PrefixLength = IP6_LINK_LOCAL_PREFIX_LENGTH;\r
159 }\r
160\r
161\r
162 //\r
7de8045a 163 // Node should delay joining the solicited-node multicast address by a random delay\r
a3bcde70
HT
164 // between 0 and MAX_RTR_SOLICITATION_DELAY (1 second).\r
165 // Thus queue the address to be processed in Duplicate Address Detection module\r
166 // after the delay time (in milliseconds).\r
167 //\r
168 Delay = (UINT64) NET_RANDOM (NetRandomInitSeed ());\r
169 Delay = MultU64x32 (Delay, IP6_ONE_SECOND_IN_MS);\r
170 Delay = RShiftU64 (Delay, 32);\r
171\r
172 DelayNode = (IP6_DELAY_JOIN_LIST *) AllocatePool (sizeof (IP6_DELAY_JOIN_LIST));\r
173 if (DelayNode == NULL) {\r
174 FreePool (AddressInfo);\r
175 return EFI_OUT_OF_RESOURCES;\r
176 }\r
177\r
178 DelayNode->DelayTime = (UINT32) (DivU64x32 (Delay, IP6_TIMER_INTERVAL_IN_MS));\r
179 DelayNode->Interface = Interface;\r
180 DelayNode->AddressInfo = AddressInfo;\r
181 DelayNode->DadCallback = DadCallback;\r
182 DelayNode->Context = Context;\r
183\r
184 InsertTailList (&Interface->DelayJoinList, &DelayNode->Link);\r
185 return EFI_SUCCESS;\r
186}\r
187\r
188/**\r
189 Create an IP6_INTERFACE.\r
190\r
191 @param[in] IpSb The IP6 service binding instance.\r
192 @param[in] LinkLocal If TRUE, the instance is created for link-local address.\r
193 Otherwise, it is not for a link-local address.\r
194\r
195 @return Point to the created IP6_INTERFACE, otherwise NULL.\r
196\r
197**/\r
198IP6_INTERFACE *\r
199Ip6CreateInterface (\r
200 IN IP6_SERVICE *IpSb,\r
201 IN BOOLEAN LinkLocal\r
202 )\r
203{\r
204 EFI_STATUS Status;\r
205 IP6_INTERFACE *Interface;\r
206 EFI_IPv6_ADDRESS *Ip6Addr;\r
207\r
208 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);\r
209\r
210 Interface = AllocatePool (sizeof (IP6_INTERFACE));\r
211 if (Interface == NULL) {\r
212 return NULL;\r
213 }\r
214\r
215 Interface->Signature = IP6_INTERFACE_SIGNATURE;\r
216 Interface->RefCnt = 1;\r
217\r
218 InitializeListHead (&Interface->AddressList);\r
219 Interface->AddressCount = 0;\r
220 Interface->Configured = FALSE;\r
221\r
222 Interface->Service = IpSb;\r
223 Interface->Controller = IpSb->Controller;\r
224 Interface->Image = IpSb->Image;\r
225\r
226 InitializeListHead (&Interface->ArpQues);\r
227 InitializeListHead (&Interface->SentFrames);\r
228\r
229 Interface->DupAddrDetect = IpSb->Ip6ConfigInstance.DadXmits.DupAddrDetectTransmits;\r
230 InitializeListHead (&Interface->DupAddrDetectList);\r
231\r
232 InitializeListHead (&Interface->DelayJoinList);\r
233\r
234 InitializeListHead (&Interface->IpInstances);\r
235 Interface->PromiscRecv = FALSE;\r
236\r
237 if (!LinkLocal) {\r
238 return Interface;\r
239 }\r
240\r
241 //\r
242 // Get the link local addr\r
243 //\r
244 Ip6Addr = Ip6CreateLinkLocalAddr (IpSb);\r
245 if (Ip6Addr == NULL) {\r
246 goto ON_ERROR;\r
247 }\r
248\r
249 //\r
250 // Perform DAD - Duplicate Address Detection.\r
251 //\r
252 Status = Ip6SetAddress (\r
253 Interface,\r
254 Ip6Addr,\r
255 FALSE,\r
256 IP6_LINK_LOCAL_PREFIX_LENGTH,\r
257 (UINT32) IP6_INFINIT_LIFETIME,\r
258 (UINT32) IP6_INFINIT_LIFETIME,\r
259 NULL,\r
260 NULL\r
261 );\r
262\r
263 FreePool (Ip6Addr);\r
264\r
265 if (EFI_ERROR (Status)) {\r
266 goto ON_ERROR;\r
267 }\r
268\r
269 return Interface;\r
270\r
271ON_ERROR:\r
272\r
273 FreePool (Interface);\r
274 return NULL;\r
275}\r
276\r
277/**\r
278 Free the interface used by IpInstance. All the IP instance with\r
279 the same Ip/prefix pair share the same interface. It is reference\r
280 counted. All the frames that haven't been sent will be cancelled.\r
281 Because the IpInstance is optional, the caller must remove\r
282 IpInstance from the interface's instance list.\r
283\r
284 @param[in] Interface The interface used by the IpInstance.\r
285 @param[in] IpInstance The IP instance that free the interface. NULL if\r
286 the IP driver is releasing the default interface.\r
287\r
288**/\r
289VOID\r
290Ip6CleanInterface (\r
291 IN IP6_INTERFACE *Interface,\r
292 IN IP6_PROTOCOL *IpInstance OPTIONAL\r
293 )\r
294{\r
295 IP6_DAD_ENTRY *Duplicate;\r
296 IP6_DELAY_JOIN_LIST *Delay;\r
297\r
298 NET_CHECK_SIGNATURE (Interface, IP6_INTERFACE_SIGNATURE);\r
299 ASSERT (Interface->RefCnt > 0);\r
300\r
301 //\r
302 // Remove all the pending transmit token related to this IP instance.\r
303 //\r
304 Ip6CancelFrames (Interface, EFI_ABORTED, Ip6CancelInstanceFrame, IpInstance);\r
305\r
306 if (--Interface->RefCnt > 0) {\r
307 return;\r
308 }\r
309\r
310 //\r
75dce340 311 // Destroy the interface if this is the last IP instance.\r
a3bcde70
HT
312 // Remove all the system transmitted packets\r
313 // from this interface, cancel the receive request if exists.\r
314 //\r
315 Ip6CancelFrames (Interface, EFI_ABORTED, Ip6CancelInstanceFrame, NULL);\r
316\r
317 ASSERT (IsListEmpty (&Interface->IpInstances));\r
318 ASSERT (IsListEmpty (&Interface->ArpQues));\r
319 ASSERT (IsListEmpty (&Interface->SentFrames));\r
320\r
321 while (!IsListEmpty (&Interface->DupAddrDetectList)) {\r
322 Duplicate = NET_LIST_HEAD (&Interface->DupAddrDetectList, IP6_DAD_ENTRY, Link);\r
323 NetListRemoveHead (&Interface->DupAddrDetectList);\r
324 FreePool (Duplicate);\r
325 }\r
326\r
327 while (!IsListEmpty (&Interface->DelayJoinList)) {\r
328 Delay = NET_LIST_HEAD (&Interface->DelayJoinList, IP6_DELAY_JOIN_LIST, Link);\r
329 NetListRemoveHead (&Interface->DelayJoinList);\r
330 FreePool (Delay);\r
331 }\r
332\r
333 Ip6RemoveAddr (Interface->Service, &Interface->AddressList, &Interface->AddressCount, NULL, 0);\r
334\r
335 RemoveEntryList (&Interface->Link);\r
336 FreePool (Interface);\r
337}\r
338\r
339/**\r
340 Create and wrap a transmit request into a newly allocated IP6_LINK_TX_TOKEN.\r
341\r
342 @param[in] Interface The interface to send out from.\r
343 @param[in] IpInstance The IpInstance that transmit the packet. NULL if\r
344 the packet is sent by the IP6 driver itself.\r
345 @param[in] Packet The packet to transmit\r
346 @param[in] CallBack Call back function to execute if transmission\r
347 finished.\r
348 @param[in] Context Opaque parameter to the callback.\r
349\r
350 @return The wrapped token if succeed or NULL.\r
351\r
352**/\r
353IP6_LINK_TX_TOKEN *\r
354Ip6CreateLinkTxToken (\r
355 IN IP6_INTERFACE *Interface,\r
356 IN IP6_PROTOCOL *IpInstance OPTIONAL,\r
357 IN NET_BUF *Packet,\r
358 IN IP6_FRAME_CALLBACK CallBack,\r
359 IN VOID *Context\r
360 )\r
361{\r
362 EFI_MANAGED_NETWORK_COMPLETION_TOKEN *MnpToken;\r
363 EFI_MANAGED_NETWORK_TRANSMIT_DATA *MnpTxData;\r
364 IP6_LINK_TX_TOKEN *Token;\r
365 EFI_STATUS Status;\r
366 UINT32 Count;\r
367\r
368 Token = AllocatePool (sizeof (IP6_LINK_TX_TOKEN) + (Packet->BlockOpNum - 1) * sizeof (EFI_MANAGED_NETWORK_FRAGMENT_DATA));\r
369\r
370 if (Token == NULL) {\r
371 return NULL;\r
372 }\r
373\r
374 Token->Signature = IP6_LINK_TX_SIGNATURE;\r
375 InitializeListHead (&Token->Link);\r
376\r
377 Token->IpInstance = IpInstance;\r
378 Token->CallBack = CallBack;\r
379 Token->Packet = Packet;\r
380 Token->Context = Context;\r
381 ZeroMem (&Token->DstMac, sizeof (EFI_MAC_ADDRESS));\r
382 IP6_COPY_LINK_ADDRESS (&Token->SrcMac, &Interface->Service->SnpMode.CurrentAddress);\r
383\r
384 MnpToken = &(Token->MnpToken);\r
385 MnpToken->Status = EFI_NOT_READY;\r
386\r
387 Status = gBS->CreateEvent (\r
388 EVT_NOTIFY_SIGNAL,\r
389 TPL_NOTIFY,\r
390 Ip6OnFrameSent,\r
391 Token,\r
392 &MnpToken->Event\r
393 );\r
394\r
395 if (EFI_ERROR (Status)) {\r
396 FreePool (Token);\r
397 return NULL;\r
398 }\r
399\r
400 MnpTxData = &Token->MnpTxData;\r
401 MnpToken->Packet.TxData = MnpTxData;\r
402\r
403 MnpTxData->DestinationAddress = &Token->DstMac;\r
404 MnpTxData->SourceAddress = &Token->SrcMac;\r
405 MnpTxData->ProtocolType = IP6_ETHER_PROTO;\r
406 MnpTxData->DataLength = Packet->TotalSize;\r
407 MnpTxData->HeaderLength = 0;\r
408\r
409 Count = Packet->BlockOpNum;\r
410\r
411 NetbufBuildExt (Packet, (NET_FRAGMENT *) MnpTxData->FragmentTable, &Count);\r
412 MnpTxData->FragmentCount = (UINT16)Count;\r
413\r
414 return Token;\r
415}\r
416\r
417/**\r
418 Free the link layer transmit token. It will close the event,\r
419 then free the memory used.\r
420\r
421 @param[in] Token Token to free.\r
422\r
423**/\r
424VOID\r
425Ip6FreeLinkTxToken (\r
426 IN IP6_LINK_TX_TOKEN *Token\r
427 )\r
428{\r
429 NET_CHECK_SIGNATURE (Token, IP6_LINK_TX_SIGNATURE);\r
430\r
431 gBS->CloseEvent (Token->MnpToken.Event);\r
432 FreePool (Token);\r
433}\r
434\r
435/**\r
436 Callback function when the received packet is freed.\r
437 Check Ip6OnFrameReceived for information.\r
438\r
439 @param[in] Context Points to EFI_MANAGED_NETWORK_RECEIVE_DATA.\r
440\r
441**/\r
442VOID\r
443EFIAPI\r
444Ip6RecycleFrame (\r
445 IN VOID *Context\r
446 )\r
447{\r
448 EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData;\r
449\r
450 RxData = (EFI_MANAGED_NETWORK_RECEIVE_DATA *) Context;\r
451\r
452 gBS->SignalEvent (RxData->RecycleEvent);\r
453}\r
454\r
455/**\r
456 Received a frame from MNP. Wrap it in net buffer then deliver\r
457 it to IP's input function. The ownship of the packet also\r
458 is transferred to IP. When Ip is finished with this packet, it\r
459 will call NetbufFree to release the packet, NetbufFree will\r
460 again call the Ip6RecycleFrame to signal MNP's event and free\r
461 the token used.\r
462\r
463 @param[in] Context Context for the callback.\r
464\r
465**/\r
466VOID\r
467EFIAPI\r
468Ip6OnFrameReceivedDpc (\r
469 IN VOID *Context\r
470 )\r
471{\r
472 EFI_MANAGED_NETWORK_COMPLETION_TOKEN *MnpToken;\r
473 EFI_MANAGED_NETWORK_RECEIVE_DATA *MnpRxData;\r
474 IP6_LINK_RX_TOKEN *Token;\r
475 NET_FRAGMENT Netfrag;\r
476 NET_BUF *Packet;\r
477 UINT32 Flag;\r
478 IP6_SERVICE *IpSb;\r
479\r
480 Token = (IP6_LINK_RX_TOKEN *) Context;\r
481 NET_CHECK_SIGNATURE (Token, IP6_LINK_RX_SIGNATURE);\r
482\r
483 //\r
484 // First clear the interface's receive request in case the\r
485 // caller wants to call Ip6ReceiveFrame in the callback.\r
486 //\r
487 IpSb = (IP6_SERVICE *) Token->Context;\r
488 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);\r
489\r
490\r
491 MnpToken = &Token->MnpToken;\r
492 MnpRxData = MnpToken->Packet.RxData;\r
493\r
494 if (EFI_ERROR (MnpToken->Status) || (MnpRxData == NULL)) {\r
495 Token->CallBack (NULL, MnpToken->Status, 0, Token->Context);\r
496 return ;\r
497 }\r
498\r
499 //\r
7de8045a 500 // Wrap the frame in a net buffer then deliver it to IP input.\r
a3bcde70
HT
501 // IP will reassemble the packet, and deliver it to upper layer\r
502 //\r
503 Netfrag.Len = MnpRxData->DataLength;\r
504 Netfrag.Bulk = MnpRxData->PacketData;\r
505\r
506 Packet = NetbufFromExt (&Netfrag, 1, IP6_MAX_HEADLEN, 0, Ip6RecycleFrame, Token->MnpToken.Packet.RxData);\r
507\r
508 if (Packet == NULL) {\r
509 gBS->SignalEvent (MnpRxData->RecycleEvent);\r
510\r
511 Token->CallBack (NULL, EFI_OUT_OF_RESOURCES, 0, Token->Context);\r
512\r
513 return ;\r
514 }\r
515\r
516 Flag = (MnpRxData->BroadcastFlag ? IP6_LINK_BROADCAST : 0);\r
517 Flag |= (MnpRxData->MulticastFlag ? IP6_LINK_MULTICAST : 0);\r
518 Flag |= (MnpRxData->PromiscuousFlag ? IP6_LINK_PROMISC : 0);\r
519\r
520 Token->CallBack (Packet, EFI_SUCCESS, Flag, Token->Context);\r
521}\r
522\r
523/**\r
524 Request Ip6OnFrameReceivedDpc as a DPC at TPL_CALLBACK.\r
525\r
526 @param Event The receive event delivered to MNP for receive.\r
527 @param Context Context for the callback.\r
528\r
529**/\r
530VOID\r
531EFIAPI\r
532Ip6OnFrameReceived (\r
533 IN EFI_EVENT Event,\r
534 IN VOID *Context\r
535 )\r
536{\r
537 //\r
538 // Request Ip6OnFrameReceivedDpc as a DPC at TPL_CALLBACK\r
539 //\r
540 QueueDpc (TPL_CALLBACK, Ip6OnFrameReceivedDpc, Context);\r
541}\r
542\r
543/**\r
544 Request to receive the packet from the interface.\r
545\r
546 @param[in] CallBack Function to call when receive finished.\r
547 @param[in] IpSb Points to IP6 service binding instance.\r
548\r
549 @retval EFI_ALREADY_STARTED There is already a pending receive request.\r
550 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to receive.\r
7de8045a 551 @retval EFI_SUCCESS The receive request has been started.\r
a3bcde70
HT
552\r
553**/\r
554EFI_STATUS\r
555Ip6ReceiveFrame (\r
556 IN IP6_FRAME_CALLBACK CallBack,\r
557 IN IP6_SERVICE *IpSb\r
558 )\r
559{\r
560 EFI_STATUS Status;\r
561 IP6_LINK_RX_TOKEN *Token;\r
f75a7f56 562\r
a3bcde70
HT
563 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);\r
564\r
565 Token = &IpSb->RecvRequest;\r
566 Token->CallBack = CallBack;\r
567 Token->Context = (VOID *) IpSb;\r
568\r
569 Status = IpSb->Mnp->Receive (IpSb->Mnp, &Token->MnpToken);\r
570 if (EFI_ERROR (Status)) {\r
571 return Status;\r
572 }\r
573\r
574 return EFI_SUCCESS;\r
575}\r
576\r
577/**\r
7de8045a 578 Callback function when frame transmission is finished. It will\r
a3bcde70
HT
579 call the frame owner's callback function to tell it the result.\r
580\r
581 @param[in] Context Context which points to the token.\r
582\r
583**/\r
584VOID\r
585EFIAPI\r
586Ip6OnFrameSentDpc (\r
587 IN VOID *Context\r
588 )\r
589{\r
590 IP6_LINK_TX_TOKEN *Token;\r
591\r
592 Token = (IP6_LINK_TX_TOKEN *) Context;\r
593 NET_CHECK_SIGNATURE (Token, IP6_LINK_TX_SIGNATURE);\r
594\r
595 RemoveEntryList (&Token->Link);\r
596\r
597 Token->CallBack (\r
598 Token->Packet,\r
599 Token->MnpToken.Status,\r
600 0,\r
601 Token->Context\r
602 );\r
603\r
604 Ip6FreeLinkTxToken (Token);\r
605}\r
606\r
607/**\r
608 Request Ip6OnFrameSentDpc as a DPC at TPL_CALLBACK.\r
609\r
610 @param[in] Event The transmit token's event.\r
611 @param[in] Context Context which points to the token.\r
612\r
613**/\r
614VOID\r
615EFIAPI\r
616Ip6OnFrameSent (\r
617 IN EFI_EVENT Event,\r
618 IN VOID *Context\r
619 )\r
620{\r
621 //\r
622 // Request Ip6OnFrameSentDpc as a DPC at TPL_CALLBACK\r
623 //\r
624 QueueDpc (TPL_CALLBACK, Ip6OnFrameSentDpc, Context);\r
625}\r
626\r
627/**\r
628 Send a frame from the interface. If the next hop is a multicast address,\r
629 it is transmitted immediately. If the next hop is a unicast,\r
630 and the NextHop's MAC is not known, it will perform address resolution.\r
631 If an error occurred, the CallBack won't be called. So, the caller\r
632 must test the return value, and take action when there is an error.\r
633\r
634 @param[in] Interface The interface to send the frame from\r
635 @param[in] IpInstance The IP child that request the transmission.\r
636 NULL if it is the IP6 driver itself.\r
637 @param[in] Packet The packet to transmit.\r
638 @param[in] NextHop The immediate destination to transmit the packet to.\r
639 @param[in] CallBack Function to call back when transmit finished.\r
640 @param[in] Context Opaque parameter to the callback.\r
641\r
642 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to send the frame.\r
643 @retval EFI_NO_MAPPING Can't resolve the MAC for the nexthop.\r
644 @retval EFI_SUCCESS The packet successfully transmitted.\r
645\r
646**/\r
647EFI_STATUS\r
648Ip6SendFrame (\r
649 IN IP6_INTERFACE *Interface,\r
650 IN IP6_PROTOCOL *IpInstance OPTIONAL,\r
651 IN NET_BUF *Packet,\r
652 IN EFI_IPv6_ADDRESS *NextHop,\r
653 IN IP6_FRAME_CALLBACK CallBack,\r
654 IN VOID *Context\r
655 )\r
656{\r
657 IP6_SERVICE *IpSb;\r
658 IP6_LINK_TX_TOKEN *Token;\r
659 EFI_STATUS Status;\r
660 IP6_NEIGHBOR_ENTRY *NeighborCache;\r
661 LIST_ENTRY *Entry;\r
662 IP6_NEIGHBOR_ENTRY *ArpQue;\r
663\r
664 IpSb = Interface->Service;\r
665 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);\r
666\r
667 //\r
668 // Only when link local address is performing DAD, the interface could be used in unconfigured.\r
669 //\r
670 if (IpSb->LinkLocalOk) {\r
671 ASSERT (Interface->Configured);\r
672 }\r
673\r
674 Token = Ip6CreateLinkTxToken (Interface, IpInstance, Packet, CallBack, Context);\r
675\r
676 if (Token == NULL) {\r
677 return EFI_OUT_OF_RESOURCES;\r
678 }\r
679\r
680 if (IP6_IS_MULTICAST (NextHop)) {\r
681 Status = Ip6GetMulticastMac (IpSb->Mnp, NextHop, &Token->DstMac);\r
682 if (EFI_ERROR (Status)) {\r
683 goto Error;\r
684 }\r
685\r
686 goto SendNow;\r
687 }\r
688\r
689 //\r
690 // If send to itself, directly send out\r
691 //\r
692 if (EFI_IP6_EQUAL (&Packet->Ip.Ip6->DestinationAddress, &Packet->Ip.Ip6->SourceAddress)) {\r
693 IP6_COPY_LINK_ADDRESS (&Token->DstMac, &IpSb->SnpMode.CurrentAddress);\r
694 goto SendNow;\r
695 }\r
696\r
697 //\r
698 // If unicast, check the neighbor state.\r
699 //\r
700\r
701 NeighborCache = Ip6FindNeighborEntry (IpSb, NextHop);\r
702 ASSERT (NeighborCache != NULL);\r
703\r
704 if (NeighborCache->Interface == NULL) {\r
705 NeighborCache->Interface = Interface;\r
706 }\r
707\r
708 switch (NeighborCache->State) {\r
709 case EfiNeighborStale:\r
710 NeighborCache->State = EfiNeighborDelay;\r
711 NeighborCache->Ticks = (UINT32) IP6_GET_TICKS (IP6_DELAY_FIRST_PROBE_TIME);\r
712 //\r
713 // Fall through\r
714 //\r
715 case EfiNeighborReachable:\r
716 case EfiNeighborDelay:\r
717 case EfiNeighborProbe:\r
718 IP6_COPY_LINK_ADDRESS (&Token->DstMac, &NeighborCache->LinkAddress);\r
719 goto SendNow;\r
720 break;\r
721\r
722 default:\r
723 break;\r
724 }\r
725\r
726 //\r
727 // Have to do asynchronous ARP resolution. First check whether there is\r
728 // already a pending request.\r
729 //\r
730 NET_LIST_FOR_EACH (Entry, &Interface->ArpQues) {\r
731 ArpQue = NET_LIST_USER_STRUCT (Entry, IP6_NEIGHBOR_ENTRY, ArpList);\r
732 if (ArpQue == NeighborCache) {\r
733 InsertTailList (&NeighborCache->Frames, &Token->Link);\r
734 NeighborCache->ArpFree = TRUE;\r
735 return EFI_SUCCESS;\r
736 }\r
737 }\r
738\r
739 //\r
740 // First frame requires ARP.\r
741 //\r
742 InsertTailList (&NeighborCache->Frames, &Token->Link);\r
743 InsertTailList (&Interface->ArpQues, &NeighborCache->ArpList);\r
744\r
745 NeighborCache->ArpFree = TRUE;\r
746\r
747 return EFI_SUCCESS;\r
748\r
749SendNow:\r
750 //\r
751 // Insert the tx token into the SentFrames list before calling Mnp->Transmit.\r
752 // Remove it if the returned status is not EFI_SUCCESS.\r
753 //\r
754 InsertTailList (&Interface->SentFrames, &Token->Link);\r
755 Status = IpSb->Mnp->Transmit (IpSb->Mnp, &Token->MnpToken);\r
756 if (EFI_ERROR (Status)) {\r
757 RemoveEntryList (&Token->Link);\r
758 goto Error;\r
759 }\r
760\r
761 return EFI_SUCCESS;\r
762\r
763Error:\r
764 Ip6FreeLinkTxToken (Token);\r
765 return Status;\r
766}\r
767\r
768/**\r
769 The heartbeat timer of IP6 service instance. It times out\r
770 all of its IP6 children's received-but-not-delivered and\r
771 transmitted-but-not-recycle packets.\r
772\r
773 @param[in] Event The IP6 service instance's heartbeat timer.\r
774 @param[in] Context The IP6 service instance.\r
775\r
776**/\r
777VOID\r
778EFIAPI\r
779Ip6TimerTicking (\r
780 IN EFI_EVENT Event,\r
781 IN VOID *Context\r
782 )\r
783{\r
784 IP6_SERVICE *IpSb;\r
785\r
786 IpSb = (IP6_SERVICE *) Context;\r
787 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);\r
788\r
789 Ip6PacketTimerTicking (IpSb);\r
790 Ip6NdTimerTicking (IpSb);\r
791 Ip6MldTimerTicking (IpSb);\r
792}\r