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
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]
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>
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
44 convert2ascii(char *buf
, const in6_addr_t
*addr
)
49 /* tempbuf must be big enough to hold ffff:\0 */
52 uint16_t *addr_component
;
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
;
61 /* First count if trailing zeroes higher in number */
62 for (hexdigits
= 0; hexdigits
< 8; hexdigits
++) {
63 if (*addr_component
== 0) {
71 addr_component
= (uint16_t *)addr
;
72 if (tail_zero
> head_zero
&& (head_zero
+ tail_zero
) != 7)
75 for (hexdigits
= 0; hexdigits
< 8; hexdigits
++) {
79 if (*addr_component
== 0) {
80 if (!first
&& *(addr_component
+ 1) == 0) {
81 if (end_zero
&& (hexdigits
< 4)) {
86 * address starts with 0s ..
87 * stick in leading ':' of pair
96 } else if (first
&& med_zero
) {
112 (void) sprintf(tempbuf
, "%x:", ntohs(*addr_component
) & 0xffff);
113 len
= strlen(tempbuf
);
114 bcopy(tempbuf
, ptr
, len
);
122 * search for char c, terminate on trailing white space
125 strchr_w(const char *sp
, int c
)
127 /* skip leading white space */
128 while (*sp
&& (*sp
== ' ' || *sp
== '\t')) {
135 if (*sp
== ' ' || *sp
== '\t')
142 str2inet_addr(char *cp
, ipaddr_t
*addrp
)
149 for (i
= 0; i
< 4; i
++) {
150 if (ddi_strtol(cp
, &end
, 10, &byte
) != 0 || byte
< 0 ||
154 addr
= (addr
<< 8) | (uint8_t)byte
;
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.
178 __inet_ntop(int af
, const void *addr
, char *buf
, int addrlen
, int compat
)
180 static char *badaf
= "<badfamily>";
185 VERIFY(addr
!= NULL
);
186 VERIFY(OK_32PTR(addr
));
191 #define UC(b) (((int)b) & 0xff)
194 ASSERT(addrlen
>= INET_ADDRSTRLEN
);
195 v4addr
= (uchar_t
*)addr
;
197 (compat
) ? "%03d.%03d.%03d.%03d" : "%d.%d.%d.%d",
198 UC(v4addr
[0]), UC(v4addr
[1]), UC(v4addr
[2]), UC(v4addr
[3]));
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]),
213 } else if (IN6_IS_ADDR_UNSPECIFIED(v6addr
)) {
214 (void) sprintf(buf
, "::");
216 convert2ascii(buf
, v6addr
);
227 * Provide fixed inet_ntop() implementation.
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
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
)))
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.
262 * 0 invalid IPv4 or IPv6 address
263 * 1 successful conversion
264 * -1 af is not AF_INET or AF_INET6
267 __inet_pton(int af
, char *inp
, void *outp
, int compat
)
275 if (str2inet_addr(inp
, (ipaddr_t
*)outp
) != 0) {
277 *(uint32_t *)outp
= htonl(*(uint32_t *)outp
);
284 uint16_t v6words_u
[8];
287 uint16_t *dbl_col
= NULL
;
288 char lastbyte
= '\0';
290 v6outp
= (union v6buf_u
*)outp
;
292 if (strchr_w(inp
, '.') != NULL
) {
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
,
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]);
315 for (i
= 0; i
< 8; i
++) {
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
323 if ((error
= ddi_strtol(inp
, &end
, 16, &byte
)) != 0) {
328 if (byte
< 0 || byte
> 0x0ffff) {
332 v6buf
.v6words_u
[i
] = (uint16_t)byte
;
334 v6buf
.v6words_u
[i
] = htons((uint16_t)byte
);
336 if (*end
== '\0' || i
== 7) {
340 if (inp
== end
) { /* not a number must be */
342 ((i
== 0 && *(inp
+ 1) == ':') ||
349 dbl_col
= &v6buf
.v6words_u
[i
];
352 } else if (*inp
== '\0' || *inp
== ' ' ||
365 if (*inp
== '\0' || *inp
== ' ' || *inp
== '\t') {
370 if (*inp
!= '\0' && *inp
!= ' ' && *inp
!= '\t') {
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
379 v6outp
->v6addr_u
= v6buf
.v6addr_u
;
384 if (dbl_col
== NULL
) {
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 */
396 v6outp
->v6words_u
[word
] = v6buf
.v6words_u
[next
];
402 return (1); /* Success */
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
422 inet_pton(int af
, char *inp
, void *outp
)
424 return (__inet_pton(af
, inp
, outp
, 1));