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