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