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