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