Merge commit 'b1e7e97d3b60469b243b3b2e22c7d8cbd11c7c90'
[unleashed.git] / kernel / net / ip / inet_ntop.c
blobc6876cc0308262c0e1cc88bd0b1ab722601a1f07
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
24 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
26 * Copyright 2017 Nexenta Systems, Inc.
29 #include <sys/types.h>
30 #include <sys/cmn_err.h>
31 #include <sys/systm.h>
32 #include <sys/socket.h>
33 #include <sys/sunddi.h>
34 #include <netinet/in.h>
35 #include <inet/led.h>
38 * v6 formats supported
39 * General format xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
40 * The short hand notation :: is used for COMPAT addr
41 * Other forms : fe80::xxxx:xxxx:xxxx:xxxx
43 static void
44 convert2ascii(char *buf, const in6_addr_t *addr)
46 int hexdigits;
47 int head_zero = 0;
48 int tail_zero = 0;
49 /* tempbuf must be big enough to hold ffff:\0 */
50 char tempbuf[6];
51 char *ptr;
52 uint16_t *addr_component;
53 size_t len;
54 boolean_t first = B_FALSE;
55 boolean_t med_zero = B_FALSE;
56 boolean_t end_zero = B_FALSE;
58 addr_component = (uint16_t *)addr;
59 ptr = buf;
61 /* First count if trailing zeroes higher in number */
62 for (hexdigits = 0; hexdigits < 8; hexdigits++) {
63 if (*addr_component == 0) {
64 if (hexdigits < 4)
65 head_zero++;
66 else
67 tail_zero++;
69 addr_component++;
71 addr_component = (uint16_t *)addr;
72 if (tail_zero > head_zero && (head_zero + tail_zero) != 7)
73 end_zero = B_TRUE;
75 for (hexdigits = 0; hexdigits < 8; hexdigits++) {
77 /* if entry is a 0 */
79 if (*addr_component == 0) {
80 if (!first && *(addr_component + 1) == 0) {
81 if (end_zero && (hexdigits < 4)) {
82 *ptr++ = '0';
83 *ptr++ = ':';
84 } else {
86 * address starts with 0s ..
87 * stick in leading ':' of pair
89 if (hexdigits == 0)
90 *ptr++ = ':';
91 /* add another */
92 *ptr++ = ':';
93 first = B_TRUE;
94 med_zero = B_TRUE;
96 } else if (first && med_zero) {
97 if (hexdigits == 7)
98 *ptr++ = ':';
99 addr_component++;
100 continue;
101 } else {
102 *ptr++ = '0';
103 *ptr++ = ':';
105 addr_component++;
106 continue;
108 if (med_zero)
109 med_zero = B_FALSE;
111 tempbuf[0] = '\0';
112 (void) sprintf(tempbuf, "%x:", ntohs(*addr_component) & 0xffff);
113 len = strlen(tempbuf);
114 bcopy(tempbuf, ptr, len);
115 ptr = ptr + len;
116 addr_component++;
118 *--ptr = '\0';
122 * search for char c, terminate on trailing white space
124 static char *
125 strchr_w(const char *sp, int c)
127 /* skip leading white space */
128 while (*sp && (*sp == ' ' || *sp == '\t')) {
129 sp++;
132 do {
133 if (*sp == (char)c)
134 return ((char *)sp);
135 if (*sp == ' ' || *sp == '\t')
136 return (NULL);
137 } while (*sp++);
138 return (NULL);
141 static int
142 str2inet_addr(char *cp, ipaddr_t *addrp)
144 char *end;
145 long byte;
146 int i;
147 ipaddr_t addr = 0;
149 for (i = 0; i < 4; i++) {
150 if (ddi_strtol(cp, &end, 10, &byte) != 0 || byte < 0 ||
151 byte > 255) {
152 return (0);
154 addr = (addr << 8) | (uint8_t)byte;
155 if (i < 3) {
156 if (*end != '.') {
157 return (0);
158 } else {
159 cp = end + 1;
161 } else {
162 cp = end;
165 *addrp = addr;
166 return (1);
170 * inet_ntop: Convert an IPv4 or IPv6 address in binary form into
171 * printable form, and return a pointer to that string. Caller should
172 * provide a buffer of correct length to store string into.
173 * Note: this routine is kernel version of inet_ntop. It has similar
174 * format as inet_ntop() defined in RFC 2553, but it does not do
175 * error handling operations exactly as RFC 2553 defines.
177 static char *
178 __inet_ntop(int af, const void *addr, char *buf, int addrlen, int compat)
180 static char *badaf = "<badfamily>";
181 in6_addr_t *v6addr;
182 uchar_t *v4addr;
183 char *caddr;
185 VERIFY(addr != NULL);
186 VERIFY(OK_32PTR(addr));
187 VERIFY(buf != NULL);
189 buf[0] = '\0';
191 #define UC(b) (((int)b) & 0xff)
192 switch (af) {
193 case AF_INET:
194 ASSERT(addrlen >= INET_ADDRSTRLEN);
195 v4addr = (uchar_t *)addr;
196 (void) sprintf(buf,
197 (compat) ? "%03d.%03d.%03d.%03d" : "%d.%d.%d.%d",
198 UC(v4addr[0]), UC(v4addr[1]), UC(v4addr[2]), UC(v4addr[3]));
199 return (buf);
200 case AF_INET6:
201 ASSERT(addrlen >= INET6_ADDRSTRLEN);
202 v6addr = (in6_addr_t *)addr;
203 if (IN6_IS_ADDR_V4MAPPED(v6addr)) {
204 caddr = (char *)addr;
205 (void) sprintf(buf, "::ffff:%d.%d.%d.%d",
206 UC(caddr[12]), UC(caddr[13]),
207 UC(caddr[14]), UC(caddr[15]));
208 } else if (IN6_IS_ADDR_V4COMPAT(v6addr)) {
209 caddr = (char *)addr;
210 (void) sprintf(buf, "::%d.%d.%d.%d",
211 UC(caddr[12]), UC(caddr[13]), UC(caddr[14]),
212 UC(caddr[15]));
213 } else if (IN6_IS_ADDR_UNSPECIFIED(v6addr)) {
214 (void) sprintf(buf, "::");
215 } else {
216 convert2ascii(buf, v6addr);
218 return (buf);
220 default:
221 return (badaf);
223 #undef UC
227 * Provide fixed inet_ntop() implementation.
229 char *
230 _inet_ntop(int af, const void *addr, char *buf, int addrlen)
232 return (__inet_ntop(af, addr, buf, addrlen, 0));
236 * Provide old inet_ntop() implementation by default for binary
237 * compatibility.
239 char *
240 inet_ntop(int af, const void *addr, char *buf, int addrlen)
242 static char local_buf[INET6_ADDRSTRLEN];
243 static char *badaddr = "<badaddr>";
245 if (addr == NULL || !(OK_32PTR(addr)))
246 return (badaddr);
248 if (buf == NULL) {
249 buf = local_buf;
250 addrlen = sizeof (local_buf);
253 return (__inet_ntop(af, addr, buf, addrlen, 1));
257 * inet_pton: This function takes string format IPv4 or IPv6 address and
258 * converts it to binary form. The format of this function corresponds to
259 * inet_pton() in the socket library.
261 * Return values:
262 * 0 invalid IPv4 or IPv6 address
263 * 1 successful conversion
264 * -1 af is not AF_INET or AF_INET6
266 static int
267 __inet_pton(int af, char *inp, void *outp, int compat)
269 int i;
270 long byte;
271 char *end;
273 switch (af) {
274 case AF_INET:
275 if (str2inet_addr(inp, (ipaddr_t *)outp) != 0) {
276 if (!compat)
277 *(uint32_t *)outp = htonl(*(uint32_t *)outp);
278 return (1);
279 } else {
280 return (0);
282 case AF_INET6: {
283 union v6buf_u {
284 uint16_t v6words_u[8];
285 in6_addr_t v6addr_u;
286 } v6buf, *v6outp;
287 uint16_t *dbl_col = NULL;
288 char lastbyte = '\0';
290 v6outp = (union v6buf_u *)outp;
292 if (strchr_w(inp, '.') != NULL) {
293 int ret = 0;
295 /* v4 mapped or v4 compatable */
296 if (strncmp(inp, "::ffff:", 7) == 0) {
297 ipaddr_t ipv4_all_zeroes = 0;
298 /* mapped - first init prefix and then fill */
299 IN6_IPADDR_TO_V4MAPPED(ipv4_all_zeroes,
300 &v6outp->v6addr_u);
301 ret = str2inet_addr(inp + 7,
302 &(v6outp->v6addr_u.s6_addr32[3]));
303 } else if (strncmp(inp, "::", 2) == 0) {
304 /* v4 compatable - prefix all zeroes */
305 bzero(&v6outp->v6addr_u, sizeof (in6_addr_t));
306 ret = str2inet_addr(inp + 2,
307 &(v6outp->v6addr_u.s6_addr32[3]));
309 if (ret > 0 && !compat) {
310 v6outp->v6addr_u.s6_addr32[3] =
311 htonl(v6outp->v6addr_u.s6_addr32[3]);
313 return (ret);
315 for (i = 0; i < 8; i++) {
316 int error;
318 * if ddi_strtol() fails it could be because
319 * the string is "::". That is valid and
320 * checked for below so just set the value to
321 * 0 and continue.
323 if ((error = ddi_strtol(inp, &end, 16, &byte)) != 0) {
324 if (error == ERANGE)
325 return (0);
326 byte = 0;
328 if (byte < 0 || byte > 0x0ffff) {
329 return (0);
331 if (compat) {
332 v6buf.v6words_u[i] = (uint16_t)byte;
333 } else {
334 v6buf.v6words_u[i] = htons((uint16_t)byte);
336 if (*end == '\0' || i == 7) {
337 inp = end;
338 break;
340 if (inp == end) { /* not a number must be */
341 if (*inp == ':' &&
342 ((i == 0 && *(inp + 1) == ':') ||
343 lastbyte == ':')) {
344 if (dbl_col) {
345 return (0);
347 if (byte != 0)
348 i++;
349 dbl_col = &v6buf.v6words_u[i];
350 if (i == 0)
351 inp++;
352 } else if (*inp == '\0' || *inp == ' ' ||
353 *inp == '\t') {
354 break;
355 } else {
356 return (0);
358 } else {
359 inp = end;
361 if (*inp != ':') {
362 return (0);
364 inp++;
365 if (*inp == '\0' || *inp == ' ' || *inp == '\t') {
366 break;
368 lastbyte = *inp;
370 if (*inp != '\0' && *inp != ' ' && *inp != '\t') {
371 return (0);
374 * v6words now contains the bytes we could translate
375 * dbl_col points to the word (should be 0) where
376 * a double colon was found
378 if (i == 7) {
379 v6outp->v6addr_u = v6buf.v6addr_u;
380 } else {
381 int rem;
382 int word;
383 int next;
384 if (dbl_col == NULL) {
385 return (0);
387 bzero(&v6outp->v6addr_u, sizeof (in6_addr_t));
388 rem = dbl_col - &v6buf.v6words_u[0];
389 for (next = 0; next < rem; next++) {
390 v6outp->v6words_u[next] = v6buf.v6words_u[next];
392 next++; /* skip dbl_col 0 */
393 rem = i - rem;
394 word = 8 - rem;
395 while (rem > 0) {
396 v6outp->v6words_u[word] = v6buf.v6words_u[next];
397 word++;
398 rem--;
399 next++;
402 return (1); /* Success */
404 } /* switch */
405 return (-1); /* return -1 for default case */
409 * Provide fixed inet_pton() implementation.
412 _inet_pton(int af, char *inp, void *outp)
414 return (__inet_pton(af, inp, outp, 0));
418 * Provide broken inet_pton() implementation by default for binary
419 * compatibility.
422 inet_pton(int af, char *inp, void *outp)
424 return (__inet_pton(af, inp, outp, 1));