17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 22*59927d31SYuri Pankov 237c478bd9Sstevel@tonic-gate /* 247c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 257c478bd9Sstevel@tonic-gate * Use is subject to license terms. 26*59927d31SYuri Pankov * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 277c478bd9Sstevel@tonic-gate */ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 317c478bd9Sstevel@tonic-gate #include <sys/systm.h> 327c478bd9Sstevel@tonic-gate #include <sys/socket.h> 337c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 347c478bd9Sstevel@tonic-gate #include <netinet/in.h> 357c478bd9Sstevel@tonic-gate #include <inet/led.h> 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate static void convert2ascii(char *, const in6_addr_t *); 387c478bd9Sstevel@tonic-gate static char *strchr_w(const char *, int); 397c478bd9Sstevel@tonic-gate static int str2inet_addr(char *, ipaddr_t *); 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate /* 427c478bd9Sstevel@tonic-gate * inet_ntop -- Convert an IPv4 or IPv6 address in binary form into 437c478bd9Sstevel@tonic-gate * printable form, and return a pointer to that string. Caller should 447c478bd9Sstevel@tonic-gate * provide a buffer of correct length to store string into. 457c478bd9Sstevel@tonic-gate * Note: this routine is kernel version of inet_ntop. It has similar 467c478bd9Sstevel@tonic-gate * format as inet_ntop() defined in rfc2553. But it does not do 477c478bd9Sstevel@tonic-gate * error handling operations exactly as rfc2553 defines. This function 487c478bd9Sstevel@tonic-gate * is used by kernel inet directory routines only for debugging. 497c478bd9Sstevel@tonic-gate * This inet_ntop() function, does not return NULL if third argument 507c478bd9Sstevel@tonic-gate * is NULL. The reason is simple that we don't want kernel to panic 517c478bd9Sstevel@tonic-gate * as the output of this function is directly fed to ip<n>dbg macro. 527c478bd9Sstevel@tonic-gate * Instead it uses a local buffer for destination address for 537c478bd9Sstevel@tonic-gate * those calls which purposely pass NULL ptr for the destination 547c478bd9Sstevel@tonic-gate * buffer. This function is thread-safe when the caller passes a non- 557c478bd9Sstevel@tonic-gate * null buffer with the third argument. 567c478bd9Sstevel@tonic-gate */ 577c478bd9Sstevel@tonic-gate /* ARGSUSED */ 587c478bd9Sstevel@tonic-gate char * 597c478bd9Sstevel@tonic-gate inet_ntop(int af, const void *addr, char *buf, int addrlen) 607c478bd9Sstevel@tonic-gate { 617c478bd9Sstevel@tonic-gate static char local_buf[INET6_ADDRSTRLEN]; 627c478bd9Sstevel@tonic-gate static char *err_buf1 = "<badaddr>"; 637c478bd9Sstevel@tonic-gate static char *err_buf2 = "<badfamily>"; 647c478bd9Sstevel@tonic-gate in6_addr_t *v6addr; 657c478bd9Sstevel@tonic-gate uchar_t *v4addr; 667c478bd9Sstevel@tonic-gate char *caddr; 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate /* 697c478bd9Sstevel@tonic-gate * We don't allow thread unsafe inet_ntop calls, they 707c478bd9Sstevel@tonic-gate * must pass a non-null buffer pointer. For DEBUG mode 717c478bd9Sstevel@tonic-gate * we use the ASSERT() and for non-debug kernel it will 727c478bd9Sstevel@tonic-gate * silently allow it for now. Someday we should remove 737c478bd9Sstevel@tonic-gate * the static buffer from this function. 747c478bd9Sstevel@tonic-gate */ 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate ASSERT(buf != NULL); 777c478bd9Sstevel@tonic-gate if (buf == NULL) 787c478bd9Sstevel@tonic-gate buf = local_buf; 797c478bd9Sstevel@tonic-gate buf[0] = '\0'; 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate /* Let user know politely not to send NULL or unaligned addr */ 827c478bd9Sstevel@tonic-gate if (addr == NULL || !(OK_32PTR(addr))) { 837c478bd9Sstevel@tonic-gate #ifdef DEBUG 847c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "inet_ntop: addr is <null> or unaligned"); 857c478bd9Sstevel@tonic-gate #endif 867c478bd9Sstevel@tonic-gate return (err_buf1); 877c478bd9Sstevel@tonic-gate } 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate #define UC(b) (((int)b) & 0xff) 917c478bd9Sstevel@tonic-gate switch (af) { 927c478bd9Sstevel@tonic-gate case AF_INET: 937c478bd9Sstevel@tonic-gate ASSERT(addrlen >= INET_ADDRSTRLEN); 947c478bd9Sstevel@tonic-gate v4addr = (uchar_t *)addr; 957c478bd9Sstevel@tonic-gate (void) sprintf(buf, "%03d.%03d.%03d.%03d", 967c478bd9Sstevel@tonic-gate UC(v4addr[0]), UC(v4addr[1]), UC(v4addr[2]), UC(v4addr[3])); 977c478bd9Sstevel@tonic-gate return (buf); 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate case AF_INET6: 1007c478bd9Sstevel@tonic-gate ASSERT(addrlen >= INET6_ADDRSTRLEN); 1017c478bd9Sstevel@tonic-gate v6addr = (in6_addr_t *)addr; 1027c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(v6addr)) { 1037c478bd9Sstevel@tonic-gate caddr = (char *)addr; 1047c478bd9Sstevel@tonic-gate (void) sprintf(buf, "::ffff:%d.%d.%d.%d", 1057c478bd9Sstevel@tonic-gate UC(caddr[12]), UC(caddr[13]), 1067c478bd9Sstevel@tonic-gate UC(caddr[14]), UC(caddr[15])); 1077c478bd9Sstevel@tonic-gate } else if (IN6_IS_ADDR_V4COMPAT(v6addr)) { 1087c478bd9Sstevel@tonic-gate caddr = (char *)addr; 1097c478bd9Sstevel@tonic-gate (void) sprintf(buf, "::%d.%d.%d.%d", 1107c478bd9Sstevel@tonic-gate UC(caddr[12]), UC(caddr[13]), UC(caddr[14]), 1117c478bd9Sstevel@tonic-gate UC(caddr[15])); 1127c478bd9Sstevel@tonic-gate } else if (IN6_IS_ADDR_UNSPECIFIED(v6addr)) { 1137c478bd9Sstevel@tonic-gate (void) sprintf(buf, "::"); 1147c478bd9Sstevel@tonic-gate } else { 1157c478bd9Sstevel@tonic-gate convert2ascii(buf, v6addr); 1167c478bd9Sstevel@tonic-gate } 1177c478bd9Sstevel@tonic-gate return (buf); 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate default: 1207c478bd9Sstevel@tonic-gate return (err_buf2); 1217c478bd9Sstevel@tonic-gate } 1227c478bd9Sstevel@tonic-gate #undef UC 1237c478bd9Sstevel@tonic-gate } 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate /* 1267c478bd9Sstevel@tonic-gate * 1277c478bd9Sstevel@tonic-gate * v6 formats supported 1287c478bd9Sstevel@tonic-gate * General format xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx 1297c478bd9Sstevel@tonic-gate * The short hand notation :: is used for COMPAT addr 1307c478bd9Sstevel@tonic-gate * Other forms : fe80::xxxx:xxxx:xxxx:xxxx 1317c478bd9Sstevel@tonic-gate */ 1327c478bd9Sstevel@tonic-gate static void 1337c478bd9Sstevel@tonic-gate convert2ascii(char *buf, const in6_addr_t *addr) 1347c478bd9Sstevel@tonic-gate { 1357c478bd9Sstevel@tonic-gate int hexdigits; 1367c478bd9Sstevel@tonic-gate int head_zero = 0; 1377c478bd9Sstevel@tonic-gate int tail_zero = 0; 1387c478bd9Sstevel@tonic-gate /* tempbuf must be big enough to hold ffff:\0 */ 1397c478bd9Sstevel@tonic-gate char tempbuf[6]; 1407c478bd9Sstevel@tonic-gate char *ptr; 1417c478bd9Sstevel@tonic-gate uint16_t *addr_component; 1427c478bd9Sstevel@tonic-gate size_t len; 1437c478bd9Sstevel@tonic-gate boolean_t first = B_FALSE; 1447c478bd9Sstevel@tonic-gate boolean_t med_zero = B_FALSE; 1457c478bd9Sstevel@tonic-gate boolean_t end_zero = B_FALSE; 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate addr_component = (uint16_t *)addr; 1487c478bd9Sstevel@tonic-gate ptr = buf; 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate /* First count if trailing zeroes higher in number */ 1517c478bd9Sstevel@tonic-gate for (hexdigits = 0; hexdigits < 8; hexdigits++) { 1527c478bd9Sstevel@tonic-gate if (*addr_component == 0) { 1537c478bd9Sstevel@tonic-gate if (hexdigits < 4) 1547c478bd9Sstevel@tonic-gate head_zero++; 1557c478bd9Sstevel@tonic-gate else 1567c478bd9Sstevel@tonic-gate tail_zero++; 1577c478bd9Sstevel@tonic-gate } 1587c478bd9Sstevel@tonic-gate addr_component++; 1597c478bd9Sstevel@tonic-gate } 1607c478bd9Sstevel@tonic-gate addr_component = (uint16_t *)addr; 1617c478bd9Sstevel@tonic-gate if (tail_zero > head_zero && (head_zero + tail_zero) != 7) 1627c478bd9Sstevel@tonic-gate end_zero = B_TRUE; 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate for (hexdigits = 0; hexdigits < 8; hexdigits++) { 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate /* if entry is a 0 */ 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate if (*addr_component == 0) { 1697c478bd9Sstevel@tonic-gate if (!first && *(addr_component + 1) == 0) { 1707c478bd9Sstevel@tonic-gate if (end_zero && (hexdigits < 4)) { 1717c478bd9Sstevel@tonic-gate *ptr++ = '0'; 1727c478bd9Sstevel@tonic-gate *ptr++ = ':'; 1737c478bd9Sstevel@tonic-gate } else { 1747c478bd9Sstevel@tonic-gate /* 1757c478bd9Sstevel@tonic-gate * address starts with 0s .. 1767c478bd9Sstevel@tonic-gate * stick in leading ':' of pair 1777c478bd9Sstevel@tonic-gate */ 1787c478bd9Sstevel@tonic-gate if (hexdigits == 0) 1797c478bd9Sstevel@tonic-gate *ptr++ = ':'; 1807c478bd9Sstevel@tonic-gate /* add another */ 1817c478bd9Sstevel@tonic-gate *ptr++ = ':'; 1827c478bd9Sstevel@tonic-gate first = B_TRUE; 1837c478bd9Sstevel@tonic-gate med_zero = B_TRUE; 1847c478bd9Sstevel@tonic-gate } 1857c478bd9Sstevel@tonic-gate } else if (first && med_zero) { 1867c478bd9Sstevel@tonic-gate if (hexdigits == 7) 1877c478bd9Sstevel@tonic-gate *ptr++ = ':'; 1887c478bd9Sstevel@tonic-gate addr_component++; 1897c478bd9Sstevel@tonic-gate continue; 1907c478bd9Sstevel@tonic-gate } else { 1917c478bd9Sstevel@tonic-gate *ptr++ = '0'; 1927c478bd9Sstevel@tonic-gate *ptr++ = ':'; 1937c478bd9Sstevel@tonic-gate } 1947c478bd9Sstevel@tonic-gate addr_component++; 1957c478bd9Sstevel@tonic-gate continue; 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate if (med_zero) 1987c478bd9Sstevel@tonic-gate med_zero = B_FALSE; 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate tempbuf[0] = '\0'; 2017c478bd9Sstevel@tonic-gate (void) sprintf(tempbuf, "%x:", ntohs(*addr_component) & 0xffff); 2027c478bd9Sstevel@tonic-gate len = strlen(tempbuf); 2037c478bd9Sstevel@tonic-gate bcopy(tempbuf, ptr, len); 2047c478bd9Sstevel@tonic-gate ptr = ptr + len; 2057c478bd9Sstevel@tonic-gate addr_component++; 2067c478bd9Sstevel@tonic-gate } 2077c478bd9Sstevel@tonic-gate *--ptr = '\0'; 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate /* 2117c478bd9Sstevel@tonic-gate * search for char c, terminate on trailing white space 2127c478bd9Sstevel@tonic-gate */ 2137c478bd9Sstevel@tonic-gate static char * 2147c478bd9Sstevel@tonic-gate strchr_w(const char *sp, int c) 2157c478bd9Sstevel@tonic-gate { 2167c478bd9Sstevel@tonic-gate /* skip leading white space */ 2177c478bd9Sstevel@tonic-gate while (*sp && (*sp == ' ' || *sp == '\t')) { 2187c478bd9Sstevel@tonic-gate sp++; 2197c478bd9Sstevel@tonic-gate } 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate do { 2227c478bd9Sstevel@tonic-gate if (*sp == (char)c) 2237c478bd9Sstevel@tonic-gate return ((char *)sp); 2247c478bd9Sstevel@tonic-gate if (*sp == ' ' || *sp == '\t') 2257c478bd9Sstevel@tonic-gate return (NULL); 2267c478bd9Sstevel@tonic-gate } while (*sp++); 2277c478bd9Sstevel@tonic-gate return (NULL); 2287c478bd9Sstevel@tonic-gate } 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate static int 2317c478bd9Sstevel@tonic-gate str2inet_addr(char *cp, ipaddr_t *addrp) 2327c478bd9Sstevel@tonic-gate { 2337c478bd9Sstevel@tonic-gate char *end; 2347c478bd9Sstevel@tonic-gate long byte; 2357c478bd9Sstevel@tonic-gate int i; 2367c478bd9Sstevel@tonic-gate ipaddr_t addr = 0; 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) { 2397c478bd9Sstevel@tonic-gate if (ddi_strtol(cp, &end, 10, &byte) != 0 || byte < 0 || 2407c478bd9Sstevel@tonic-gate byte > 255) { 2417c478bd9Sstevel@tonic-gate return (0); 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate addr = (addr << 8) | (uint8_t)byte; 2447c478bd9Sstevel@tonic-gate if (i < 3) { 2457c478bd9Sstevel@tonic-gate if (*end != '.') { 2467c478bd9Sstevel@tonic-gate return (0); 2477c478bd9Sstevel@tonic-gate } else { 2487c478bd9Sstevel@tonic-gate cp = end + 1; 2497c478bd9Sstevel@tonic-gate } 2507c478bd9Sstevel@tonic-gate } else { 2517c478bd9Sstevel@tonic-gate cp = end; 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate *addrp = addr; 2557c478bd9Sstevel@tonic-gate return (1); 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate /* 2597c478bd9Sstevel@tonic-gate * inet_pton: This function takes string format IPv4 or IPv6 address and 2607c478bd9Sstevel@tonic-gate * converts it to binary form. The format of this function corresponds to 2617c478bd9Sstevel@tonic-gate * inet_pton() in the socket library. 262*59927d31SYuri Pankov * 263*59927d31SYuri Pankov * Return values: 264*59927d31SYuri Pankov * 0 invalid IPv4 or IPv6 address 265*59927d31SYuri Pankov * 1 successful conversion 266*59927d31SYuri Pankov * -1 af is not AF_INET or AF_INET6 2677c478bd9Sstevel@tonic-gate */ 2687c478bd9Sstevel@tonic-gate int 269*59927d31SYuri Pankov __inet_pton(int af, char *inp, void *outp, int compat) 2707c478bd9Sstevel@tonic-gate { 2717c478bd9Sstevel@tonic-gate int i; 2727c478bd9Sstevel@tonic-gate long byte; 2737c478bd9Sstevel@tonic-gate char *end; 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate switch (af) { 2767c478bd9Sstevel@tonic-gate case AF_INET: 277*59927d31SYuri Pankov if (str2inet_addr(inp, (ipaddr_t *)outp) != 0) { 278*59927d31SYuri Pankov if (!compat) 279*59927d31SYuri Pankov *(uint32_t *)outp = htonl(*(uint32_t *)outp); 280*59927d31SYuri Pankov return (1); 281*59927d31SYuri Pankov } else { 282*59927d31SYuri Pankov return (0); 283*59927d31SYuri Pankov } 2847c478bd9Sstevel@tonic-gate case AF_INET6: { 2857c478bd9Sstevel@tonic-gate union v6buf_u { 2867c478bd9Sstevel@tonic-gate uint16_t v6words_u[8]; 2877c478bd9Sstevel@tonic-gate in6_addr_t v6addr_u; 2887c478bd9Sstevel@tonic-gate } v6buf, *v6outp; 2897c478bd9Sstevel@tonic-gate uint16_t *dbl_col = NULL; 2907c478bd9Sstevel@tonic-gate char lastbyte = NULL; 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate v6outp = (union v6buf_u *)outp; 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate if (strchr_w(inp, '.') != NULL) { 2957c478bd9Sstevel@tonic-gate /* v4 mapped or v4 compatable */ 2967c478bd9Sstevel@tonic-gate if (strncmp(inp, "::ffff:", 7) == 0) { 2977c478bd9Sstevel@tonic-gate ipaddr_t ipv4_all_zeroes = 0; 2987c478bd9Sstevel@tonic-gate /* mapped - first init prefix and then fill */ 2997c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(ipv4_all_zeroes, 3007c478bd9Sstevel@tonic-gate &v6outp->v6addr_u); 3017c478bd9Sstevel@tonic-gate return (str2inet_addr(inp + 7, 3027c478bd9Sstevel@tonic-gate &(v6outp->v6addr_u.s6_addr32[3]))); 3037c478bd9Sstevel@tonic-gate } else if (strncmp(inp, "::", 2) == 0) { 3047c478bd9Sstevel@tonic-gate /* v4 compatable - prefix all zeroes */ 3057c478bd9Sstevel@tonic-gate bzero(&v6outp->v6addr_u, sizeof (in6_addr_t)); 3067c478bd9Sstevel@tonic-gate return (str2inet_addr(inp + 2, 3077c478bd9Sstevel@tonic-gate &(v6outp->v6addr_u.s6_addr32[3]))); 3087c478bd9Sstevel@tonic-gate } 3097c478bd9Sstevel@tonic-gate return (0); 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate for (i = 0; i < 8; i++) { 3127c478bd9Sstevel@tonic-gate int error; 3137c478bd9Sstevel@tonic-gate /* 3147c478bd9Sstevel@tonic-gate * if ddi_strtol() fails it could be because 3157c478bd9Sstevel@tonic-gate * the string is "::". That is valid and 3167c478bd9Sstevel@tonic-gate * checked for below so just set the value to 3177c478bd9Sstevel@tonic-gate * 0 and continue. 3187c478bd9Sstevel@tonic-gate */ 3197c478bd9Sstevel@tonic-gate if ((error = ddi_strtol(inp, &end, 16, &byte)) != 0) { 3207c478bd9Sstevel@tonic-gate if (error == ERANGE) 3217c478bd9Sstevel@tonic-gate return (0); 3227c478bd9Sstevel@tonic-gate byte = 0; 3237c478bd9Sstevel@tonic-gate } 3247c478bd9Sstevel@tonic-gate if (byte < 0 || byte > 0x0ffff) { 3257c478bd9Sstevel@tonic-gate return (0); 3267c478bd9Sstevel@tonic-gate } 327*59927d31SYuri Pankov if (compat) { 328*59927d31SYuri Pankov v6buf.v6words_u[i] = (uint16_t)byte; 329*59927d31SYuri Pankov } else { 330*59927d31SYuri Pankov v6buf.v6words_u[i] = htons((uint16_t)byte); 331*59927d31SYuri Pankov } 3327c478bd9Sstevel@tonic-gate if (*end == NULL || i == 7) { 3337c478bd9Sstevel@tonic-gate inp = end; 3347c478bd9Sstevel@tonic-gate break; 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate if (inp == end) { /* not a number must be */ 3377c478bd9Sstevel@tonic-gate if (*inp == ':' && 3387c478bd9Sstevel@tonic-gate ((i == 0 && *(inp + 1) == ':') || 3397c478bd9Sstevel@tonic-gate lastbyte == ':')) { 3407c478bd9Sstevel@tonic-gate if (dbl_col) { 3417c478bd9Sstevel@tonic-gate return (0); 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate if (byte != 0) 3447c478bd9Sstevel@tonic-gate i++; 3457c478bd9Sstevel@tonic-gate dbl_col = &v6buf.v6words_u[i]; 3467c478bd9Sstevel@tonic-gate if (i == 0) 3477c478bd9Sstevel@tonic-gate inp++; 3487c478bd9Sstevel@tonic-gate } else if (*inp == NULL || *inp == ' ' || 3497c478bd9Sstevel@tonic-gate *inp == '\t') { 3507c478bd9Sstevel@tonic-gate break; 3517c478bd9Sstevel@tonic-gate } else { 3527c478bd9Sstevel@tonic-gate return (0); 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate } else { 3557c478bd9Sstevel@tonic-gate inp = end; 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate if (*inp != ':') { 3587c478bd9Sstevel@tonic-gate return (0); 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate inp++; 3617c478bd9Sstevel@tonic-gate if (*inp == NULL || *inp == ' ' || *inp == '\t') { 3627c478bd9Sstevel@tonic-gate break; 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate lastbyte = *inp; 3657c478bd9Sstevel@tonic-gate } 3667c478bd9Sstevel@tonic-gate if (*inp != NULL && *inp != ' ' && *inp != '\t') { 3677c478bd9Sstevel@tonic-gate return (0); 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate /* 3707c478bd9Sstevel@tonic-gate * v6words now contains the bytes we could translate 3717c478bd9Sstevel@tonic-gate * dbl_col points to the word (should be 0) where 3727c478bd9Sstevel@tonic-gate * a double colon was found 3737c478bd9Sstevel@tonic-gate */ 3747c478bd9Sstevel@tonic-gate if (i == 7) { 3757c478bd9Sstevel@tonic-gate v6outp->v6addr_u = v6buf.v6addr_u; 3767c478bd9Sstevel@tonic-gate } else { 3777c478bd9Sstevel@tonic-gate int rem; 3787c478bd9Sstevel@tonic-gate int word; 3797c478bd9Sstevel@tonic-gate int next; 3807c478bd9Sstevel@tonic-gate if (dbl_col == NULL) { 3817c478bd9Sstevel@tonic-gate return (0); 3827c478bd9Sstevel@tonic-gate } 3837c478bd9Sstevel@tonic-gate bzero(&v6outp->v6addr_u, sizeof (in6_addr_t)); 3847c478bd9Sstevel@tonic-gate rem = dbl_col - &v6buf.v6words_u[0]; 3857c478bd9Sstevel@tonic-gate for (next = 0; next < rem; next++) { 3867c478bd9Sstevel@tonic-gate v6outp->v6words_u[next] = v6buf.v6words_u[next]; 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate next++; /* skip dbl_col 0 */ 3897c478bd9Sstevel@tonic-gate rem = i - rem; 3907c478bd9Sstevel@tonic-gate word = 8 - rem; 3917c478bd9Sstevel@tonic-gate while (rem > 0) { 3927c478bd9Sstevel@tonic-gate v6outp->v6words_u[word] = v6buf.v6words_u[next]; 3937c478bd9Sstevel@tonic-gate word++; 3947c478bd9Sstevel@tonic-gate rem--; 3957c478bd9Sstevel@tonic-gate next++; 3967c478bd9Sstevel@tonic-gate } 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate return (1); /* Success */ 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate } /* switch */ 4017c478bd9Sstevel@tonic-gate return (-1); /* return -1 for default case */ 4027c478bd9Sstevel@tonic-gate } 403*59927d31SYuri Pankov 404*59927d31SYuri Pankov /* 405*59927d31SYuri Pankov * Provide fixed inet_pton() implementation. 406*59927d31SYuri Pankov */ 407*59927d31SYuri Pankov int 408*59927d31SYuri Pankov _inet_pton(int af, char *inp, void *outp) 409*59927d31SYuri Pankov { 410*59927d31SYuri Pankov return (__inet_pton(af, inp, outp, 0)); 411*59927d31SYuri Pankov } 412*59927d31SYuri Pankov 413*59927d31SYuri Pankov /* 414*59927d31SYuri Pankov * Provide broken inet_pton() implementation by default for binary 415*59927d31SYuri Pankov * compatibility. 416*59927d31SYuri Pankov */ 417*59927d31SYuri Pankov int 418*59927d31SYuri Pankov inet_pton(int af, char *inp, void *outp) 419*59927d31SYuri Pankov { 420*59927d31SYuri Pankov return (__inet_pton(af, inp, outp, 1)); 421*59927d31SYuri Pankov } 422