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