xref: /FreeRTOS-Plus-TCP-v4.0.0/source/FreeRTOS_DHCPv6.c (revision ae3cd024381c80437710445fe01a1bfb92e055f6)
1 /*
2  * FreeRTOS+TCP V2.3.1
3  * Copyright (C) 2022 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * http://aws.amazon.com/freertos
23  * http://www.FreeRTOS.org
24  */
25 
26 /**
27  * @file FreeRTOS_DHCPv6.c
28  * @brief A DHCPv6 client.
29  */
30 
31 /* Standard includes. */
32 #include <stdio.h>
33 #include <ctype.h>
34 
35 /* FreeRTOS includes. */
36 #include <FreeRTOS.h>
37 #include "task.h"
38 #include "timers.h"
39 #include "queue.h"
40 #include "semphr.h"
41 
42 /* FreeRTOS+TCP includes. */
43 #include "FreeRTOS_IP.h"
44 
45 /* *INDENT-OFF* */
46     #if ( ipconfigUSE_IPv6 != 0 ) && ( ipconfigUSE_DHCPv6 != 0 )
47 /* *INDENT-ON* */
48 
49 #include "FreeRTOS_Sockets.h"
50 #include "FreeRTOS_DHCPv6.h"
51 #include "FreeRTOS_DNS.h"
52 #include "NetworkBufferManagement.h"
53 #include "FreeRTOS_ARP.h"
54 #include "FreeRTOS_Sockets.h"
55 #include "FreeRTOS_IP_Private.h"
56 #include "FreeRTOS_IP_Timers.h"
57 
58 #include "FreeRTOS_BitConfig.h"
59 
60 #include "FreeRTOS_Routing.h"
61 
62 #include "FreeRTOS_ND.h"
63 
64 /* Timer parameters */
65 #ifndef dhcpINITIAL_DHCP_TX_PERIOD
66     /** @brief DHCP timer period in ms */
67     #define dhcpINITIAL_TIMER_PERIOD      ( pdMS_TO_TICKS( 250U ) )
68     /** @brief DHCP transmit period in ms */
69     #define dhcpINITIAL_DHCP_TX_PERIOD    ( pdMS_TO_TICKS( 5000U ) )
70 #endif
71 
72 /** @brief The following define is temporary and serves to make the /single source
73  * code more similar to the /multi version. */
74 
75 #define EP_DHCPData                    pxEndPoint->xDHCPData
76 /** @brief Macro to access the IPv6 settings from the pxEndPoint */
77 #define EP_IPv6_SETTINGS               pxEndPoint->ipv6_settings
78 
79 /** @brief The maximum size of send buffer. */
80 #define DHCPv6_SEND_MAX_BUFFER_SIZE    ( 256 )
81 
82 /** @brief When a reply is received, some options are mandatory for this driver. */
83 #define dhcpMANDATORY_OPTIONS                                      \
84     ( ( ( ( uint32_t ) 1U ) << DHCPv6_Option_Client_Identifier ) | \
85       ( ( ( uint32_t ) 1U ) << DHCPv6_Option_Server_Identifier ) )
86 
87 /** @brief The UDP socket which is shared by all end-points that need DHCPv6. */
88 static Socket_t xDHCPv6Socket;
89 
90 /** @brief A reference count makes sure that the UDP socket will be deleted when it
91  * is not used anymore. */
92 static BaseType_t xDHCPv6SocketUserCount;
93 
94 static BaseType_t prvIsOptionLengthValid( uint16_t usOption,
95                                           size_t uxOptionLength,
96                                           size_t uxRemainingSize );
97 
98 static BaseType_t prvDHCPv6Analyse( struct xNetworkEndPoint * pxEndPoint,
99                                     const uint8_t * pucAnswer,
100                                     size_t uxTotalLength,
101                                     DHCPMessage_IPv6_t * pxDHCPMessage );
102 
103 static void vDHCPv6ProcessEndPoint( BaseType_t xReset,
104                                     NetworkEndPoint_t * pxEndPoint,
105                                     DHCPMessage_IPv6_t * pxDHCPMessage );
106 
107 static void prvInitialiseDHCPv6( NetworkEndPoint_t * pxEndPoint );
108 
109 static void prvSendDHCPMessage( NetworkEndPoint_t * pxEndPoint );
110 
111 /*
112  * Create the DHCP socket, if it has not been created already.
113  */
114 static void prvCreateDHCPv6Socket( NetworkEndPoint_t * pxEndPoint );
115 
116 /*
117  * Close the DHCP socket, only when not in use anymore (i.e. xDHCPv6SocketUserCount = 0).
118  */
119 static void prvCloseDHCPv6Socket( NetworkEndPoint_t * pxEndPoint );
120 
121 #if ( ipconfigHAS_DEBUG_PRINTF == 1 )
122     static const char * prvStateName( eDHCPState_t eState );
123 #endif
124 
125 static BaseType_t xDHCPv6Process_PassReplyToEndPoint( struct xNetworkEndPoint * pxEndPoint );
126 
127 static void vDHCPv6ProcessEndPoint_HandleReply( NetworkEndPoint_t * pxEndPoint,
128                                                 DHCPMessage_IPv6_t * pxDHCPMessage );
129 
130 
131 static BaseType_t xDHCPv6ProcessEndPoint_HandleAdvertise( NetworkEndPoint_t * pxEndPoint,
132                                                           DHCPMessage_IPv6_t * pxDHCPMessage );
133 
134 static BaseType_t xDHCPv6ProcessEndPoint_HandleState( NetworkEndPoint_t * pxEndPoint,
135                                                       DHCPMessage_IPv6_t * pxDHCPMessage );
136 
137 static BaseType_t prvDHCPv6_subOption( uint16_t usOption,
138                                        const DHCPOptionSet_t * pxSet,
139                                        DHCPMessage_IPv6_t * pxDHCPMessage,
140                                        BitConfig_t * pxMessage );
141 
142 static BaseType_t prvDHCPv6_handleOption( struct xNetworkEndPoint * pxEndPoint,
143                                           uint16_t usOption,
144                                           const DHCPOptionSet_t * pxSet,
145                                           DHCPMessage_IPv6_t * pxDHCPMessage,
146                                           BitConfig_t * pxMessage );
147 
148 
149 /*-----------------------------------------------------------*/
150 
151 /**
152  * @brief DHCP IPv6 message object
153  */
154 static DHCPMessage_IPv6_t xDHCPMessage;
155 
156 /**
157  * @brief Get the DHCP state from a given endpoint.
158  *
159  * @param[in] pxEndPoint The end-point for which vDHCPv6Process() is called.
160  *
161  * @return DHCP state of the given endpoint
162  *
163  */
eGetDHCPv6State(struct xNetworkEndPoint * pxEndPoint)164 eDHCPState_t eGetDHCPv6State( struct xNetworkEndPoint * pxEndPoint )
165 {
166     configASSERT( pxEndPoint );
167     return EP_DHCPData.eDHCPState;
168 }
169 /*-----------------------------------------------------------*/
170 
171 /**
172  * @brief Check if option length is less than buffer size and larger than minimum requirement.
173  *
174  * @param[in] usOption The option code.
175  * @param[in] uxOptionLength The option length to check.
176  * @param[in] uxRemainingSize Remaining size in the buffer.
177  *
178  * @return pdTRUE if the length is valid, otherwise pdFALSE.
179  */
prvIsOptionLengthValid(uint16_t usOption,size_t uxOptionLength,size_t uxRemainingSize)180 static BaseType_t prvIsOptionLengthValid( uint16_t usOption,
181                                           size_t uxOptionLength,
182                                           size_t uxRemainingSize )
183 {
184     BaseType_t xReturn = pdTRUE;
185     size_t uxMinOptLength = 0U;
186 
187     switch( usOption )
188     {
189         case DHCPv6_Option_NonTemporaryAddress:
190             /* Refer to RFC3315 - sec 22.4, the length of IA_NA should never less than 12. */
191             uxMinOptLength = 12U;
192             break;
193 
194         case DHCPv6_Option_TemporaryAddress:
195             /* Refer to RFC3315 - sec 22.5, the length of IA_TA should never less than 4. */
196             uxMinOptLength = 4U;
197             break;
198 
199         case DHCPv6_Option_IA_Address:
200             /* Refer to RFC3315 - sec 22.6, the length of IA should never less than 24. */
201             uxMinOptLength = 24U;
202             break;
203 
204         case DHCPv6_Option_Preference:
205             /* Refer to RFC3315 - sec 22.8, the length of IA should never less than 1. */
206             uxMinOptLength = 1U;
207             break;
208 
209         case DHCPv6_Option_Status_Code:
210             /* Refer to RFC3315 - sec 22.13, the length of status code should never less than 2. */
211             uxMinOptLength = 2U;
212             break;
213 
214         case DHCPv6_Option_IA_for_Prefix_Delegation:
215             /* Refer to RFC3633 - sec 9, the length of IA_PD should never less than 12. */
216             uxMinOptLength = 12U;
217             break;
218 
219         case DHCPv6_Option_IA_Prefix:
220             /* Refer to RFC3633 - sec 10, the length of status code should never less than 25. */
221             uxMinOptLength = 25U;
222             break;
223 
224         default:
225             /* No constrain for other options. */
226             uxMinOptLength = 0U;
227             break;
228     }
229 
230     if( uxOptionLength < uxMinOptLength )
231     {
232         FreeRTOS_printf( ( "prvIsOptionLengthValid: Length %lu of option %u is less than minimum requirement %lu\n",
233                            uxOptionLength,
234                            usOption,
235                            uxMinOptLength ) );
236         xReturn = pdFALSE;
237     }
238     else if( uxOptionLength > uxRemainingSize )
239     {
240         FreeRTOS_printf( ( "prvIsOptionLengthValid: Length %lu of option %u is larger than remaining buffer size %lu\n",
241                            uxOptionLength,
242                            usOption,
243                            uxRemainingSize ) );
244         xReturn = pdFALSE;
245     }
246     else
247     {
248         /* Do nothing. */
249     }
250 
251     return xReturn;
252 }
253 
254 /**
255  * @brief A DHCP packet has a list of options, one of them is Status Code. This function is used to parse it.
256  * @param[in] uxLength Total length for status code.
257  * @param[in] pxMessage The raw packet as it was received.
258  *
259  * @return pdTRUE if status is success, otherwise pdFALSE.
260  */
prvDHCPv6_handleStatusCode(size_t uxLength,BitConfig_t * pxMessage)261 static BaseType_t prvDHCPv6_handleStatusCode( size_t uxLength,
262                                               BitConfig_t * pxMessage )
263 {
264     BaseType_t xReturn = pdTRUE;
265     /* Since length is checked before entering, we can read message directly. */
266     uint16_t usStatus = usBitConfig_read_16( pxMessage );
267     uint8_t ucMessage[ 50 ];
268     /* Minus 2 because we read 2 bytes for usStatus. */
269     size_t uxReadLength = uxLength - 2U;
270 
271     FreeRTOS_printf( ( "Got status code %u\n",
272                        usStatus ) );
273 
274     if( uxReadLength > sizeof( ucMessage ) - 1U )
275     {
276         uxReadLength = sizeof( ucMessage ) - 1U;
277     }
278 
279     ( void ) xBitConfig_read_uc( pxMessage, ucMessage, uxReadLength );
280     ucMessage[ uxReadLength ] = 0;
281     FreeRTOS_printf( ( "Msg: '%s'\n", ucMessage ) );
282 
283     /* Read the remainder, if present. */
284     if( uxLength > uxReadLength + 2U )
285     {
286         uxReadLength = uxLength - ( uxReadLength + 2U );
287         ( void ) xBitConfig_read_uc( pxMessage, NULL, uxReadLength );
288     }
289 
290     /* A status of 0 means: Success. (RFC 3315 - sec 24.4). */
291     if( usStatus != 0U )
292     {
293         xReturn = pdFALSE;
294     }
295 
296     return xReturn;
297 }
298 
299 /**
300  * @brief A DHCPv6 reply has been received. See to which end-point it belongs and pass it.
301  *
302  * @param[in] pxEndPoint The end-point for which vDHCPv6Process() is called.
303  *
304  * @return In case the message is passed to 'pxEndPoint', return pdFALSE, meaning that
305  *         the it has done its periodic processing.
306  */
xDHCPv6Process_PassReplyToEndPoint(struct xNetworkEndPoint * pxEndPoint)307 static BaseType_t xDHCPv6Process_PassReplyToEndPoint( struct xNetworkEndPoint * pxEndPoint )
308 {
309     uint32_t ulCompareResult = pdTRUE;
310     BaseType_t xDoProcess = pdTRUE;
311     struct xNetworkEndPoint * pxIterator;
312 
313     pxIterator = pxNetworkEndPoints;
314 
315     /* Find the end-point with given transaction ID. */
316     while( pxIterator != NULL )
317     {
318         if( ( pxIterator->bits.bIPv6 != pdFALSE_UNSIGNED ) && ( pxIterator->bits.bWantDHCP != pdFALSE_UNSIGNED ) )
319         {
320             FreeRTOS_printf( ( "vDHCPProcess: 0x%06X == 0x%06X ?\n",
321                                ( unsigned int ) xDHCPMessage.ulTransactionID,
322                                ( unsigned int ) pxIterator->xDHCPData.ulTransactionId ) );
323 
324             if( ( xDHCPMessage.ulTransactionID == pxIterator->xDHCPData.ulTransactionId ) &&
325                 ( pxIterator->xDHCPData.eDHCPState != eLeasedAddress ) )
326             {
327                 break;
328             }
329         }
330 
331         pxIterator = pxIterator->pxNext;
332     }
333 
334     if( pxIterator != NULL )
335     {
336         if( pxIterator->pxDHCPMessage->xServerID.usDUIDType != 0U )
337         {
338             /* Check if the ID-type, the length and the contents are equal. */
339             if( pxIterator->pxDHCPMessage->xServerID.uxLength > DHCPv6_MAX_CLIENT_SERVER_ID_LENGTH )
340             {
341                 FreeRTOS_printf( ( "DHCPv6 invalid uxLength.\n" ) );
342                 ulCompareResult = pdFAIL;
343             }
344             else if( ( xDHCPMessage.xServerID.usDUIDType != pxIterator->pxDHCPMessage->xServerID.usDUIDType ) ||
345                      ( xDHCPMessage.xServerID.uxLength != pxIterator->pxDHCPMessage->xServerID.uxLength ) ||
346                      ( memcmp( xDHCPMessage.xServerID.pucID, pxIterator->pxDHCPMessage->xServerID.pucID, pxIterator->pxDHCPMessage->xServerID.uxLength ) != 0 ) )
347             {
348                 FreeRTOS_printf( ( "DHCPv6 reply contains an unknown ID.\n" ) );
349                 ulCompareResult = pdFAIL;
350             }
351             else
352             {
353                 /* do nothing, coverity happy */
354             }
355         }
356 
357         if( ulCompareResult == pdPASS )
358         {
359             ( void ) memcpy( ( void * ) pxIterator->pxDHCPMessage, ( const void * ) &xDHCPMessage, sizeof( xDHCPMessage ) );
360 
361             /* The second parameter pdTRUE tells to check for a UDP message. */
362             vDHCPv6ProcessEndPoint( pdFALSE, pxIterator, pxIterator->pxDHCPMessage );
363             pxIterator->pxDHCPMessage->ucHasUID = 0U;
364 
365             if( pxEndPoint == pxIterator )
366             {
367                 xDoProcess = pdFALSE;
368             }
369         }
370     }
371 
372     return xDoProcess;
373 }
374 /*-----------------------------------------------------------*/
375 
376 /**
377  * @brief Check the DHCP socket and run one cycle of the DHCP state machine.
378  *
379  * @param[in] xReset When pdTRUE, the state machine needs to be reset.  This may happen
380  *            when the end-point has just become up.
381  * @param[in] pxEndPoint The end-point that wants a DHCPv6 address.
382  */
vDHCPv6Process(BaseType_t xReset,struct xNetworkEndPoint * pxEndPoint)383 void vDHCPv6Process( BaseType_t xReset,
384                      struct xNetworkEndPoint * pxEndPoint )
385 {
386     BaseType_t xDoProcess = pdTRUE;
387 
388     configASSERT( pxEndPoint != NULL );
389 
390     /* Is DHCP starting over? */
391     if( xReset != pdFALSE )
392     {
393         EP_DHCPData.eDHCPState = eInitialWait;
394 
395         if( pxEndPoint->pxDHCPMessage == NULL )
396         {
397             pxEndPoint->pxDHCPMessage = pvPortMalloc( sizeof( *pxEndPoint->pxDHCPMessage ) );
398 
399             if( pxEndPoint->pxDHCPMessage != NULL )
400             {
401                 ( void ) memset( pxEndPoint->pxDHCPMessage, 0, sizeof( *pxEndPoint->pxDHCPMessage ) );
402             }
403             else
404             {
405                 FreeRTOS_printf( ( "vDHCPv6Process: malloc failed %u bytes\n", ( unsigned int ) sizeof( *pxEndPoint->pxDHCPMessage ) ) );
406 
407                 /* Use static IP address. */
408                 taskENTER_CRITICAL();
409                 {
410                     ( void ) memcpy( EP_IPv6_SETTINGS.xIPAddress.ucBytes, pxEndPoint->ipv6_defaults.xIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
411                     iptraceDHCP_REQUESTS_FAILED_USING_DEFAULT_IPv6_ADDRESS( EP_IPv6_SETTINGS.xIPAddress );
412                 }
413                 taskEXIT_CRITICAL();
414 
415                 EP_DHCPData.eDHCPState = eNotUsingLeasedAddress;
416                 vIPSetDHCP_RATimerEnableState( pxEndPoint, pdFALSE );
417                 xDoProcess = pdFALSE;
418             }
419         }
420     }
421 
422     /* If there is a socket, check for incoming messages first. */
423     if( ( xDoProcess != pdFALSE ) && ( EP_DHCPData.xDHCPSocket != NULL ) )
424     {
425         uint8_t * pucUDPPayload;
426 
427         BaseType_t lBytes;
428         size_t uxLength;
429 
430         for( ; ; )
431         {
432             BaseType_t xResult;
433             BaseType_t xRecvFlags = ( BaseType_t ) FREERTOS_ZERO_COPY;
434 
435             /* Get the next UDP message. */
436             lBytes = FreeRTOS_recvfrom( EP_DHCPData.xDHCPSocket, &( pucUDPPayload ), 0, xRecvFlags, NULL, NULL );
437 
438             if( lBytes <= 0 )
439             {
440                 if( ( lBytes < 0 ) && ( lBytes != -pdFREERTOS_ERRNO_EAGAIN ) )
441                 {
442                     FreeRTOS_printf( ( "vDHCPProcess: FreeRTOS_recvfrom returns %d\n", ( int ) lBytes ) );
443                 }
444 
445                 break;
446             }
447 
448             uxLength = ( size_t ) lBytes;
449 
450             xResult = prvDHCPv6Analyse( pxEndPoint, pucUDPPayload, uxLength, &( xDHCPMessage ) );
451 
452             FreeRTOS_printf( ( "prvDHCPv6Analyse: %s\n", ( xResult == pdPASS ) ? "Pass" : "Fail" ) );
453 
454             if( xResult == pdPASS )
455             {
456                 xDoProcess = xDHCPv6Process_PassReplyToEndPoint( pxEndPoint );
457             }
458         }
459     }
460 
461     if( xDoProcess != pdFALSE )
462     {
463         /* Process the end-point, but do not expect incoming packets. */
464         vDHCPv6ProcessEndPoint( xReset, pxEndPoint, pxEndPoint->pxDHCPMessage );
465     }
466 }
467 /*-----------------------------------------------------------*/
468 
469 /**
470  * @brief The DHCP process is about ready: the server sends a confirmation that the
471  *        assigned IPv6 address may be used. The settings will be copied to 'pxEndPoint->ipv6_settings'.
472  * @param[in] pxEndPoint The end-point that is asking for an IP-address.
473  * @param[in] pxDHCPMessage The reply received from the DHCP server.
474  */
vDHCPv6ProcessEndPoint_HandleReply(NetworkEndPoint_t * pxEndPoint,DHCPMessage_IPv6_t * pxDHCPMessage)475 static void vDHCPv6ProcessEndPoint_HandleReply( NetworkEndPoint_t * pxEndPoint,
476                                                 DHCPMessage_IPv6_t * pxDHCPMessage )
477 {
478     size_t uxDNSIndex;
479 
480     FreeRTOS_printf( ( "vDHCPProcess: acked %xip\n", ( unsigned ) FreeRTOS_ntohl( EP_DHCPData.ulOfferedIPAddress ) ) );
481 
482     /* DHCP completed.  The IP address can now be used, and the
483      * timer set to the lease timeout time. */
484     pxEndPoint->ipv6_settings.uxPrefixLength = pxDHCPMessage->ucprefixLength;                                                             /* Number of valid bytes in the network prefix. */
485     ( void ) memcpy( pxEndPoint->ipv6_settings.xIPAddress.ucBytes, pxDHCPMessage->xIPAddress.xIP_IPv6.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
486     ( void ) memcpy( pxEndPoint->ipv6_settings.xPrefix.ucBytes, pxDHCPMessage->xPrefixAddress.xIP_IPv6.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); /* The network prefix, e.g. fe80::/10 */
487     /*pxEndPoint->xGatewayAddress;	/ * Gateway to the web. * / */
488 
489     for( uxDNSIndex = 0; uxDNSIndex < pxDHCPMessage->uxDNSCount; uxDNSIndex++ )
490     {
491         ( void ) memcpy( pxEndPoint->ipv6_settings.xDNSServerAddresses[ uxDNSIndex ].ucBytes, pxDHCPMessage->xDNSServers[ uxDNSIndex ].xIP_IPv6.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
492     }
493 
494     EP_DHCPData.eDHCPState = eLeasedAddress;
495 
496     iptraceDHCP_SUCCEDEED( EP_DHCPData.ulOfferedIPAddress );
497 
498     /* Close socket to ensure packets don't queue on it. */
499     prvCloseDHCPv6Socket( pxEndPoint );
500 
501     if( EP_DHCPData.ulLeaseTime == 0U )
502     {
503         EP_DHCPData.ulLeaseTime = dhcpv6DEFAULT_LEASE_TIME;
504     }
505     else if( EP_DHCPData.ulLeaseTime < dhcpv6MINIMUM_LEASE_TIME )
506     {
507         EP_DHCPData.ulLeaseTime = dhcpv6MINIMUM_LEASE_TIME;
508     }
509     else
510     {
511         /* The lease time is already valid. */
512     }
513 
514     /* Check for clashes. */
515 
516     vDHCP_RATimerReload( ( struct xNetworkEndPoint * ) pxEndPoint, EP_DHCPData.ulLeaseTime );
517 
518     /* DHCP failed, the default configured IP-address will be used
519      * Now call vIPNetworkUpCalls() to send the network-up event and
520      * start the ARP timer. */
521     vIPNetworkUpCalls( pxEndPoint );
522 }
523 /*-----------------------------------------------------------*/
524 
525 /**
526  * @brief An advertise packet has been received. Ask the application if
527  *        it it shall send a request to obtain this IP-address.
528  * @param[in] pxEndPoint The end-point that is asking for an IP-address.
529  * @param[in] pxDHCPMessage The advertisement received from the DHCP server.
530  * @return When the request will be send, pdFALSE will be returned.
531  */
xDHCPv6ProcessEndPoint_HandleAdvertise(NetworkEndPoint_t * pxEndPoint,DHCPMessage_IPv6_t * pxDHCPMessage)532 static BaseType_t xDHCPv6ProcessEndPoint_HandleAdvertise( NetworkEndPoint_t * pxEndPoint,
533                                                           DHCPMessage_IPv6_t * pxDHCPMessage )
534 {
535     BaseType_t xGivingUp = pdFALSE;
536 
537     #if ( ipconfigUSE_DHCP_HOOK != 0 ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE != 1 )
538         eDHCPCallbackAnswer_t eAnswer;
539     #endif /* ( ipconfigUSE_DHCP_HOOK != 0 ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE != 1 ) */
540 
541     #if ( ipconfigUSE_DHCP_HOOK != 0 ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE != 1 )
542         /* Ask the user if a DHCP request is required. */
543         eAnswer = xApplicationDHCPHook_Multi( eDHCPPhasePreRequest, pxEndPoint, &( pxDHCPMessage->xIPAddress ) );
544 
545         if( eAnswer == eDHCPContinue )
546     #endif /* ( ipconfigUSE_DHCP_HOOK != 0 ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE != 1 ) */
547     {
548         /* An offer has been made, the user wants to continue,
549          * generate the request. */
550         EP_DHCPData.xDHCPTxTime = xTaskGetTickCount();
551         EP_DHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;
552         /* Force creating a new transaction ID. */
553         pxDHCPMessage->ucHasUID = 0U;
554         prvSendDHCPMessage( pxEndPoint );
555         EP_DHCPData.eDHCPState = eWaitingAcknowledge;
556     }
557 
558     #if ( ipconfigUSE_DHCP_HOOK != 0 ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE != 1 )
559         else
560         {
561             if( eAnswer == eDHCPUseDefaults )
562             {
563                 ( void ) memcpy( &( pxEndPoint->ipv6_settings ), &( pxEndPoint->ipv6_defaults ), sizeof( pxEndPoint->ipv6_settings ) );
564             }
565 
566             /* The user indicates that the DHCP process does not continue. */
567             FreeRTOS_debug_printf( ( "xGivingUp because call-back 2\n" ) );
568             xGivingUp = pdTRUE;
569         }
570     #endif /* ( ipconfigUSE_DHCP_HOOK != 0 ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE != 1 ) */
571 
572     return xGivingUp;
573 }
574 /*-----------------------------------------------------------*/
575 
576 /**
577  * @brief This function is called periodically, or when a message was received for this end-point.
578  * @param[in] pxEndPoint The end-point that is asking for an IP-address.
579  * @param[in] pxDHCPMessage when not NULL, a message that was received for this end-point.
580  * @return It returns pdTRUE in case the DHCP process is to be cancelled.
581  */
xDHCPv6ProcessEndPoint_HandleState(NetworkEndPoint_t * pxEndPoint,DHCPMessage_IPv6_t * pxDHCPMessage)582 static BaseType_t xDHCPv6ProcessEndPoint_HandleState( NetworkEndPoint_t * pxEndPoint,
583                                                       DHCPMessage_IPv6_t * pxDHCPMessage )
584 
585 {
586     BaseType_t xGivingUp = pdFALSE;
587 
588     #if ( ipconfigUSE_DHCP_HOOK != 0 ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE != 1 )
589         eDHCPCallbackAnswer_t eAnswer;
590     #endif /* ( ipconfigUSE_DHCP_HOOK != 0 ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE != 1 ) */
591 
592     configASSERT( pxDHCPMessage != NULL );
593 
594     switch( EP_DHCPData.eDHCPState )
595     {
596         case eInitialWait:
597 
598             /* Initial state.  Create the DHCP socket, timer, etc. if they
599              * have not already been created. */
600             prvInitialiseDHCPv6( pxEndPoint );
601             EP_DHCPData.eDHCPState = eWaitingSendFirstDiscover;
602             break;
603 
604         case eWaitingSendFirstDiscover:
605             /* Ask the user if a DHCP discovery is required. */
606             #if ( ipconfigUSE_DHCP_HOOK != 0 ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE != 1 )
607                 eAnswer = xApplicationDHCPHook_Multi( eDHCPPhasePreDiscover, pxEndPoint, &( pxDHCPMessage->xIPAddress ) );
608 
609                 if( eAnswer == eDHCPContinue )
610             #endif /* ( ipconfigUSE_DHCP_HOOK != 0 ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE != 1 ) */
611             {
612                 /* See if prvInitialiseDHCPv6() has created a socket. */
613                 if( EP_DHCPData.xDHCPSocket == NULL )
614                 {
615                     FreeRTOS_debug_printf( ( "xGivingUp because socket is closed\n" ) );
616                     xGivingUp = pdTRUE;
617                 }
618                 else
619                 {
620                     /* Send the first discover request. */
621                     EP_DHCPData.xDHCPTxTime = xTaskGetTickCount();
622                     prvSendDHCPMessage( pxEndPoint );
623                     EP_DHCPData.eDHCPState = eWaitingOffer;
624                 }
625             }
626 
627             #if ( ipconfigUSE_DHCP_HOOK != 0 ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE != 1 )
628                 else
629                 {
630                     if( eAnswer == eDHCPUseDefaults )
631                     {
632                         ( void ) memcpy( &( pxEndPoint->ipv6_settings ), &( pxEndPoint->ipv6_defaults ), sizeof( pxEndPoint->ipv6_settings ) );
633                     }
634 
635                     /* The user indicates that the DHCP process does not continue. */
636                     FreeRTOS_debug_printf( ( "xGivingUp because call-back\n" ) );
637                     xGivingUp = pdTRUE;
638                 }
639             #endif /* ( ipconfigUSE_DHCP_HOOK != 0 ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE != 1 ) */
640             break;
641 
642         case eWaitingOffer:
643 
644             xGivingUp = pdFALSE;
645 
646             /* Look for offers coming in. */
647             if( pxDHCPMessage->uxMessageType == DHCPv6_message_Type_Advertise )
648             {
649                 xGivingUp = xDHCPv6ProcessEndPoint_HandleAdvertise( pxEndPoint, pxDHCPMessage );
650             }
651 
652             /* Is it time to send another Discover? */
653             else if( ( xTaskGetTickCount() - EP_DHCPData.xDHCPTxTime ) > EP_DHCPData.xDHCPTxPeriod )
654             {
655                 /* It is time to send another Discover.  Increase the time
656                  * period, and if it has not got to the point of giving up - send
657                  * another discovery. */
658                 EP_DHCPData.xDHCPTxPeriod <<= 1;
659 
660                 if( EP_DHCPData.xDHCPTxPeriod <= ipconfigMAXIMUM_DISCOVER_TX_PERIOD )
661                 {
662                     EP_DHCPData.xDHCPTxTime = xTaskGetTickCount();
663                     /* Make sure that the DHCP solicit request will be sent. */
664                     EP_DHCPData.eDHCPState = eWaitingSendFirstDiscover;
665                     prvSendDHCPMessage( pxEndPoint );
666                     EP_DHCPData.eDHCPState = eWaitingOffer;
667                     FreeRTOS_debug_printf( ( "vDHCPProcess: timeout %lu ticks\n", EP_DHCPData.xDHCPTxPeriod ) );
668                 }
669                 else
670                 {
671                     FreeRTOS_debug_printf( ( "vDHCPProcess: giving up %lu > %lu ticks\n", EP_DHCPData.xDHCPTxPeriod, ipconfigMAXIMUM_DISCOVER_TX_PERIOD ) );
672 
673                     xGivingUp = pdTRUE;
674                 }
675             }
676             else
677             {
678                 /* There was no DHCP reply, there was no time-out, just keep on waiting. */
679             }
680 
681             break;
682 
683         case eWaitingAcknowledge:
684 
685             if( pxDHCPMessage->uxMessageType == DHCPv6_message_Type_Reply )
686             {
687                 /* DHCP completed.  The IP address can now be used, and the
688                  * timer set to the lease timeout time. */
689                 vDHCPv6ProcessEndPoint_HandleReply( pxEndPoint, pxDHCPMessage );
690             }
691             else if( ( xTaskGetTickCount() - EP_DHCPData.xDHCPTxTime ) > EP_DHCPData.xDHCPTxPeriod )
692             {
693                 /* It is time to send another Request.  Increase the time
694                  * period, and if it has not got to the point of giving up - send
695                  * another discovery. */
696                 EP_DHCPData.xDHCPTxPeriod <<= 1;
697 
698                 if( EP_DHCPData.xDHCPTxPeriod <= ipconfigMAXIMUM_DISCOVER_TX_PERIOD )
699                 {
700                     EP_DHCPData.xDHCPTxTime = xTaskGetTickCount();
701                     /* Make sure that the DHCPv6_message_Type_Request will be sent. */
702                     EP_DHCPData.eDHCPState = eWaitingOffer;
703                     prvSendDHCPMessage( pxEndPoint );
704                     EP_DHCPData.eDHCPState = eWaitingAcknowledge;
705                     FreeRTOS_debug_printf( ( "vDHCPProcess: timeout %lu ticks\n", EP_DHCPData.xDHCPTxPeriod ) );
706                 }
707                 else
708                 {
709                     /* Give up, start again. */
710                     EP_DHCPData.eDHCPState = eInitialWait;
711                     FreeRTOS_debug_printf( ( "vDHCPProcess: timeout period is out of bound, restart DHCPv6\n" ) );
712                     vDHCP_RATimerReload( pxEndPoint, dhcpINITIAL_TIMER_PERIOD );
713                 }
714             }
715 
716             break;
717 
718         case eLeasedAddress:
719 
720             /* Resend the request at the appropriate time to renew the lease. */
721             prvCreateDHCPv6Socket( pxEndPoint );
722 
723             EP_DHCPData.xDHCPTxTime = xTaskGetTickCount();
724             EP_DHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;
725             prvSendDHCPMessage( pxEndPoint );
726             EP_DHCPData.eDHCPState = eWaitingAcknowledge;
727 
728             /* From now on, we should be called more often */
729             vDHCP_RATimerReload( pxEndPoint, dhcpINITIAL_TIMER_PERIOD );
730 
731             break;
732 
733         case eNotUsingLeasedAddress:
734 
735             vIPSetDHCP_RATimerEnableState( pxEndPoint, pdFALSE );
736             break;
737 
738         default:
739             /* Lint: all options are included. */
740             break;
741     }
742 
743     return xGivingUp;
744 }
745 /*-----------------------------------------------------------*/
746 
747 /**
748  * @brief Run one cycle of the DHCP state machine.
749  *
750  * @param[in] xReset pdTRUE is the state machine has to be reset.
751  * @param[in] pxEndPoint The end-point that needs DHCP.
752  * @param[in] pxDHCPMessage A DHCP message that has just been received, or NULL.
753  */
vDHCPv6ProcessEndPoint(BaseType_t xReset,NetworkEndPoint_t * pxEndPoint,DHCPMessage_IPv6_t * pxDHCPMessage)754 static void vDHCPv6ProcessEndPoint( BaseType_t xReset,
755                                     NetworkEndPoint_t * pxEndPoint,
756                                     DHCPMessage_IPv6_t * pxDHCPMessage )
757 {
758     BaseType_t xGivingUp = pdFALSE;
759 
760     /* Is DHCP starting over? */
761     if( xReset != pdFALSE )
762     {
763         EP_DHCPData.eDHCPState = eInitialWait;
764     }
765 
766     if( ( EP_DHCPData.eDHCPState != EP_DHCPData.eExpectedState ) && ( xReset == pdFALSE ) )
767     {
768         /* When the DHCP event was generated, the DHCP client was
769         * in a different state.  Therefore, ignore this event. */
770         FreeRTOS_debug_printf( ( "vDHCPv6ProcessEndPoint: wrong state: expect: %d got: %d : ignore\n",
771                                  EP_DHCPData.eExpectedState, EP_DHCPData.eDHCPState ) );
772     }
773     else
774     {
775         #if ( ipconfigHAS_DEBUG_PRINTF == 1 )
776             {
777                 static eDHCPState_t lastState = eNotUsingLeasedAddress;
778 
779                 if( lastState != EP_DHCPData.eDHCPState )
780                 {
781                     lastState = EP_DHCPData.eDHCPState;
782                     FreeRTOS_debug_printf( ( "vDHCPv6ProcessEndPoint: enter %s (%d)\n", prvStateName( EP_DHCPData.eDHCPState ), EP_DHCPData.eDHCPState ) );
783                 }
784             }
785         #endif /* ( ipconfigHAS_DEBUG_PRINTF == 1 ) */
786 
787         xGivingUp = xDHCPv6ProcessEndPoint_HandleState( pxEndPoint, pxDHCPMessage );
788 
789         if( xGivingUp != pdFALSE )
790         {
791             FreeRTOS_debug_printf( ( "vDHCPv6ProcessEndPoint: Giving up\n" ) );
792 
793             /* xGivingUp became true either because of a time-out, or because
794              * xApplicationDHCPHook_Multi() returned another value than 'eDHCPContinue',
795              * meaning that the conversion is cancelled from here. */
796 
797             /* Revert to static IP address. */
798             taskENTER_CRITICAL();
799             {
800                 ( void ) memcpy( EP_IPv6_SETTINGS.xIPAddress.ucBytes, pxEndPoint->ipv6_defaults.xIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
801                 iptraceDHCP_REQUESTS_FAILED_USING_DEFAULT_IPv6_ADDRESS( EP_IPv6_SETTINGS.xIPAddress );
802             }
803             taskEXIT_CRITICAL();
804 
805             EP_DHCPData.eDHCPState = eNotUsingLeasedAddress;
806             vIPSetDHCP_RATimerEnableState( pxEndPoint, pdFALSE );
807 
808             /* Close socket to ensure packets don't queue on it. */
809             prvCloseDHCPv6Socket( pxEndPoint );
810 
811             /* DHCP failed, the default configured IP-address will be used. Now
812              * call vIPNetworkUpCalls() to send the network-up event and start the ARP
813              * timer. */
814             vIPNetworkUpCalls( pxEndPoint );
815         }
816     }
817 }
818 /*-----------------------------------------------------------*/
819 
820 /**
821  * @brief Close the shared UDP/DHCP socket.  This results in lowering the reference count.
822  *        The last user of the socket will close it.
823  *
824  * @param[in] pxEndPoint The end-point that wants to close the socket.
825  */
prvCloseDHCPv6Socket(NetworkEndPoint_t * pxEndPoint)826 static void prvCloseDHCPv6Socket( NetworkEndPoint_t * pxEndPoint )
827 {
828     if( ( EP_DHCPData.xDHCPSocket == NULL ) || ( EP_DHCPData.xDHCPSocket != xDHCPv6Socket ) )
829     {
830         /* the socket can not be closed. */
831     }
832     else if( xDHCPv6SocketUserCount > 0 )
833     {
834         xDHCPv6SocketUserCount--;
835 
836         if( xDHCPv6SocketUserCount == 0 )
837         {
838             /* This modules runs from the IP-task. Use the internal
839              * function 'vSocketClose()` to close the socket. */
840             ( void ) vSocketClose( xDHCPv6Socket );
841             xDHCPv6Socket = NULL;
842         }
843 
844         EP_DHCPData.xDHCPSocket = NULL;
845     }
846     else
847     {
848         /* Strange: there is a socket, but there are no users. */
849     }
850 
851     FreeRTOS_printf( ( "DHCP-socket[%02x-%02x]: closed, user count %d\n",
852                        pxEndPoint->xMACAddress.ucBytes[ 4 ],
853                        pxEndPoint->xMACAddress.ucBytes[ 5 ],
854                        ( int ) xDHCPv6SocketUserCount ) );
855 }
856 
857 /**
858  * @brief Return the UDP/DHCP socket, or create if it doesn't exist.
859  *
860  * @param[in] pxEndPoint The end-point that needs the socket.
861  */
prvCreateDHCPv6Socket(NetworkEndPoint_t * pxEndPoint)862 static void prvCreateDHCPv6Socket( NetworkEndPoint_t * pxEndPoint )
863 {
864     struct freertos_sockaddr xAddress;
865     BaseType_t xReturn;
866     TickType_t xTimeoutTime = ( TickType_t ) 0;
867 
868     if( ( xDHCPv6Socket != NULL ) && ( EP_DHCPData.xDHCPSocket == xDHCPv6Socket ) )
869     {
870         /* the socket is still valid. */
871     }
872     else if( xDHCPv6Socket == NULL ) /* Create the socket, if it has not already been created. */
873     {
874         xDHCPv6Socket = FreeRTOS_socket( FREERTOS_AF_INET6, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );
875         configASSERT( xSocketValid( xDHCPv6Socket ) == pdTRUE );
876 
877         /* Ensure the Rx and Tx timeouts are zero as the DHCP executes in the
878          * context of the IP task. */
879         ( void ) FreeRTOS_setsockopt( xDHCPv6Socket, 0, FREERTOS_SO_RCVTIMEO, &( xTimeoutTime ), sizeof( TickType_t ) );
880         ( void ) FreeRTOS_setsockopt( xDHCPv6Socket, 0, FREERTOS_SO_SNDTIMEO, &( xTimeoutTime ), sizeof( TickType_t ) );
881 
882         memset( &xAddress, 0, sizeof( xAddress ) );
883         xAddress.sin_family = FREERTOS_AF_INET6;
884         xAddress.sin_len = ( uint8_t ) sizeof( xAddress );
885         /* Bind to the standard DHCP client port. */
886         xAddress.sin_port = FreeRTOS_htons( ipDHCPv6_CLIENT_PORT );
887         xReturn = vSocketBind( xDHCPv6Socket, &xAddress, sizeof( xAddress ), pdFALSE );
888         configASSERT( xReturn == 0 );
889         xDHCPv6SocketUserCount = 1;
890         FreeRTOS_printf( ( "DHCP-socket[%02x-%02x]: DHCP Socket Create\n",
891                            pxEndPoint->xMACAddress.ucBytes[ 4 ],
892                            pxEndPoint->xMACAddress.ucBytes[ 5 ] ) );
893 
894         ( void ) xReturn;
895     }
896     else
897     {
898         xDHCPv6SocketUserCount++;
899     }
900 
901     EP_DHCPData.xDHCPSocket = xDHCPv6Socket;
902 }
903 /*-----------------------------------------------------------*/
904 
905 /**
906  * @brief Initialise the DHCP state machine of a given end-point.
907  *
908  * @param[in] pxEndPoint The end-point.
909  */
prvInitialiseDHCPv6(NetworkEndPoint_t * pxEndPoint)910 static void prvInitialiseDHCPv6( NetworkEndPoint_t * pxEndPoint )
911 {
912     /* Initialise the parameters that will be set by the DHCP process. Per
913      * https://www.ietf.org/rfc/rfc2131.txt, Transaction ID should be a random
914      * value chosen by the client. */
915 
916     /* Check for random number generator API failure. */
917     EP_DHCPData.ulOfferedIPAddress = 0U;
918     EP_DHCPData.ulDHCPServerAddress = 0U;
919     EP_DHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;
920     /* Force creating a new transaction ID. */
921     pxEndPoint->pxDHCPMessage->ucHasUID = 0U;
922 
923     /* Create the DHCP socket if it has not already been created. */
924     prvCreateDHCPv6Socket( pxEndPoint );
925     FreeRTOS_debug_printf( ( "prvInitialiseDHCPv6: start after %lu ticks\n", dhcpINITIAL_TIMER_PERIOD ) );
926     vDHCP_RATimerReload( pxEndPoint, dhcpINITIAL_TIMER_PERIOD );
927 }
928 /*-----------------------------------------------------------*/
929 
930 /**
931  * @brief Send a DHCPv6 message to a DHCP server.
932  *
933  * @param[in] pxEndPoint The end-point for which a message will be sent.
934  */
prvSendDHCPMessage(NetworkEndPoint_t * pxEndPoint)935 static void prvSendDHCPMessage( NetworkEndPoint_t * pxEndPoint )
936 {
937     BaseType_t xRandomOk = pdTRUE;
938     DHCPMessage_IPv6_t * pxDHCPMessage = NULL;
939 
940     configASSERT( pxEndPoint != NULL );
941 
942     pxDHCPMessage = pxEndPoint->pxDHCPMessage;
943 
944     if( pxDHCPMessage->ucHasUID == 0U )
945     {
946         uint32_t ulTransactionID = 0U;
947         uint32_t ulCurTime;
948 
949         xRandomOk = xApplicationGetRandomNumber( &( ulTransactionID ) );
950         ulTransactionID &= 0xffffffU;
951 
952         /* The application should supply the following time-function. */
953         ulCurTime = ulApplicationTimeHook();
954 
955         pxDHCPMessage->ulTimeStamp = ulCurTime - ( uint32_t ) SECS_FROM_1970_TILL_2000;
956         pxDHCPMessage->ucHasUID = 1U;
957         pxDHCPMessage->ucTransactionID[ 0 ] = ( uint8_t ) ( ( ulTransactionID >> 16 ) & 0xffU );
958         pxDHCPMessage->ucTransactionID[ 1 ] = ( uint8_t ) ( ( ulTransactionID >> 8 ) & 0xffU );
959         pxDHCPMessage->ucTransactionID[ 2 ] = ( uint8_t ) ( ulTransactionID & 0xffU );
960         EP_DHCPData.ulTransactionId = ulTransactionID;
961         FreeRTOS_debug_printf( ( "Created transaction ID : 0x%06X\n", ulTransactionID ) );
962     }
963 
964     if( ( xRandomOk == pdPASS ) && ( EP_DHCPData.xDHCPSocket != NULL ) )
965     {
966         BitConfig_t xMessage;
967         struct freertos_sockaddr xAddress;
968         uint8_t ucMessageType = 0;
969 
970         /* Not useful, but MISRA issues a mandatory warning. */
971         ( void ) memset( &( xMessage ), 0, sizeof( xMessage ) );
972 
973         if( xBitConfig_init( &( xMessage ), NULL, DHCPv6_SEND_MAX_BUFFER_SIZE ) == pdTRUE )
974         {
975             switch( EP_DHCPData.eDHCPState )
976             {
977                 case eWaitingSendFirstDiscover:
978                     ucMessageType = DHCPv6_message_Type_Solicit;
979                     break;
980 
981                 case eWaitingOffer:
982                 case eLeasedAddress:
983                     ucMessageType = DHCPv6_message_Type_Request;
984                     break;
985 
986                 default:
987                     /* No message to be sent in this stage. */
988                     break;
989             }
990 
991             if( ucMessageType != 0U )
992             {
993                 vBitConfig_write_8( &( xMessage ), ucMessageType ); /* 1 Solicit, 3, request */
994                 vBitConfig_write_uc( &( xMessage ), pxDHCPMessage->ucTransactionID, 3 );
995 
996                 pxDHCPMessage->xClientID.usDUIDType = 1U;
997                 pxDHCPMessage->xClientID.usHardwareType = 1U;
998 
999                 /* DHCPv6_Option_Client_Identifier */
1000                 vBitConfig_write_16( &( xMessage ), DHCPv6_Option_Client_Identifier );                             /* Option is 1: Client Identifier */
1001                 vBitConfig_write_16( &( xMessage ), 14U );                                                         /* The length is 14 */
1002                 vBitConfig_write_16( &( xMessage ), pxDHCPMessage->xClientID.usDUIDType );                         /* 1 : Link Layer address + time */
1003                 vBitConfig_write_16( &( xMessage ), pxDHCPMessage->xClientID.usHardwareType );                     /* 1 : Ethernet */
1004                 vBitConfig_write_32( &( xMessage ), pxDHCPMessage->ulTimeStamp );                                  /* DUID Time: seconds since 1-1-2000. */
1005                 vBitConfig_write_uc( &( xMessage ), pxEndPoint->xMACAddress.ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ); /* Link Layer address, 6 bytes */
1006                 ( void ) pucBitConfig_peek_last_index_uc( &( xMessage ), EP_DHCPData.ucClientDUID, dhcpIPv6_CLIENT_DUID_LENGTH );
1007 
1008                 if( pxDHCPMessage->xServerID.uxLength != 0U )
1009                 {
1010                     uint16_t usLength = ( uint16_t ) pxDHCPMessage->xServerID.uxLength;
1011                     /* DHCPv6_Option_Server_Identifier */
1012                     vBitConfig_write_16( &( xMessage ), DHCPv6_Option_Server_Identifier );     /* Option is 1: Server Identifier */
1013                     vBitConfig_write_16( &( xMessage ), ( uint16_t ) ( usLength + 4U ) );      /* The length is 14 */
1014                     vBitConfig_write_16( &( xMessage ), pxDHCPMessage->xServerID.usDUIDType ); /* The type of DUID: 1, 2, or 3. */
1015                     vBitConfig_write_16( &( xMessage ), pxDHCPMessage->xServerID.usHardwareType );
1016                     vBitConfig_write_uc( &( xMessage ), pxDHCPMessage->xServerID.pucID, pxDHCPMessage->xServerID.uxLength );
1017                 }
1018 
1019                 if( ( EP_DHCPData.eDHCPState == eWaitingOffer ) || ( EP_DHCPData.eDHCPState == eLeasedAddress ) )
1020                 {
1021                     /* DHCPv6_Option_Option_List */
1022                     vBitConfig_write_16( &( xMessage ), DHCPv6_Option_Option_List );               /* usOption;	Option is 6 */
1023                     vBitConfig_write_16( &( xMessage ), 4U );                                      /* usLength;	length is 4 */
1024                     vBitConfig_write_16( &( xMessage ), DHCP6_OPTION_REQUEST_DNS );                /* usOption_1;	00 17 : DNS Recursive name server. */
1025                     vBitConfig_write_16( &( xMessage ), DHCP6_OPTION_REQUEST_DOMAIN_SEARCH_LIST ); /* usOption_2;	00 18 : Domain search list. */
1026                 }
1027 
1028                 /* DHCPv6_Option_Elapsed_Time */
1029                 vBitConfig_write_16( &( xMessage ), DHCPv6_Option_Elapsed_Time ); /* usOption;	Option is 8 * / */
1030                 vBitConfig_write_16( &( xMessage ), 2U );                         /* usLength;	length is 2 * / */
1031                 vBitConfig_write_16( &( xMessage ), 0x0000 );                     /* usTime;		00 00 : 0 ms. * / */
1032 
1033                 /* DHCPv6_Option_IA_for_Prefix_Delegation */
1034                 uint32_t ulIAID = 0x27fe8f95;
1035                 uint32_t ulTime_1 = 3600U;
1036                 uint32_t ulTime_2 = 5400U;
1037 
1038                 vBitConfig_write_16( &( xMessage ), DHCPv6_Option_IA_for_Prefix_Delegation ); /* usOption;	Option is 25 */
1039                 vBitConfig_write_16( &( xMessage ), 41 );                                     /* usLength;	length is 12 + 29 = 41 */
1040                 vBitConfig_write_32( &( xMessage ), ulIAID );                                 /* 27 fe 8f 95. */
1041                 vBitConfig_write_32( &( xMessage ), ulTime_1 );                               /* 00 00 0e 10: 3600 sec */
1042                 vBitConfig_write_32( &( xMessage ), ulTime_2 );                               /* 00 00 15 18: 5400 sec */
1043 
1044                 /* DHCPv6_Option_IA_Prefix */
1045                 uint32_t ulPreferredLifeTime = 4500U;
1046                 uint32_t ulPValidLifeTime = 7200U;
1047                 uint8_t ucPrefixLength = ( uint8_t ) pxEndPoint->ipv6_settings.uxPrefixLength;
1048 
1049                 vBitConfig_write_16( &( xMessage ), DHCPv6_Option_IA_Prefix );                                           /* usOption   Option is 26 */
1050                 vBitConfig_write_16( &( xMessage ), 25 );                                                                /* usLength   length is 25 */
1051                 vBitConfig_write_32( &( xMessage ), ulPreferredLifeTime );                                               /* 4500 */
1052                 vBitConfig_write_32( &( xMessage ), ulPValidLifeTime );                                                  /* e.g. 7200 seconds. */
1053                 vBitConfig_write_8( &( xMessage ), ucPrefixLength );                                                     /* e.g. 64 bits */
1054                 vBitConfig_write_uc( &( xMessage ), pxEndPoint->ipv6_settings.xPrefix.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); /* 2001:0:0:fe00:: */
1055 
1056                 vBitConfig_write_16( &( xMessage ), DHCPv6_Option_NonTemporaryAddress );                                 /* usOption   Option is 3 */
1057                 vBitConfig_write_16( &( xMessage ), 12 );                                                                /* usLength   length is 12 */
1058                 vBitConfig_write_32( &( xMessage ), ulIAID );                                                            /* 27 fe 8f 95. */
1059                 vBitConfig_write_32( &( xMessage ), ulPreferredLifeTime );                                               /* 4500 */
1060                 vBitConfig_write_32( &( xMessage ), ulPValidLifeTime );                                                  /* 7200 */
1061 
1062                 if( ( EP_DHCPData.eDHCPState == eWaitingOffer ) || ( EP_DHCPData.eDHCPState == eLeasedAddress ) )
1063                 {
1064                     vBitConfig_write_16( &( xMessage ), DHCPv6_Option_DNS_recursive_name_server ); /* usOption   Option is 23 */
1065                     vBitConfig_write_16( &( xMessage ), 0U );                                      /* usLength   length is 0 */
1066                 }
1067 
1068                 ( void ) memset( &( xAddress ), 0, sizeof xAddress );
1069                 ( void ) FreeRTOS_inet_pton6( "ff02::1:2", xAddress.sin_address.xIP_IPv6.ucBytes );
1070                 xAddress.sin_len = ( uint8_t ) sizeof xAddress; /* length of this structure. */
1071                 xAddress.sin_family = FREERTOS_AF_INET6;
1072                 xAddress.sin_port = FreeRTOS_htons( ipDHCPv6_SERVER_PORT );
1073 
1074                 struct freertos_sockaddr * pxAddress = &( xAddress );
1075 
1076                 FreeRTOS_printf( ( "DHCP Sending request %u.\n", ucMessageType ) );
1077                 ( void ) FreeRTOS_sendto( EP_DHCPData.xDHCPSocket, ( const void * ) xMessage.ucContents, xMessage.uxIndex, 0, pxAddress, sizeof xAddress );
1078             }
1079 
1080             vBitConfig_release( &( xMessage ) );
1081         } /* if( xBitConfig_init( &( xMessage ), NULL, 256 ) == pdTRUE ) */
1082     }     /* ( xRandomOk == pdPASS ) && ( EP_DHCPData.xDHCPSocket != NULL ) */
1083 }
1084 /*-----------------------------------------------------------*/
1085 
1086 /**
1087  * @brief Either the option 'NonTemporaryAddress' or 'IA_for_Prefix_Delegation'
1088  *        was received.  This function will read sub options like 'IA_Address',
1089  *        IA_Prefix, and Status_Code.
1090  *        It parses the raw message and fills 'pxDHCPMessage'.
1091  * @param[in] usOption The DHCPv6 option that was received.
1092  * @param[in] pxSet It contains the length and offset of the DHCP option.
1093  * @param[out] pxDHCPMessage it will be filled with the information from the option.
1094  * @param[in] pxMessage The raw packet as it was received.
1095  *
1096  * @return It returns pdTRUE in case the option parsed successfully, otherwise pdFALSE.
1097  */
prvDHCPv6_subOption(uint16_t usOption,const DHCPOptionSet_t * pxSet,DHCPMessage_IPv6_t * pxDHCPMessage,BitConfig_t * pxMessage)1098 static BaseType_t prvDHCPv6_subOption( uint16_t usOption,
1099                                        const DHCPOptionSet_t * pxSet,
1100                                        DHCPMessage_IPv6_t * pxDHCPMessage,
1101                                        BitConfig_t * pxMessage )
1102 {
1103     uint32_t ulIAID = ulBitConfig_read_32( pxMessage );
1104     uint32_t ulTime_1 = ulBitConfig_read_32( pxMessage );
1105     uint32_t ulTime_2 = ulBitConfig_read_32( pxMessage );
1106     size_t uxUsed = pxMessage->uxIndex - pxSet->uxStart;
1107     size_t uxRemain = 0U;
1108     uint16_t usOption2;
1109     uint16_t uxLength2;
1110     BaseType_t xReturn = pdTRUE;
1111 
1112     ( void ) ulIAID;
1113     ( void ) ulTime_1;
1114     ( void ) ulTime_2;
1115     ( void ) usOption;
1116 
1117     if( pxSet->uxOptionLength >= uxUsed )
1118     {
1119         uxRemain = pxSet->uxOptionLength - uxUsed;
1120     }
1121     else
1122     {
1123         FreeRTOS_printf( ( "prvDHCPv6_subOption: Option %u used length %lu is larger than option length %lu\n", usOption, uxUsed, pxSet->uxOptionLength ) );
1124         xReturn = pdFALSE;
1125     }
1126 
1127     while( uxRemain > 0U )
1128     {
1129         if( uxRemain < 4U )
1130         {
1131             /* Sub-option length is always larger than 4 to store option code and length. */
1132             FreeRTOS_printf( ( "prvDHCPv6_subOption: %s has invalid option with length %lu\n",
1133                                ( usOption == DHCPv6_Option_NonTemporaryAddress ) ? "Address assignment" : "Prefix Delegation",
1134                                uxRemain ) );
1135             xReturn = pdFALSE;
1136             break;
1137         }
1138 
1139         usOption2 = usBitConfig_read_16( pxMessage );
1140         uxLength2 = usBitConfig_read_16( pxMessage );
1141 
1142         uxUsed = pxMessage->uxIndex - pxSet->uxStart;
1143 
1144         /* Check sub-option length. */
1145         if( prvIsOptionLengthValid( usOption2, uxLength2, pxMessage->uxSize - pxMessage->uxIndex ) != pdTRUE )
1146         {
1147             FreeRTOS_printf( ( "prvDHCPv6_subOption: %u has invalid length %u, remaining buffer size %lu\n",
1148                                usOption2,
1149                                uxLength2,
1150                                pxMessage->uxSize - pxMessage->uxIndex ) );
1151             xReturn = pdFALSE;
1152             break;
1153         }
1154 
1155         switch( usOption2 )
1156         {
1157             case DHCPv6_Option_IA_Address:
1158                 ( void ) xBitConfig_read_uc( pxMessage, pxDHCPMessage->xIPAddress.xIP_IPv6.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
1159                 pxDHCPMessage->ulPreferredLifeTime = ulBitConfig_read_32( pxMessage );
1160                 pxDHCPMessage->ulValidLifeTime = ulBitConfig_read_32( pxMessage );
1161                 FreeRTOS_printf( ( "IP Address %pip\n", ( void * ) pxDHCPMessage->xIPAddress.xIP_IPv6.ucBytes ) );
1162                 break;
1163 
1164             case DHCPv6_Option_IA_Prefix:
1165                 pxDHCPMessage->ulPreferredLifeTime = ulBitConfig_read_32( pxMessage );
1166                 pxDHCPMessage->ulValidLifeTime = ulBitConfig_read_32( pxMessage );
1167                 pxDHCPMessage->ucprefixLength = ucBitConfig_read_8( pxMessage );
1168                 ( void ) xBitConfig_read_uc( pxMessage, pxDHCPMessage->xPrefixAddress.xIP_IPv6.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
1169                 FreeRTOS_printf( ( "Address prefix: %pip length %d\n", ( void * ) pxDHCPMessage->xPrefixAddress.xIP_IPv6.ucBytes, pxDHCPMessage->ucprefixLength ) );
1170                 break;
1171 
1172             case DHCPv6_Option_Status_Code:
1173                 xReturn = prvDHCPv6_handleStatusCode( uxLength2,
1174                                                       pxMessage );
1175                 break;
1176 
1177             default:
1178                 ( void ) xBitConfig_read_uc( pxMessage, NULL, uxLength2 - uxUsed );
1179                 FreeRTOS_printf( ( "prvDHCPv6Analyse: skipped unknown option %u\n", usOption2 ) );
1180                 break;
1181         }
1182 
1183         if( xReturn != pdTRUE )
1184         {
1185             FreeRTOS_printf( ( "prvDHCPv6_subOption: One of sub-options %d returns error\n", usOption2 ) );
1186             break;
1187         }
1188 
1189         /* Update remaining length. */
1190         uxUsed = pxMessage->uxIndex - pxSet->uxStart;
1191         uxRemain = 0U;
1192 
1193         if( pxSet->uxOptionLength > uxUsed )
1194         {
1195             uxRemain = pxSet->uxOptionLength - uxUsed;
1196         }
1197     }
1198 
1199     return xReturn;
1200 }
1201 /*-----------------------------------------------------------*/
1202 
1203 /**
1204  * @brief A DHCP packet has a list of options, each one starting with a type and a length
1205  *        field. This function parses a single DHCP option.
1206  * @param[in] pxEndPoint The end-point that wants a DHCPv6 address.
1207  * @param[in] usOption IPv6 DHCP option to be handled.
1208  * @param[in] pxSet It contains the length and offset of the DHCP option.
1209  * @param[out] pxDHCPMessage it will be filled with the information from the option.
1210  * @param[in] pxMessage The raw packet as it was received.
1211  */
prvDHCPv6_handleOption(struct xNetworkEndPoint * pxEndPoint,uint16_t usOption,const DHCPOptionSet_t * pxSet,DHCPMessage_IPv6_t * pxDHCPMessage,BitConfig_t * pxMessage)1212 static BaseType_t prvDHCPv6_handleOption( struct xNetworkEndPoint * pxEndPoint,
1213                                           uint16_t usOption,
1214                                           const DHCPOptionSet_t * pxSet,
1215                                           DHCPMessage_IPv6_t * pxDHCPMessage,
1216                                           BitConfig_t * pxMessage )
1217 {
1218     BaseType_t xReady = pdFALSE;
1219     int32_t lIDSize = 0;
1220     uint8_t ucClientDUID[ dhcpIPv6_CLIENT_DUID_LENGTH ];
1221 
1222     if( prvIsOptionLengthValid( usOption, pxSet->uxOptionLength, pxMessage->uxSize - pxMessage->uxIndex ) != pdTRUE )
1223     {
1224         FreeRTOS_printf( ( "prvDHCPv6_handleOption: Option %u has invalid length %lu, remaining buffer size %lu\n",
1225                            usOption,
1226                            pxSet->uxOptionLength,
1227                            pxMessage->uxSize - pxMessage->uxIndex ) );
1228         xReady = pdTRUE;
1229     }
1230 
1231     if( xReady == pdFALSE )
1232     {
1233         switch( usOption )
1234         {
1235             case DHCPv6_Option_Status_Code:
1236 
1237                 if( prvDHCPv6_handleStatusCode( pxSet->uxOptionLength, pxMessage ) != pdTRUE )
1238                 {
1239                     pxMessage->xHasError = pdTRUE_UNSIGNED;
1240                 }
1241 
1242                 break;
1243 
1244             case DHCPv6_Option_Client_Identifier:
1245                 lIDSize = ( int32_t ) ( pxSet->uxOptionLength ) - 4;
1246 
1247                 if( lIDSize >= 0 )
1248                 {
1249                     /*
1250                      *  1 : Link-layer address plus time (DUID-LLT)
1251                      *  2 : Vendor-assigned unique ID based on Enterprise Number (DUID-EN)
1252                      *  3 : Link-layer address (DUID-LL)
1253                      */
1254                     pxDHCPMessage->xClientID.uxLength = ( size_t ) lIDSize;
1255                     pxDHCPMessage->xClientID.usDUIDType = usBitConfig_read_16( pxMessage );     /* 0x0001 : Link Layer address + time */
1256                     pxDHCPMessage->xClientID.usHardwareType = usBitConfig_read_16( pxMessage ); /* 1 = Ethernet. */
1257 
1258                     if( ( size_t ) lIDSize <= sizeof( pxDHCPMessage->xClientID.pucID ) )
1259                     {
1260                         /* Refer to RFC3315 - sec 15.3, we need to discard packets with following conditions:
1261                          *  - the message does not include a Server Identifier option.
1262                          *  - the message does not include a Client Identifier option.
1263                          *  - the contents of the Client Identifier option does not match the client's DUID.
1264                          *  - the "transaction-id" field value does not match the value the client used in its Solicit message. */
1265                         ( void ) xBitConfig_read_uc( pxMessage, pxDHCPMessage->xClientID.pucID, ( size_t ) lIDSize ); /* Link Layer address, 6 bytes */
1266 
1267                         /* Check client DUID. */
1268                         if( ( pxSet->uxOptionLength != dhcpIPv6_CLIENT_DUID_LENGTH ) ||
1269                             ( pucBitConfig_peek_last_index_uc( pxMessage, ucClientDUID, pxSet->uxOptionLength ) != pdTRUE ) ||
1270                             ( memcmp( ucClientDUID, EP_DHCPData.ucClientDUID, dhcpIPv6_CLIENT_DUID_LENGTH ) != 0 ) )
1271                         {
1272                             FreeRTOS_printf( ( "prvDHCPv6Analyse: wrong client ID\n" ) );
1273                             pxMessage->xHasError = pdTRUE;
1274                         }
1275                     }
1276                     else
1277                     {
1278                         /* The value of DHCPv6_Option_Client_Identifier is invalid. */
1279                         FreeRTOS_printf( ( "prvDHCPv6Analyse: client ID too long\n" ) );
1280                         xReady = pdTRUE;
1281                     }
1282                 }
1283                 else
1284                 {
1285                     /* The value of DHCPv6_Option_Client_Identifier is invalid. */
1286                     FreeRTOS_printf( ( "prvDHCPv6Analyse: client ID too short\n" ) );
1287                     xReady = pdTRUE;
1288                 }
1289 
1290                 break;
1291 
1292             case DHCPv6_Option_Server_Identifier:
1293                 lIDSize = ( int32_t ) ( pxSet->uxOptionLength ) - 4;
1294 
1295                 if( lIDSize >= 0 )
1296                 {
1297                     /*
1298                      *  1 : Link-layer address plus time (DUID-LLT)
1299                      *  2 : Vendor-assigned unique ID based on Enterprise Number (DUID-EN)
1300                      *  3 : Link-layer address (DUID-LL)
1301                      */
1302                     pxDHCPMessage->xServerID.uxLength = ( size_t ) lIDSize;
1303                     pxDHCPMessage->xServerID.usDUIDType = usBitConfig_read_16( pxMessage );     /* 0x0001 : Link Layer address + time */
1304                     pxDHCPMessage->xServerID.usHardwareType = usBitConfig_read_16( pxMessage ); /* 1 = Ethernet. */
1305 
1306                     if( ( size_t ) lIDSize <= sizeof( pxDHCPMessage->xServerID.pucID ) )
1307                     {
1308                         ( void ) xBitConfig_read_uc( pxMessage, pxDHCPMessage->xServerID.pucID, ( size_t ) lIDSize ); /* Link Layer address, 6 bytes */
1309                     }
1310                     else
1311                     {
1312                         FreeRTOS_printf( ( "prvDHCPv6Analyse: server ID too long\n" ) );
1313                         xReady = pdTRUE;
1314                     }
1315                 }
1316                 else
1317                 {
1318                     /* The value of DHCPv6_Option_Server_Identifier is invalid. */
1319                     FreeRTOS_printf( ( "prvDHCPv6Analyse: server ID too short\n" ) );
1320                     xReady = pdTRUE;
1321                 }
1322 
1323                 break;
1324 
1325             case DHCPv6_Option_Preference:
1326                {
1327                    uint8_t ucPreference = ucBitConfig_read_8( pxMessage );
1328                    ( void ) ucPreference;
1329                    break;
1330                }
1331 
1332             case DHCPv6_Option_DNS_recursive_name_server:
1333                {
1334                    size_t uDNSCount;
1335 
1336                    if( ( pxSet->uxOptionLength == 0U ) || ( ( pxSet->uxOptionLength % ipSIZE_OF_IPv6_ADDRESS ) != 0U ) )
1337                    {
1338                        FreeRTOS_printf( ( "prvDHCPv6Analyse: bad DNS length\n" ) );
1339                        xReady = pdTRUE;
1340                        break;
1341                    }
1342 
1343                    uDNSCount = pxSet->uxOptionLength / ipSIZE_OF_IPv6_ADDRESS;
1344 
1345                    while( uDNSCount > 0U )
1346                    {
1347                        if( pxDHCPMessage->uxDNSCount < ipconfigENDPOINT_DNS_ADDRESS_COUNT )
1348                        {
1349                            ( void ) xBitConfig_read_uc( pxMessage, pxDHCPMessage->xDNSServers[ pxDHCPMessage->uxDNSCount ].xIP_IPv6.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
1350                            pxDHCPMessage->uxDNSCount++;
1351                        }
1352                        else
1353                        {
1354                            /* The DNS address can not be stored. Just advance the pointer. */
1355                            ( void ) xBitConfig_read_uc( pxMessage, NULL, ipSIZE_OF_IPv6_ADDRESS );
1356                        }
1357 
1358                        uDNSCount--;
1359                    }
1360 
1361                    break;
1362                }
1363 
1364             case DHCPv6_Option_Domain_Search_List:
1365                 ( void ) xBitConfig_read_uc( pxMessage, NULL, pxSet->uxOptionLength );
1366                 break;
1367 
1368             case DHCPv6_Option_NonTemporaryAddress:
1369             case DHCPv6_Option_IA_for_Prefix_Delegation:
1370 
1371                 if( prvDHCPv6_subOption( usOption, pxSet, pxDHCPMessage, pxMessage ) != pdTRUE )
1372                 {
1373                     FreeRTOS_printf( ( "prvDHCPv6_handleOption: prvDHCPv6_subOption returns error.\n" ) );
1374                     xReady = pdTRUE;
1375                 }
1376 
1377                 break;
1378 
1379             default:
1380                 FreeRTOS_printf( ( "prvDHCPv6Analyse: Option %u not implemented\n", usOption ) );
1381                 ( void ) xBitConfig_read_uc( pxMessage, NULL, pxSet->uxOptionLength );
1382                 break;
1383         }
1384     }
1385 
1386     return xReady;
1387 }
1388 /*-----------------------------------------------------------*/
1389 
1390 /**
1391  * @brief Analyse the reply from a DHCP server.
1392  *
1393  * @param[in] pxEndPoint The end-point that wants a DHCPv6 address.
1394  * @param[in] pucAnswer The payload text of the incoming packet.
1395  * @param[in] uxTotalLength The number of valid bytes in pucAnswer.
1396  * @param[in] pxDHCPMessage The DHCP object of the end-point.
1397  *
1398  * @return pdTRUE if the analysis was successful.
1399  */
prvDHCPv6Analyse(struct xNetworkEndPoint * pxEndPoint,const uint8_t * pucAnswer,size_t uxTotalLength,DHCPMessage_IPv6_t * pxDHCPMessage)1400 static BaseType_t prvDHCPv6Analyse( struct xNetworkEndPoint * pxEndPoint,
1401                                     const uint8_t * pucAnswer,
1402                                     size_t uxTotalLength,
1403                                     DHCPMessage_IPv6_t * pxDHCPMessage )
1404 {
1405     BitConfig_t xMessage;
1406     BaseType_t xResult = pdPASS;
1407     uint32_t ulOptionsReceived = 0U;
1408 
1409     /* Allocate enough space in 'xMessage' and clear it. */
1410     if( xBitConfig_init( &xMessage, pucAnswer, uxTotalLength ) != pdFAIL )
1411     {
1412         BaseType_t xReady = pdFALSE;
1413 
1414         ( void ) memset( pxDHCPMessage, 0, sizeof( *pxDHCPMessage ) );
1415 
1416         pxDHCPMessage->uxMessageType = ucBitConfig_read_8( &xMessage );
1417         ( void ) xBitConfig_read_uc( &xMessage, pxDHCPMessage->ucTransactionID, 3 );
1418 
1419         pxDHCPMessage->ulTransactionID =
1420             ( ( ( uint32_t ) pxDHCPMessage->ucTransactionID[ 0 ] ) << 16 ) |
1421             ( ( ( uint32_t ) pxDHCPMessage->ucTransactionID[ 1 ] ) << 8 ) |
1422             ( ( ( uint32_t ) pxDHCPMessage->ucTransactionID[ 2 ] ) );
1423 
1424         if( EP_DHCPData.ulTransactionId != pxDHCPMessage->ulTransactionID )
1425         {
1426             FreeRTOS_printf( ( "prvDHCPv6Analyse: Message %u transaction ID 0x%06X is different from sent ID 0x%06X\n",
1427                                ( unsigned ) pxDHCPMessage->uxMessageType,
1428                                ( unsigned ) pxDHCPMessage->ulTransactionID,
1429                                EP_DHCPData.ulTransactionId ) );
1430 
1431             xResult = pdFAIL;
1432         }
1433 
1434         FreeRTOS_printf( ( "prvDHCPv6Analyse: Message %u ID theirs 0x%06X\n",
1435                            ( unsigned ) pxDHCPMessage->uxMessageType,
1436                            ( unsigned ) pxDHCPMessage->ulTransactionID ) );
1437 
1438         switch( pxDHCPMessage->uxMessageType )
1439         {
1440             case DHCPv6_message_Type_Advertise:
1441             case DHCPv6_message_Type_Confirm:
1442             case DHCPv6_message_Type_Reply:
1443             case DHCPv6_message_Type_Decline:
1444                 break;
1445 
1446             default:
1447                 FreeRTOS_printf( ( "prvDHCPv6Analyse: Can not handle message type %u\n",
1448                                    ( unsigned ) pxDHCPMessage->uxMessageType ) );
1449                 xResult = pdFAIL;
1450                 break;
1451         }
1452 
1453         if( xResult == pdFAIL )
1454         {
1455             /* Ignore the reply because the message type is wrong. */
1456             xReady = pdTRUE;
1457         }
1458         else if( xMessage.xHasError != pdFALSE )
1459         {
1460             xReady = pdTRUE;
1461             xResult = pdFAIL;
1462         }
1463         else
1464         {
1465             /* xResult still equals 'pdPASS', carry on. */
1466         }
1467 
1468         while( xReady == pdFALSE )
1469         {
1470             uint16_t usOption;
1471             DHCPOptionSet_t xSet;
1472 
1473             ( void ) memset( &( xSet ), 0, sizeof( xSet ) );
1474 
1475             usOption = usBitConfig_read_16( &xMessage );
1476             xSet.uxOptionLength = ( size_t ) usBitConfig_read_16( &xMessage );
1477             xSet.uxStart = xMessage.uxIndex;
1478 
1479             if( xMessage.xHasError != pdFALSE )
1480             {
1481                 FreeRTOS_printf( ( "prvDHCPv6Analyse: bad input\n" ) );
1482                 xReady = pdTRUE;
1483                 xResult = pdFAIL;
1484             }
1485             else
1486             {
1487                 ulOptionsReceived |= ( ( ( uint32_t ) 1U ) << usOption );
1488                 xReady = prvDHCPv6_handleOption( pxEndPoint, usOption, &( xSet ), pxDHCPMessage, &( xMessage ) );
1489             }
1490 
1491             if( xMessage.xHasError != pdFALSE )
1492             {
1493                 FreeRTOS_printf( ( "prvDHCPv6Analyse: bad input\n" ) );
1494                 xReady = pdTRUE;
1495                 xResult = pdFAIL;
1496             }
1497             else if( xReady == pdTRUE )
1498             {
1499                 /* xReady might be set to pdTRUE by prvDHCPv6_handleOption when there happens any error on parsing options. */
1500                 FreeRTOS_printf( ( "prvDHCPv6Analyse: prvDHCPv6_handleOption returns error.\n" ) );
1501                 xResult = pdFAIL;
1502             }
1503             else if( xMessage.uxIndex == xMessage.uxSize )
1504             {
1505                 xReady = pdTRUE;
1506             }
1507             else
1508             {
1509                 /* More options will follow. */
1510             }
1511         } /* while( xReady == pdFALSE ) */
1512 
1513         vBitConfig_release( &( xMessage ) );
1514 
1515         if( xResult == pdPASS )
1516         {
1517             ulOptionsReceived &= dhcpMANDATORY_OPTIONS;
1518 
1519             if( ulOptionsReceived != dhcpMANDATORY_OPTIONS )
1520             {
1521                 xResult = pdFAIL;
1522                 FreeRTOS_printf( ( "prvDHCPv6Analyse: Missing options: %X not equal to %X\n", ( unsigned int ) ulOptionsReceived, ( unsigned int ) dhcpMANDATORY_OPTIONS ) );
1523             }
1524         }
1525     } /* if( xBitConfig_init() ) */
1526     else
1527     {
1528         xResult = pdFAIL;
1529     }
1530 
1531     return xResult;
1532 }
1533 /*-----------------------------------------------------------*/
1534 
1535 /**
1536  * @brief transform a state number in a descriptive string.
1537  *
1538  * @param[in] eState The DHCP state number.
1539  *
1540  * @return A descriptive string.
1541  */
1542 #if ( ipconfigHAS_DEBUG_PRINTF == 1 )
prvStateName(eDHCPState_t eState)1543     static const char * prvStateName( eDHCPState_t eState )
1544     {
1545         const char * pcName;
1546 
1547         switch( eState )
1548         {
1549             case eInitialWait:
1550                 pcName = "eInitialWait";
1551                 break;
1552 
1553             case eWaitingSendFirstDiscover:
1554                 pcName = "eWaitingSendFirstDiscover";
1555                 break;
1556 
1557             case eWaitingOffer:
1558                 pcName = "eWaitingOffer";
1559                 break;
1560 
1561             case eWaitingAcknowledge:
1562                 pcName = "eWaitingAcknowledge";
1563                 break;
1564 
1565             case eLeasedAddress:
1566                 pcName = "eLeasedAddress";
1567                 break;
1568 
1569             case eNotUsingLeasedAddress:
1570                 pcName = "eNotUsingLeasedAddress";
1571                 break;
1572 
1573             case eSendDHCPRequest:
1574                 pcName = "eSendDHCPRequest";
1575                 break;
1576 
1577             default:
1578                 pcName = "Unknown state";
1579                 break;
1580         }
1581 
1582         return pcName;
1583     }
1584 #endif /* ( ipconfigHAS_DEBUG_PRINTF == 1 ) */
1585 
1586 /* *INDENT-OFF* */
1587     #endif /* ( ipconfigUSE_IPv6 != 0 ) && ( ipconfigUSE_DHCPv6 != 0 ) */
1588 /* *INDENT-ON* */
1589