1 /*
2  * Copyright (c) 2017-2018, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*****************************************************************************/
34 /* Include files                                                             */
35 /*****************************************************************************/
36 
37 #include <unistd.h>  /* needed? */
38 #include <string.h>
39 #include <stdlib.h>
40 
41 #include <ti/net/slnetutils.h>
42 #include <ti/net/slnetif.h>
43 #include <ti/net/slneterr.h>
44 
45 /*****************************************************************************/
46 /* Macro declarations                                                        */
47 /*****************************************************************************/
48 
49 #define SLNETUTIL_NORMALIZE_NEEDED 0
50 #if SLNETUTIL_NORMALIZE_NEEDED
51     #define SLNETUTIL_NORMALIZE_RET_VAL(retVal,err) ((retVal < 0)?(retVal = err):(retVal))
52 #else
53     #define SLNETUTIL_NORMALIZE_RET_VAL(retVal,err)
54 #endif
55 
56 /* Size needed for getaddrinfo mem allocation */
57 #define SLNETUTIL_ADDRINFO_ALLOCSZ ((sizeof(SlNetUtil_addrInfo_t)) + \
58         (sizeof(SlNetSock_AddrIn6_t)))
59 
60 /* Cap number of mem allocations in case of large number of results from DNS */
61 #define SLNETUTIL_ADDRINFO_MAX_DNS_NODES 10
62 
63 #define SLNETUTIL_DNSBUFSIZE ((SLNETUTIL_ADDRINFO_MAX_DNS_NODES) * \
64         (sizeof(uint32_t)))
65 
66 #define LL_PREFIX 0xFE80
67 
68 /*****************************************************************************/
69 /* Structure/Enum declarations                                               */
70 /*****************************************************************************/
71 
72 
73 /*****************************************************************************/
74 /* Function prototypes                                                       */
75 /*****************************************************************************/
76 
77 static int32_t SlNetUtil_UTOA(uint16_t value, char * string, uint16_t base);
78 static int32_t SlNetUtil_bin2StrIpV4(SlNetSock_InAddr_t *binaryAddr, char *strAddr, uint16_t strAddrLen);
79 static int32_t SlNetUtil_bin2StrIpV6(SlNetSock_In6Addr_t *binaryAddr, char *strAddr, uint16_t strAddrLen);
80 static int32_t SlNetUtil_strTok(char **string, char *returnstring, int retstringlength, const char *delimiter);
81 static int32_t SlNetUtil_str2BinIpV4(char *strAddr, SlNetSock_InAddr_t *binaryAddr);
82 static int32_t SlNetUtil_str2BinIpV6(char *strAddr, SlNetSock_In6Addr_t *binaryAddr);
83 
84 /* Local SlNetUtil_getAddrInfo utility functions */
85 static SlNetUtil_addrInfo_t *setAddrInfo(uint16_t ifID, SlNetSock_Addr_t *addr,
86         int family, const char *service, const SlNetUtil_addrInfo_t *hints);
87 
88 static SlNetUtil_addrInfo_t *createAddrInfo(uint16_t ifID,
89         SlNetSock_Addr_t *addr, int family, const char *service, int flags,
90         int socktype, int protocol);
91 
92 static int mergeLists(SlNetUtil_addrInfo_t **curList,
93         SlNetUtil_addrInfo_t **newList);
94 
95 //*****************************************************************************
96 //
97 // SlNetUtil_init - Initialize the slnetutil module
98 //
99 //*****************************************************************************
SlNetUtil_init(int32_t flags)100 int32_t SlNetUtil_init(int32_t flags)
101 {
102     return 0;
103 }
104 
105 
106 //*****************************************************************************
107 //  SlNetUtil_gaiStrErr
108 //*****************************************************************************
109 
110 /*
111  * Error codes for gai_strerror
112  * The order of this array MUST match the numbering of the SLNETUTIL_EAI_CODE
113  * defines in <ti/net/slneterr.h>
114  */
115 static const char *strErrorMsgs[] =
116 {
117     "Temporary failure in name resolution",         /* SLNETUTIL_EAI_AGAIN */
118     "Bad value for ai_flags",                       /* SLNETUTIL_EAI_BADFLAGS */
119     "Non-recoverable failure in name resolution",   /* SLNETUTIL_EAI_FAIL */
120     "ai_family not supported",                      /* SLNETUTIL_EAI_FAMILY */
121     "Memory allocation failure",                    /* SLNETUTIL_EAI_MEMORY */
122     "Node or service not known, "                   /* SLNETUTIL_EAI_NONAME */
123     "or both node and service are NULL",
124     "Service (port number) not supported "          /* SLNETUTIL_EAI_SERVICE */
125     "for ai_socktype",
126     "ai_socktype not supported",                    /* SLNETUTIL_EAI_SOCKTYPE */
127     "System error",                                 /* SLNETUTIL_EAI_SYSTEM */
128     "An argument buffer overflowed",                /* SLNETUTIL_EAI_OVERFLOW */
129     "Address family for node not supported"         /* SLNETUTIL_EAI_ADDRFAMILY */
130 };
131 
SlNetUtil_gaiStrErr(int32_t errorCode)132 const char *SlNetUtil_gaiStrErr(int32_t errorCode)
133 {
134     /*
135      * Error codes are negative starting with -3121 so
136      * ~(errorCode - SLNETUTIL_EAI_BASE) takes the one's compliment of the code
137      * minus the base of the error codes to convert the code into a positive
138      * value that matches the StrerrorMsgs array index.
139      */
140     int msgsIndex = ~(errorCode - SLNETUTIL_EAI_BASE);
141     int msgsRange = sizeof(strErrorMsgs) / sizeof(strErrorMsgs[0]);
142 
143     if ((msgsIndex < msgsRange) && (msgsIndex >= 0))
144     {
145         return strErrorMsgs[msgsIndex];
146     }
147     else
148     {
149         return "Unknown error";
150     }
151 }
152 
153 //*****************************************************************************
154 //
155 // SlNetUtil_getHostByName - Obtain the IP Address of machine on network, by
156 //                           machine name
157 //
158 //*****************************************************************************
SlNetUtil_getHostByName(uint32_t ifBitmap,char * name,const uint16_t nameLen,uint32_t * ipAddr,uint16_t * ipAddrLen,const uint8_t family)159 int32_t SlNetUtil_getHostByName(uint32_t ifBitmap, char *name, const uint16_t nameLen, uint32_t *ipAddr, uint16_t *ipAddrLen, const uint8_t family)
160 {
161     uint16_t origIpAddrLen;
162     SlNetIf_t *netIf;
163     int32_t    retVal;
164 
165     /* When ifBitmap is 0, that means automatic selection of all interfaces
166        is required, enable all bits in ifBitmap                              */
167     if (0 == ifBitmap)
168     {
169         ifBitmap = ~ifBitmap;
170     }
171 
172     /*
173      * Save original value of ipAddrLen. If DNS resolution fails, ipAddrLen
174      * will be overwritten with zero, which is problematic for next iteration
175      * of the while loop.
176      */
177     origIpAddrLen = *ipAddrLen;
178 
179     /* This loop tries to run get host by name on the required interface
180        only if it in state enable and connected status
181        When multiple interfaces, in addition to the enable and connected it
182        will try to run the function on the interface from the highest
183        priority until an answer will return or until no interfaces left      */
184     do
185     {
186         /* Search for the highest priority interface according to the
187            ifBitmap and the queryFlags                                       */
188         netIf = SlNetIf_queryIf(ifBitmap, SLNETIF_QUERY_IF_STATE_BIT | SLNETIF_QUERY_IF_CONNECTION_STATUS_BIT);
189 
190         /* Check if the function returned NULL or the requested interface
191            exists                                                            */
192         if ( (NULL == netIf) || ( NULL == (netIf->ifConf)->utilGetHostByName) )
193         {
194             /* Interface doesn't exists, return error code                   */
195             return SLNETERR_RET_CODE_INVALID_INPUT;
196         }
197         else
198         {
199             /* Disable the ifID bit from the ifBitmap after finding the netIf*/
200             ifBitmap &= ~(netIf->ifID);
201 
202             /* Use SlNetUtil_inetPton to test if name is already an IP address.
203                If so, point ipAddr to the binary value of the IP and return  */
204             if (SlNetUtil_inetPton(family, name, ipAddr)) {
205                 /* Convert ipAddr to host byte order as getHostByName requires
206                    ipAddr to be in host byte order */
207                 *ipAddr = SlNetUtil_ntohl(*ipAddr);
208 
209                 *ipAddrLen = 1;
210                 return netIf->ifID;
211             }
212 
213             /* Interface exists, return interface IP address                 */
214             retVal = (netIf->ifConf)->utilGetHostByName(netIf->ifContext, name, nameLen, ipAddr, ipAddrLen, family);
215             SLNETUTIL_NORMALIZE_RET_VAL(retVal, SLNETUTIL_ERR_UTILGETHOSTBYNAME_FAILED);
216 
217             /* Check retVal for error codes                                  */
218             if (retVal < SLNETERR_RET_CODE_OK)
219             {
220                 /*
221                  * utilGetHostByName failed. Restore the size of the ipAddr
222                  * array and continue to the next ifID
223                  */
224                 *ipAddrLen = origIpAddrLen;
225                 continue;
226             }
227             else
228             {
229                 /* Return success                                            */
230                 return netIf->ifID;
231             }
232         }
233     }while ( ifBitmap > 0 );
234     /* Interface doesn't exists, return error code                   */
235     return SLNETERR_RET_CODE_INVALID_INPUT;
236 }
237 
238 //*****************************************************************************
239 // SlNetUtil_getAddrInfo
240 //*****************************************************************************
SlNetUtil_getAddrInfo(uint16_t ifID,const char * node,const char * service,const struct SlNetUtil_addrInfo_t * hints,struct SlNetUtil_addrInfo_t ** res)241 int32_t SlNetUtil_getAddrInfo(uint16_t ifID, const char *node,
242         const char *service, const struct SlNetUtil_addrInfo_t *hints,
243         struct SlNetUtil_addrInfo_t **res)
244 {
245     int i;
246     int retval = 0;
247     int resolved = 0;
248     int numNodes = 0;
249     char *buffer = NULL;
250     char *currAddr = NULL;
251     uint16_t numIpAddrs;
252     int32_t selectedIfId;
253     int32_t ipv4DnsError = 0;
254     int32_t ipv6DnsError = 0;
255 
256     SlNetUtil_addrInfo_t *ai = NULL;
257     SlNetUtil_addrInfo_t *aiTmp = NULL;
258     SlNetSock_AddrIn_t sin;
259     SlNetSock_AddrIn6_t sin6;
260 
261     /* check args passed in for errors */
262     if (!node && !service) {
263         /* Error: node and service args cannot both be NULL */
264         return (SLNETUTIL_EAI_NONAME);
265     }
266 
267     if (!service) {
268         service = "0";
269     }
270 
271     if (!res) {
272         /* Error: res cannot be NULL */
273         return (SLNETUTIL_EAI_NONAME);
274     }
275 
276     if (!hints) {
277         /* User passed NULL hints. Create a hints for them with all 0 values */
278         static const SlNetUtil_addrInfo_t defHints = {
279             0,                   /* ai_flags */
280             SLNETSOCK_AF_UNSPEC, /* ai_family */
281             0,                   /* ai_socktype */
282             0,                   /* ai_protocol */
283             0,                   /* ai_addrlen */
284             NULL,                /* ai_addr */
285             NULL,                /* ai_canonname */
286             NULL                 /* ai_next */
287         };
288         hints = &defHints;
289     }
290     else {
291         /* Check the user's hints for invalid settings */
292         if (hints->ai_socktype != SLNETSOCK_SOCK_STREAM &&
293                 hints->ai_socktype != SLNETSOCK_SOCK_DGRAM &&
294                 hints->ai_socktype != 0) {
295             /* Error: invalid or unknown socktype */
296             return (SLNETUTIL_EAI_SOCKTYPE);
297         }
298         else if (hints->ai_protocol != SLNETSOCK_PROTO_TCP &&
299                 hints->ai_protocol != SLNETSOCK_PROTO_UDP &&
300                 hints->ai_protocol != 0) {
301             /* Error: invalid or unknown protocol */
302             return (SLNETUTIL_EAI_SOCKTYPE);
303         }
304         else if ((hints->ai_family != SLNETSOCK_AF_INET) &&
305                 (hints->ai_family != SLNETSOCK_AF_INET6) &&
306                 (hints->ai_family != SLNETSOCK_AF_UNSPEC)) {
307             /* Error: invalid or unknown family */
308             return (SLNETUTIL_EAI_FAMILY);
309         }
310     }
311 
312     if (node) {
313         /*
314          * Client case. User needs an address structure to call connect() with.
315          *
316          * Determine what caller has passed to us for 'node'. Should be either:
317          *     - an IPv4 address
318          *     - an IPv6 address
319          *     - or a hostname
320          */
321 
322         /* Test if 'node' is an IPv4 address */
323         retval = SlNetUtil_inetAton(node, &(sin.sin_addr));
324         if (retval) {
325             /* Ensure address family matches */
326             if (hints->ai_family != SLNETSOCK_AF_INET &&
327                     hints->ai_family != SLNETSOCK_AF_UNSPEC) {
328                 return (SLNETUTIL_EAI_ADDRFAMILY);
329             }
330 
331             /*
332              * Create addrinfo struct(s) containing this IPv4 address. If ai
333              * is NULL, this will be caught at end of getaddrinfo
334              *
335              * Pass zero for IF ID. This is a don't care for the case of node
336              * being set to an IPv4 address
337              */
338             ai = setAddrInfo(0, (SlNetSock_Addr_t *)&sin, SLNETSOCK_AF_INET,
339                     service, hints);
340         }
341         else {
342             /* 'node' is either an IPv6 address or a hostname (or invalid) */
343 
344             /* Test if 'node' is an IPv6 address */
345             retval = SlNetUtil_inetPton(SLNETSOCK_AF_INET6, node,
346                     &(sin6.sin6_addr));
347             if (retval > 0) {
348                 /* Ensure address family matches */
349                 if (hints->ai_family != SLNETSOCK_AF_INET6 &&
350                         hints->ai_family != SLNETSOCK_AF_UNSPEC) {
351                     return (SLNETUTIL_EAI_ADDRFAMILY);
352                 }
353 
354                 /*
355                  * If we were given a link local address and corresponding IF,
356                  * pass the IF number through. It must be used for the scope ID
357                  */
358                 if ((SlNetUtil_ntohs(sin6.sin6_addr._S6_un._S6_u16[0]) ==
359                         LL_PREFIX) && ifID != 0) {
360                      selectedIfId = ifID;
361                 }
362                 else {
363                     /*
364                      * Set scope ID to zero for these cases:
365                      *     - Link local addr and ifID == 0:
366                      *         (caller responsibe for setting scope ID)
367                      *
368                      *     - Non-local addr with ifID == 0:
369                      *     - Non-local addr with ifID == 1:
370                      *         scope ID not used and should be set to 0
371                      */
372                     selectedIfId = 0;
373                 }
374 
375                 /*
376                  * Create addrinfo struct(s) containing this IPv6 address. If
377                  * ai is NULL, this will be caught at end of getaddrinfo
378                  */
379                 ai = setAddrInfo(selectedIfId, (SlNetSock_Addr_t *)&sin6,
380                         SLNETSOCK_AF_INET6, service, hints);
381             }
382             else {
383                 /* Test if 'node' is a host name. Use DNS to resolve it. */
384 
385                 /*
386                  * Per RFC 2553, if node is not a valid numeric address string
387                  * and AI_NUMERICHOST is set, return error (and prevent call to
388                  * DNS).
389                  */
390                 if (hints->ai_flags & SLNETUTIL_AI_NUMERICHOST) {
391                     return (SLNETUTIL_EAI_NONAME);
392                 }
393 
394                 buffer = malloc(SLNETUTIL_DNSBUFSIZE);
395                 if (!buffer) {
396                     /* Error: couldn't alloc DNS buffer */
397                     return (SLNETUTIL_EAI_MEMORY);
398                 }
399 
400                 /* IPv4 DNS lookup */
401                 if (hints->ai_family == SLNETSOCK_AF_INET ||
402                         hints->ai_family == SLNETSOCK_AF_UNSPEC) {
403                     /*
404                      * Set the size of the buffer to the number of 32-bit IPv4
405                      * addresses this buffer can hold
406                      */
407                     numIpAddrs = SLNETUTIL_DNSBUFSIZE / sizeof(uint32_t);
408 
409                     selectedIfId = SlNetUtil_getHostByName(ifID, (char *)node,
410                             strlen(node), (uint32_t *)buffer, &numIpAddrs,
411                             SLNETSOCK_AF_INET);
412 
413                     if (selectedIfId > 0) {
414 
415                         /*
416                          * Process the results returned by DNS. Upon success,
417                          * numIpAddrs contains the number of IP addresses stored
418                          * into the buffer
419                          */
420                         resolved = 1;
421                         currAddr = buffer;
422                         for (i = 0; i < numIpAddrs &&
423                                 numNodes < SLNETUTIL_ADDRINFO_MAX_DNS_NODES;
424                                 i++) {
425                             sin.sin_addr.s_addr =
426                                     SlNetUtil_htonl(*((uint32_t *)currAddr));
427                             /*
428                              * Create addrinfo struct(s) containing this IPv4
429                              * address. This can return a list with multiple
430                              * nodes, depending on hints provided. Empty lists
431                              * are handled before returning.
432                              *
433                              * Pass zero for IF ID. This is a don't care for
434                              * the case of node being set to an IPv4 address.
435                              */
436                             aiTmp = setAddrInfo(0, (SlNetSock_Addr_t *)&sin,
437                                     SLNETSOCK_AF_INET, service, hints);
438 
439                             if (aiTmp) {
440                                 /*
441                                  * Merge the results into the main list
442                                  * for each loop iteration:
443                                  */
444                                 numNodes += mergeLists(&ai, &aiTmp);
445                             }
446 
447                             /* move to the next IPv4 address */
448                             currAddr += sizeof(uint32_t);
449                         }
450                     }
451                     else {
452                         /* save the IPv4 error code */
453                         ipv4DnsError = selectedIfId;
454                     }
455                 }
456 
457                 /* IPv6 DNS lookup */
458                 if (hints->ai_family == SLNETSOCK_AF_INET6 ||
459                         hints->ai_family == SLNETSOCK_AF_UNSPEC) {
460                     /*
461                      * Set the size of the buffer to the number of 128-bit IPv6
462                      * addresses this buffer can hold
463                      */
464                     numIpAddrs =
465                             SLNETUTIL_DNSBUFSIZE / sizeof(SlNetSock_In6Addr_t);
466 
467                     selectedIfId = SlNetUtil_getHostByName(ifID, (char *)node,
468                             strlen(node), (uint32_t *)buffer, &numIpAddrs,
469                             SLNETSOCK_AF_INET6);
470 
471                     if (selectedIfId > 0) {
472 
473                         /*
474                          * Process the results returned by DNS. Upon success,
475                          * numIpAddrs contains the number of IP addresses stored
476                          * into the buffer
477                          */
478                         resolved = 1;
479                         currAddr = buffer;
480                         for (i = 0; i < numIpAddrs &&
481                                 numNodes < SLNETUTIL_ADDRINFO_MAX_DNS_NODES;
482                                 i++) {
483 
484                             /* Copy the IPv6 address out of the buffer */
485                             memcpy(&(sin6.sin6_addr), currAddr,
486                                     sizeof(SlNetSock_In6Addr_t));
487 
488                             /*
489                              * Is this address non-local? If so, IF ID is a
490                              * don't care
491                              */
492                             if (sin6.sin6_addr._S6_un._S6_u16[0] != LL_PREFIX) {
493                                 selectedIfId = 0;
494                             }
495 
496                             /* Change byte ordering to net byte order */
497                             sin6.sin6_addr._S6_un._S6_u16[0] = SlNetUtil_htons(
498                                     sin6.sin6_addr._S6_un._S6_u16[0]);
499                             sin6.sin6_addr._S6_un._S6_u16[1] = SlNetUtil_htons(
500                                     sin6.sin6_addr._S6_un._S6_u16[1]);
501                             sin6.sin6_addr._S6_un._S6_u16[2] = SlNetUtil_htons(
502                                     sin6.sin6_addr._S6_un._S6_u16[2]);
503                             sin6.sin6_addr._S6_un._S6_u16[3] = SlNetUtil_htons(
504                                     sin6.sin6_addr._S6_un._S6_u16[3]);
505                             sin6.sin6_addr._S6_un._S6_u16[4] = SlNetUtil_htons(
506                                     sin6.sin6_addr._S6_un._S6_u16[4]);
507                             sin6.sin6_addr._S6_un._S6_u16[5] = SlNetUtil_htons(
508                                     sin6.sin6_addr._S6_un._S6_u16[5]);
509                             sin6.sin6_addr._S6_un._S6_u16[6] = SlNetUtil_htons(
510                                     sin6.sin6_addr._S6_un._S6_u16[6]);
511                             sin6.sin6_addr._S6_un._S6_u16[7] = SlNetUtil_htons(
512                                     sin6.sin6_addr._S6_un._S6_u16[7]);
513 
514                             /*
515                              * Create addrinfo struct(s) containing this IPv6
516                              * address. This can return a list with multiple
517                              * nodes, depending on hints provided. Empty lists
518                              * are handled before returning.
519                              *
520                              * Pass down the appropriate IF number or zero,
521                              * depending on whether this address is
522                              * local or not
523                              */
524 
525                             aiTmp = setAddrInfo(selectedIfId,
526                                     (SlNetSock_Addr_t *)&sin6,
527                                     SLNETSOCK_AF_INET6, service, hints);
528 
529                             if (aiTmp) {
530                                 /*
531                                  * Merge the results into the main list
532                                  * for each loop iteration:
533                                  */
534                                 numNodes += mergeLists(&ai, &aiTmp);
535                             }
536 
537                             /* move to the next IPv6 address */
538                             currAddr += sizeof(SlNetSock_In6Addr_t);
539                         }
540                     }
541                     else {
542                         /* save the IPv6 error code */
543                         ipv6DnsError = selectedIfId;
544                     }
545                 }
546 
547                 free(buffer);
548 
549                 if (!resolved) {
550                     /*
551                      * Error: couldn't resolve host name
552                      * Translate the SlNetSock error code to a GAI error code.
553                      * Give the IPv4 error precedence:
554                      */
555                     retval = (ipv4DnsError != 0) ? ipv4DnsError : ipv6DnsError;
556 
557                     switch (retval) {
558                         case SLNETERR_NET_APP_DNS_ALLOC_ERROR:
559                             retval = SLNETUTIL_EAI_MEMORY;
560                             break;
561                         case SLNETERR_NET_APP_DNS_INVALID_FAMILY_TYPE:
562                             retval = SLNETUTIL_EAI_FAMILY;
563                             break;
564                         case SLNETERR_NET_APP_DNS_IPV6_REQ_BUT_IPV6_DISABLED:
565                             retval = SLNETUTIL_EAI_SERVICE;
566                             break;
567                         case SLNETERR_NET_APP_DNS_PARAM_ERROR:
568                         case SLNETERR_NET_APP_DNS_QUERY_FAILED:
569                         default:
570                             retval = SLNETUTIL_EAI_FAIL;
571                             break;
572                     }
573                     return (retval);
574                 }
575             }
576         }
577     }
578     else {
579         /* Server case. User needs an address structure to call bind() with. */
580         if (hints->ai_family == SLNETSOCK_AF_INET ||
581                 hints->ai_family == SLNETSOCK_AF_UNSPEC) {
582             if (hints->ai_flags & SLNETUTIL_AI_PASSIVE) {
583                 /* Per RFC 2553, accept connections on any IF */
584                 sin.sin_addr.s_addr = SlNetUtil_htonl(SLNETSOCK_INADDR_ANY);
585             }
586             else {
587                 /* Per RFC 2553, accept connections on loopback IF */
588                 retval = SlNetUtil_inetPton(SLNETSOCK_AF_INET, "127.0.0.1",
589                         &(sin.sin_addr.s_addr));
590                 if (retval <= 0) {
591                     return (SLNETUTIL_EAI_SYSTEM);
592                 }
593             }
594 
595             /*
596              * Create addrinfo struct(s) containing this IPv4 address. If ai
597              * is NULL, this will be caught at end of getaddrinfo
598              *
599              * Pass zero for IF ID. This is a don't care for
600              * the case of setting up a server socket.
601              */
602             ai = setAddrInfo(0, (SlNetSock_Addr_t *)&sin,
603                     SLNETSOCK_AF_INET, service, hints);
604         }
605 
606         if (hints->ai_family == SLNETSOCK_AF_INET6 ||
607                 hints->ai_family == SLNETSOCK_AF_UNSPEC) {
608             if (hints->ai_flags & SLNETUTIL_AI_PASSIVE) {
609                 /*
610                  * Per RFC 2553, accept connections on any IF
611                  * (The IPv6 unspecified address is all zeroes)
612                  */
613                 /* TODO: use in6addr_any, once available (NS-84) */
614                 memset(&(sin6.sin6_addr), 0, sizeof(SlNetSock_In6Addr_t));
615             }
616             else {
617                 /*
618                  * Per RFC 2553, accept connections on loopback IF
619                  * (The IPv6 loopback address is a 1 preceded by all zeroes)
620                  */
621                 /* TODO: use in6addr_loopback, once available (NS-84) */
622                 sin6.sin6_addr._S6_un._S6_u32[0] = 0;
623                 sin6.sin6_addr._S6_un._S6_u32[1] = 0;
624                 sin6.sin6_addr._S6_un._S6_u32[2] = 0;
625                 sin6.sin6_addr._S6_un._S6_u32[3] = SlNetUtil_htonl(1);
626             }
627 
628             /*
629              * Create addrinfo struct(s) containing this IPv6 address. If ai
630              * is NULL, this will be caught at end of getaddrinfo
631              *
632              * Pass zero for IF ID. This is a don't care for
633              * the case of setting up a server socket.
634              */
635             aiTmp = setAddrInfo(0, (SlNetSock_Addr_t *)&sin6,
636                     SLNETSOCK_AF_INET6, service, hints);
637 
638             if (aiTmp) {
639                 /*
640                  * The current list (ai) may not be empty.  Merge the new
641                  * results (aiTmp) into the existing ai to handle this case.
642                  */
643                 mergeLists(&ai, &aiTmp);
644             }
645         }
646     }
647 
648     /* Give user our allocated and initialized addrinfo struct(s) */
649     *res = ai;
650 
651     if (!ai) {
652         /* Our list is empty - memory allocations failed */
653         return (SLNETUTIL_EAI_MEMORY);
654     }
655 
656     return (0);
657 }
658 
659 //*****************************************************************************
660 // SlNetUtil_freeAddrInfo
661 //*****************************************************************************
SlNetUtil_freeAddrInfo(struct SlNetUtil_addrInfo_t * res)662 void SlNetUtil_freeAddrInfo(struct SlNetUtil_addrInfo_t *res)
663 {
664     SlNetUtil_addrInfo_t *aiTmp;
665 
666     /* Delete all nodes in linked list */
667     while (res) {
668         aiTmp = res->ai_next;
669         free((void *)res);
670         res = aiTmp;
671     }
672 }
673 
674 //*****************************************************************************
675 // setAddrInfo
676 // Intermediate step to handle permutations of ai_socktype and ai_protocol
677 // hints fields, passed by the user.  If both socktype and protocol are 0, must
678 // create a results struct for each socktype and protocol.
679 // Returns an empty list (NULL) or a list with one or more nodes.
680 //*****************************************************************************
setAddrInfo(uint16_t ifID,SlNetSock_Addr_t * addr,int family,const char * service,const SlNetUtil_addrInfo_t * hints)681 static SlNetUtil_addrInfo_t *setAddrInfo(uint16_t ifID, SlNetSock_Addr_t *addr,
682         int family, const char *service,
683         const SlNetUtil_addrInfo_t *hints)
684 {
685     SlNetUtil_addrInfo_t *ai = NULL;
686     SlNetUtil_addrInfo_t *aiTmp = NULL;
687 
688     if ((hints->ai_socktype == 0 && hints->ai_protocol == 0) ||
689         (hints->ai_socktype == 0 && hints->ai_protocol == SLNETSOCK_PROTO_UDP)
690         || (hints->ai_socktype == SLNETSOCK_SOCK_DGRAM &&
691         hints->ai_protocol == 0) || (hints->ai_socktype == SLNETSOCK_SOCK_DGRAM
692         && hints->ai_protocol == SLNETSOCK_PROTO_UDP)) {
693 
694         ai = createAddrInfo(ifID, addr, family, service, hints->ai_flags,
695                 SLNETSOCK_SOCK_DGRAM, SLNETSOCK_PROTO_UDP);
696     }
697 
698     if ((hints->ai_socktype == 0 && hints->ai_protocol == 0) ||
699         (hints->ai_socktype == 0 && hints->ai_protocol == SLNETSOCK_PROTO_TCP)
700         || (hints->ai_socktype == SLNETSOCK_SOCK_STREAM &&
701         hints->ai_protocol == 0) || (hints->ai_socktype == SLNETSOCK_SOCK_STREAM
702         && hints->ai_protocol == SLNETSOCK_PROTO_TCP)) {
703 
704         aiTmp = createAddrInfo(ifID, addr, family, service, hints->ai_flags,
705                 SLNETSOCK_SOCK_STREAM, SLNETSOCK_PROTO_TCP);
706 
707         if (aiTmp) {
708             /* Insert into front of list (assume UDP node was added above) */
709             aiTmp->ai_next = ai;
710             ai = aiTmp;
711         }
712     }
713 
714     return (ai);
715 }
716 
717 //*****************************************************************************
718 // createAddrInfo
719 // Create new address info structure. Returns a single node.
720 //*****************************************************************************
createAddrInfo(uint16_t ifID,SlNetSock_Addr_t * addr,int family,const char * service,int flags,int socktype,int protocol)721 static SlNetUtil_addrInfo_t *createAddrInfo(uint16_t ifID,
722         SlNetSock_Addr_t *addr, int family, const char *service, int flags,
723         int socktype, int protocol)
724 {
725     SlNetUtil_addrInfo_t *ai = NULL;
726 
727     /*
728      * Allocate memory for the addrinfo struct, which we must fill out and
729      * return to the caller.  This struct also has a pointer to a generic socket
730      * address struct, which will point to either struct sockaddr_in, or
731      * struct sockaddr_in6, depending.  Need to allocate enough space to hold
732      * that struct, too.
733      */
734     ai = (SlNetUtil_addrInfo_t *)calloc(1, SLNETUTIL_ADDRINFO_ALLOCSZ);
735     if (!ai) {
736         /* Error: memory allocation failed */
737         return (NULL);
738     }
739 
740     ai->ai_flags = flags;
741     ai->ai_socktype = socktype;
742     ai->ai_protocol = protocol;
743     ai->ai_canonname = NULL;
744     ai->ai_next = NULL;
745 
746     /* Store socket addr struct after the addrinfo struct in our memory block */
747     ai->ai_addr = (SlNetSock_Addr_t *)(ai + 1);
748 
749     if (family == SLNETSOCK_AF_INET) {
750         /* Fill in structure for IPv4 */
751         ai->ai_family = SLNETSOCK_AF_INET;
752         ai->ai_addrlen = sizeof(SlNetSock_AddrIn_t);
753 
754         /* Write values to addrinfo's socket struct as an sockaddr_in struct */
755         ((SlNetSock_AddrIn_t *)ai->ai_addr)->sin_family = SLNETSOCK_AF_INET;
756 
757         ((SlNetSock_AddrIn_t *)ai->ai_addr)->sin_port =
758                 SlNetUtil_htons(atoi(service));
759 
760         ((SlNetSock_AddrIn_t *)ai->ai_addr)->sin_addr =
761                 ((SlNetSock_AddrIn_t *)addr)->sin_addr;
762     }
763     else {
764         /* Fill in structure for IPv6 */
765         ai->ai_family = SLNETSOCK_AF_INET6;
766         ai->ai_addrlen = sizeof(SlNetSock_AddrIn6_t);
767 
768         /* Write values to addrinfo's socket struct as an sockaddr_in6 struct */
769         ((SlNetSock_AddrIn6_t *)ai->ai_addr)->sin6_family = SLNETSOCK_AF_INET6;
770 
771         ((SlNetSock_AddrIn6_t *)ai->ai_addr)->sin6_port =
772                 SlNetUtil_htons(atoi(service));
773 
774         memcpy(&(((SlNetSock_AddrIn6_t *)ai->ai_addr)->sin6_addr),
775                 &(((SlNetSock_AddrIn6_t *)addr)->sin6_addr),
776                 sizeof(SlNetSock_In6Addr_t));
777 
778         /* Scope ID should have been determined correctly by the caller */
779         ((SlNetSock_AddrIn6_t *)ai->ai_addr)->sin6_scope_id = (uint32_t)ifID;
780     }
781 
782     return (ai);
783 }
784 
785 //*****************************************************************************
786 // mergeLists
787 // Combines an existing linked list of addrinfo structs (curList) and a newly
788 // obtained list (newList) into a single list. If the existing list is empty,
789 // it will be initialized to the new list.  If both lists are empty, no action
790 // is taken.
791 //*****************************************************************************
mergeLists(SlNetUtil_addrInfo_t ** curList,SlNetUtil_addrInfo_t ** newList)792 static int mergeLists(SlNetUtil_addrInfo_t **curList,
793         SlNetUtil_addrInfo_t **newList)
794 {
795     int numNodes = 0;
796     SlNetUtil_addrInfo_t *tail = NULL;
797 
798     /* Check params */
799     if (!curList || !newList || !(*newList)) {
800         return (numNodes);
801     }
802 
803     /* Update node count & find end of new list */
804     for (tail = *newList; tail != NULL;) {
805         numNodes++;
806         if (tail->ai_next != NULL) {
807             /* Not the tail, keep traversing */
808             tail = tail->ai_next;
809         }
810         else {
811             /* Tail found, quit loop */
812             break;
813         }
814     }
815 
816     /* Append current list to end of new list */
817     tail->ai_next = *curList;
818     *curList = *newList;
819 
820     return (numNodes);
821 }
822 
823 //*****************************************************************************
824 //
825 // SlNetUtil_htonl - Reorder the bytes of a 32-bit unsigned value from host
826 //                   order to network order(Big endian)
827 //
828 //*****************************************************************************
SlNetUtil_htonl(uint32_t val)829 uint32_t SlNetUtil_htonl(uint32_t val)
830 {
831     uint32_t i = 1;
832     int8_t  *p = (int8_t *)&i;
833 
834     /* When the LSB of i stored in the smallest address of *p                */
835     if (p[0] == 1) /* little endian */
836     {
837         /* Swap the places of the value                                      */
838         p[0] = ((int8_t *)&val)[3];
839         p[1] = ((int8_t *)&val)[2];
840         p[2] = ((int8_t *)&val)[1];
841         p[3] = ((int8_t *)&val)[0];
842 
843         /* return the reordered bytes                                        */
844         return i;
845     }
846     else /* big endian */
847     {
848         /* return the input without any changes                              */
849         return val;
850     }
851 }
852 
853 
854 //*****************************************************************************
855 //
856 // SlNetUtil_ntohl - Reorder the bytes of a 32-bit unsigned value from network
857 //                   order(Big endian) to host order
858 //
859 //*****************************************************************************
SlNetUtil_ntohl(uint32_t val)860 uint32_t SlNetUtil_ntohl(uint32_t val)
861 {
862     /* return the reordered bytes                                            */
863     return SlNetUtil_htonl(val);
864 }
865 
866 
867 //*****************************************************************************
868 //
869 // SlNetUtil_htons - Reorder the bytes of a 16-bit unsigned value from host
870 //                   order to network order(Big endian)
871 //
872 //*****************************************************************************
SlNetUtil_htons(uint16_t val)873 uint16_t SlNetUtil_htons(uint16_t val)
874 {
875     int16_t i = 1;
876     int8_t *p = (int8_t *)&i;
877 
878     /* When the LSB of i stored in the smallest address of *p                */
879     if (p[0] == 1) /* little endian */
880     {
881         /* Swap the places of the value                                      */
882         p[0] = ((int8_t *)&val)[1];
883         p[1] = ((int8_t *)&val)[0];
884 
885         /* return the reordered bytes                                        */
886         return (uint16_t)i;
887     }
888     else /* big endian */
889     {
890         /* return the input without any changes                              */
891         return val;
892     }
893 }
894 
895 
896 //*****************************************************************************
897 //
898 // SlNetUtil_ntohs - Reorder the bytes of a 16-bit unsigned value from network
899 //                   order(Big endian) to host order
900 //
901 //*****************************************************************************
SlNetUtil_ntohs(uint16_t val)902 uint16_t SlNetUtil_ntohs(uint16_t val)
903 {
904     /* return the reordered bytes                                            */
905     return SlNetUtil_htons(val);
906 }
907 
908 //*****************************************************************************
909 //
910 // SlNetUtil_UTOA - converts unsigned 16 bits binary number to string with
911 //                  maximum of 4 characters + 1 NULL terminated
912 //
913 //*****************************************************************************
SlNetUtil_UTOA(uint16_t value,char * string,uint16_t base)914 static int32_t SlNetUtil_UTOA(uint16_t value, char * string, uint16_t base)
915 {
916     uint16_t Index         = 4;
917     char     tempString[5] = { 0 };
918     char *   ptempString   = tempString;
919     char *   pString       = string;
920 
921     /* Check if the inputs valid                                             */
922     if ( (NULL == string) || ((base < 2 ) && (base > 16 )) )
923     {
924         return SLNETERR_RET_CODE_INVALID_INPUT;
925     }
926 
927     /* If value is zero, that means that the returned string needs to be zero*/
928     if (0 == value)
929     {
930         *ptempString = '0';
931         ptempString++;
932         Index--;
933     }
934 
935     /* Run until all value digits are 0 or until Index get to 0              */
936     for (; (value && (Index > 0)); Index--, value /= base)
937     {
938         *ptempString = "0123456789abcdef"[value % base];
939         ptempString++;
940     }
941     /* Invalid value input                                                   */
942     if (0 != value)
943     {
944         return SLNETERR_RET_CODE_INVALID_INPUT;
945     }
946 
947     /* Reverse the string and initialize temporary array                     */
948     while (Index < 4)
949     {
950         *(pString++) = *(--ptempString);
951         *ptempString = '\0';
952         *pString     = '\0';
953         Index++;
954     }
955 
956     return 0;
957 }
958 
959 //*****************************************************************************
960 //
961 // SlNetUtil_bin2StrIpV4 - converts IPv4 address in binary representation
962 //                         (network byte order) to IP address in string
963 //                         representation
964 //
965 //*****************************************************************************
SlNetUtil_bin2StrIpV4(SlNetSock_InAddr_t * binaryAddr,char * strAddr,uint16_t strAddrLen)966 static int32_t SlNetUtil_bin2StrIpV4(SlNetSock_InAddr_t *binaryAddr, char *strAddr, uint16_t strAddrLen)
967 {
968     uint8_t  tempOctet;
969     uint32_t tempBinAddr;
970     int32_t  octetIndex      = 0;
971     char     tempStrOctet[4] = { 0 };
972 
973     /* Check if the strAddr buffer is at least in the minimum required size  */
974     if (strAddrLen < SLNETSOCK_INET_ADDRSTRLEN)
975     {
976         /* Return error code                                                 */
977         return SLNETERR_RET_CODE_INVALID_INPUT;
978     }
979 
980     /* initialize strAddr to an empty string (so we can strcat() later)      */
981     strAddr[0] = '\0';
982 
983     /* Copy the address value for further use                                */
984     memcpy(&tempBinAddr, binaryAddr, sizeof(SlNetSock_InAddr_t));
985 
986     /* Run over all octets (in network byte order), starting with the
987        most significant octet and ending with the least significant octet    */
988     while ( octetIndex <= 3 )
989     {
990         /* Save octet on tempOctet for further usage.
991            When converting from binary representation to string
992            representation, the MSO of the binary number is the first char
993            of the string, so it needs to copied to the first location of
994            the array                                                         */
995         tempOctet = ((int8_t *)&tempBinAddr)[octetIndex];
996 
997         /* Initialize the octet for validation after copying the value       */
998         ((int8_t *)&tempBinAddr)[octetIndex] = 0;
999 
1000         /* Convert tempOctet to string                                       */
1001         SlNetUtil_UTOA(tempOctet, tempStrOctet, 10);
1002 
1003         /* Appends the tempStrOctet to strAddr                               */
1004         strcat(strAddr, tempStrOctet);
1005 
1006         /* Appends the "." to strAddr for the first 3 octets                 */
1007         if ( octetIndex < 3)
1008         {
1009             strcat(strAddr, ".");
1010         }
1011 
1012         /* Move to the next octet                                            */
1013         octetIndex ++;
1014 
1015     }
1016 
1017     /* Check if the address had only 4 octets, this was done by initializing
1018        each octet that was copied and than checking if the number equal to 0 */
1019     if ( 0 == tempBinAddr )
1020     {
1021         /* Return success                                                    */
1022         return SLNETERR_RET_CODE_OK;
1023     }
1024     else
1025     {
1026         /* Return error code                                                 */
1027         return SLNETERR_RET_CODE_INVALID_INPUT;
1028     }
1029 }
1030 
1031 
1032 //*****************************************************************************
1033 //
1034 // SlNetUtil_bin2StrIpV6 - converts IPv6 address in binary representation to
1035 //                         IP address in string representation
1036 //
1037 //*****************************************************************************
SlNetUtil_bin2StrIpV6(SlNetSock_In6Addr_t * binaryAddr,char * strAddr,uint16_t strAddrLen)1038 static int32_t SlNetUtil_bin2StrIpV6(SlNetSock_In6Addr_t *binaryAddr, char *strAddr, uint16_t strAddrLen)
1039 {
1040     uint16_t tempHextet;
1041     int32_t  hextetIndex      = 0;
1042     uint8_t  tempBinAddr[16]  = { 0 };
1043     char     tempStrHextet[5] = { 0 };
1044 
1045     /* Check if the strAddr buffer is at least in the minimum required size  */
1046     if (strAddrLen < SLNETSOCK_INET6_ADDRSTRLEN)
1047     {
1048         /* Return error code                                                 */
1049         return SLNETERR_RET_CODE_INVALID_INPUT;
1050     }
1051 
1052     /* initialize strAddr to an empty string (so we can strcat() later)      */
1053     strAddr[0] = '\0';
1054 
1055     /* Copy the address value for further use                                */
1056     memcpy(tempBinAddr, binaryAddr, sizeof(SlNetSock_In6Addr_t));
1057 
1058     /* Run over all octets, from the latest hextet (the most significant
1059        hextet) until the first one (the least significant hextet)            */
1060     while (hextetIndex < 8)
1061     {
1062         /* Save hextet on tempHextet for further usage.
1063            When converting from binary representation to string
1064            representation, the most significant hextet of the binary number
1065            is the first char of the string, so it needs to copied to the
1066            first location of the array                                       */
1067         tempHextet = (tempBinAddr[hextetIndex * 2] << 8) |
1068             (tempBinAddr[(hextetIndex * 2) + 1]);
1069 
1070         /* Convert tempHextet to string                                      */
1071         SlNetUtil_UTOA(tempHextet, tempStrHextet, 16);
1072 
1073         /* Appends the tempStrHextet to strAddr                              */
1074         strcat(strAddr, tempStrHextet);
1075 
1076         /* Appends the ":" after each hextet (without the last one)          */
1077         if (hextetIndex < 7)
1078         {
1079             strcat(strAddr, ":");
1080         }
1081 
1082         /* Move to the next hextet                                           */
1083         hextetIndex++;
1084 
1085     }
1086 
1087     /* Return success                                                    */
1088     return SLNETERR_RET_CODE_OK;
1089 }
1090 
1091 
1092 //*****************************************************************************
1093 //
1094 // SlNetUtil_inetNtop - converts IP address in binary representation to IP
1095 //                      address in string representation
1096 //
1097 //*****************************************************************************
SlNetUtil_inetNtop(int16_t addrFamily,const void * binaryAddr,char * strAddr,SlNetSocklen_t strAddrLen)1098 const char *SlNetUtil_inetNtop(int16_t addrFamily, const void *binaryAddr, char *strAddr, SlNetSocklen_t strAddrLen)
1099 {
1100     int32_t retVal;
1101 
1102     /* Switch according to the address family                                */
1103     switch(addrFamily)
1104     {
1105         case SLNETSOCK_AF_INET:
1106             /* Convert from IPv4 string to numeric/binary representation     */
1107             retVal = SlNetUtil_bin2StrIpV4((SlNetSock_InAddr_t *)binaryAddr, strAddr, strAddrLen);
1108 
1109         break;
1110         case SLNETSOCK_AF_INET6:
1111             /* Convert from IPv6 string to numeric/binary representation     */
1112             retVal = SlNetUtil_bin2StrIpV6((SlNetSock_In6Addr_t *)binaryAddr, strAddr, strAddrLen);
1113 
1114         break;
1115         default:
1116             /* wrong address family - function error, return NULL error      */
1117             return NULL;
1118     }
1119 
1120     /* Check if conversion was successful                                    */
1121     if (retVal != SLNETERR_RET_CODE_OK)
1122     {
1123         /* Conversion failed, return NULL as error code                      */
1124         return NULL;
1125     }
1126     /* Conversion success - return strAddr for success                       */
1127     return strAddr;
1128 }
1129 
1130 //*****************************************************************************
1131 //
1132 // SlNetUtil_strTok - Split a valid ipv4 string up into tokens
1133 //
1134 //*****************************************************************************
SlNetUtil_strTok(char ** string,char * returnstring,int retstringlength,const char * delimiter)1135 static int32_t SlNetUtil_strTok(char **string, char *returnstring, int retstringlength, const char *delimiter)
1136 {
1137     char * retStr;
1138     int count = 0;
1139 
1140     retStr = returnstring;
1141 
1142     while ( (**string !='\0') && (**string != *delimiter) &&
1143            (count != (retstringlength-1)))
1144     {
1145         *retStr = **string;
1146         retStr++;
1147         (*string)++;
1148         count++;
1149     }
1150     /* string portion has to either end with delimiter or null char to be an
1151        ipv4 string                                                           */
1152     if (**string !='\0' && **string != *delimiter)
1153     {
1154         return SLNETERR_RET_CODE_INVALID_INPUT;
1155     }
1156     /* skip delimiter chars                                                  */
1157     if (**string == *delimiter)
1158     {
1159         (*string)++;
1160     }
1161     *retStr = '\0';
1162 
1163     return SLNETERR_RET_CODE_OK;
1164 }
1165 
1166 //*****************************************************************************
1167 //
1168 // SlNetUtil_str2BinIpV4 - converts IPv4 address in string representation to
1169 //                         IP address in binary representation
1170 //
1171 //*****************************************************************************
SlNetUtil_str2BinIpV4(char * strAddr,SlNetSock_InAddr_t * binaryAddr)1172 static int32_t SlNetUtil_str2BinIpV4(char *strAddr, SlNetSock_InAddr_t *binaryAddr)
1173 {
1174     uint32_t  decNumber;
1175     char      token[4];
1176     char     *end;
1177     int32_t   retVal;
1178     int32_t   ipOctet     = 0;
1179     uint32_t  ipv4Address = 0;
1180     char     *modifiedStr = strAddr;
1181 
1182     /* split strAddr into tokens separated by "."                            */
1183     retVal = SlNetUtil_strTok(&modifiedStr, token, 4, ".");
1184     if (SLNETERR_RET_CODE_OK != retVal)
1185     {
1186         return retVal;
1187     }
1188 
1189     /* run 4 times as IPv4 contain of four octets and separated by periods   */
1190     while(ipOctet < 4)
1191     {
1192         /* Parses the token strAddr, interpreting its content as an integral
1193            number of the specified base 10                               */
1194         decNumber = (int)strtoul(token, &end, 10);
1195 
1196         /* Check if the octet holds valid number between the range 0-255.
1197            end points the end of the numeric portion of the input string
1198            for strtoul, so if end == token that means no conversion has
1199            occured as there was no numeric portion detected              */
1200         if (decNumber < 256 && end != token)
1201         {
1202             /* manually place each byte in network order */
1203             ((int8_t *)&ipv4Address)[ipOctet] = (uint8_t)decNumber;
1204 
1205             /* split strAddr into tokens separated by "."                */
1206             SlNetUtil_strTok(&modifiedStr, token, 4, ".");
1207             ipOctet++;
1208         }
1209         else
1210         {
1211             return SLNETERR_RET_CODE_INVALID_INPUT;
1212         }
1213     }
1214 
1215     /* Copy the temporary variable to the input variable                     */
1216     memcpy(binaryAddr, &ipv4Address, sizeof(SlNetSock_InAddr_t));
1217 
1218     return SLNETERR_RET_CODE_OK;
1219 }
1220 
1221 
1222 //*****************************************************************************
1223 //
1224 // SlNetUtil_str2BinIpV6 - converts IPv6 address in string representation to
1225 //                         IP address in binary representation
1226 //
1227 //*****************************************************************************
SlNetUtil_str2BinIpV6(char * strAddr,SlNetSock_In6Addr_t * binaryAddr)1228 static int32_t SlNetUtil_str2BinIpV6(char *strAddr, SlNetSock_In6Addr_t *binaryAddr)
1229 {
1230 
1231     int32_t   octetIndex      = 0;
1232     int32_t   octetTailIndex;
1233     uint8_t  *pLocalStr;
1234     uint8_t   tmp[16];
1235     int32_t   zeroCompressPos = -1;
1236     uint16_t  value           = 0;
1237     uint8_t   asciiCharacter  = 0;
1238 
1239     /* Copy the first address of the string                                  */
1240     pLocalStr = (uint8_t *)strAddr;
1241 
1242     /* Initialize tmp parameter                                              */
1243     memset(tmp, 0, sizeof(tmp));
1244 
1245     /* Check if the IP starts with "::"                                      */
1246     if(*pLocalStr==':')
1247     {
1248         /* If the IP starts with ":", check if it doesn't have the second ":"
1249            If so, return an error                                            */
1250         if(*++pLocalStr!=':')
1251         {
1252             return SLNETERR_RET_CODE_INVALID_INPUT;
1253         }
1254     }
1255 
1256     /* run over the remaining two octets                                     */
1257     while(*pLocalStr && (octetIndex < 16))
1258     {
1259         /* Check if the ASCII character is a number between "0" to "9"       */
1260         if(*pLocalStr >= '0' && *pLocalStr <= '9')
1261         {
1262             /* Each ASCII character can be max 4 bits, shift the number
1263               4 bits and copy the new converted number                       */
1264             value = (value << 4) | (*pLocalStr - '0');
1265 
1266             /* Set the flag for ASCII character                              */
1267             asciiCharacter = 1;
1268         }
1269         /* Check if the ASCII character is a hex character between "a" to "f"*/
1270         else if(*pLocalStr >= 'a' && *pLocalStr <= 'f')
1271         {
1272             /* Each ASCII character can be max 4 bits, shift the number
1273               4 bits and copy the new converted number                       */
1274             value = (value << 4) | ((*pLocalStr - 'a') + 10);
1275 
1276             /* Set the flag for ASCII character                              */
1277             asciiCharacter = 1;
1278         }
1279         /* Check if the ASCII character is a hex character between "A" to "F"*/
1280         else if(*pLocalStr >= 'A' && *pLocalStr <= 'F')
1281         {
1282             /* Each ASCII character can be max 4 bits, shift the number
1283               4 bits and copy the new converted number                       */
1284             value = (value << 4) | ((*pLocalStr - 'A') + 10);
1285 
1286             /* Set the flag for ASCII character                              */
1287             asciiCharacter = 1;
1288         }
1289         /* Check if the hextet (two octets) finished with ":" and still a
1290            part of the IP                                                    */
1291         else if((*pLocalStr == ':') && (octetIndex < 14))
1292         {
1293             /* Check if the hextet contain ASCII character                   */
1294             if(asciiCharacter)
1295             {
1296                 /* ASCII character exists, store the converted number in tmp
1297                    and reset the value and ascii character parameters        */
1298                 tmp[octetIndex++] = (value >> 8) & 0xFF;
1299                 tmp[octetIndex++] = (value) & 0xFF;
1300                 asciiCharacter = 0;
1301                 value = 0;
1302             }
1303             else
1304             {
1305                 /* ASCII character doesn't exists, compressed hextet found   */
1306                 if(zeroCompressPos < 0)
1307                 {
1308                     /* first compressed hextet found, sore the octet Index   */
1309                     zeroCompressPos = octetIndex;
1310                 }
1311                 else
1312                 {
1313                     /* Second compressed hextet found, return error code     */
1314                     return SLNETERR_RET_CODE_INVALID_INPUT;
1315                 }
1316             }
1317         }
1318         /* None of the valid characters have matched so this is not an ipv6
1319            address                                                           */
1320         else
1321         {
1322             return SLNETERR_RET_CODE_INVALID_INPUT;
1323         }
1324         /* Continue to the next ASCII character                              */
1325         pLocalStr++;
1326     }
1327 
1328     /* if more than 15 octets found, return error code                       */
1329     if(octetIndex > 15)
1330     {
1331         return SLNETERR_RET_CODE_INVALID_INPUT;
1332     }
1333     /* if less than 14 octets found, and without any compress hextet,
1334        return error code                                                     */
1335     else if(asciiCharacter && (zeroCompressPos < 0) && (octetIndex < 14))
1336     {
1337         return SLNETERR_RET_CODE_INVALID_INPUT;
1338     }
1339     /* if all octets found, but still found compressed hextet,
1340        return error code                                                     */
1341     else if((zeroCompressPos >= 0) && octetIndex >= 14)
1342     {
1343         return SLNETERR_RET_CODE_INVALID_INPUT;
1344     }
1345 
1346     /* copy the last available hextet to the tmp array                       */
1347     if((asciiCharacter) && (octetIndex <= 14))
1348     {
1349         /* Store the converted number in tmp and reset the value and
1350            ascii character parameters                                        */
1351         tmp[octetIndex++] = (value >> 8) & 0xFF;
1352         tmp[octetIndex++] = (value) & 0xFF;
1353         asciiCharacter = 0;
1354         value = 0;
1355     }
1356 
1357     /* compressed position found, add zeros in the compressed sections       */
1358     if(zeroCompressPos >= 0)
1359     {
1360         /* compressed position found, add zeros in the compressed sections   */
1361         octetIndex--;
1362         octetTailIndex = 15;
1363         /* Move the converted octets from the position they are located on
1364            to the end of the array and add zero instead */
1365         while(octetIndex >= zeroCompressPos)
1366         {
1367             /* Check if the indexes are still in range                       */
1368             if ((octetTailIndex >= 0) && (octetIndex >= 0))
1369             {
1370                 /* Move all the octets after the zero compress position to
1371                    the end of the array                                      */
1372                 tmp[octetTailIndex] = tmp[octetIndex];
1373                 tmp[octetIndex] = 0;
1374                 octetTailIndex--;
1375                 octetIndex--;
1376             }
1377         }
1378     }
1379 
1380     /* Copy the temporary variable to the input variable                     */
1381     memcpy(binaryAddr, tmp, sizeof(tmp));
1382 
1383     return SLNETERR_RET_CODE_OK;
1384 
1385 }
1386 
1387 //*****************************************************************************
1388 //
1389 // SlNetUtil_inetAton - Converts a string to a network address structure
1390 //
1391 //*****************************************************************************
SlNetUtil_inetAton(const char * str,SlNetSock_InAddr_t * addr)1392 int SlNetUtil_inetAton(const char *str, SlNetSock_InAddr_t *addr)
1393 {
1394     uint32_t val[4];
1395     uint32_t base;
1396     int sect;
1397     char c;
1398 
1399     sect = -1;
1400     while (*str) {
1401         /* New section */
1402         sect++;
1403 
1404         /* Get the base for this number */
1405         base = 10;
1406         if (*str == '0')
1407         {
1408             if (*(str + 1) == 'x' || *(str + 1) == 'X') {
1409                 base = 16;
1410                 str += 2;
1411             }
1412             else {
1413                 base = 8;
1414                 str++;
1415             }
1416         }
1417 
1418         /* Now decode this number */
1419         val[sect] = 0;
1420         for (;;) {
1421             c = *str++;
1422 
1423             if ((c >= '0' && c <= '9')) {
1424                 val[sect] = (val[sect] * base) + (c - '0');
1425             }
1426             else if (base == 16 && (c >= 'A' && c <= 'F')) {
1427                 val[sect] = (val[sect] * 16) + (c - 'A') + 10;
1428             }
1429             else if (base == 16 && (c >= 'a' && c <= 'f')) {
1430                 val[sect] = (val[sect] * 16) + (c - 'a') + 10;
1431             }
1432             else if (c == '.') {
1433                 /* validate value */
1434                 if(val[sect] > 255) {
1435                     return (0);
1436                 }
1437 
1438                 /*
1439                  * Once we have four sections, quit.
1440                  * We want to accept: "1.2.3.4.in-addr.arpa"
1441                  */
1442                 if (sect == 3) {
1443                     goto done;
1444                 }
1445 
1446                 /* Break this section */
1447                 break;
1448             }
1449             else if (!c) {
1450                 goto done;
1451             }
1452             else if (c != ' ') {
1453                 return (0);
1454             }
1455         }
1456     }
1457 
1458 done:
1459     /* What we do changes based on the number of sections */
1460     switch (sect) {
1461         case 0:
1462             addr->s_addr = val[0];
1463             break;
1464         case 1:
1465             if (val[1] > 0xffffff) {
1466                 return (0);
1467             }
1468             addr->s_addr = val[0] << 24;
1469             addr->s_addr += val[1];
1470             break;
1471         case 2:
1472             if (val[2] > 0xffff) {
1473                 return (0);
1474             }
1475             addr->s_addr = val[0] << 24;
1476             addr->s_addr += (val[1] << 16);
1477             addr->s_addr += val[2];
1478             break;
1479         case 3:
1480             if (val[3] > 0xff) {
1481                 return (0);
1482             }
1483             addr->s_addr = val[0] << 24;
1484             addr->s_addr += (val[1] << 16);
1485             addr->s_addr += (val[2] << 8);
1486             addr->s_addr += val[3];
1487             break;
1488         default:
1489             return (0);
1490     }
1491 
1492     addr->s_addr = SlNetUtil_htonl(addr->s_addr);
1493     return (1);
1494 }
1495 
1496 //*****************************************************************************
1497 //
1498 // SlNetUtil_inetPton - converts IP address in string representation to IP
1499 //                      address in binary representation
1500 //
1501 //*****************************************************************************
SlNetUtil_inetPton(int16_t addrFamily,const char * strAddr,void * binaryAddr)1502 int32_t SlNetUtil_inetPton(int16_t addrFamily, const char *strAddr, void *binaryAddr)
1503 {
1504     int32_t retVal;
1505 
1506     /* Switch according to the address family                                */
1507     switch(addrFamily)
1508     {
1509         case SLNETSOCK_AF_INET:
1510             /* Convert from IPv4 string to numeric/binary representation     */
1511             retVal = SlNetUtil_str2BinIpV4((char *)strAddr, (SlNetSock_InAddr_t *)binaryAddr);
1512             break;
1513 
1514         case SLNETSOCK_AF_INET6:
1515             /* Convert from IPv6 string to numeric/binary representation     */
1516             retVal = SlNetUtil_str2BinIpV6((char *)strAddr, (SlNetSock_In6Addr_t *)binaryAddr);
1517             break;
1518 
1519         default:
1520             /* wrong address family - function error, return -1 error        */
1521             return -1;
1522     }
1523 
1524     /* Check if conversion was successful                                    */
1525     if (retVal != SLNETERR_RET_CODE_OK)
1526     {
1527         /* Conversion failed, that means the input wasn't a
1528            valid IP address, return 0 as error code                          */
1529         return 0;
1530     }
1531     /* Conversion success - return 1 for success                             */
1532     return 1;
1533 }
1534