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