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