]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/Dhcp6Dxe/Dhcp6Io.c
MdeModulePkg/DxeCore: invoke the emulator protocol for foreign images
[mirror_edk2.git] / NetworkPkg / Dhcp6Dxe / Dhcp6Io.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 Dhcp6 internal functions implementation.\r
3\r
8f586b85 4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
f75a7f56 5 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
a3bcde70 6\r
ecf98fbc 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
a3bcde70
HT
8\r
9**/\r
10\r
11#include "Dhcp6Impl.h"\r
12\r
13\r
14/**\r
15 Enqueue the packet into the retry list in case of timeout.\r
16\r
17 @param[in] Instance The pointer to the Dhcp6 instance.\r
18 @param[in] Packet The pointer to the Dhcp6 packet to retry.\r
19 @param[in] Elapsed The pointer to the elapsed time value in the packet.\r
20 @param[in] RetryCtl The pointer to the transmission control of the packet.\r
21 This parameter is optional and may be NULL.\r
22\r
23 @retval EFI_SUCCESS Successfully enqueued the packet into the retry list according\r
24 to its message type.\r
25 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
26 @retval EFI_DEVICE_ERROR An unexpected message type.\r
27\r
28**/\r
29EFI_STATUS\r
30Dhcp6EnqueueRetry (\r
31 IN DHCP6_INSTANCE *Instance,\r
32 IN EFI_DHCP6_PACKET *Packet,\r
33 IN UINT16 *Elapsed,\r
34 IN EFI_DHCP6_RETRANSMISSION *RetryCtl OPTIONAL\r
35 )\r
36{\r
37 DHCP6_TX_CB *TxCb;\r
38 DHCP6_IA_CB *IaCb;\r
39\r
40 ASSERT (Packet != NULL);\r
41\r
42 IaCb = &Instance->IaCb;\r
43 TxCb = AllocateZeroPool (sizeof (DHCP6_TX_CB));\r
44\r
45 if (TxCb == NULL) {\r
46 return EFI_OUT_OF_RESOURCES;\r
47 }\r
48\r
49 //\r
75dce340 50 // Save tx packet pointer, and it will be destroyed when reply received.\r
a3bcde70
HT
51 //\r
52 TxCb->TxPacket = Packet;\r
53 TxCb->Xid = Packet->Dhcp6.Header.TransactionId;\r
54\r
55 //\r
56 // Save pointer to elapsed-time value so we can update it on retransmits.\r
57 //\r
58 TxCb->Elapsed = Elapsed;\r
59\r
60 //\r
61 // Calculate the retransmission according to the the message type.\r
62 //\r
63 switch (Packet->Dhcp6.Header.MessageType) {\r
64 case Dhcp6MsgSolicit:\r
65 //\r
66 // Calculate the retransmission threshold value for solicit packet.\r
67 // Use the default value by rfc-3315 if user doesn't configure.\r
68 //\r
69 if (RetryCtl == NULL) {\r
70 TxCb->RetryCtl.Irt = DHCP6_SOL_IRT;\r
71 TxCb->RetryCtl.Mrc = DHCP6_SOL_MRC;\r
72 TxCb->RetryCtl.Mrt = DHCP6_SOL_MRT;\r
73 TxCb->RetryCtl.Mrd = DHCP6_SOL_MRD;\r
74 } else {\r
75 TxCb->RetryCtl.Irt = (RetryCtl->Irt != 0) ? RetryCtl->Irt : DHCP6_SOL_IRT;\r
76 TxCb->RetryCtl.Mrc = (RetryCtl->Mrc != 0) ? RetryCtl->Mrc : DHCP6_SOL_MRC;\r
77 TxCb->RetryCtl.Mrt = (RetryCtl->Mrt != 0) ? RetryCtl->Mrt : DHCP6_SOL_MRT;\r
78 TxCb->RetryCtl.Mrd = (RetryCtl->Mrd != 0) ? RetryCtl->Mrd : DHCP6_SOL_MRD;\r
79 }\r
80\r
81 TxCb->RetryExp = Dhcp6CalculateExpireTime (\r
82 TxCb->RetryCtl.Irt,\r
83 TRUE,\r
84 FALSE\r
85 );\r
86 break;\r
87\r
88 case Dhcp6MsgRequest:\r
89 //\r
90 // Calculate the retransmission threshold value for request packet.\r
91 //\r
92 TxCb->RetryCtl.Irt = DHCP6_REQ_IRT;\r
93 TxCb->RetryCtl.Mrc = DHCP6_REQ_MRC;\r
94 TxCb->RetryCtl.Mrt = DHCP6_REQ_MRT;\r
95 TxCb->RetryCtl.Mrd = DHCP6_REQ_MRD;\r
96 TxCb->RetryExp = Dhcp6CalculateExpireTime (\r
97 TxCb->RetryCtl.Irt,\r
98 TRUE,\r
99 TRUE\r
100 );\r
101 break;\r
102\r
103 case Dhcp6MsgConfirm:\r
104 //\r
105 // Calculate the retransmission threshold value for confirm packet.\r
106 //\r
107 TxCb->RetryCtl.Irt = DHCP6_CNF_IRT;\r
108 TxCb->RetryCtl.Mrc = DHCP6_CNF_MRC;\r
109 TxCb->RetryCtl.Mrt = DHCP6_CNF_MRT;\r
110 TxCb->RetryCtl.Mrd = DHCP6_CNF_MRD;\r
111 TxCb->RetryExp = Dhcp6CalculateExpireTime (\r
112 TxCb->RetryCtl.Irt,\r
113 TRUE,\r
114 TRUE\r
115 );\r
116 break;\r
117\r
118 case Dhcp6MsgRenew:\r
119 //\r
120 // Calculate the retransmission threshold value for renew packet.\r
121 //\r
122 TxCb->RetryCtl.Irt = DHCP6_REB_IRT;\r
123 TxCb->RetryCtl.Mrc = DHCP6_REB_MRC;\r
124 TxCb->RetryCtl.Mrt = DHCP6_REB_MRT;\r
125 TxCb->RetryCtl.Mrd = IaCb->T2 - IaCb->T1;\r
126 TxCb->RetryExp = Dhcp6CalculateExpireTime (\r
127 TxCb->RetryCtl.Irt,\r
128 TRUE,\r
129 TRUE\r
130 );\r
131 break;\r
132\r
133 case Dhcp6MsgRebind:\r
134 //\r
135 // Calculate the retransmission threshold value for rebind packet.\r
136 //\r
137 TxCb->RetryCtl.Irt = DHCP6_REN_IRT;\r
138 TxCb->RetryCtl.Mrc = DHCP6_REN_MRC;\r
139 TxCb->RetryCtl.Mrt = DHCP6_REN_MRT;\r
140 TxCb->RetryCtl.Mrd = IaCb->AllExpireTime - IaCb->T2;\r
141 TxCb->RetryExp = Dhcp6CalculateExpireTime (\r
142 TxCb->RetryCtl.Irt,\r
143 TRUE,\r
144 TRUE\r
145 );\r
146 break;\r
147\r
148 case Dhcp6MsgDecline:\r
149 //\r
150 // Calculate the retransmission threshold value for decline packet.\r
151 //\r
152 TxCb->RetryCtl.Irt = DHCP6_DEC_IRT;\r
153 TxCb->RetryCtl.Mrc = DHCP6_DEC_MRC;\r
154 TxCb->RetryCtl.Mrt = DHCP6_DEC_MRT;\r
155 TxCb->RetryCtl.Mrd = DHCP6_DEC_MRD;\r
156 TxCb->RetryExp = Dhcp6CalculateExpireTime (\r
157 TxCb->RetryCtl.Irt,\r
158 TRUE,\r
159 TRUE\r
160 );\r
161 break;\r
162\r
163 case Dhcp6MsgRelease:\r
164 //\r
165 // Calculate the retransmission threshold value for release packet.\r
166 //\r
167 TxCb->RetryCtl.Irt = DHCP6_REL_IRT;\r
168 TxCb->RetryCtl.Mrc = DHCP6_REL_MRC;\r
169 TxCb->RetryCtl.Mrt = DHCP6_REL_MRT;\r
170 TxCb->RetryCtl.Mrd = DHCP6_REL_MRD;\r
171 TxCb->RetryExp = Dhcp6CalculateExpireTime (\r
172 TxCb->RetryCtl.Irt,\r
173 TRUE,\r
174 TRUE\r
175 );\r
176 break;\r
177\r
178 case Dhcp6MsgInfoRequest:\r
179 //\r
180 // Calculate the retransmission threshold value for info-request packet.\r
181 // Use the default value by rfc-3315 if user doesn't configure.\r
182 //\r
183 if (RetryCtl == NULL) {\r
184 TxCb->RetryCtl.Irt = DHCP6_INF_IRT;\r
185 TxCb->RetryCtl.Mrc = DHCP6_INF_MRC;\r
186 TxCb->RetryCtl.Mrt = DHCP6_INF_MRT;\r
187 TxCb->RetryCtl.Mrd = DHCP6_INF_MRD;\r
188 } else {\r
189 TxCb->RetryCtl.Irt = (RetryCtl->Irt != 0) ? RetryCtl->Irt : DHCP6_INF_IRT;\r
190 TxCb->RetryCtl.Mrc = (RetryCtl->Mrc != 0) ? RetryCtl->Mrc : DHCP6_INF_MRC;\r
191 TxCb->RetryCtl.Mrt = (RetryCtl->Mrt != 0) ? RetryCtl->Mrt : DHCP6_INF_MRT;\r
192 TxCb->RetryCtl.Mrd = (RetryCtl->Mrd != 0) ? RetryCtl->Mrd : DHCP6_INF_MRD;\r
193 }\r
194\r
195 TxCb->RetryExp = Dhcp6CalculateExpireTime (\r
196 TxCb->RetryCtl.Irt,\r
197 TRUE,\r
198 TRUE\r
199 );\r
200 break;\r
201\r
202 default:\r
203 //\r
204 // Unexpected message type.\r
205 //\r
206 return EFI_DEVICE_ERROR;\r
207 }\r
208\r
209 //\r
210 // Insert into the retransmit list of the instance.\r
211 //\r
212 InsertTailList (&Instance->TxList, &TxCb->Link);\r
213\r
214 return EFI_SUCCESS;\r
215}\r
216\r
217\r
218/**\r
219 Dequeue the packet from retry list if reply received or timeout at last.\r
220\r
221 @param[in] Instance The pointer to the Dhcp6 instance.\r
222 @param[in] PacketXid The packet transaction id to match.\r
223 @param[in] NeedSignal If TRUE, then an timeout event need be signaled when it is existed.\r
224 Otherwise, this parameter is ignored.\r
225\r
226 @retval EFI_SUCCESS Successfully dequeued the packet into retry list .\r
227 @retval EFI_NOT_FOUND There is no xid matched in retry list.\r
228\r
229**/\r
230EFI_STATUS\r
231Dhcp6DequeueRetry (\r
232 IN DHCP6_INSTANCE *Instance,\r
233 IN UINT32 PacketXid,\r
234 IN BOOLEAN NeedSignal\r
235 )\r
236{\r
237 LIST_ENTRY *Entry;\r
238 LIST_ENTRY *NextEntry;\r
239 DHCP6_TX_CB *TxCb;\r
240 DHCP6_INF_CB *InfCb;\r
241\r
242 //\r
243 // Seek the retransmit node in the retransmit list by packet xid.\r
244 //\r
245 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->TxList) {\r
246\r
247 TxCb = NET_LIST_USER_STRUCT (Entry, DHCP6_TX_CB, Link);\r
248 ASSERT(TxCb->TxPacket);\r
249\r
250 if (TxCb->Xid == PacketXid) {\r
251\r
252 if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest) {\r
253\r
254 //\r
255 // Seek the info-request node in the info-request list by packet xid.\r
256 //\r
257 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->InfList) {\r
258\r
259 InfCb = NET_LIST_USER_STRUCT (Entry, DHCP6_INF_CB, Link);\r
260\r
261 if (InfCb->Xid == PacketXid) {\r
262 //\r
263 // Remove the info-request node, and signal the event if timeout.\r
264 //\r
265 if (InfCb->TimeoutEvent != NULL && NeedSignal) {\r
266 gBS->SignalEvent (InfCb->TimeoutEvent);\r
267 }\r
268\r
269 RemoveEntryList (&InfCb->Link);\r
270 FreePool (InfCb);\r
271 }\r
272 }\r
273 }\r
274 //\r
275 // Remove the retransmit node.\r
276 //\r
277 RemoveEntryList (&TxCb->Link);\r
278 ASSERT(TxCb->TxPacket);\r
279 FreePool (TxCb->TxPacket);\r
280 FreePool (TxCb);\r
281 return EFI_SUCCESS;\r
282 }\r
283 }\r
284\r
285 return EFI_NOT_FOUND;\r
286}\r
287\r
288\r
289/**\r
290 Clean up the specific nodes in the retry list.\r
291\r
292 @param[in] Instance The pointer to the Dhcp6 instance.\r
293 @param[in] Scope The scope of cleanup nodes.\r
294\r
295**/\r
296VOID\r
297Dhcp6CleanupRetry (\r
298 IN DHCP6_INSTANCE *Instance,\r
299 IN UINT32 Scope\r
300 )\r
301{\r
302 LIST_ENTRY *Entry;\r
303 LIST_ENTRY *NextEntry;\r
304 DHCP6_TX_CB *TxCb;\r
305 DHCP6_INF_CB *InfCb;\r
306\r
307 //\r
308 // Clean up all the stateful messages from the retransmit list.\r
309 //\r
310 if (Scope == DHCP6_PACKET_STATEFUL || Scope == DHCP6_PACKET_ALL) {\r
311\r
312 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->TxList) {\r
313\r
314 TxCb = NET_LIST_USER_STRUCT (Entry, DHCP6_TX_CB, Link);\r
315 ASSERT(TxCb->TxPacket);\r
316\r
317 if (TxCb->TxPacket->Dhcp6.Header.MessageType != Dhcp6MsgInfoRequest) {\r
318 RemoveEntryList (&TxCb->Link);\r
319 FreePool (TxCb->TxPacket);\r
320 FreePool (TxCb);\r
321 }\r
322 }\r
323 }\r
324\r
325 //\r
326 // Clean up all the stateless messages from the retransmit list.\r
327 //\r
328 if (Scope == DHCP6_PACKET_STATELESS || Scope == DHCP6_PACKET_ALL) {\r
329\r
330 //\r
331 // Clean up all the retransmit list for stateless messages.\r
332 //\r
333 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->TxList) {\r
334\r
335 TxCb = NET_LIST_USER_STRUCT (Entry, DHCP6_TX_CB, Link);\r
336 ASSERT(TxCb->TxPacket);\r
337\r
338 if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest) {\r
339 RemoveEntryList (&TxCb->Link);\r
340 FreePool (TxCb->TxPacket);\r
341 FreePool (TxCb);\r
342 }\r
343 }\r
344\r
345 //\r
346 // Clean up all the info-request messages list.\r
347 //\r
348 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->InfList) {\r
349\r
350 InfCb = NET_LIST_USER_STRUCT (Entry, DHCP6_INF_CB, Link);\r
351\r
352 if (InfCb->TimeoutEvent != NULL) {\r
353 gBS->SignalEvent (InfCb->TimeoutEvent);\r
354 }\r
355 RemoveEntryList (&InfCb->Link);\r
356 FreePool (InfCb);\r
357 }\r
358 }\r
359}\r
360\r
d2ea3b83
FS
361/**\r
362 Check whether the TxCb is still a valid control block in the instance's retry list.\r
363\r
364 @param[in] Instance The pointer to DHCP6_INSTANCE.\r
365 @param[in] TxCb The control block for a transmitted message.\r
366\r
367 @retval TRUE The control block is in Instance's retry list.\r
368 @retval FALSE The control block is NOT in Instance's retry list.\r
f75a7f56 369\r
d2ea3b83
FS
370**/\r
371BOOLEAN\r
372Dhcp6IsValidTxCb (\r
373 IN DHCP6_INSTANCE *Instance,\r
374 IN DHCP6_TX_CB *TxCb\r
375 )\r
376{\r
377 LIST_ENTRY *Entry;\r
378\r
379 NET_LIST_FOR_EACH (Entry, &Instance->TxList) {\r
380 if (TxCb == NET_LIST_USER_STRUCT (Entry, DHCP6_TX_CB, Link)) {\r
381 return TRUE;\r
382 }\r
383 }\r
384\r
385 return FALSE;\r
386}\r
a3bcde70
HT
387\r
388/**\r
389 Clean up the session of the instance stateful exchange.\r
390\r
391 @param[in, out] Instance The pointer to the Dhcp6 instance.\r
392 @param[in] Status The return status from udp.\r
393\r
394**/\r
395VOID\r
396Dhcp6CleanupSession (\r
397 IN OUT DHCP6_INSTANCE *Instance,\r
398 IN EFI_STATUS Status\r
399 )\r
400{\r
401 UINTN Index;\r
402 EFI_DHCP6_IA *Ia;\r
403\r
404 ASSERT(Instance->Config);\r
405 ASSERT(Instance->IaCb.Ia);\r
406\r
407 //\r
408 // Clean up the retransmit list for stateful messages.\r
409 //\r
410 Dhcp6CleanupRetry (Instance, DHCP6_PACKET_STATEFUL);\r
411\r
412 if (Instance->Unicast != NULL) {\r
413 FreePool (Instance->Unicast);\r
414 }\r
415\r
416 if (Instance->AdSelect != NULL) {\r
417 FreePool (Instance->AdSelect);\r
418 }\r
419\r
420 if (Instance->IaCb.Ia->ReplyPacket != NULL) {\r
421 FreePool (Instance->IaCb.Ia->ReplyPacket);\r
422 }\r
423\r
424 //\r
425 // Reinitialize the Ia fields of the instance.\r
426 //\r
427 Instance->UdpSts = Status;\r
428 Instance->AdSelect = NULL;\r
429 Instance->AdPref = 0;\r
430 Instance->Unicast = NULL;\r
431 Instance->IaCb.T1 = 0;\r
432 Instance->IaCb.T2 = 0;\r
433 Instance->IaCb.AllExpireTime = 0;\r
434 Instance->IaCb.LeaseTime = 0;\r
435\r
436 //\r
437 // Clear start time\r
438 //\r
439 Instance->StartTime = 0;\r
440\r
441 Ia = Instance->IaCb.Ia;\r
442 Ia->State = Dhcp6Init;\r
443 Ia->ReplyPacket = NULL;\r
444\r
445 //\r
446 // Set the addresses as zero lifetime, and then the notify\r
447 // function in Ip6Config will remove these timeout address.\r
448 //\r
449 for (Index = 0; Index < Ia->IaAddressCount; Index++) {\r
450 Ia->IaAddress[Index].PreferredLifetime = 0;\r
451 Ia->IaAddress[Index].ValidLifetime = 0;\r
452 }\r
453\r
454 //\r
455 //\r
456 // Signal the Ia information updated event to informal user.\r
457 //\r
458 if (Instance->Config->IaInfoEvent != NULL) {\r
459 gBS->SignalEvent (Instance->Config->IaInfoEvent);\r
460 }\r
461}\r
462\r
463\r
464/**\r
465 Callback to user when Dhcp6 transmit/receive occurs.\r
466\r
467 @param[in] Instance The pointer to the Dhcp6 instance.\r
468 @param[in] Event The current Dhcp6 event.\r
469 @param[in, out] Packet The pointer to the packet sending or received.\r
470\r
471 @retval EFI_SUCCESS The user function returns success.\r
472 @retval EFI_NOT_READY Direct the caller to continue collecting the offer.\r
473 @retval EFI_ABORTED The user function ask it to abort.\r
474\r
475**/\r
476EFI_STATUS\r
477EFIAPI\r
478Dhcp6CallbackUser (\r
479 IN DHCP6_INSTANCE *Instance,\r
480 IN EFI_DHCP6_EVENT Event,\r
481 IN OUT EFI_DHCP6_PACKET **Packet\r
482 )\r
483{\r
484 EFI_STATUS Status;\r
485 EFI_DHCP6_PACKET *NewPacket;\r
486 EFI_DHCP6_CALLBACK Callback;\r
487 VOID *Context;\r
488\r
489 ASSERT (Packet != NULL);\r
490 ASSERT (Instance->Config != NULL);\r
491 ASSERT (Instance->IaCb.Ia != NULL);\r
492\r
493 NewPacket = NULL;\r
494 Status = EFI_SUCCESS;\r
495 Callback = Instance->Config->Dhcp6Callback;\r
496 Context = Instance->Config->CallbackContext;\r
497\r
498 //\r
499 // Callback to user with the new message if has.\r
500 //\r
501 if (Callback != NULL) {\r
502\r
503 Status = Callback (\r
504 &Instance->Dhcp6,\r
505 Context,\r
506 Instance->IaCb.Ia->State,\r
507 Event,\r
508 *Packet,\r
509 &NewPacket\r
510 );\r
511 //\r
512 // Updated the new packet from user to replace the original one.\r
513 //\r
514 if (NewPacket != NULL) {\r
515 ASSERT (*Packet != NULL);\r
516 FreePool (*Packet);\r
517 *Packet = NewPacket;\r
518 }\r
519 }\r
520\r
521 return Status;\r
522}\r
523\r
524\r
525/**\r
526 Update Ia according to the new reply message.\r
527\r
528 @param[in, out] Instance The pointer to the Dhcp6 instance.\r
529 @param[in] Packet The pointer to reply messages.\r
530\r
531 @retval EFI_SUCCESS Updated the Ia information successfully.\r
532 @retval EFI_DEVICE_ERROR An unexpected error.\r
533\r
534**/\r
535EFI_STATUS\r
536Dhcp6UpdateIaInfo (\r
537 IN OUT DHCP6_INSTANCE *Instance,\r
538 IN EFI_DHCP6_PACKET *Packet\r
539 )\r
540{\r
541 EFI_STATUS Status;\r
a3bcde70
HT
542 UINT8 *Option;\r
543 UINT8 *IaInnerOpt;\r
544 UINT16 IaInnerLen;\r
545 UINT16 StsCode;\r
546 UINT32 T1;\r
547 UINT32 T2;\r
548\r
549 ASSERT (Instance->Config != NULL);\r
550 //\r
551 // If the reply was received in reponse to a solicit with rapid commit option,\r
552 // request, renew or rebind message, the client updates the information it has\r
553 // recorded about IAs from the IA options contained in the reply message:\r
554 // 1. record the T1 and T2 times\r
555 // 2. add any new addresses in the IA\r
556 // 3. discard any addresses from the IA, that have a valid lifetime of 0\r
557 // 4. update lifetimes for any addresses that alread recorded\r
558 // 5. leave unchanged any information about addresses\r
559 //\r
560 // See details in the section-18.1.8 of rfc-3315.\r
561 //\r
a3bcde70
HT
562 Option = Dhcp6SeekIaOption (\r
563 Packet->Dhcp6.Option,\r
564 Packet->Length - sizeof (EFI_DHCP6_HEADER),\r
565 &Instance->Config->IaDescriptor\r
566 );\r
567 if (Option == NULL) {\r
568 return EFI_DEVICE_ERROR;\r
569 }\r
570\r
571 //\r
572 // The format of the IA_NA option is:\r
573 //\r
574 // 0 1 2 3\r
575 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
576 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
577 // | OPTION_IA_NA | option-len |\r
578 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
579 // | IAID (4 octets) |\r
580 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
581 // | T1 |\r
582 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
583 // | T2 |\r
584 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
585 // | |\r
586 // . IA_NA-options .\r
587 // . .\r
588 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
589 //\r
590 // The format of the IA_TA option is:\r
591 //\r
592 // 0 1 2 3\r
593 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
594 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
595 // | OPTION_IA_TA | option-len |\r
596 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
597 // | IAID (4 octets) |\r
598 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
599 // | |\r
600 // . IA_TA-options .\r
601 // . .\r
602 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
603 //\r
604\r
605 //\r
606 // sizeof (option-code + option-len + IaId) = 8\r
607 // sizeof (option-code + option-len + IaId + T1) = 12\r
608 // sizeof (option-code + option-len + IaId + T1 + T2) = 16\r
609 //\r
610 // The inner options still start with 2 bytes option-code and 2 bytes option-len.\r
611 //\r
612 if (Instance->Config->IaDescriptor.Type == Dhcp6OptIana) {\r
613 T1 = NTOHL (ReadUnaligned32 ((UINT32 *) (Option + 8)));\r
614 T2 = NTOHL (ReadUnaligned32 ((UINT32 *) (Option + 12)));\r
685e44a5 615 //\r
616 // Refer to RFC3155 Chapter 22.4. If a client receives an IA_NA with T1 greater than T2,\r
617 // and both T1 and T2 are greater than 0, the client discards the IA_NA option and processes\r
618 // the remainder of the message as though the server had not included the invalid IA_NA option.\r
619 //\r
620 if (T1 > T2 && T2 > 0) {\r
621 return EFI_DEVICE_ERROR;\r
622 }\r
a3bcde70
HT
623 IaInnerOpt = Option + 16;\r
624 IaInnerLen = (UINT16) (NTOHS (ReadUnaligned16 ((UINT16 *) (Option + 2))) - 12);\r
625 } else {\r
626 T1 = 0;\r
627 T2 = 0;\r
628 IaInnerOpt = Option + 8;\r
629 IaInnerLen = (UINT16) (NTOHS (ReadUnaligned16 ((UINT16 *) (Option + 2))) - 4);\r
630 }\r
631\r
632 //\r
633 // The format of the Status Code option is:\r
634 //\r
635 // 0 1 2 3\r
636 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
637 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
638 // | OPTION_STATUS_CODE | option-len |\r
639 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
640 // | status-code | |\r
641 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |\r
642 // . .\r
643 // . status-message .\r
644 // . .\r
645 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
646 //\r
647\r
648 //\r
649 // sizeof (option-code + option-len) = 4\r
650 //\r
651 StsCode = Dhcp6StsSuccess;\r
652 Option = Dhcp6SeekOption (IaInnerOpt, IaInnerLen, Dhcp6OptStatusCode);\r
653\r
654 if (Option != NULL) {\r
655 StsCode = NTOHS (ReadUnaligned16 ((UINT16 *) (Option + 4)));\r
656 if (StsCode != Dhcp6StsSuccess) {\r
657 return EFI_DEVICE_ERROR;\r
658 }\r
659 }\r
660\r
661 //\r
662 // Generate control block for the Ia.\r
663 //\r
664 Status = Dhcp6GenerateIaCb (\r
665 Instance,\r
666 IaInnerOpt,\r
667 IaInnerLen,\r
668 T1,\r
669 T2\r
670 );\r
671\r
672 return Status;\r
673}\r
674\r
675\r
676\r
677/**\r
678 Seek StatusCode Option in package. A Status Code option may appear in the\r
679 options field of a DHCP message and/or in the options field of another option.\r
680 See details in section 22.13, RFC3315.\r
681\r
682 @param[in] Instance The pointer to the Dhcp6 instance.\r
683 @param[in] Packet The pointer to reply messages.\r
684 @param[out] Option The pointer to status code option.\r
685\r
686 @retval EFI_SUCCESS Seek status code option successfully.\r
687 @retval EFI_DEVICE_ERROR An unexpected error.\r
688\r
689**/\r
690EFI_STATUS\r
691Dhcp6SeekStsOption (\r
692 IN DHCP6_INSTANCE *Instance,\r
693 IN EFI_DHCP6_PACKET *Packet,\r
694 OUT UINT8 **Option\r
695 )\r
696{\r
697 UINT8 *IaInnerOpt;\r
698 UINT16 IaInnerLen;\r
699 UINT16 StsCode;\r
700\r
701 //\r
702 // Seek StatusCode option directly in DHCP message body. That is, search in\r
703 // non-encapsulated option fields.\r
704 //\r
705 *Option = Dhcp6SeekOption (\r
706 Packet->Dhcp6.Option,\r
707 Packet->Length - 4,\r
708 Dhcp6OptStatusCode\r
709 );\r
710\r
711 if (*Option != NULL) {\r
712 StsCode = NTOHS (ReadUnaligned16 ((UINT16 *) (*Option + 4)));\r
713 if (StsCode != Dhcp6StsSuccess) {\r
714 return EFI_DEVICE_ERROR;\r
715 }\r
716 }\r
717\r
718 //\r
719 // Seek in encapsulated options, IA_NA and IA_TA.\r
720 //\r
721 *Option = Dhcp6SeekIaOption (\r
722 Packet->Dhcp6.Option,\r
723 Packet->Length - sizeof (EFI_DHCP6_HEADER),\r
724 &Instance->Config->IaDescriptor\r
725 );\r
726 if (*Option == NULL) {\r
685e44a5 727 return EFI_SUCCESS;\r
a3bcde70
HT
728 }\r
729\r
730 //\r
731 // The format of the IA_NA option is:\r
732 //\r
733 // 0 1 2 3\r
734 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
735 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
736 // | OPTION_IA_NA | option-len |\r
737 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
738 // | IAID (4 octets) |\r
739 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
740 // | T1 |\r
741 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
742 // | T2 |\r
743 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
744 // | |\r
745 // . IA_NA-options .\r
746 // . .\r
747 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
748 //\r
749 // The format of the IA_TA option is:\r
750 //\r
751 // 0 1 2 3\r
752 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
753 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
754 // | OPTION_IA_TA | option-len |\r
755 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
756 // | IAID (4 octets) |\r
757 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
758 // | |\r
759 // . IA_TA-options .\r
760 // . .\r
761 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
762 //\r
763\r
764 //\r
765 // sizeof (option-code + option-len + IaId) = 8\r
766 // sizeof (option-code + option-len + IaId + T1) = 12\r
767 // sizeof (option-code + option-len + IaId + T1 + T2) = 16\r
768 //\r
769 // The inner options still start with 2 bytes option-code and 2 bytes option-len.\r
770 //\r
771 if (Instance->Config->IaDescriptor.Type == Dhcp6OptIana) {\r
772 IaInnerOpt = *Option + 16;\r
773 IaInnerLen = (UINT16) (NTOHS (ReadUnaligned16 ((UINT16 *) (*Option + 2))) - 12);\r
774 } else {\r
775 IaInnerOpt = *Option + 8;\r
776 IaInnerLen = (UINT16) (NTOHS (ReadUnaligned16 ((UINT16 *) (*Option + 2))) - 4);\r
777 }\r
778\r
779 //\r
780 // The format of the Status Code option is:\r
781 //\r
782 // 0 1 2 3\r
783 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
784 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
785 // | OPTION_STATUS_CODE | option-len |\r
786 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
787 // | status-code | |\r
788 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |\r
789 // . .\r
790 // . status-message .\r
791 // . .\r
792 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
793 //\r
794\r
795 //\r
796 // sizeof (option-code + option-len) = 4\r
797 //\r
798 *Option = Dhcp6SeekOption (IaInnerOpt, IaInnerLen, Dhcp6OptStatusCode);\r
799 if (*Option != NULL) {\r
800 StsCode = NTOHS (ReadUnaligned16 ((UINT16 *) (*Option + 4)));\r
801 if (StsCode != Dhcp6StsSuccess) {\r
802 return EFI_DEVICE_ERROR;\r
803 }\r
804 }\r
805\r
806 return EFI_SUCCESS;\r
807}\r
808\r
809\r
810/**\r
811 Transmit Dhcp6 message by udpio.\r
812\r
813 @param[in] Instance The pointer to the Dhcp6 instance.\r
814 @param[in] Packet The pointer to transmit message.\r
815 @param[in] Elapsed The pointer to the elapsed time value to fill in.\r
816\r
817 @retval EFI_SUCCESS Successfully transmitted the packet.\r
818 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
819 @retval Others Failed to transmit the packet.\r
820\r
821**/\r
822EFI_STATUS\r
823Dhcp6TransmitPacket (\r
824 IN DHCP6_INSTANCE *Instance,\r
825 IN EFI_DHCP6_PACKET *Packet,\r
826 IN UINT16 *Elapsed\r
827 )\r
828{\r
829 EFI_STATUS Status;\r
830 NET_BUF *Wrap;\r
831 NET_FRAGMENT Frag;\r
832 UDP_END_POINT EndPt;\r
833 DHCP6_SERVICE *Service;\r
834\r
835 Service = Instance->Service;\r
836\r
837 //\r
838 // Wrap it into a netbuf then send it.\r
839 //\r
840 Frag.Bulk = (UINT8 *) &Packet->Dhcp6.Header;\r
841 Frag.Len = Packet->Length;\r
842\r
843 //\r
844 // Do not register free packet here, which will be handled in retry list.\r
845 //\r
846 Wrap = NetbufFromExt (&Frag, 1, 0, 0, Dhcp6DummyExtFree, NULL);\r
847\r
848 if (Wrap == NULL) {\r
849 return EFI_OUT_OF_RESOURCES;\r
850 }\r
851\r
852 //\r
853 // Multicast the Dhcp6 message, unless get the unicast server address by option.\r
854 //\r
855 ZeroMem (&EndPt, sizeof (UDP_END_POINT));\r
856\r
857 if (Instance->Unicast != NULL) {\r
858 CopyMem (\r
859 &EndPt.RemoteAddr,\r
860 Instance->Unicast,\r
861 sizeof (EFI_IPv6_ADDRESS)\r
862 );\r
863 } else {\r
864 CopyMem (\r
865 &EndPt.RemoteAddr,\r
866 &mAllDhcpRelayAndServersAddress,\r
867 sizeof (EFI_IPv6_ADDRESS)\r
868 );\r
869 }\r
870\r
871 EndPt.RemotePort = DHCP6_PORT_SERVER;\r
872 EndPt.LocalPort = DHCP6_PORT_CLIENT;\r
873\r
874 //\r
875 // Update the elapsed time value.\r
876 //\r
877 if (Elapsed != NULL) {\r
878 SetElapsedTime (Elapsed, Instance);\r
879 }\r
880\r
881 //\r
882 // Send out the message by the configured Udp6Io.\r
883 //\r
884 Status = UdpIoSendDatagram (\r
885 Service->UdpIo,\r
886 Wrap,\r
887 &EndPt,\r
888 NULL,\r
889 Dhcp6OnTransmitted,\r
890 NULL\r
891 );\r
892\r
893 if (EFI_ERROR (Status)) {\r
894 NetbufFree (Wrap);\r
895 return Status;\r
896 }\r
897\r
898 return EFI_SUCCESS;\r
899}\r
900\r
901\r
902/**\r
903 Create the solicit message and send it.\r
904\r
905 @param[in] Instance The pointer to the Dhcp6 instance.\r
906\r
907 @retval EFI_SUCCESS Created and sent the solicit message successfully.\r
908 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
909 @retval Others Failed to send the solicit message.\r
910\r
911**/\r
912EFI_STATUS\r
913Dhcp6SendSolicitMsg (\r
914 IN DHCP6_INSTANCE *Instance\r
915 )\r
916{\r
917 EFI_STATUS Status;\r
918 EFI_DHCP6_PACKET *Packet;\r
919 EFI_DHCP6_PACKET_OPTION *UserOpt;\r
920 EFI_DHCP6_DUID *ClientId;\r
921 DHCP6_SERVICE *Service;\r
922 UINT8 *Cursor;\r
923 UINT16 *Elapsed;\r
924 UINT32 UserLen;\r
925 UINTN Index;\r
926 UINT16 Length;\r
927\r
928 Service = Instance->Service;\r
929 ClientId = Service->ClientId;\r
930 UserLen = 0;\r
931\r
932 ASSERT (Service->ClientId != NULL);\r
933 ASSERT (Instance->Config != NULL);\r
934 ASSERT (Instance->IaCb.Ia != NULL);\r
935\r
936 //\r
937 // Calculate the added length of customized option list.\r
938 //\r
939 for (Index = 0; Index < Instance->Config->OptionCount; Index++) {\r
940 UserLen += (NTOHS (Instance->Config->OptionList[Index]->OpLen) + 4);\r
941 }\r
942\r
943 //\r
944 // Create the Dhcp6 packet and initialize commone fields.\r
945 //\r
946 Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen);\r
947 if (Packet == NULL) {\r
948 return EFI_OUT_OF_RESOURCES;\r
949 }\r
950\r
951 Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen;\r
952 Packet->Length = sizeof (EFI_DHCP6_HEADER);\r
953 Packet->Dhcp6.Header.MessageType = Dhcp6MsgSolicit;\r
954 Packet->Dhcp6.Header.TransactionId = Service->Xid++;\r
955\r
956 //\r
957 // Assembly Dhcp6 options for solicit message.\r
958 //\r
959 Cursor = Packet->Dhcp6.Option;\r
960\r
961 Length = HTONS (ClientId->Length);\r
962 Cursor = Dhcp6AppendOption (\r
963 Cursor,\r
964 HTONS (Dhcp6OptClientId),\r
965 Length,\r
966 ClientId->Duid\r
967 );\r
968\r
969 Cursor = Dhcp6AppendETOption (\r
970 Cursor,\r
971 Instance,\r
972 &Elapsed\r
973 );\r
974\r
975 Cursor = Dhcp6AppendIaOption (\r
976 Cursor,\r
977 Instance->IaCb.Ia,\r
978 Instance->IaCb.T1,\r
685e44a5 979 Instance->IaCb.T2,\r
980 Packet->Dhcp6.Header.MessageType\r
a3bcde70
HT
981 );\r
982\r
983 //\r
984 // Append user-defined when configurate Dhcp6 service.\r
985 //\r
986 for (Index = 0; Index < Instance->Config->OptionCount; Index++) {\r
987\r
988 UserOpt = Instance->Config->OptionList[Index];\r
989 Cursor = Dhcp6AppendOption(\r
990 Cursor,\r
991 UserOpt->OpCode,\r
992 UserOpt->OpLen,\r
993 UserOpt->Data\r
994 );\r
995 }\r
996\r
997 //\r
998 // Determine the size/length of packet.\r
999 //\r
1000 Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option);\r
1001 ASSERT (Packet->Size > Packet->Length + 8);\r
1002\r
1003 //\r
1004 // Callback to user with the packet to be sent and check the user's feedback.\r
1005 //\r
1006 Status = Dhcp6CallbackUser (Instance, Dhcp6SendSolicit, &Packet);\r
1007\r
1008 if (EFI_ERROR (Status)) {\r
1009 FreePool (Packet);\r
1010 return Status;\r
1011 }\r
1012\r
1013 //\r
1014 // Send solicit packet with the state transition from Dhcp6init to\r
1015 // Dhcp6selecting.\r
1016 //\r
1017 Instance->IaCb.Ia->State = Dhcp6Selecting;\r
685e44a5 1018 //\r
1019 // Clear initial time for current transaction.\r
1020 //\r
1021 Instance->StartTime = 0;\r
a3bcde70
HT
1022\r
1023 Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
1024\r
1025 if (EFI_ERROR (Status)) {\r
1026 FreePool (Packet);\r
1027 return Status;\r
1028 }\r
1029\r
1030 //\r
1031 // Enqueue the sent packet for the retransmission in case reply timeout.\r
1032 //\r
1033 return Dhcp6EnqueueRetry (\r
1034 Instance,\r
1035 Packet,\r
1036 Elapsed,\r
1037 Instance->Config->SolicitRetransmission\r
1038 );\r
1039}\r
1040\r
1041/**\r
1042 Configure some parameter to initiate SolicitMsg.\r
1043\r
1044 @param[in] Instance The pointer to the Dhcp6 instance.\r
1045\r
1046 @retval EFI_SUCCESS Created and sent the solicit message successfully.\r
1047 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
1048 @retval Others Failed to send the solicit message.\r
1049\r
1050**/\r
1051EFI_STATUS\r
1052Dhcp6InitSolicitMsg (\r
1053 IN DHCP6_INSTANCE *Instance\r
1054 )\r
1055{\r
1056 Instance->IaCb.T1 = 0;\r
1057 Instance->IaCb.T2 = 0;\r
1058 Instance->IaCb.Ia->IaAddressCount = 0;\r
1059\r
1060 return Dhcp6SendSolicitMsg (Instance);\r
1061}\r
1062\r
1063\r
1064/**\r
1065 Create the request message and send it.\r
1066\r
1067 @param[in] Instance The pointer to the Dhcp6 instance.\r
1068\r
1069 @retval EFI_SUCCESS Created and sent the request message successfully.\r
1070 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
1071 @retval EFI_DEVICE_ERROR An unexpected error.\r
1072 @retval Others Failed to send the request message.\r
1073\r
1074**/\r
1075EFI_STATUS\r
1076Dhcp6SendRequestMsg (\r
1077 IN DHCP6_INSTANCE *Instance\r
1078 )\r
1079{\r
1080 EFI_STATUS Status;\r
1081 EFI_DHCP6_PACKET *Packet;\r
1082 EFI_DHCP6_PACKET_OPTION *UserOpt;\r
1083 EFI_DHCP6_DUID *ClientId;\r
1084 EFI_DHCP6_DUID *ServerId;\r
1085 DHCP6_SERVICE *Service;\r
1086 UINT8 *Option;\r
1087 UINT8 *Cursor;\r
1088 UINT16 *Elapsed;\r
1089 UINT32 UserLen;\r
1090 UINTN Index;\r
1091 UINT16 Length;\r
1092\r
1093 ASSERT(Instance->AdSelect != NULL);\r
1094 ASSERT(Instance->Config != NULL);\r
1095 ASSERT(Instance->IaCb.Ia != NULL);\r
1096 ASSERT(Instance->Service != NULL);\r
1097\r
1098 Service = Instance->Service;\r
1099 ClientId = Service->ClientId;\r
1100\r
1101 ASSERT(ClientId != NULL);\r
1102\r
1103 //\r
1104 // Get the server Id from the selected advertisement message.\r
1105 //\r
1106 Option = Dhcp6SeekOption (\r
1107 Instance->AdSelect->Dhcp6.Option,\r
1108 Instance->AdSelect->Length - 4,\r
1109 Dhcp6OptServerId\r
1110 );\r
1111 if (Option == NULL) {\r
1112 return EFI_DEVICE_ERROR;\r
1113 }\r
1114\r
1115 ServerId = (EFI_DHCP6_DUID *) (Option + 2);\r
1116\r
1117 //\r
1118 // Calculate the added length of customized option list.\r
1119 //\r
1120 UserLen = 0;\r
1121 for (Index = 0; Index < Instance->Config->OptionCount; Index++) {\r
1122 UserLen += (NTOHS (Instance->Config->OptionList[Index]->OpLen) + 4);\r
1123 }\r
1124\r
1125 //\r
1126 // Create the Dhcp6 packet and initialize commone fields.\r
1127 //\r
1128 Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen);\r
1129 if (Packet == NULL) {\r
1130 return EFI_OUT_OF_RESOURCES;\r
1131 }\r
1132\r
1133 Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen;\r
1134 Packet->Length = sizeof (EFI_DHCP6_HEADER);\r
1135 Packet->Dhcp6.Header.MessageType = Dhcp6MsgRequest;\r
1136 Packet->Dhcp6.Header.TransactionId = Service->Xid++;\r
1137\r
1138 //\r
1139 // Assembly Dhcp6 options for request message.\r
1140 //\r
1141 Cursor = Packet->Dhcp6.Option;\r
1142\r
1143 Length = HTONS (ClientId->Length);\r
1144 Cursor = Dhcp6AppendOption (\r
1145 Cursor,\r
1146 HTONS (Dhcp6OptClientId),\r
1147 Length,\r
1148 ClientId->Duid\r
1149 );\r
1150\r
1151 Cursor = Dhcp6AppendETOption (\r
1152 Cursor,\r
1153 Instance,\r
1154 &Elapsed\r
1155 );\r
1156\r
1157 Cursor = Dhcp6AppendOption (\r
1158 Cursor,\r
1159 HTONS (Dhcp6OptServerId),\r
1160 ServerId->Length,\r
1161 ServerId->Duid\r
1162 );\r
1163\r
1164 Cursor = Dhcp6AppendIaOption (\r
1165 Cursor,\r
1166 Instance->IaCb.Ia,\r
1167 Instance->IaCb.T1,\r
685e44a5 1168 Instance->IaCb.T2,\r
1169 Packet->Dhcp6.Header.MessageType\r
a3bcde70
HT
1170 );\r
1171\r
1172 //\r
1173 // Append user-defined when configurate Dhcp6 service.\r
1174 //\r
1175 for (Index = 0; Index < Instance->Config->OptionCount; Index++) {\r
1176\r
1177 UserOpt = Instance->Config->OptionList[Index];\r
1178 Cursor = Dhcp6AppendOption(\r
1179 Cursor,\r
1180 UserOpt->OpCode,\r
1181 UserOpt->OpLen,\r
1182 UserOpt->Data\r
1183 );\r
1184 }\r
1185\r
1186 //\r
1187 // Determine the size/length of packet.\r
1188 //\r
1189 Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option);\r
1190 ASSERT (Packet->Size > Packet->Length + 8);\r
1191\r
1192 //\r
1193 // Callback to user with the packet to be sent and check the user's feedback.\r
1194 //\r
1195 Status = Dhcp6CallbackUser (Instance, Dhcp6SendRequest, &Packet);\r
1196\r
1197 if (EFI_ERROR (Status)) {\r
1198 FreePool (Packet);\r
1199 return Status;\r
1200 }\r
1201\r
1202 //\r
1203 // Send request packet with the state transition from Dhcp6selecting to\r
1204 // Dhcp6requesting.\r
1205 //\r
1206 Instance->IaCb.Ia->State = Dhcp6Requesting;\r
685e44a5 1207 //\r
1208 // Clear initial time for current transaction.\r
1209 //\r
1210 Instance->StartTime = 0;\r
a3bcde70
HT
1211\r
1212 Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
1213\r
1214 if (EFI_ERROR (Status)) {\r
1215 FreePool (Packet);\r
1216 return Status;\r
1217 }\r
1218\r
1219 //\r
1220 // Enqueue the sent packet for the retransmission in case reply timeout.\r
1221 //\r
1222 return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL);\r
1223}\r
1224\r
1225\r
1226/**\r
1227 Create the decline message and send it.\r
1228\r
1229 @param[in] Instance The pointer to the Dhcp6 instance.\r
1230 @param[in] DecIa The pointer to the decline Ia.\r
1231\r
1232 @retval EFI_SUCCESS Created and sent the decline message successfully.\r
1233 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
1234 @retval EFI_DEVICE_ERROR An unexpected error.\r
1235 @retval Others Failed to send the decline message.\r
1236\r
1237**/\r
1238EFI_STATUS\r
1239Dhcp6SendDeclineMsg (\r
1240 IN DHCP6_INSTANCE *Instance,\r
1241 IN EFI_DHCP6_IA *DecIa\r
1242 )\r
1243{\r
1244 EFI_STATUS Status;\r
1245 EFI_DHCP6_PACKET *Packet;\r
1246 EFI_DHCP6_PACKET *LastReply;\r
1247 EFI_DHCP6_DUID *ClientId;\r
1248 EFI_DHCP6_DUID *ServerId;\r
1249 DHCP6_SERVICE *Service;\r
1250 UINT8 *Option;\r
1251 UINT8 *Cursor;\r
1252 UINT16 *Elapsed;\r
1253 UINT16 Length;\r
1254\r
1255 ASSERT (Instance->Config != NULL);\r
1256 ASSERT (Instance->IaCb.Ia != NULL);\r
1257 ASSERT (Instance->Service != NULL);\r
1258\r
1259 Service = Instance->Service;\r
1260 ClientId = Service->ClientId;\r
1261 LastReply = Instance->IaCb.Ia->ReplyPacket;\r
1262\r
1263 ASSERT (ClientId != NULL);\r
1264 ASSERT (LastReply != NULL);\r
1265\r
1266 //\r
1267 // Get the server Id from the last reply message.\r
1268 //\r
1269 Option = Dhcp6SeekOption (\r
1270 LastReply->Dhcp6.Option,\r
1271 LastReply->Length - 4,\r
1272 Dhcp6OptServerId\r
1273 );\r
1274 if (Option == NULL) {\r
1275 return EFI_DEVICE_ERROR;\r
1276 }\r
1277\r
1278 //\r
1279 // EFI_DHCP6_DUID contains a length field of 2 bytes.\r
1280 //\r
1281 ServerId = (EFI_DHCP6_DUID *) (Option + 2);\r
1282\r
1283 //\r
1284 // Create the Dhcp6 packet and initialize commone fields.\r
1285 //\r
1286 Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE);\r
1287 if (Packet == NULL) {\r
1288 return EFI_OUT_OF_RESOURCES;\r
1289 }\r
1290\r
1291 Packet->Size = DHCP6_BASE_PACKET_SIZE;\r
1292 Packet->Length = sizeof (EFI_DHCP6_HEADER);\r
1293 Packet->Dhcp6.Header.MessageType = Dhcp6MsgDecline;\r
1294 Packet->Dhcp6.Header.TransactionId = Service->Xid++;\r
1295\r
1296 //\r
1297 // Assembly Dhcp6 options for rebind/renew message.\r
1298 //\r
1299 Cursor = Packet->Dhcp6.Option;\r
1300\r
1301 Length = HTONS (ClientId->Length);\r
1302 Cursor = Dhcp6AppendOption (\r
1303 Cursor,\r
1304 HTONS (Dhcp6OptClientId),\r
1305 Length,\r
1306 ClientId->Duid\r
1307 );\r
1308\r
1309 Cursor = Dhcp6AppendETOption (\r
1310 Cursor,\r
1311 Instance,\r
1312 &Elapsed\r
1313 );\r
1314\r
1315 Cursor = Dhcp6AppendOption (\r
1316 Cursor,\r
1317 HTONS (Dhcp6OptServerId),\r
1318 ServerId->Length,\r
1319 ServerId->Duid\r
1320 );\r
1321\r
685e44a5 1322 Cursor = Dhcp6AppendIaOption (Cursor, DecIa, 0, 0, Packet->Dhcp6.Header.MessageType);\r
a3bcde70
HT
1323\r
1324 //\r
1325 // Determine the size/length of packet.\r
1326 //\r
1327 Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option);\r
1328 ASSERT (Packet->Size > Packet->Length + 8);\r
1329\r
1330 //\r
1331 // Callback to user with the packet to be sent and check the user's feedback.\r
1332 //\r
1333 Status = Dhcp6CallbackUser (Instance, Dhcp6SendDecline, &Packet);\r
1334\r
1335 if (EFI_ERROR (Status)) {\r
1336 FreePool (Packet);\r
1337 return Status;\r
1338 }\r
1339\r
1340 //\r
1341 // Send decline packet with the state transition from Dhcp6bound to\r
1342 // Dhcp6declining.\r
1343 //\r
1344 Instance->IaCb.Ia->State = Dhcp6Declining;\r
685e44a5 1345 //\r
1346 // Clear initial time for current transaction.\r
1347 //\r
1348 Instance->StartTime = 0;\r
a3bcde70
HT
1349\r
1350 Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
1351\r
1352 if (EFI_ERROR (Status)) {\r
1353 FreePool (Packet);\r
1354 return Status;\r
1355 }\r
1356\r
1357 //\r
1358 // Enqueue the sent packet for the retransmission in case reply timeout.\r
1359 //\r
1360 return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL);\r
1361}\r
1362\r
1363\r
1364/**\r
1365 Create the release message and send it.\r
1366\r
1367 @param[in] Instance The pointer to the Dhcp6 instance.\r
1368 @param[in] RelIa The pointer to the release Ia.\r
1369\r
1370 @retval EFI_SUCCESS Created and sent the release message successfully.\r
1371 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
1372 @retval EFI_DEVICE_ERROR An unexpected error.\r
1373 @retval Others Failed to send the release message.\r
1374\r
1375**/\r
1376EFI_STATUS\r
1377Dhcp6SendReleaseMsg (\r
1378 IN DHCP6_INSTANCE *Instance,\r
1379 IN EFI_DHCP6_IA *RelIa\r
1380 )\r
1381{\r
1382 EFI_STATUS Status;\r
1383 EFI_DHCP6_PACKET *Packet;\r
1384 EFI_DHCP6_PACKET *LastReply;\r
1385 EFI_DHCP6_DUID *ClientId;\r
1386 EFI_DHCP6_DUID *ServerId;\r
1387 DHCP6_SERVICE *Service;\r
1388 UINT8 *Option;\r
1389 UINT8 *Cursor;\r
1390 UINT16 *Elapsed;\r
1391 UINT16 Length;\r
1392\r
1393 ASSERT(Instance->Config);\r
1394 ASSERT(Instance->IaCb.Ia);\r
1395\r
1396 Service = Instance->Service;\r
1397 ClientId = Service->ClientId;\r
1398 LastReply = Instance->IaCb.Ia->ReplyPacket;\r
1399\r
1400 ASSERT(ClientId);\r
1401 ASSERT(LastReply);\r
1402\r
1403 //\r
1404 // Get the server Id from the last reply message.\r
1405 //\r
1406 Option = Dhcp6SeekOption (\r
1407 LastReply->Dhcp6.Option,\r
1408 LastReply->Length - 4,\r
1409 Dhcp6OptServerId\r
1410 );\r
1411 if (Option == NULL) {\r
1412 return EFI_DEVICE_ERROR;\r
1413 }\r
1414\r
1415 ServerId = (EFI_DHCP6_DUID *) (Option + 2);\r
1416\r
1417 //\r
1418 // Create the Dhcp6 packet and initialize commone fields.\r
1419 //\r
1420 Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE);\r
1421 if (Packet == NULL) {\r
1422 return EFI_OUT_OF_RESOURCES;\r
1423 }\r
1424\r
1425 Packet->Size = DHCP6_BASE_PACKET_SIZE;\r
1426 Packet->Length = sizeof (EFI_DHCP6_HEADER);\r
1427 Packet->Dhcp6.Header.MessageType = Dhcp6MsgRelease;\r
1428 Packet->Dhcp6.Header.TransactionId = Service->Xid++;\r
1429\r
1430 //\r
1431 // Assembly Dhcp6 options for rebind/renew message\r
1432 //\r
1433 Cursor = Packet->Dhcp6.Option;\r
1434\r
1435 Length = HTONS (ClientId->Length);\r
1436 Cursor = Dhcp6AppendOption (\r
1437 Cursor,\r
1438 HTONS (Dhcp6OptClientId),\r
1439 Length,\r
1440 ClientId->Duid\r
1441 );\r
1442\r
1443 //\r
1444 // ServerId is extracted from packet, it's network order.\r
1445 //\r
1446 Cursor = Dhcp6AppendOption (\r
1447 Cursor,\r
1448 HTONS (Dhcp6OptServerId),\r
1449 ServerId->Length,\r
1450 ServerId->Duid\r
1451 );\r
1452\r
1453 Cursor = Dhcp6AppendETOption (\r
1454 Cursor,\r
1455 Instance,\r
1456 &Elapsed\r
1457 );\r
1458\r
685e44a5 1459 Cursor = Dhcp6AppendIaOption (Cursor, RelIa, 0, 0, Packet->Dhcp6.Header.MessageType);\r
a3bcde70
HT
1460\r
1461 //\r
1462 // Determine the size/length of packet\r
1463 //\r
1464 Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option);\r
1465 ASSERT (Packet->Size > Packet->Length + 8);\r
1466\r
1467 //\r
1468 // Callback to user with the packet to be sent and check the user's feedback.\r
1469 //\r
1470 Status = Dhcp6CallbackUser (Instance, Dhcp6SendRelease, &Packet);\r
1471\r
1472 if (EFI_ERROR (Status)) {\r
1473 FreePool (Packet);\r
1474 return Status;\r
1475 }\r
1476\r
1477 //\r
1478 // Send release packet with the state transition from Dhcp6bound to\r
1479 // Dhcp6releasing.\r
1480 //\r
1481 Instance->IaCb.Ia->State = Dhcp6Releasing;\r
1482\r
1483 Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
1484\r
1485 if (EFI_ERROR (Status)) {\r
1486 FreePool (Packet);\r
1487 return Status;\r
1488 }\r
1489\r
1490 //\r
1491 // Enqueue the sent packet for the retransmission in case reply timeout.\r
1492 //\r
1493 return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL);\r
1494}\r
1495\r
1496\r
1497/**\r
1498 Create the renew/rebind message and send it.\r
1499\r
1500 @param[in] Instance The pointer to the Dhcp6 instance.\r
1501 @param[in] RebindRequest If TRUE, it is a Rebind type message.\r
1502 Otherwise, it is a Renew type message.\r
1503\r
1504 @retval EFI_SUCCESS Created and sent the renew/rebind message successfully.\r
1505 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
1506 @retval EFI_DEVICE_ERROR An unexpected error.\r
1507 @retval Others Failed to send the renew/rebind message.\r
1508\r
1509**/\r
1510EFI_STATUS\r
1511Dhcp6SendRenewRebindMsg (\r
1512 IN DHCP6_INSTANCE *Instance,\r
1513 IN BOOLEAN RebindRequest\r
1514 )\r
1515{\r
1516 EFI_STATUS Status;\r
1517 EFI_DHCP6_PACKET *Packet;\r
1518 EFI_DHCP6_PACKET *LastReply;\r
1519 EFI_DHCP6_PACKET_OPTION *UserOpt;\r
1520 EFI_DHCP6_DUID *ClientId;\r
1521 EFI_DHCP6_DUID *ServerId;\r
1522 EFI_DHCP6_STATE State;\r
1523 EFI_DHCP6_EVENT Event;\r
1524 DHCP6_SERVICE *Service;\r
1525 UINT8 *Option;\r
1526 UINT8 *Cursor;\r
1527 UINT16 *Elapsed;\r
1528 UINT32 UserLen;\r
1529 UINTN Index;\r
1530 UINT16 Length;\r
1531\r
1532 ASSERT(Instance->Config);\r
1533 ASSERT(Instance->IaCb.Ia);\r
1534\r
1535 Service = Instance->Service;\r
1536 ClientId = Service->ClientId;\r
1537\r
1538 ASSERT(ClientId);\r
1539\r
1540 //\r
1541 // Calculate the added length of customized option list.\r
1542 //\r
1543 UserLen = 0;\r
1544 for (Index = 0; Index < Instance->Config->OptionCount; Index++) {\r
1545 UserLen += (NTOHS (Instance->Config->OptionList[Index]->OpLen) + 4);\r
1546 }\r
1547\r
1548 //\r
1549 // Create the Dhcp6 packet and initialize commone fields.\r
1550 //\r
1551 Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen);\r
1552 if (Packet == NULL) {\r
1553 return EFI_OUT_OF_RESOURCES;\r
1554 }\r
1555\r
1556 Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen;\r
1557 Packet->Length = sizeof (EFI_DHCP6_HEADER);\r
1558 Packet->Dhcp6.Header.MessageType = RebindRequest ? Dhcp6MsgRebind : Dhcp6MsgRenew;\r
1559 Packet->Dhcp6.Header.TransactionId = Service->Xid++;\r
1560\r
1561 //\r
1562 // Assembly Dhcp6 options for rebind/renew message.\r
1563 //\r
1564 Cursor = Packet->Dhcp6.Option;\r
1565\r
1566 Length = HTONS (ClientId->Length);\r
1567 Cursor = Dhcp6AppendOption (\r
1568 Cursor,\r
1569 HTONS (Dhcp6OptClientId),\r
1570 Length,\r
1571 ClientId->Duid\r
1572 );\r
1573\r
1574 Cursor = Dhcp6AppendETOption (\r
1575 Cursor,\r
1576 Instance,\r
1577 &Elapsed\r
1578 );\r
1579\r
1580 Cursor = Dhcp6AppendIaOption (\r
1581 Cursor,\r
1582 Instance->IaCb.Ia,\r
1583 Instance->IaCb.T1,\r
685e44a5 1584 Instance->IaCb.T2,\r
1585 Packet->Dhcp6.Header.MessageType\r
a3bcde70
HT
1586 );\r
1587\r
1588 if (!RebindRequest) {\r
1589 //\r
1590 // Get the server Id from the last reply message and\r
1591 // insert it for rebind request.\r
1592 //\r
1593 LastReply = Instance->IaCb.Ia->ReplyPacket;\r
1594 ASSERT (LastReply);\r
1595\r
1596 Option = Dhcp6SeekOption (\r
1597 LastReply->Dhcp6.Option,\r
1598 LastReply->Length - 4,\r
1599 Dhcp6OptServerId\r
1600 );\r
1601 if (Option == NULL) {\r
1602 FreePool (Packet);\r
1603 return EFI_DEVICE_ERROR;\r
1604 }\r
1605\r
1606 ServerId = (EFI_DHCP6_DUID *) (Option + 2);\r
1607\r
1608 Cursor = Dhcp6AppendOption (\r
1609 Cursor,\r
1610 HTONS (Dhcp6OptServerId),\r
1611 ServerId->Length,\r
1612 ServerId->Duid\r
1613 );\r
1614 }\r
1615\r
1616 //\r
1617 // Append user-defined when configurate Dhcp6 service.\r
1618 //\r
1619 for (Index = 0; Index < Instance->Config->OptionCount; Index++) {\r
1620\r
1621 UserOpt = Instance->Config->OptionList[Index];\r
1622 Cursor = Dhcp6AppendOption(\r
1623 Cursor,\r
1624 UserOpt->OpCode,\r
1625 UserOpt->OpLen,\r
1626 UserOpt->Data\r
1627 );\r
1628 }\r
1629\r
1630 //\r
1631 // Determine the size/length of packet.\r
1632 //\r
1633 Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option);\r
1634 ASSERT (Packet->Size > Packet->Length + 8);\r
1635\r
1636 //\r
1637 // Callback to user with the packet to be sent and check the user's feedback.\r
1638 //\r
1639 State = (RebindRequest) ? Dhcp6Rebinding : Dhcp6Renewing;\r
1640 Event = (RebindRequest) ? Dhcp6EnterRebinding : Dhcp6EnterRenewing;\r
1641\r
1642 Status = Dhcp6CallbackUser (Instance, Event, &Packet);\r
1643\r
1644 if (EFI_ERROR (Status)) {\r
1645 FreePool (Packet);\r
1646 return Status;\r
1647 }\r
1648\r
1649 //\r
1650 // Send renew/rebind packet with the state transition from Dhcp6bound to\r
1651 // Dhcp6renew/rebind.\r
1652 // And sync the lease time when send renew/rebind, in case that user send\r
1653 // renew/rebind actively.\r
1654 //\r
1655 Instance->IaCb.Ia->State = State;\r
1656 Instance->IaCb.LeaseTime = (RebindRequest) ? Instance->IaCb.T2 : Instance->IaCb.T1;\r
685e44a5 1657 //\r
1658 // Clear initial time for current transaction.\r
1659 //\r
1660 Instance->StartTime = 0;\r
a3bcde70
HT
1661\r
1662 Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
1663\r
1664 if (EFI_ERROR (Status)) {\r
1665 FreePool (Packet);\r
1666 return Status;\r
1667 }\r
1668\r
1669 //\r
1670 // Enqueue the sent packet for the retransmission in case reply timeout.\r
1671 //\r
1672 return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL);\r
1673}\r
1674\r
cc658224 1675/**\r
1676 Start the information request process.\r
1677\r
1678 @param[in] Instance The pointer to the Dhcp6 instance.\r
1679 @param[in] SendClientId If TRUE, the client identifier option will be included in\r
1680 information request message. Otherwise, the client identifier\r
1681 option will not be included.\r
1682 @param[in] OptionRequest The pointer to the option request option.\r
1683 @param[in] OptionCount The number options in the OptionList.\r
1684 @param[in] OptionList The array pointers to the appended options.\r
1685 @param[in] Retransmission The pointer to the retransmission control.\r
1686 @param[in] TimeoutEvent The event of timeout.\r
1687 @param[in] ReplyCallback The callback function when the reply was received.\r
1688 @param[in] CallbackContext The pointer to the parameter passed to the callback.\r
1689\r
1690 @retval EFI_SUCCESS Start the info-request process successfully.\r
1691 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
1692 @retval EFI_NO_MAPPING No source address is available for use.\r
1693 @retval Others Failed to start the info-request process.\r
1694\r
1695**/\r
1696EFI_STATUS\r
1697Dhcp6StartInfoRequest (\r
1698 IN DHCP6_INSTANCE *Instance,\r
1699 IN BOOLEAN SendClientId,\r
1700 IN EFI_DHCP6_PACKET_OPTION *OptionRequest,\r
1701 IN UINT32 OptionCount,\r
1702 IN EFI_DHCP6_PACKET_OPTION *OptionList[] OPTIONAL,\r
1703 IN EFI_DHCP6_RETRANSMISSION *Retransmission,\r
1704 IN EFI_EVENT TimeoutEvent OPTIONAL,\r
1705 IN EFI_DHCP6_INFO_CALLBACK ReplyCallback,\r
1706 IN VOID *CallbackContext OPTIONAL\r
1707 )\r
1708{\r
1709 EFI_STATUS Status;\r
1710 DHCP6_INF_CB *InfCb;\r
1711 DHCP6_SERVICE *Service;\r
1712 EFI_TPL OldTpl;\r
1713\r
1714 Service = Instance->Service;\r
1715\r
1716 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
1717 Instance->UdpSts = EFI_ALREADY_STARTED;\r
1718 //\r
1719 // Create and initialize the control block for the info-request.\r
1720 //\r
1721 InfCb = AllocateZeroPool (sizeof(DHCP6_INF_CB));\r
1722\r
1723 if (InfCb == NULL) {\r
1724 gBS->RestoreTPL (OldTpl);\r
1725 return EFI_OUT_OF_RESOURCES;\r
1726 }\r
1727\r
1728 InfCb->ReplyCallback = ReplyCallback;\r
1729 InfCb->CallbackContext = CallbackContext;\r
1730 InfCb->TimeoutEvent = TimeoutEvent;\r
1731\r
1732 InsertTailList (&Instance->InfList, &InfCb->Link);\r
1733\r
1734 //\r
1735 // Send the info-request message to start exchange process.\r
1736 //\r
1737 Status = Dhcp6SendInfoRequestMsg (\r
1738 Instance,\r
1739 InfCb,\r
1740 SendClientId,\r
1741 OptionRequest,\r
1742 OptionCount,\r
1743 OptionList,\r
1744 Retransmission\r
1745 );\r
1746\r
1747 if (EFI_ERROR (Status)) {\r
1748 goto ON_ERROR;\r
1749 }\r
1750\r
1751 //\r
1752 // Register receive callback for the stateless exchange process.\r
1753 //\r
1754 Status = UdpIoRecvDatagram(\r
1755 Service->UdpIo,\r
1756 Dhcp6ReceivePacket,\r
1757 Service,\r
1758 0\r
1759 );\r
1760\r
1761 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
1762 goto ON_ERROR;\r
1763 }\r
f75a7f56 1764\r
cc658224 1765 gBS->RestoreTPL (OldTpl);\r
1766 return EFI_SUCCESS;\r
f75a7f56 1767\r
cc658224 1768ON_ERROR:\r
f75a7f56 1769 gBS->RestoreTPL (OldTpl);\r
cc658224 1770 RemoveEntryList (&InfCb->Link);\r
1771 FreePool (InfCb);\r
1772\r
1773 return Status;\r
1774}\r
a3bcde70
HT
1775\r
1776/**\r
1777 Create the information request message and send it.\r
1778\r
1779 @param[in] Instance The pointer to the Dhcp6 instance.\r
1780 @param[in] InfCb The pointer to the information request control block.\r
1781 @param[in] SendClientId If TRUE, the client identifier option will be included in\r
1782 information request message. Otherwise, the client identifier\r
1783 option will not be included.\r
1784 @param[in] OptionRequest The pointer to the option request option.\r
1785 @param[in] OptionCount The number options in the OptionList.\r
1786 @param[in] OptionList The array pointers to the appended options.\r
1787 @param[in] Retransmission The pointer to the retransmission control.\r
1788\r
1789 @retval EFI_SUCCESS Created and sent the info-request message successfully.\r
1790 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
1791 @retval Others Failed to send the info-request message.\r
1792\r
1793**/\r
1794EFI_STATUS\r
1795Dhcp6SendInfoRequestMsg (\r
1796 IN DHCP6_INSTANCE *Instance,\r
1797 IN DHCP6_INF_CB *InfCb,\r
1798 IN BOOLEAN SendClientId,\r
1799 IN EFI_DHCP6_PACKET_OPTION *OptionRequest,\r
1800 IN UINT32 OptionCount,\r
1801 IN EFI_DHCP6_PACKET_OPTION *OptionList[],\r
1802 IN EFI_DHCP6_RETRANSMISSION *Retransmission\r
1803 )\r
1804{\r
1805 EFI_STATUS Status;\r
1806 EFI_DHCP6_PACKET *Packet;\r
1807 EFI_DHCP6_PACKET_OPTION *UserOpt;\r
1808 EFI_DHCP6_DUID *ClientId;\r
1809 DHCP6_SERVICE *Service;\r
1810 UINT8 *Cursor;\r
1811 UINT16 *Elapsed;\r
1812 UINT32 UserLen;\r
1813 UINTN Index;\r
1814 UINT16 Length;\r
1815\r
1816 ASSERT(OptionRequest);\r
1817\r
1818 Service = Instance->Service;\r
1819 ClientId = Service->ClientId;\r
1820 UserLen = NTOHS (OptionRequest->OpLen) + 4;\r
1821\r
1822 ASSERT(ClientId);\r
1823\r
1824 //\r
1825 // Calculate the added length of customized option list.\r
1826 //\r
1827 for (Index = 0; Index < OptionCount; Index++) {\r
1828 UserLen += (NTOHS (OptionList[Index]->OpLen) + 4);\r
1829 }\r
1830\r
1831 //\r
1832 // Create the Dhcp6 packet and initialize commone fields.\r
1833 //\r
1834 Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen);\r
1835 if (Packet == NULL) {\r
1836 return EFI_OUT_OF_RESOURCES;\r
1837 }\r
1838\r
1839 Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen;\r
1840 Packet->Length = sizeof (EFI_DHCP6_HEADER);\r
1841 Packet->Dhcp6.Header.MessageType = Dhcp6MsgInfoRequest;\r
1842 Packet->Dhcp6.Header.TransactionId = Service->Xid++;\r
1843\r
1844 InfCb->Xid = Packet->Dhcp6.Header.TransactionId;\r
1845\r
1846 //\r
1847 // Assembly Dhcp6 options for info-request message.\r
1848 //\r
1849 Cursor = Packet->Dhcp6.Option;\r
1850\r
1851 if (SendClientId) {\r
1852 Length = HTONS (ClientId->Length);\r
1853 Cursor = Dhcp6AppendOption (\r
1854 Cursor,\r
1855 HTONS (Dhcp6OptClientId),\r
1856 Length,\r
1857 ClientId->Duid\r
1858 );\r
1859 }\r
1860\r
1861 Cursor = Dhcp6AppendETOption (\r
1862 Cursor,\r
1863 Instance,\r
1864 &Elapsed\r
1865 );\r
1866\r
1867 Cursor = Dhcp6AppendOption (\r
1868 Cursor,\r
1869 OptionRequest->OpCode,\r
1870 OptionRequest->OpLen,\r
1871 OptionRequest->Data\r
1872 );\r
1873\r
1874 //\r
1875 // Append user-defined when configurate Dhcp6 service.\r
1876 //\r
1877 for (Index = 0; Index < OptionCount; Index++) {\r
1878\r
1879 UserOpt = OptionList[Index];\r
1880 Cursor = Dhcp6AppendOption(\r
1881 Cursor,\r
1882 UserOpt->OpCode,\r
1883 UserOpt->OpLen,\r
1884 UserOpt->Data\r
1885 );\r
1886 }\r
1887\r
1888 //\r
1889 // Determine the size/length of packet.\r
1890 //\r
1891 Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option);\r
1892 ASSERT (Packet->Size > Packet->Length + 8);\r
f75a7f56 1893\r
685e44a5 1894 //\r
1895 // Clear initial time for current transaction.\r
1896 //\r
1897 Instance->StartTime = 0;\r
a3bcde70
HT
1898\r
1899 //\r
1900 // Send info-request packet with no state.\r
1901 //\r
1902 Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
1903\r
1904 if (EFI_ERROR (Status)) {\r
1905 FreePool (Packet);\r
1906 return Status;\r
1907 }\r
1908\r
1909 //\r
1910 // Enqueue the sent packet for the retransmission in case reply timeout.\r
1911 //\r
1912 return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, Retransmission);\r
1913}\r
1914\r
1915\r
1916/**\r
1917 Create the Confirm message and send it.\r
1918\r
1919 @param[in] Instance The pointer to the Dhcp6 instance.\r
1920\r
1921 @retval EFI_SUCCESS Created and sent the confirm message successfully.\r
1922 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
1923 @retval EFI_DEVICE_ERROR An unexpected error.\r
1924 @retval Others Failed to send the confirm message.\r
1925\r
1926**/\r
1927EFI_STATUS\r
1928Dhcp6SendConfirmMsg (\r
1929 IN DHCP6_INSTANCE *Instance\r
1930 )\r
1931{\r
1932 UINT8 *Cursor;\r
1933 UINTN Index;\r
1934 UINT16 Length;\r
1935 UINT32 UserLen;\r
1936 EFI_STATUS Status;\r
1937 DHCP6_SERVICE *Service;\r
1938 EFI_DHCP6_DUID *ClientId;\r
1939 EFI_DHCP6_PACKET *Packet;\r
1940 EFI_DHCP6_PACKET_OPTION *UserOpt;\r
1941 UINT16 *Elapsed;\r
1942\r
1943 ASSERT (Instance->Config != NULL);\r
1944 ASSERT (Instance->IaCb.Ia != NULL);\r
1945 ASSERT (Instance->Service != NULL);\r
1946\r
1947 Service = Instance->Service;\r
1948 ClientId = Service->ClientId;\r
1949 ASSERT (ClientId != NULL);\r
1950\r
1951 //\r
1952 // Calculate the added length of customized option list.\r
1953 //\r
1954 UserLen = 0;\r
1955 for (Index = 0; Index < Instance->Config->OptionCount; Index++) {\r
1956 UserLen += (NTOHS (Instance->Config->OptionList[Index]->OpLen) + 4);\r
1957 }\r
1958\r
1959 //\r
1960 // Create the Dhcp6 packet and initialize common fields.\r
1961 //\r
1962 Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen);\r
1963 if (Packet == NULL) {\r
1964 return EFI_OUT_OF_RESOURCES;\r
1965 }\r
1966\r
1967 Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen;\r
1968 Packet->Length = sizeof (EFI_DHCP6_HEADER);\r
1969 Packet->Dhcp6.Header.MessageType = Dhcp6MsgConfirm;\r
1970 Packet->Dhcp6.Header.TransactionId = Service->Xid++;\r
1971\r
1972 //\r
1973 // Assembly Dhcp6 options for solicit message.\r
1974 //\r
1975 Cursor = Packet->Dhcp6.Option;\r
1976\r
1977 Length = HTONS (ClientId->Length);\r
1978 Cursor = Dhcp6AppendOption (\r
1979 Cursor,\r
1980 HTONS (Dhcp6OptClientId),\r
1981 Length,\r
1982 ClientId->Duid\r
1983 );\r
1984\r
1985 Cursor = Dhcp6AppendETOption (\r
1986 Cursor,\r
1987 Instance,\r
1988 &Elapsed\r
1989 );\r
1990\r
1991 Cursor = Dhcp6AppendIaOption (\r
1992 Cursor,\r
1993 Instance->IaCb.Ia,\r
1994 Instance->IaCb.T1,\r
685e44a5 1995 Instance->IaCb.T2,\r
1996 Packet->Dhcp6.Header.MessageType\r
a3bcde70
HT
1997 );\r
1998\r
1999 //\r
2000 // Append user-defined when configurate Dhcp6 service.\r
2001 //\r
2002 for (Index = 0; Index < Instance->Config->OptionCount; Index++) {\r
2003 UserOpt = Instance->Config->OptionList[Index];\r
2004 Cursor = Dhcp6AppendOption (\r
2005 Cursor,\r
2006 UserOpt->OpCode,\r
2007 UserOpt->OpLen,\r
2008 UserOpt->Data\r
2009 );\r
2010 }\r
2011\r
2012 //\r
2013 // Determine the size/length of packet.\r
2014 //\r
2015 Packet->Length += (UINT32) (Cursor - Packet->Dhcp6.Option);\r
2016 ASSERT (Packet->Size > Packet->Length + 8);\r
2017\r
2018 //\r
2019 // Callback to user with the packet to be sent and check the user's feedback.\r
2020 //\r
2021 Status = Dhcp6CallbackUser (Instance, Dhcp6SendConfirm, &Packet);\r
2022\r
2023 if (EFI_ERROR (Status)) {\r
2024 FreePool (Packet);\r
2025 return Status;\r
2026 }\r
2027\r
2028 //\r
2029 // Send confirm packet with the state transition from Dhcp6Bound to\r
2030 // Dhcp6Confirming.\r
2031 //\r
2032 Instance->IaCb.Ia->State = Dhcp6Confirming;\r
685e44a5 2033 //\r
2034 // Clear initial time for current transaction.\r
2035 //\r
2036 Instance->StartTime = 0;\r
a3bcde70
HT
2037\r
2038 Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
2039\r
2040 if (EFI_ERROR (Status)) {\r
2041 FreePool (Packet);\r
2042 return Status;\r
2043 }\r
2044\r
2045 //\r
2046 // Enqueue the sent packet for the retransmission in case reply timeout.\r
2047 //\r
2048 return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL);\r
2049}\r
2050\r
2051\r
2052\r
2053/**\r
2054 Handle with the Dhcp6 reply message.\r
2055\r
2056 @param[in] Instance The pointer to Dhcp6 instance.\r
2057 @param[in] Packet The pointer to the Dhcp6 reply message.\r
2058\r
2059 @retval EFI_SUCCESS Processed the reply message successfully.\r
2060 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
2061 @retval EFI_DEVICE_ERROR An unexpected error.\r
2062 @retval Others Failed to process the reply message.\r
2063\r
2064**/\r
2065EFI_STATUS\r
2066Dhcp6HandleReplyMsg (\r
2067 IN DHCP6_INSTANCE *Instance,\r
2068 IN EFI_DHCP6_PACKET *Packet\r
2069 )\r
2070{\r
2071 EFI_STATUS Status;\r
2072 UINT8 *Option;\r
2073 UINT16 StsCode;\r
2074\r
2075 ASSERT (Instance->Config != NULL);\r
2076 ASSERT (Instance->IaCb.Ia != NULL);\r
2077 ASSERT (Packet != NULL);\r
2078\r
685e44a5 2079 Status = EFI_SUCCESS;\r
2080\r
a3bcde70
HT
2081 if (Packet->Dhcp6.Header.MessageType != Dhcp6MsgReply) {\r
2082 return EFI_DEVICE_ERROR;\r
2083 }\r
2084\r
2085 //\r
2086 // If the client subsequently receives a valid reply message that includes a\r
2087 // rapid commit option since send a solicit with rapid commit option before,\r
2088 // preocess the reply message and discard any reply messages received in\r
2089 // response to the request message.\r
2090 // See details in the section-17.1.4 of rfc-3315.\r
2091 //\r
2092 Option = Dhcp6SeekOption (\r
2093 Packet->Dhcp6.Option,\r
2094 Packet->Length - 4,\r
2095 Dhcp6OptRapidCommit\r
2096 );\r
2097\r
2098 if ((Option != NULL && !Instance->Config->RapidCommit) || (Option == NULL && Instance->Config->RapidCommit)) {\r
2099 return EFI_DEVICE_ERROR;\r
2100 }\r
2101\r
2102 //\r
2103 // As to a valid reply packet in response to a request/renew/rebind packet,\r
2104 // ignore the packet if not contains the Ia option\r
2105 //\r
2106 if (Instance->IaCb.Ia->State == Dhcp6Requesting ||\r
2107 Instance->IaCb.Ia->State == Dhcp6Renewing ||\r
2108 Instance->IaCb.Ia->State == Dhcp6Rebinding\r
2109 ) {\r
2110\r
2111 Option = Dhcp6SeekIaOption (\r
2112 Packet->Dhcp6.Option,\r
2113 Packet->Length,\r
2114 &Instance->Config->IaDescriptor\r
2115 );\r
2116 if (Option == NULL) {\r
685e44a5 2117 return EFI_SUCCESS;\r
a3bcde70
HT
2118 }\r
2119 }\r
2120\r
2121 //\r
2122 // Callback to user with the received packet and check the user's feedback.\r
2123 //\r
2124 Status = Dhcp6CallbackUser (Instance, Dhcp6RcvdReply, &Packet);\r
2125\r
2126 if (EFI_ERROR (Status)) {\r
2127 return Status;\r
2128 }\r
2129\r
a3bcde70
HT
2130 //\r
2131 // When receive a valid reply packet in response to a decline/release packet,\r
2132 // the client considers the decline/release event completed regardless of the\r
2133 // status code.\r
2134 //\r
2135 if (Instance->IaCb.Ia->State == Dhcp6Declining || Instance->IaCb.Ia->State == Dhcp6Releasing) {\r
2136\r
2137 if (Instance->IaCb.Ia->IaAddressCount != 0) {\r
2138 Instance->IaCb.Ia->State = Dhcp6Bound;\r
2139 } else {\r
2140 ASSERT (Instance->IaCb.Ia->ReplyPacket);\r
2141 FreePool (Instance->IaCb.Ia->ReplyPacket);\r
2142 Instance->IaCb.Ia->ReplyPacket = NULL;\r
2143 Instance->IaCb.Ia->State = Dhcp6Init;\r
2144 }\r
2145\r
2146 //\r
2147 // For sync, set the success flag out of polling in decline/release.\r
2148 //\r
2149 Instance->UdpSts = EFI_SUCCESS;\r
2150\r
2151 //\r
2152 // For async, signal the Ia event to inform Ia infomation update.\r
2153 //\r
2154 if (Instance->Config->IaInfoEvent != NULL) {\r
2155 gBS->SignalEvent (Instance->Config->IaInfoEvent);\r
2156 }\r
2157\r
2158 //\r
2159 // Reset start time for next exchange.\r
2160 //\r
2161 Instance->StartTime = 0;\r
2162\r
685e44a5 2163 Status = EFI_SUCCESS;\r
2164 goto ON_EXIT;\r
a3bcde70
HT
2165 }\r
2166\r
2167 //\r
2168 // Upon the receipt of a valid reply packet in response to a solicit, request,\r
2169 // confirm, renew and rebind, the behavior depends on the status code option.\r
2170 // See the details in the section-18.1.8 of rfc-3315.\r
2171 //\r
2172 Option = NULL;\r
2173 Status = Dhcp6SeekStsOption (\r
2174 Instance,\r
2175 Packet,\r
2176 &Option\r
2177 );\r
2178\r
2179 if (!EFI_ERROR (Status)) {\r
a3bcde70
HT
2180 //\r
2181 // No status code or no error status code means succeed to reply.\r
2182 //\r
2183 Status = Dhcp6UpdateIaInfo (Instance, Packet);\r
685e44a5 2184 if (!EFI_ERROR (Status)) {\r
2185 //\r
2186 // Reset start time for next exchange.\r
2187 //\r
2188 Instance->StartTime = 0;\r
a3bcde70 2189\r
685e44a5 2190 //\r
2191 // Set bound state and store the reply packet.\r
2192 //\r
2193 if (Instance->IaCb.Ia->ReplyPacket != NULL) {\r
2194 FreePool (Instance->IaCb.Ia->ReplyPacket);\r
2195 }\r
a3bcde70 2196\r
685e44a5 2197 Instance->IaCb.Ia->ReplyPacket = AllocateZeroPool (Packet->Size);\r
a3bcde70 2198\r
685e44a5 2199 if (Instance->IaCb.Ia->ReplyPacket == NULL) {\r
2200 Status = EFI_OUT_OF_RESOURCES;\r
2201 goto ON_EXIT;\r
2202 }\r
a3bcde70 2203\r
685e44a5 2204 CopyMem (Instance->IaCb.Ia->ReplyPacket, Packet, Packet->Size);\r
a3bcde70 2205\r
685e44a5 2206 Instance->IaCb.Ia->State = Dhcp6Bound;\r
a3bcde70 2207\r
685e44a5 2208 //\r
2209 // For sync, set the success flag out of polling in start/renewrebind.\r
2210 //\r
2211 Instance->UdpSts = EFI_SUCCESS;\r
a3bcde70 2212\r
685e44a5 2213 //\r
2214 // Maybe this is a new round DHCP process due to some reason, such as NotOnLink\r
2215 // ReplyMsg for ConfirmMsg should triger new round to acquire new address. In that\r
2216 // case, clear old address.ValidLifetime and append to new address. Therefore, DHCP\r
2217 // consumers can be notified to flush old address.\r
2218 //\r
2219 Dhcp6AppendCacheIa (Instance);\r
a3bcde70 2220\r
685e44a5 2221 //\r
2222 // For async, signal the Ia event to inform Ia infomation update.\r
2223 //\r
2224 if (Instance->Config->IaInfoEvent != NULL) {\r
2225 gBS->SignalEvent (Instance->Config->IaInfoEvent);\r
2226 }\r
2227 } else if (Status == EFI_NOT_FOUND) {\r
2228 //\r
f75a7f56 2229 // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message,\r
685e44a5 2230 // the client sends a Renew or Rebind if the IA is not in the Reply message.\r
2231 // Return EFI_SUCCESS so we can continue to restart the Renew/Rebind process.\r
2232 //\r
2233 return EFI_SUCCESS;\r
a3bcde70 2234 }\r
f75a7f56 2235\r
685e44a5 2236 goto ON_EXIT;\r
f75a7f56 2237\r
a3bcde70
HT
2238 } else if (Option != NULL) {\r
2239 //\r
2240 // Any error status code option is found.\r
2241 //\r
2242 StsCode = NTOHS (ReadUnaligned16 ((UINT16 *) (Option + 4)));\r
2243 switch (StsCode) {\r
2244 case Dhcp6StsUnspecFail:\r
2245 //\r
2246 // It indicates the server is unable to process the message due to an\r
2247 // unspecified failure condition, so just retry if possible.\r
2248 //\r
2249 break;\r
2250\r
2251 case Dhcp6StsUseMulticast:\r
2252 //\r
2253 // It indicates the server receives a message via unicast from a client\r
2254 // to which the server has not sent a unicast option, so retry it by\r
2255 // multi-cast address.\r
2256 //\r
2257 if (Instance->Unicast != NULL) {\r
2258 FreePool (Instance->Unicast);\r
2259 Instance->Unicast = NULL;\r
2260 }\r
2261 break;\r
2262\r
2263 case Dhcp6StsNotOnLink:\r
2264 if (Instance->IaCb.Ia->State == Dhcp6Confirming) {\r
2265 //\r
2266 // Before initiate new round DHCP, cache the current IA.\r
2267 //\r
2268 Status = Dhcp6CacheIa (Instance);\r
2269 if (EFI_ERROR (Status)) {\r
2270 return Status;\r
2271 }\r
2272\r
2273 //\r
2274 // Restart S.A.R.R process to acquire new address.\r
2275 //\r
2276 Status = Dhcp6InitSolicitMsg (Instance);\r
2277 if (EFI_ERROR (Status)) {\r
2278 return Status;\r
2279 }\r
2280 }\r
2281 break;\r
2282\r
685e44a5 2283 case Dhcp6StsNoBinding:\r
2284 if (Instance->IaCb.Ia->State == Dhcp6Renewing || Instance->IaCb.Ia->State == Dhcp6Rebinding) {\r
2285 //\r
f75a7f56 2286 // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message, the client\r
685e44a5 2287 // sends a Request message if the IA contained a Status Code option with the NoBinding status.\r
2288 //\r
2289 Status = Dhcp6SendRequestMsg(Instance);\r
2290 if (EFI_ERROR (Status)) {\r
2291 return Status;\r
2292 }\r
2293 }\r
2294 break;\r
2295\r
a3bcde70
HT
2296 default:\r
2297 //\r
2298 // The other status code, just restart solicitation.\r
2299 //\r
2300 break;\r
2301 }\r
2302 }\r
2303\r
2304 return EFI_SUCCESS;\r
f75a7f56 2305\r
685e44a5 2306ON_EXIT:\r
2307\r
2308 if (!EFI_ERROR(Status)) {\r
2309 Status = Dhcp6DequeueRetry (\r
2310 Instance,\r
2311 Packet->Dhcp6.Header.TransactionId,\r
2312 FALSE\r
2313 );\r
2314 }\r
f75a7f56 2315\r
685e44a5 2316 return Status;\r
a3bcde70
HT
2317}\r
2318\r
2319\r
2320/**\r
2321 Select the appointed Dhcp6 advertisement message.\r
2322\r
2323 @param[in] Instance The pointer to the Dhcp6 instance.\r
2324 @param[in] AdSelect The pointer to the selected Dhcp6 advertisement message.\r
2325\r
2326 @retval EFI_SUCCESS Selected the right advertisement message successfully.\r
2327 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
2328 @retval Others Failed to select the advertise message.\r
2329\r
2330**/\r
2331EFI_STATUS\r
2332Dhcp6SelectAdvertiseMsg (\r
2333 IN DHCP6_INSTANCE *Instance,\r
2334 IN EFI_DHCP6_PACKET *AdSelect\r
2335 )\r
2336{\r
2337 EFI_STATUS Status;\r
2338 UINT8 *Option;\r
2339\r
2340 ASSERT (AdSelect != NULL);\r
2341\r
2342 //\r
2343 // Callback to user with the selected advertisement packet, and the user\r
2344 // might overwrite it.\r
2345 //\r
2346 Status = Dhcp6CallbackUser (Instance, Dhcp6SelectAdvertise, &AdSelect);\r
2347\r
2348 if (EFI_ERROR (Status)) {\r
2349 return Status;\r
2350 }\r
2351\r
2352 Instance->AdSelect = AdSelect;\r
2353\r
2354 //\r
2355 // Dequeue the sent packet for the retransmission since advertisement selected.\r
2356 //\r
2357 Status = Dhcp6DequeueRetry (\r
2358 Instance,\r
2359 AdSelect->Dhcp6.Header.TransactionId,\r
2360 FALSE\r
2361 );\r
2362\r
2363 if (EFI_ERROR(Status)) {\r
2364 return Status;\r
2365 }\r
2366\r
2367 //\r
2368 // Check whether there is server unicast option in the selected advertise\r
2369 // packet, and update it.\r
2370 //\r
2371 Option = Dhcp6SeekOption(\r
2372 AdSelect->Dhcp6.Option,\r
2373 AdSelect->Length - 4,\r
2374 Dhcp6OptServerUnicast\r
2375 );\r
2376\r
2377 if (Option != NULL) {\r
2378\r
2379 Instance->Unicast = AllocateZeroPool (sizeof(EFI_IPv6_ADDRESS));\r
2380\r
2381 if (Instance->Unicast == NULL) {\r
2382 return EFI_OUT_OF_RESOURCES;\r
2383 }\r
2384\r
2385 CopyMem (Instance->Unicast, Option + 4, sizeof(EFI_IPv6_ADDRESS));\r
2386 }\r
2387\r
2388 //\r
2389 // Update the information of the Ia by the selected advertisement message.\r
2390 //\r
2391 Status = Dhcp6UpdateIaInfo (Instance, AdSelect);\r
2392\r
2393 if (EFI_ERROR (Status)) {\r
2394 return Status;\r
2395 }\r
2396\r
2397 //\r
2398 // Send the request message to continue the S.A.R.R. process.\r
2399 //\r
2400 return Dhcp6SendRequestMsg (Instance);\r
2401}\r
2402\r
2403\r
2404/**\r
2405 Handle with the Dhcp6 advertisement message.\r
2406\r
2407 @param[in] Instance The pointer to the Dhcp6 instance.\r
2408 @param[in] Packet The pointer to the Dhcp6 advertisement message.\r
2409\r
2410 @retval EFI_SUCCESS Processed the advertisement message successfully.\r
2411 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
2412 @retval EFI_DEVICE_ERROR An unexpected error.\r
2413 @retval Others Failed to process the advertise message.\r
2414\r
2415**/\r
2416EFI_STATUS\r
2417Dhcp6HandleAdvertiseMsg (\r
2418 IN DHCP6_INSTANCE *Instance,\r
2419 IN EFI_DHCP6_PACKET *Packet\r
2420 )\r
2421{\r
2422 EFI_STATUS Status;\r
2423 UINT8 *Option;\r
a3bcde70
HT
2424 BOOLEAN Timeout;\r
2425\r
2426 ASSERT(Instance->Config);\r
2427 ASSERT(Instance->IaCb.Ia);\r
2428\r
2429 Timeout = FALSE;\r
a3bcde70
HT
2430\r
2431 //\r
2432 // If the client does receives a valid reply message that includes a rapid\r
2433 // commit option since a solicit with rapid commit optioin sent before, select\r
2434 // this reply message. Or else, process the advertise messages as normal.\r
2435 // See details in the section-17.1.4 of rfc-3315.\r
2436 //\r
2437 Option = Dhcp6SeekOption(\r
2438 Packet->Dhcp6.Option,\r
2439 Packet->Length - 4,\r
2440 Dhcp6OptRapidCommit\r
2441 );\r
2442\r
2443 if (Option != NULL && Instance->Config->RapidCommit && Packet->Dhcp6.Header.MessageType == Dhcp6MsgReply) {\r
2444\r
2445 return Dhcp6HandleReplyMsg (Instance, Packet);\r
2446 }\r
2447\r
2448 if (Packet->Dhcp6.Header.MessageType != Dhcp6MsgAdvertise) {\r
2449 return EFI_DEVICE_ERROR;\r
2450 }\r
2451\r
2452 //\r
2453 // Client must ignore any advertise message that includes a status code option\r
2454 // containing the value noaddrsavail, with the exception that the client may\r
2455 // display the associated status message to the user.\r
2456 // See the details in the section-17.1.3 of rfc-3315.\r
2457 //\r
685e44a5 2458 Status = Dhcp6SeekStsOption (\r
2459 Instance,\r
2460 Packet,\r
2461 &Option\r
a3bcde70 2462 );\r
685e44a5 2463 if (EFI_ERROR (Status)) {\r
2464 return EFI_DEVICE_ERROR;\r
a3bcde70
HT
2465 }\r
2466\r
2467 //\r
2468 // Callback to user with the received packet and check the user's feedback.\r
2469 //\r
2470 Status = Dhcp6CallbackUser (Instance, Dhcp6RcvdAdvertise, &Packet);\r
2471\r
2472 if (!EFI_ERROR (Status)) {\r
2473 //\r
2474 // Success means user choose the current advertisement packet.\r
2475 //\r
2476 if (Instance->AdSelect != NULL) {\r
2477 FreePool (Instance->AdSelect);\r
2478 }\r
2479\r
2480 //\r
2481 // Store the selected advertisement packet and set a flag.\r
2482 //\r
2483 Instance->AdSelect = AllocateZeroPool (Packet->Size);\r
2484\r
2485 if (Instance->AdSelect == NULL) {\r
2486 return EFI_OUT_OF_RESOURCES;\r
2487 }\r
2488\r
2489 CopyMem (Instance->AdSelect, Packet, Packet->Size);\r
2490\r
2491 Instance->AdPref = 0xff;\r
2492\r
2493 } else if (Status == EFI_NOT_READY) {\r
2494 //\r
2495 // Not_ready means user wants to continue to receive more advertise packets.\r
2496 //\r
2497 if (Instance->AdPref == 0xff && Instance->AdSelect == NULL) {\r
2498 //\r
2499 // It's a tricky point. The timer routine set adpref as 0xff if the first\r
2500 // rt timeout and no advertisement received, which means any advertisement\r
2501 // received will be selected after the first rt.\r
2502 //\r
2503 Timeout = TRUE;\r
2504 }\r
2505\r
2506 //\r
2507 // Check whether the current packet has a 255 preference option or not.\r
2508 // Take non-preference option as 0 value.\r
2509 //\r
2510 Option = Dhcp6SeekOption(\r
2511 Packet->Dhcp6.Option,\r
2512 Packet->Length - 4,\r
2513 Dhcp6OptPreference\r
2514 );\r
2515\r
2516 if (Instance->AdSelect == NULL || (Option != NULL && *(Option + 4) > Instance->AdPref)) {\r
2517 //\r
2518 // No advertisements received before or preference is more than other\r
2519 // advertisements received before. Then store the new packet and the\r
2520 // preference value.\r
2521 //\r
2522 if (Instance->AdSelect != NULL) {\r
2523 FreePool (Instance->AdSelect);\r
2524 }\r
2525\r
2526 Instance->AdSelect = AllocateZeroPool (Packet->Size);\r
2527\r
2528 if (Instance->AdSelect == NULL) {\r
2529 return EFI_OUT_OF_RESOURCES;\r
2530 }\r
2531\r
2532 CopyMem (Instance->AdSelect, Packet, Packet->Size);\r
2533\r
2534 if (Option != NULL) {\r
2535 Instance->AdPref = *(Option + 4);\r
2536 }\r
2537 } else {\r
2538 //\r
2539 // Non-preference and other advertisements received before or current\r
2540 // preference is less than other advertisements received before.\r
2541 // Leave the packet alone.\r
2542 }\r
2543\r
2544 } else {\r
2545 //\r
2546 // Other error status means termination.\r
2547 //\r
2548 return Status;\r
2549 }\r
2550\r
2551 //\r
2552 // Client must collect advertise messages as more as possible until the first\r
2553 // RT has elapsed, or get a highest preference 255 advertise.\r
2554 // See details in the section-17.1.2 of rfc-3315.\r
2555 //\r
2556 if (Instance->AdPref == 0xff || Timeout) {\r
2557 Status = Dhcp6SelectAdvertiseMsg (Instance, Instance->AdSelect);\r
2558 }\r
2559\r
2560 return Status;\r
2561}\r
2562\r
2563\r
2564/**\r
2565 The Dhcp6 stateful exchange process routine.\r
2566\r
2567 @param[in] Instance The pointer to the Dhcp6 instance.\r
2568 @param[in] Packet The pointer to the received Dhcp6 message.\r
2569\r
2570**/\r
2571VOID\r
2572Dhcp6HandleStateful (\r
2573 IN DHCP6_INSTANCE *Instance,\r
2574 IN EFI_DHCP6_PACKET *Packet\r
2575 )\r
2576{\r
2577 EFI_STATUS Status;\r
2578 EFI_DHCP6_DUID *ClientId;\r
2579 DHCP6_SERVICE *Service;\r
2580 UINT8 *Option;\r
2581\r
2582 Service = Instance->Service;\r
2583 ClientId = Service->ClientId;\r
2584 Status = EFI_SUCCESS;\r
2585\r
216f7970 2586 if (Instance->Config == NULL) {\r
a3bcde70
HT
2587 goto ON_CONTINUE;\r
2588 }\r
2589\r
2590 ASSERT (ClientId);\r
2591 ASSERT (Instance->Config);\r
2592 ASSERT (Instance->IaCb.Ia);\r
2593\r
2594 //\r
2595 // Discard the packet if not advertisement or reply packet.\r
2596 //\r
2597 if (Packet->Dhcp6.Header.MessageType != Dhcp6MsgAdvertise && Packet->Dhcp6.Header.MessageType != Dhcp6MsgReply) {\r
2598 goto ON_CONTINUE;\r
2599 }\r
2600\r
2601 //\r
2602 // Check whether include client Id or not.\r
2603 //\r
2604 Option = Dhcp6SeekOption(\r
2605 Packet->Dhcp6.Option,\r
2606 Packet->Length - 4,\r
2607 Dhcp6OptClientId\r
2608 );\r
2609\r
2610 if (Option == NULL || CompareMem (Option + 4, ClientId->Duid, ClientId->Length) != 0) {\r
2611 goto ON_CONTINUE;\r
2612 }\r
2613\r
2614 //\r
2615 // Check whether include server Id or not.\r
2616 //\r
2617 Option = Dhcp6SeekOption(\r
2618 Packet->Dhcp6.Option,\r
2619 Packet->Length - 4,\r
2620 Dhcp6OptServerId\r
2621 );\r
2622\r
2623 if (Option == NULL) {\r
2624 goto ON_CONTINUE;\r
2625 }\r
2626\r
2627 switch (Instance->IaCb.Ia->State) {\r
2628 case Dhcp6Selecting:\r
2629 //\r
2630 // Handle the advertisement message when in the Dhcp6Selecting state.\r
2631 // Do not need check return status, if failed, just continue to the next.\r
2632 //\r
2633 Dhcp6HandleAdvertiseMsg (Instance, Packet);\r
2634 break;\r
2635\r
2636 case Dhcp6Requesting:\r
2637 case Dhcp6Confirming:\r
2638 case Dhcp6Renewing:\r
2639 case Dhcp6Rebinding:\r
2640 case Dhcp6Releasing:\r
2641 case Dhcp6Declining:\r
2642 //\r
2643 // Handle the reply message when in the Dhcp6Requesting, Dhcp6Renewing\r
2644 // Dhcp6Rebinding, Dhcp6Releasing and Dhcp6Declining state.\r
2645 // If failed here, it should reset the current session.\r
2646 //\r
2647 Status = Dhcp6HandleReplyMsg (Instance, Packet);\r
2648 if (EFI_ERROR (Status)) {\r
2649 goto ON_EXIT;\r
2650 }\r
2651 break;\r
2652 default:\r
2653 //\r
2654 // Other state has not supported yet.\r
2655 //\r
2656 break;\r
2657 }\r
2658\r
2659ON_CONTINUE:\r
2660 //\r
2661 // Continue to receive the following Dhcp6 message.\r
2662 //\r
2663 Status = UdpIoRecvDatagram (\r
2664 Service->UdpIo,\r
2665 Dhcp6ReceivePacket,\r
2666 Service,\r
2667 0\r
2668 );\r
2669ON_EXIT:\r
2670 if (EFI_ERROR (Status)) {\r
2671 Dhcp6CleanupSession (Instance, Status);\r
2672 }\r
2673}\r
2674\r
2675\r
2676/**\r
2677 The Dhcp6 stateless exchange process routine.\r
2678\r
2679 @param[in] Instance The pointer to the Dhcp6 instance.\r
2680 @param[in] Packet The pointer to the received Dhcp6 message.\r
2681\r
2682**/\r
2683VOID\r
2684Dhcp6HandleStateless (\r
2685 IN DHCP6_INSTANCE *Instance,\r
2686 IN EFI_DHCP6_PACKET *Packet\r
2687 )\r
2688{\r
2689 EFI_STATUS Status;\r
2690 DHCP6_SERVICE *Service;\r
2691 DHCP6_INF_CB *InfCb;\r
2692 UINT8 *Option;\r
2693 BOOLEAN IsMatched;\r
2694\r
2695 Service = Instance->Service;\r
2696 Status = EFI_SUCCESS;\r
2697 IsMatched = FALSE;\r
2698 InfCb = NULL;\r
2699\r
a3bcde70
HT
2700 if (Packet->Dhcp6.Header.MessageType != Dhcp6MsgReply) {\r
2701 goto ON_EXIT;\r
2702 }\r
2703\r
2704 //\r
2705 // Check whether it's a desired Info-request message by Xid.\r
2706 //\r
2707 while (!IsListEmpty (&Instance->InfList)) {\r
2708 InfCb = NET_LIST_HEAD (&Instance->InfList, DHCP6_INF_CB, Link);\r
2709 if (InfCb->Xid == Packet->Dhcp6.Header.TransactionId) {\r
2710 IsMatched = TRUE;\r
2711 break;\r
2712 }\r
2713 }\r
2714\r
2715 if (!IsMatched) {\r
2716 goto ON_EXIT;\r
2717 }\r
2718\r
2719 //\r
2720 // Check whether include server Id or not.\r
2721 //\r
2722 Option = Dhcp6SeekOption (\r
2723 Packet->Dhcp6.Option,\r
2724 Packet->Length - 4,\r
2725 Dhcp6OptServerId\r
2726 );\r
2727\r
2728 if (Option == NULL) {\r
2729 goto ON_EXIT;\r
2730 }\r
2731\r
2732 //\r
2733 // Callback to user with the received packet and check the user's feedback.\r
2734 //\r
2735 Status = InfCb->ReplyCallback (\r
2736 &Instance->Dhcp6,\r
2737 InfCb->CallbackContext,\r
2738 Packet\r
2739 );\r
2740\r
2741 if (Status == EFI_NOT_READY) {\r
2742 //\r
2743 // Success or aborted will both stop this info-request exchange process,\r
2744 // but not ready means user wants to continue to receive reply.\r
2745 //\r
2746 goto ON_EXIT;\r
2747 }\r
2748\r
2749 //\r
2750 // Dequeue the sent packet from the txlist if the xid matched, and ignore\r
2751 // if no xid matched.\r
2752 //\r
2753 Dhcp6DequeueRetry (\r
2754 Instance,\r
2755 Packet->Dhcp6.Header.TransactionId,\r
2756 FALSE\r
2757 );\r
2758\r
2759 //\r
2760 // For sync, set the status out of polling for info-request.\r
2761 //\r
2762 Instance->UdpSts = Status;\r
2763\r
2764ON_EXIT:\r
2765\r
2766 Status = UdpIoRecvDatagram (\r
2767 Service->UdpIo,\r
2768 Dhcp6ReceivePacket,\r
2769 Service,\r
2770 0\r
2771 );\r
2772\r
2773 if (EFI_ERROR (Status)) {\r
2774 Dhcp6CleanupRetry (Instance, DHCP6_PACKET_STATELESS);\r
2775 }\r
2776}\r
2777\r
2778\r
2779/**\r
2780 The receive callback function for Dhcp6 exchange process.\r
2781\r
2782 @param[in] Udp6Wrap The pointer to the received net buffer.\r
2783 @param[in] EndPoint The pointer to the udp end point.\r
2784 @param[in] IoStatus The return status from udp io.\r
2785 @param[in] Context The opaque parameter to the function.\r
2786\r
2787**/\r
2788VOID\r
2789EFIAPI\r
2790Dhcp6ReceivePacket (\r
2791 IN NET_BUF *Udp6Wrap,\r
2792 IN UDP_END_POINT *EndPoint,\r
2793 IN EFI_STATUS IoStatus,\r
2794 IN VOID *Context\r
2795 )\r
2796{\r
2797 EFI_DHCP6_HEADER *Head;\r
2798 EFI_DHCP6_PACKET *Packet;\r
2799 DHCP6_SERVICE *Service;\r
2800 DHCP6_INSTANCE *Instance;\r
2801 DHCP6_TX_CB *TxCb;\r
2802 UINT32 Size;\r
2803 BOOLEAN IsDispatched;\r
2804 BOOLEAN IsStateless;\r
2805 LIST_ENTRY *Entry1;\r
2806 LIST_ENTRY *Next1;\r
2807 LIST_ENTRY *Entry2;\r
2808 LIST_ENTRY *Next2;\r
4701d965 2809 EFI_STATUS Status;\r
a3bcde70
HT
2810\r
2811 ASSERT (Udp6Wrap != NULL);\r
2812 ASSERT (Context != NULL);\r
2813\r
2814 Service = (DHCP6_SERVICE *) Context;\r
2815 Instance = NULL;\r
2816 Packet = NULL;\r
2817 IsDispatched = FALSE;\r
2818 IsStateless = FALSE;\r
2819\r
2820 if (EFI_ERROR (IoStatus)) {\r
2821 return ;\r
2822 }\r
2823\r
37b68011
FS
2824 if (Udp6Wrap->TotalSize < sizeof (EFI_DHCP6_HEADER)) {\r
2825 goto ON_CONTINUE;\r
2826 }\r
2827\r
a3bcde70
HT
2828 //\r
2829 // Copy the net buffer received from upd6 to a Dhcp6 packet.\r
2830 //\r
2831 Size = sizeof (EFI_DHCP6_PACKET) + Udp6Wrap->TotalSize;\r
2832 Packet = (EFI_DHCP6_PACKET *) AllocateZeroPool (Size);\r
2833\r
2834 if (Packet == NULL) {\r
2835 goto ON_CONTINUE;\r
2836 }\r
2837\r
2838 Packet->Size = Size;\r
2839 Head = &Packet->Dhcp6.Header;\r
2840 Packet->Length = NetbufCopy (Udp6Wrap, 0, Udp6Wrap->TotalSize, (UINT8 *) Head);\r
2841\r
2842 if (Packet->Length == 0) {\r
2843 goto ON_CONTINUE;\r
2844 }\r
2845\r
2846 //\r
2847 // Dispatch packet to right instance by transaction id.\r
2848 //\r
2849 NET_LIST_FOR_EACH_SAFE (Entry1, Next1, &Service->Child) {\r
2850\r
2851 Instance = NET_LIST_USER_STRUCT (Entry1, DHCP6_INSTANCE, Link);\r
2852\r
2853 NET_LIST_FOR_EACH_SAFE (Entry2, Next2, &Instance->TxList) {\r
2854\r
2855 TxCb = NET_LIST_USER_STRUCT (Entry2, DHCP6_TX_CB, Link);\r
2856\r
2857 if (Packet->Dhcp6.Header.TransactionId == TxCb->Xid) {\r
2858 //\r
2859 // Find the corresponding packet in tx list, and check it whether belongs\r
2860 // to stateful exchange process.\r
2861 //\r
2862 if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest) {\r
2863 IsStateless = TRUE;\r
2864 }\r
2865 IsDispatched = TRUE;\r
2866 break;\r
2867 }\r
2868 }\r
2869\r
2870 if (IsDispatched) {\r
2871 break;\r
2872 }\r
2873 }\r
2874\r
2875 //\r
2876 // Skip this packet if not dispatched to any instance.\r
2877 //\r
2878 if (!IsDispatched) {\r
2879 goto ON_CONTINUE;\r
2880 }\r
2881\r
2882 //\r
2883 // Dispatch the received packet ot the right instance.\r
2884 //\r
2885 if (IsStateless) {\r
2886 Dhcp6HandleStateless (Instance, Packet);\r
2887 } else {\r
2888 Dhcp6HandleStateful (Instance, Packet);\r
2889 }\r
2890\r
2891ON_CONTINUE:\r
2892\r
4701d965
GL
2893 if (!IsDispatched) {\r
2894 Status = UdpIoRecvDatagram (\r
2895 Service->UdpIo,\r
2896 Dhcp6ReceivePacket,\r
2897 Service,\r
2898 0\r
2899 );\r
2900 if (EFI_ERROR (Status)) {\r
01b699a9
SQ
2901 NET_LIST_FOR_EACH_SAFE (Entry1, Next1, &Service->Child) {\r
2902 Instance = NET_LIST_USER_STRUCT (Entry1, DHCP6_INSTANCE, Link);\r
2903 Dhcp6CleanupRetry (Instance, DHCP6_PACKET_ALL);\r
2904 }\r
4701d965
GL
2905 }\r
2906 }\r
2907\r
a3bcde70
HT
2908 NetbufFree (Udp6Wrap);\r
2909\r
2910 if (Packet != NULL) {\r
2911 FreePool (Packet);\r
2912 }\r
2913}\r
2914\r
2915/**\r
2916 Detect Link movement for specified network device.\r
2917\r
2918 This routine will try to invoke Snp->GetStatus() to get the media status.\r
2919 If media present status switches from unpresent to present, a link movement\r
2920 is detected. Note that the underlying UNDI driver may not support reporting\r
2921 media status from GET_STATUS command. If that, fail to detect link movement.\r
2922\r
2923 @param[in] Instance The pointer to DHCP6_INSTANCE.\r
2924\r
2925 @retval TRUE A link movement is detected.\r
2926 @retval FALSE A link movement is not detected.\r
2927\r
2928**/\r
2929BOOLEAN\r
2930Dhcp6LinkMovDetect (\r
2931 IN DHCP6_INSTANCE *Instance\r
2932 )\r
2933{\r
2934 UINT32 InterruptStatus;\r
2935 BOOLEAN MediaPresent;\r
2936 EFI_STATUS Status;\r
2937 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
2938\r
2939 ASSERT (Instance != NULL);\r
2940 Snp = Instance->Service->Snp;\r
2941 MediaPresent = Instance->MediaPresent;\r
2942\r
2943 //\r
2944 // Check whether SNP support media detection\r
2945 //\r
2946 if (!Snp->Mode->MediaPresentSupported) {\r
2947 return FALSE;\r
2948 }\r
2949\r
2950 //\r
2951 // Invoke Snp->GetStatus() to refresh MediaPresent field in SNP mode data\r
2952 //\r
2953 Status = Snp->GetStatus (Snp, &InterruptStatus, NULL);\r
2954 if (EFI_ERROR (Status)) {\r
2955 return FALSE;\r
2956 }\r
2957\r
2958 Instance->MediaPresent = Snp->Mode->MediaPresent;\r
2959 //\r
2960 // Media transimit Unpresent to Present means new link movement is detected.\r
2961 //\r
2962 if (!MediaPresent && Instance->MediaPresent) {\r
2963 return TRUE;\r
2964 }\r
2965 return FALSE;\r
2966}\r
2967\r
2968\r
2969/**\r
2970 The timer routine of the Dhcp6 instance for each second.\r
2971\r
2972 @param[in] Event The timer event.\r
2973 @param[in] Context The opaque parameter to the function.\r
2974\r
2975**/\r
2976VOID\r
2977EFIAPI\r
2978Dhcp6OnTimerTick (\r
2979 IN EFI_EVENT Event,\r
2980 IN VOID *Context\r
2981 )\r
2982{\r
2983 LIST_ENTRY *Entry;\r
2984 LIST_ENTRY *NextEntry;\r
2985 DHCP6_INSTANCE *Instance;\r
2986 DHCP6_TX_CB *TxCb;\r
2987 DHCP6_IA_CB *IaCb;\r
2988 UINT32 LossTime;\r
42737ed9 2989 EFI_STATUS Status;\r
a3bcde70
HT
2990\r
2991 ASSERT (Context != NULL);\r
2992\r
2993 Instance = (DHCP6_INSTANCE *) Context;\r
2994\r
2995 //\r
2996 // 1. Loop the tx list, count live time of every tx packet to check whether\r
2997 // need re-transmit or not.\r
2998 //\r
2999 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->TxList) {\r
3000\r
3001 TxCb = NET_LIST_USER_STRUCT (Entry, DHCP6_TX_CB, Link);\r
3002\r
3003 TxCb->TickTime++;\r
3004\r
3005 if (TxCb->TickTime > TxCb->RetryExp) {\r
3006 //\r
3007 // Handle the first rt in the transmission of solicit specially.\r
3008 //\r
129b8b09 3009 if ((TxCb->RetryCnt == 0 || TxCb->SolicitRetry) && TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgSolicit) {\r
a3bcde70
HT
3010 if (Instance->AdSelect == NULL) {\r
3011 //\r
3012 // Set adpref as 0xff here to indicate select any advertisement\r
3013 // afterwards.\r
3014 //\r
3015 Instance->AdPref = 0xff;\r
3016 } else {\r
3017 //\r
3018 // Select the advertisement received before.\r
3019 //\r
42737ed9 3020 Status = Dhcp6SelectAdvertiseMsg (Instance, Instance->AdSelect);\r
b9f256bb 3021 if (Status == EFI_ABORTED) {\r
3022 goto ON_CLOSE;\r
3023 } else if (EFI_ERROR (Status)) {\r
42737ed9 3024 TxCb->RetryCnt++;\r
3025 }\r
a3bcde70
HT
3026 return;\r
3027 }\r
3028 }\r
3029 //\r
3030 // Increase the retry count for the packet and add up the total loss time.\r
3031 //\r
3032 TxCb->RetryCnt++;\r
3033 TxCb->RetryLos += TxCb->RetryExp;\r
3034\r
3035 //\r
3036 // Check whether overflow the max retry count limit for this packet\r
3037 //\r
3038 if (TxCb->RetryCtl.Mrc != 0 && TxCb->RetryCtl.Mrc < TxCb->RetryCnt) {\r
b9f256bb 3039 Status = EFI_NO_RESPONSE;\r
a3bcde70
HT
3040 goto ON_CLOSE;\r
3041 }\r
3042\r
3043 //\r
3044 // Check whether overflow the max retry duration for this packet\r
3045 //\r
3046 if (TxCb->RetryCtl.Mrd != 0 && TxCb->RetryCtl.Mrd <= TxCb->RetryLos) {\r
b9f256bb 3047 Status = EFI_NO_RESPONSE;\r
a3bcde70
HT
3048 goto ON_CLOSE;\r
3049 }\r
3050\r
3051 //\r
3052 // Re-calculate retry expire timeout for the next time.\r
3053 //\r
3054 // Firstly, Check the new calculated time whether overflow the max retry\r
3055 // expire time.\r
3056 //\r
3057 TxCb->RetryExp = Dhcp6CalculateExpireTime (\r
3058 TxCb->RetryExp,\r
3059 FALSE,\r
3060 TRUE\r
3061 );\r
3062\r
3063 if (TxCb->RetryCtl.Mrt != 0 && TxCb->RetryCtl.Mrt < TxCb->RetryExp) {\r
3064 TxCb->RetryExp = Dhcp6CalculateExpireTime (\r
3065 TxCb->RetryCtl.Mrt,\r
3066 TRUE,\r
3067 TRUE\r
3068 );\r
3069 }\r
3070\r
3071 //\r
3072 // Secondly, Check the new calculated time whether overflow the max retry\r
3073 // duration time.\r
3074 //\r
3075 LossTime = TxCb->RetryLos + TxCb->RetryExp;\r
3076 if (TxCb->RetryCtl.Mrd != 0 && TxCb->RetryCtl.Mrd < LossTime) {\r
3077 TxCb->RetryExp = TxCb->RetryCtl.Mrd - TxCb->RetryLos;\r
3078 }\r
3079\r
3080 //\r
3081 // Reset the tick time for the next retransmission\r
3082 //\r
3083 TxCb->TickTime = 0;\r
3084\r
3085 //\r
3086 // Retransmit the last sent packet again.\r
3087 //\r
3088 Dhcp6TransmitPacket (Instance, TxCb->TxPacket, TxCb->Elapsed);\r
129b8b09 3089 TxCb->SolicitRetry = FALSE;\r
3090 if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgSolicit) {\r
3091 TxCb->SolicitRetry = TRUE;\r
3092 }\r
a3bcde70
HT
3093 }\r
3094 }\r
3095\r
3096 //\r
3097 // 2. Check the configured Ia, count lease time of every valid Ia to check\r
3098 // whether need to renew or rebind this Ia.\r
3099 //\r
3100 IaCb = &Instance->IaCb;\r
3101\r
3102 if (Instance->Config == NULL || IaCb->Ia == NULL) {\r
3103 return;\r
3104 }\r
3105\r
3106 if (IaCb->Ia->State == Dhcp6Bound || IaCb->Ia->State == Dhcp6Renewing || IaCb->Ia->State == Dhcp6Rebinding) {\r
3107\r
3108 IaCb->LeaseTime++;\r
3109\r
3110 if (IaCb->LeaseTime > IaCb->T2 && IaCb->Ia->State == Dhcp6Bound) {\r
3111 //\r
3112 // Exceed t2, send rebind packet to extend the Ia lease.\r
3113 //\r
3114 Dhcp6SendRenewRebindMsg (Instance, TRUE);\r
3115\r
3116 } else if (IaCb->LeaseTime > IaCb->T1 && IaCb->Ia->State == Dhcp6Bound) {\r
3117\r
3118 //\r
3119 // Exceed t1, send renew packet to extend the Ia lease.\r
3120 //\r
3121 Dhcp6SendRenewRebindMsg (Instance, FALSE);\r
3122 }\r
3123 }\r
3124\r
3125 //\r
3126 // 3. In any situation when a client may have moved to a new link, the\r
3127 // client MUST initiate a Confirm/Reply message exchange.\r
3128 //\r
3129 if (Dhcp6LinkMovDetect (Instance) && (IaCb->Ia->State == Dhcp6Bound)) {\r
3130 Dhcp6SendConfirmMsg (Instance);\r
3131 }\r
3132\r
3133 return;\r
3134\r
3135 ON_CLOSE:\r
3136\r
d2ea3b83
FS
3137 if (Dhcp6IsValidTxCb (Instance, TxCb) &&\r
3138 TxCb->TxPacket != NULL &&\r
b9f256bb 3139 (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest ||\r
a3bcde70 3140 TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgRenew ||\r
b9f256bb 3141 TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgConfirm)\r
a3bcde70
HT
3142 ) {\r
3143 //\r
3144 // The failure of renew/Confirm will still switch to the bound state.\r
3145 //\r
3146 if ((TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgRenew) ||\r
3147 (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgConfirm)) {\r
3148 ASSERT (Instance->IaCb.Ia);\r
3149 Instance->IaCb.Ia->State = Dhcp6Bound;\r
3150 }\r
3151 //\r
3152 // The failure of info-request will return no response.\r
3153 //\r
3154 if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest) {\r
3155 Instance->UdpSts = EFI_NO_RESPONSE;\r
3156 }\r
3157 Dhcp6DequeueRetry (\r
3158 Instance,\r
3159 TxCb->Xid,\r
3160 TRUE\r
3161 );\r
3162 } else {\r
3163 //\r
3164 // The failure of the others will terminate current state machine if timeout.\r
3165 //\r
b9f256bb 3166 Dhcp6CleanupSession (Instance, Status);\r
a3bcde70
HT
3167 }\r
3168}\r