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