VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c

最後變更 在這個檔案是 105670,由 vboxsync 提交於 4 月 前

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette