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