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