1 /*
2 * FreeRTOS+TCP <DEVELOPMENT BRANCH>
3 * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 *
5 * SPDX-License-Identifier: MIT
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy of
8 * this software and associated documentation files (the "Software"), to deal in
9 * the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 * the Software, and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * http://aws.amazon.com/freertos
25 * http://www.FreeRTOS.org
26 */
27
28 /**
29 * @file FreeRTOS_IPv6_Sockets.c
30 * @brief Implements the Sockets API based on Berkeley sockets for the FreeRTOS+TCP network stack.
31 * Sockets are used by the application processes to interact with the IP-task which in turn
32 * interacts with the hardware.
33 */
34
35 /* Standard includes. */
36 #include <stdint.h>
37 #include <stdio.h>
38
39 /* FreeRTOS includes. */
40 #include "FreeRTOS.h"
41
42 /* FreeRTOS+TCP includes. */
43 #include "FreeRTOS_IP.h"
44 #include "FreeRTOS_IPv6_Sockets.h"
45
46 /* *INDENT-OFF* */
47 #if( ipconfigUSE_IPv6 != 0 )
48 /* *INDENT-ON* */
49
50 #if ( ipconfigUSE_TCP == 1 )
51
52 /**
53 * @brief Called by pxTCPSocketLookup(), this function will check if a socket
54 * is connected to a remote IP-address. It will be called from a loop
55 * iterating through all sockets.
56 * @param[in] pxSocket The socket to be inspected.
57 * @param[in] pxAddress The IPv4/IPv6 address.
58 * @return The socket in case it is connected to the remote IP-address.
59 */
pxTCPSocketLookup_IPv6(FreeRTOS_Socket_t * pxSocket,const IPv46_Address_t * pxAddress)60 FreeRTOS_Socket_t * pxTCPSocketLookup_IPv6( FreeRTOS_Socket_t * pxSocket,
61 const IPv46_Address_t * pxAddress )
62 {
63 FreeRTOS_Socket_t * pxResult = NULL;
64
65 if( ( pxSocket != NULL ) && ( pxAddress != NULL ) )
66 {
67 if( pxSocket->bits.bIsIPv6 != pdFALSE_UNSIGNED )
68 {
69 if( pxAddress->xIs_IPv6 != pdFALSE )
70 {
71 if( memcmp( pxSocket->u.xTCP.xRemoteIP.xIP_IPv6.ucBytes, pxAddress->xIPAddress.xIP_IPv6.ucBytes, ipSIZE_OF_IPv6_ADDRESS ) == 0 )
72 {
73 /* For sockets not in listening mode, find a match with
74 * uxLocalPort, ulRemoteIP AND uxRemotePort. */
75 pxResult = pxSocket;
76 }
77 }
78 }
79 else
80 {
81 if( pxAddress->xIs_IPv6 == pdFALSE )
82 {
83 if( pxSocket->u.xTCP.xRemoteIP.ulIP_IPv4 == pxAddress->xIPAddress.ulIP_IPv4 )
84 {
85 /* For sockets not in listening mode, find a match with
86 * uxLocalPort, ulRemoteIP AND uxRemotePort. */
87 pxResult = pxSocket;
88 }
89 }
90 }
91 }
92
93 return pxResult;
94 }
95
96 #endif /* if ( ( ipconfigUSE_TCP == 1 ) */
97
98 /**
99 * @brief Called by prvSendUDPPacket(), this function will UDP packet
100 * fields and IPv6 address for the packet to be send.
101 * @param[in] pxNetworkBuffer The packet to be sent.
102 * @param[in] pxDestinationAddress The IPv4 socket address.
103 * @return Returns NULL, always.
104 */
xSend_UDP_Update_IPv6(NetworkBufferDescriptor_t * pxNetworkBuffer,const struct freertos_sockaddr * pxDestinationAddress)105 void * xSend_UDP_Update_IPv6( NetworkBufferDescriptor_t * pxNetworkBuffer,
106 const struct freertos_sockaddr * pxDestinationAddress )
107 {
108 /* MISRA Ref 11.3.1 [Misaligned access] */
109 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
110 /* coverity[misra_c_2012_rule_11_3_violation] */
111 UDPPacket_IPv6_t * pxUDPPacket_IPv6 = ( ( UDPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer );
112
113 pxNetworkBuffer->xIPAddress.ulIP_IPv4 = 0U;
114
115 configASSERT( pxDestinationAddress != NULL );
116 ( void ) memcpy( pxUDPPacket_IPv6->xIPHeader.xDestinationAddress.ucBytes, pxDestinationAddress->sin_address.xIP_IPv6.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
117 ( void ) memcpy( pxNetworkBuffer->xIPAddress.xIP_IPv6.ucBytes, pxDestinationAddress->sin_address.xIP_IPv6.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
118 pxUDPPacket_IPv6->xEthernetHeader.usFrameType = ipIPv6_FRAME_TYPE;
119
120 return NULL;
121 }
122
123 /**
124 * @brief Called by FreeRTOS_recvfrom(), this function will update socket
125 * address with IPv6 address from the packet received.
126 * @param[in] pxNetworkBuffer The packet received.
127 * @param[in] pxSourceAddress The IPv4 socket address.
128 * @return The Payload Offset.
129 */
xRecv_Update_IPv6(const NetworkBufferDescriptor_t * pxNetworkBuffer,struct freertos_sockaddr * pxSourceAddress)130 size_t xRecv_Update_IPv6( const NetworkBufferDescriptor_t * pxNetworkBuffer,
131 struct freertos_sockaddr * pxSourceAddress )
132 {
133 /* MISRA Ref 11.3.1 [Misaligned access] */
134 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
135 /* coverity[misra_c_2012_rule_11_3_violation] */
136 const UDPPacket_IPv6_t * pxUDPPacketV6 = ( ( const UDPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer );
137 size_t uxPayloadOffset = 0;
138
139 if( pxUDPPacketV6->xEthernetHeader.usFrameType == ipIPv6_FRAME_TYPE )
140 {
141 if( pxSourceAddress != NULL )
142 {
143 ( void ) memcpy( ( void * ) pxSourceAddress->sin_address.xIP_IPv6.ucBytes,
144 ( const void * ) pxUDPPacketV6->xIPHeader.xSourceAddress.ucBytes,
145 ipSIZE_OF_IPv6_ADDRESS );
146 pxSourceAddress->sin_family = ( uint8_t ) FREERTOS_AF_INET6;
147 pxSourceAddress->sin_port = pxNetworkBuffer->usPort;
148 }
149
150 uxPayloadOffset = ipUDP_PAYLOAD_OFFSET_IPv6;
151 }
152
153 return uxPayloadOffset;
154 }
155
156
157 /**
158 * @brief Converts a 4 bit (nibble) value to a readable hex character, e.g. 14 becomes 'e'.
159 * @param usValue The value to be converted, must be between 0 and 15.
160 * @return The character, between '0' and '9', or between 'a' and 'f'.
161 */
cHexToChar(uint16_t usValue)162 char cHexToChar( uint16_t usValue )
163 {
164 char cReturn = '0';
165
166 if( usValue <= 9U )
167 {
168 cReturn = ( char ) ( cReturn + usValue );
169 }
170 else if( usValue <= 15U )
171 {
172 cReturn = 'a';
173 cReturn = ( char ) ( cReturn + ( usValue - ( uint16_t ) 10 ) );
174 }
175 else
176 {
177 /* The value passed to 'usValue' has been and-ed with 0x0f,
178 * so this else clause should never be reached. */
179 configASSERT( 0 == 1 );
180 }
181
182 return cReturn;
183 }
184
185 /*-----------------------------------------------------------*/
186
187 /**
188 * @brief Convert a short numeric value to a hex string of at most 4 characters.
189 * The resulting string is **not** null-terminated. The resulting string
190 * will not have leading zero's, except when 'usValue' equals zero.
191 * @param[in] pcBuffer The buffer to which the string is written.
192 * @param[in] uxBufferSize The size of the buffer pointed to by 'pcBuffer'.
193 * @param[in] usValue The 16-bit value to be converted.
194 * @return The number of bytes written to 'pcBuffer'.
195 */
uxHexPrintShort(char * pcBuffer,size_t uxBufferSize,uint16_t usValue)196 socklen_t uxHexPrintShort( char * pcBuffer,
197 size_t uxBufferSize,
198 uint16_t usValue )
199 {
200 const size_t uxNibbleCount = 4U;
201 size_t uxNibble;
202 socklen_t uxIndex = 0U;
203 uint16_t usShifter = usValue;
204 BaseType_t xHadNonZero = pdFALSE;
205
206 for( uxNibble = 0; uxNibble < uxNibbleCount; uxNibble++ )
207 {
208 uint16_t usNibble = ( usShifter >> 12 ) & 0x0FU;
209
210 if( usNibble != 0U )
211 {
212 xHadNonZero = pdTRUE;
213 }
214
215 if( ( xHadNonZero != pdFALSE ) || ( uxNibble == ( uxNibbleCount - 1U ) ) )
216 {
217 if( uxIndex >= ( uxBufferSize - 1U ) )
218 {
219 break;
220 }
221
222 pcBuffer[ uxIndex ] = cHexToChar( usNibble );
223 uxIndex++;
224 }
225
226 usShifter = ( uint16_t ) ( usShifter << 4 );
227 }
228
229 return uxIndex;
230 }
231 /*-----------------------------------------------------------*/
232
233 /**
234 * @brief Scan the binary IPv6 address and find the longest train of consecutive zero's.
235 * The result of this search will be stored in 'xZeroStart' and 'xZeroLength'.
236 * @param pxSet the set of parameters as used by FreeRTOS_inet_ntop6().
237 */
prv_ntop6_search_zeros(struct sNTOP6_Set * pxSet)238 void prv_ntop6_search_zeros( struct sNTOP6_Set * pxSet )
239 {
240 BaseType_t xIndex = 0; /* The index in the IPv6 address: 0..7. */
241 BaseType_t xCurStart = 0; /* The position of the first zero found so far. */
242 BaseType_t xCurLength = 0; /* The number of zero's seen so far. */
243 const BaseType_t xShortCount = 8; /* An IPv6 address consists of 8 shorts. */
244
245 /* Default: when xZeroStart is negative, it won't match with any xIndex. */
246 pxSet->xZeroStart = -1;
247
248 /* Look for the longest train of zero's 0:0:0:... */
249 for( ; xIndex < xShortCount; xIndex++ )
250 {
251 uint16_t usValue = pxSet->pusAddress[ xIndex ];
252
253 if( usValue == 0U )
254 {
255 if( xCurLength == 0 )
256 {
257 /* Remember the position of the first zero. */
258 xCurStart = xIndex;
259 }
260
261 /* Count consecutive zeros. */
262 xCurLength++;
263 }
264
265 if( ( usValue != 0U ) || ( xIndex == ( xShortCount - 1 ) ) )
266 {
267 /* Has a longer train of zero's been found? */
268 if( ( xCurLength > 1 ) && ( pxSet->xZeroLength < xCurLength ) )
269 {
270 /* Remember the number of consecutive zeros. */
271 pxSet->xZeroLength = xCurLength;
272 /* Remember the index of the first zero found. */
273 pxSet->xZeroStart = xCurStart;
274 }
275
276 /* Reset the counter of consecutive zeros. */
277 xCurLength = 0;
278 }
279 }
280 }
281 /*-----------------------------------------------------------*/
282
283 /**
284 * @brief The location is now at the longest train of zero's. Two colons have to
285 * be printed without a numeric value, e.g. "ff02::1".
286 * @param pcDestination the output buffer where the colons will be printed.
287 * @param uxSize the remaining length of the output buffer.
288 * @param pxSet the set of parameters as used by FreeRTOS_inet_ntop6().
289 * @return pdPASS in case the output buffer is big enough to contain the colons.
290 * @note uxSize must be at least 2, enough to print "::". The string will get
291 * null-terminated later on.
292 */
prv_ntop6_write_zeros(char * pcDestination,size_t uxSize,struct sNTOP6_Set * pxSet)293 static BaseType_t prv_ntop6_write_zeros( char * pcDestination,
294 size_t uxSize,
295 struct sNTOP6_Set * pxSet )
296 {
297 BaseType_t xReturn = pdPASS;
298 const BaseType_t xShortCount = 8; /* An IPv6 address consists of 8 shorts. */
299
300 if( pxSet->uxTargetIndex <= ( uxSize - 1U ) )
301 {
302 pcDestination[ pxSet->uxTargetIndex ] = ':';
303 pxSet->uxTargetIndex++;
304
305 if( ( pxSet->xIndex + pxSet->xZeroLength ) == xShortCount )
306 {
307 /* Reached the last index, write a second ":". */
308 if( pxSet->uxTargetIndex <= ( uxSize - 1U ) )
309 {
310 pcDestination[ pxSet->uxTargetIndex ] = ':';
311 pxSet->uxTargetIndex++;
312 }
313 else
314 {
315 /* Can not write the second colon. */
316 xReturn = pdFAIL;
317 }
318 }
319 else
320 {
321 /* Otherwise the function prv_ntop6_write_short() will places the second colon. */
322 }
323 }
324 else
325 {
326 /* Can not write the first colon. */
327 xReturn = pdFAIL;
328 }
329
330 return xReturn;
331 }
332 /*-----------------------------------------------------------*/
333
334 /**
335 * @brief Write a short value, as a hex number with at most 4 characters. E.g. the
336 * value 15 will be printed as "f".
337 * @param pcDestination the output buffer where the hex number is to be printed.
338 * @param uxSize the remaining length of the output buffer.
339 * @param pxSet the set of parameters as used by FreeRTOS_inet_ntop6().
340 * @return pdPASS in case the output buffer is big enough to contain the string.
341 * @note uxSize must be at least 4, enough to print "abcd". The string will get
342 * null-terminated later on.
343 */
prv_ntop6_write_short(char * pcDestination,size_t uxSize,struct sNTOP6_Set * pxSet)344 static BaseType_t prv_ntop6_write_short( char * pcDestination,
345 size_t uxSize,
346 struct sNTOP6_Set * pxSet )
347 {
348 socklen_t uxLength;
349 BaseType_t xReturn = pdPASS;
350 const size_t uxBytesPerShortValue = 4U;
351
352 if( pxSet->xIndex > 0 )
353 {
354 if( pxSet->uxTargetIndex >= ( uxSize - 1U ) )
355 {
356 xReturn = pdFAIL;
357 }
358 else
359 {
360 pcDestination[ pxSet->uxTargetIndex ] = ':';
361 pxSet->uxTargetIndex++;
362 }
363 }
364
365 if( xReturn == pdPASS )
366 {
367 /* If there is enough space to write a short. */
368 if( pxSet->uxTargetIndex <= ( uxSize - uxBytesPerShortValue ) )
369 {
370 /* Write hex value of short. at most 4 + 1 bytes. */
371 uxLength = uxHexPrintShort( &( pcDestination[ pxSet->uxTargetIndex ] ),
372 uxBytesPerShortValue + 1U,
373 FreeRTOS_ntohs( pxSet->pusAddress[ pxSet->xIndex ] ) );
374
375 /* uxLength will be non zero and positive always. */
376 pxSet->uxTargetIndex += uxLength;
377 }
378 else
379 {
380 xReturn = pdFAIL;
381 }
382 }
383
384 return xReturn;
385 }
386 /*-----------------------------------------------------------*/
387
388 /**
389 * @brief This function converts a binary IPv6 address to a human readable notation.
390 *
391 * @param[in] pvSource The binary address, 16 bytes long..
392 * @param[out] pcDestination The human-readable ( hexadecimal ) notation of the
393 * address.
394 * @param[in] uxSize The size of pvDestination. A value of 40 is recommended.
395 *
396 * @return pdPASS if the translation was successful or else pdFAIL.
397 */
FreeRTOS_inet_ntop6(const void * pvSource,char * pcDestination,socklen_t uxSize)398 const char * FreeRTOS_inet_ntop6( const void * pvSource,
399 char * pcDestination,
400 socklen_t uxSize )
401 {
402 const char * pcReturn; /* The return value, which is either 'pcDestination' or NULL. */
403 struct sNTOP6_Set xSet; /* A set of values for easy exchange with the helper functions prv_ntop6_xxx(). */
404
405 ( void ) memset( &( xSet ), 0, sizeof( xSet ) );
406
407 xSet.pusAddress = pvSource;
408
409 if( uxSize < 3U )
410 {
411 /* Can not even print :: */
412 }
413 else
414 {
415 prv_ntop6_search_zeros( &( xSet ) );
416
417 while( xSet.xIndex < 8 )
418 {
419 if( xSet.xIndex == xSet.xZeroStart )
420 {
421 if( prv_ntop6_write_zeros( pcDestination, uxSize, &( xSet ) ) == pdFAIL )
422 {
423 break;
424 }
425
426 xSet.xIndex += xSet.xZeroLength;
427 }
428 else
429 {
430 if( prv_ntop6_write_short( pcDestination, uxSize, &( xSet ) ) == pdFAIL )
431 {
432 break;
433 }
434
435 xSet.xIndex++;
436 }
437 }
438 }
439
440 if( xSet.xIndex < 8 )
441 {
442 /* Didn't reach the last nibble: clear the string. */
443 pcReturn = NULL;
444 }
445 else
446 {
447 pcDestination[ xSet.uxTargetIndex ] = '\0';
448 pcReturn = pcDestination;
449 }
450
451 return pcReturn;
452 }
453 /*-----------------------------------------------------------*/
454
455 /**
456 * @brief Converting a readable IPv6 address to its binary form, add one nibble.
457 *
458 * @param[in] pxSet A set of variables describing the conversion.
459 * @param[in] ucNew The hex value, between 0 and 15
460 * @param[in] ch The character, such as '5', 'f', or ':'.
461 *
462 * @return pdTRUE when the nibble was added, otherwise pdFALSE.
463 */
prv_inet_pton6_add_nibble(struct sPTON6_Set * pxSet,uint8_t ucNew,char ch)464 static BaseType_t prv_inet_pton6_add_nibble( struct sPTON6_Set * pxSet,
465 uint8_t ucNew,
466 char ch )
467 {
468 BaseType_t xReturn = pdPASS;
469
470 if( ucNew != ( uint8_t ) socketINVALID_HEX_CHAR )
471 {
472 /* Shift in 4 bits. */
473 pxSet->ulValue <<= 4;
474 pxSet->ulValue |= ( uint32_t ) ucNew;
475
476 /* Remember that ulValue is valid now. */
477 pxSet->xHadDigit = pdTRUE;
478
479 /* Check if the number is not becoming larger than 16 bits. */
480 if( pxSet->ulValue > 0xffffU )
481 {
482 /* The highest nibble has already been set,
483 * an overflow would occur. Break out of the for-loop. */
484 xReturn = pdFAIL;
485 }
486 }
487 else if( ch == ':' )
488 {
489 if( pxSet->xHadDigit == pdFALSE )
490 {
491 /* A "::" sequence has been received. Check if it is not a third colon. */
492 if( pxSet->xColon >= 0 )
493 {
494 xReturn = pdFAIL;
495 }
496 else
497 {
498 /* Two or more zero's are expected, starting at position 'xColon'. */
499 pxSet->xColon = pxSet->xTargetIndex;
500 }
501 }
502 else
503 {
504 if( pxSet->xTargetIndex <= pxSet->xHighestIndex )
505 {
506 /* Store a short value at position 'xTargetIndex'. */
507 pxSet->pucTarget[ pxSet->xTargetIndex ] = ( uint8_t ) ( ( pxSet->ulValue >> 8 ) & 0xffU );
508 pxSet->pucTarget[ pxSet->xTargetIndex + 1 ] = ( uint8_t ) ( pxSet->ulValue & 0xffU );
509 pxSet->xTargetIndex += 2;
510 pxSet->xHadDigit = pdFALSE;
511 pxSet->ulValue = 0U;
512 }
513 else
514 {
515 xReturn = pdFAIL;
516 }
517 }
518 }
519 else
520 {
521 /* When an IPv4 address or rubbish is provided, this statement will be reached. */
522 xReturn = pdFAIL;
523 }
524
525 return xReturn;
526 }
527 /*-----------------------------------------------------------*/
528
529 /**
530 * @brief Convert an ASCII character to its corresponding hexadecimal value.
531 * A :: block was found, now fill in the zero's.
532 * @param[in] pxSet A set of variables describing the conversion.
533 */
prv_inet_pton6_set_zeros(struct sPTON6_Set * pxSet)534 static void prv_inet_pton6_set_zeros( struct sPTON6_Set * pxSet )
535 {
536 /* The number of bytes that were written after the :: */
537 const BaseType_t xCount = pxSet->xTargetIndex - pxSet->xColon;
538 const BaseType_t xTopIndex = ( BaseType_t ) ipSIZE_OF_IPv6_ADDRESS;
539 BaseType_t xIndex;
540 BaseType_t xTarget = xTopIndex - 1;
541 BaseType_t xSource = pxSet->xColon + ( xCount - 1 );
542
543 /* Inserting 'xCount' zero's. */
544 for( xIndex = 0; xIndex < xCount; xIndex++ )
545 {
546 pxSet->pucTarget[ xTarget ] = pxSet->pucTarget[ xSource ];
547 pxSet->pucTarget[ xSource ] = 0;
548 xTarget--;
549 xSource--;
550 }
551
552 pxSet->xTargetIndex = ( BaseType_t ) ipSIZE_OF_IPv6_ADDRESS;
553 }
554 /*-----------------------------------------------------------*/
555
556 /**
557 * @brief Convert an IPv6 address in hexadecimal notation to a binary format of 16 bytes.
558 *
559 * @param[in] pcSource The address in hexadecimal notation.
560 * @param[out] pvDestination The address in binary format, 16 bytes long.
561 *
562 * @return The 32-bit representation of IP(v4) address.
563 */
FreeRTOS_inet_pton6(const char * pcSource,void * pvDestination)564 BaseType_t FreeRTOS_inet_pton6( const char * pcSource,
565 void * pvDestination )
566 {
567 char ch;
568 uint8_t ucNew;
569 BaseType_t xResult;
570 struct sPTON6_Set xSet;
571
572 const char * pcIterator = pcSource;
573
574 ( void ) memset( &( xSet ), 0, sizeof( xSet ) );
575 xSet.xColon = -1;
576 xSet.pucTarget = pvDestination;
577
578 ( void ) memset( xSet.pucTarget, 0, ipSIZE_OF_IPv6_ADDRESS );
579
580 xResult = 0;
581
582 /* Leading :: requires some special handling. */
583 if( strcmp( pcIterator, "::" ) == 0 )
584 {
585 xResult = 1;
586 }
587 else
588 {
589 if( pcIterator[ 0 ] == ':' )
590 {
591 pcIterator++;
592 }
593
594 /* The last bytes will be written at position 14 and 15. */
595 xSet.xHighestIndex = ( BaseType_t ) ipSIZE_OF_IPv6_ADDRESS;
596 xSet.xHighestIndex -= ( BaseType_t ) sizeof( uint16_t );
597
598 /* The value in ulValue is not yet valid. */
599 xSet.xHadDigit = pdFALSE;
600 xSet.ulValue = 0U;
601
602 for( ; ; )
603 {
604 ch = *( pcIterator );
605 pcIterator++;
606
607 if( ch == ( char ) '\0' )
608 {
609 /* The string is parsed now.
610 * Store the last short, if present. */
611 if( ( xSet.xHadDigit != pdFALSE ) &&
612 ( xSet.xTargetIndex <= xSet.xHighestIndex ) )
613 {
614 /* Add the last value seen, network byte order ( MSB first ). */
615 xSet.pucTarget[ xSet.xTargetIndex ] = ( uint8_t ) ( ( xSet.ulValue >> 8 ) & 0xffU );
616 xSet.pucTarget[ xSet.xTargetIndex + 1 ] = ( uint8_t ) ( xSet.ulValue & 0xffU );
617 xSet.xTargetIndex += 2;
618 }
619
620 /* Break out of the for-ever loop. */
621 break;
622 }
623
624 /* Convert from a readable character to a hex value. */
625 ucNew = ucASCIIToHex( ch );
626 /* See if this is a digit or a colon. */
627 xResult = prv_inet_pton6_add_nibble( &( xSet ), ucNew, ch );
628
629 if( xResult == pdFALSE )
630 {
631 /* The new character was not accepted. */
632 break;
633 }
634 } /* for( ;; ) */
635
636 if( xSet.xColon >= 0 )
637 {
638 /* The address contains a block of zero. */
639 prv_inet_pton6_set_zeros( &( xSet ) );
640 }
641
642 if( xSet.xTargetIndex == ( BaseType_t ) ipSIZE_OF_IPv6_ADDRESS )
643 {
644 xResult = 1;
645 }
646 }
647
648 if( xResult != 1 )
649 {
650 xSet.pucTarget = ( uint8_t * ) pvDestination;
651 ( void ) memset( xSet.pucTarget, 0, ipSIZE_OF_IPv6_ADDRESS );
652 }
653
654 return xResult;
655 }
656
657 /*-----------------------------------------------------------*/
658 /* *INDENT-OFF* */
659 #endif /* ipconfigUSE_IPv6 != 0 */
660 /* *INDENT-ON* */
661