Home | History | Annotate | Download | only in ip
      1  0  stevel /*
      2  0  stevel  * CDDL HEADER START
      3  0  stevel  *
      4  0  stevel  * The contents of this file are subject to the terms of the
      5  0  stevel  * Common Development and Distribution License, Version 1.0 only
      6  0  stevel  * (the "License").  You may not use this file except in compliance
      7  0  stevel  * with the License.
      8  0  stevel  *
      9  0  stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  0  stevel  * or http://www.opensolaris.org/os/licensing.
     11  0  stevel  * See the License for the specific language governing permissions
     12  0  stevel  * and limitations under the License.
     13  0  stevel  *
     14  0  stevel  * When distributing Covered Code, include this CDDL HEADER in each
     15  0  stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  0  stevel  * If applicable, add the following below this CDDL HEADER, with the
     17  0  stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     18  0  stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  0  stevel  *
     20  0  stevel  * CDDL HEADER END
     21  0  stevel  */
     22  0  stevel /*
     23  0  stevel  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
     24  0  stevel  * Use is subject to license terms.
     25  0  stevel  */
     26  0  stevel 
     27  0  stevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28  0  stevel 
     29  0  stevel #include <sys/types.h>
     30  0  stevel #include <sys/cmn_err.h>
     31  0  stevel #include <sys/systm.h>
     32  0  stevel #include <sys/socket.h>
     33  0  stevel #include <sys/sunddi.h>
     34  0  stevel #include <netinet/in.h>
     35  0  stevel #include <inet/led.h>
     36  0  stevel 
     37  0  stevel static void	convert2ascii(char *, const in6_addr_t *);
     38  0  stevel static char	*strchr_w(const char *, int);
     39  0  stevel static int	str2inet_addr(char *, ipaddr_t *);
     40  0  stevel 
     41  0  stevel /*
     42  0  stevel  * inet_ntop -- Convert an IPv4 or IPv6 address in binary form into
     43  0  stevel  * printable form, and return a pointer to that string. Caller should
     44  0  stevel  * provide a buffer of correct length to store string into.
     45  0  stevel  * Note: this routine is kernel version of inet_ntop. It has similar
     46  0  stevel  * format as inet_ntop() defined in rfc2553. But it does not do
     47  0  stevel  * error handling operations exactly as rfc2553 defines. This function
     48  0  stevel  * is used by kernel inet directory routines only for debugging.
     49  0  stevel  * This inet_ntop() function, does not return NULL if third argument
     50  0  stevel  * is NULL. The reason is simple that we don't want kernel to panic
     51  0  stevel  * as the output of this function is directly fed to ip<n>dbg macro.
     52  0  stevel  * Instead it uses a local buffer for destination address for
     53  0  stevel  * those calls which purposely pass NULL ptr for the destination
     54  0  stevel  * buffer. This function is thread-safe when the caller passes a non-
     55  0  stevel  * null buffer with the third argument.
     56  0  stevel  */
     57  0  stevel /* ARGSUSED */
     58  0  stevel char *
     59  0  stevel inet_ntop(int af, const void *addr, char *buf, int addrlen)
     60  0  stevel {
     61  0  stevel 	static char local_buf[INET6_ADDRSTRLEN];
     62  0  stevel 	static char *err_buf1 = "<badaddr>";
     63  0  stevel 	static char *err_buf2 = "<badfamily>";
     64  0  stevel 	in6_addr_t	*v6addr;
     65  0  stevel 	uchar_t		*v4addr;
     66  0  stevel 	char		*caddr;
     67  0  stevel 
     68  0  stevel 	/*
     69  0  stevel 	 * We don't allow thread unsafe inet_ntop calls, they
     70  0  stevel 	 * must pass a non-null buffer pointer. For DEBUG mode
     71  0  stevel 	 * we use the ASSERT() and for non-debug kernel it will
     72  0  stevel 	 * silently allow it for now. Someday we should remove
     73  0  stevel 	 * the static buffer from this function.
     74  0  stevel 	 */
     75  0  stevel 
     76  0  stevel 	ASSERT(buf != NULL);
     77  0  stevel 	if (buf == NULL)
     78  0  stevel 		buf = local_buf;
     79  0  stevel 	buf[0] = '\0';
     80  0  stevel 
     81  0  stevel 	/* Let user know politely not to send NULL or unaligned addr */
     82  0  stevel 	if (addr == NULL || !(OK_32PTR(addr))) {
     83  0  stevel #ifdef DEBUG
     84  0  stevel 		cmn_err(CE_WARN, "inet_ntop: addr is <null> or unaligned");
     85  0  stevel #endif
     86  0  stevel 		return (err_buf1);
     87  0  stevel 	}
     88  0  stevel 
     89  0  stevel 
     90  0  stevel #define	UC(b)	(((int)b) & 0xff)
     91  0  stevel 	switch (af) {
     92  0  stevel 	case AF_INET:
     93  0  stevel 		ASSERT(addrlen >= INET_ADDRSTRLEN);
     94  0  stevel 		v4addr = (uchar_t *)addr;
     95  0  stevel 		(void) sprintf(buf, "%03d.%03d.%03d.%03d",
     96  0  stevel 		    UC(v4addr[0]), UC(v4addr[1]), UC(v4addr[2]), UC(v4addr[3]));
     97  0  stevel 		return (buf);
     98  0  stevel 
     99  0  stevel 	case AF_INET6:
    100  0  stevel 		ASSERT(addrlen >= INET6_ADDRSTRLEN);
    101  0  stevel 		v6addr = (in6_addr_t *)addr;
    102  0  stevel 		if (IN6_IS_ADDR_V4MAPPED(v6addr)) {
    103  0  stevel 			caddr = (char *)addr;
    104  0  stevel 			(void) sprintf(buf, "::ffff:%d.%d.%d.%d",
    105  0  stevel 			    UC(caddr[12]), UC(caddr[13]),
    106  0  stevel 			    UC(caddr[14]), UC(caddr[15]));
    107  0  stevel 		} else if (IN6_IS_ADDR_V4COMPAT(v6addr)) {
    108  0  stevel 			caddr = (char *)addr;
    109  0  stevel 			(void) sprintf(buf, "::%d.%d.%d.%d",
    110  0  stevel 			    UC(caddr[12]), UC(caddr[13]), UC(caddr[14]),
    111  0  stevel 			    UC(caddr[15]));
    112  0  stevel 		} else if (IN6_IS_ADDR_UNSPECIFIED(v6addr)) {
    113  0  stevel 			(void) sprintf(buf, "::");
    114  0  stevel 		} else {
    115  0  stevel 			convert2ascii(buf, v6addr);
    116  0  stevel 		}
    117  0  stevel 		return (buf);
    118  0  stevel 
    119  0  stevel 	default:
    120  0  stevel 		return (err_buf2);
    121  0  stevel 	}
    122  0  stevel #undef UC
    123  0  stevel }
    124  0  stevel 
    125  0  stevel /*
    126  0  stevel  *
    127  0  stevel  * v6 formats supported
    128  0  stevel  * General format xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
    129  0  stevel  * The short hand notation :: is used for COMPAT addr
    130  0  stevel  * Other forms : fe80::xxxx:xxxx:xxxx:xxxx
    131  0  stevel  */
    132  0  stevel static void
    133  0  stevel convert2ascii(char *buf, const in6_addr_t *addr)
    134  0  stevel {
    135  0  stevel 	int		hexdigits;
    136  0  stevel 	int		head_zero = 0;
    137  0  stevel 	int		tail_zero = 0;
    138  0  stevel 	/* tempbuf must be big enough to hold ffff:\0 */
    139  0  stevel 	char		tempbuf[6];
    140  0  stevel 	char		*ptr;
    141  0  stevel 	uint16_t	*addr_component;
    142  0  stevel 	size_t		len;
    143  0  stevel 	boolean_t	first = B_FALSE;
    144  0  stevel 	boolean_t	med_zero = B_FALSE;
    145  0  stevel 	boolean_t	end_zero = B_FALSE;
    146  0  stevel 
    147  0  stevel 	addr_component = (uint16_t *)addr;
    148  0  stevel 	ptr = buf;
    149  0  stevel 
    150  0  stevel 	/* First count if trailing zeroes higher in number */
    151  0  stevel 	for (hexdigits = 0; hexdigits < 8; hexdigits++) {
    152  0  stevel 		if (*addr_component == 0) {
    153  0  stevel 			if (hexdigits < 4)
    154  0  stevel 				head_zero++;
    155  0  stevel 			else
    156  0  stevel 				tail_zero++;
    157  0  stevel 		}
    158  0  stevel 		addr_component++;
    159  0  stevel 	}
    160  0  stevel 	addr_component = (uint16_t *)addr;
    161  0  stevel 	if (tail_zero > head_zero && (head_zero + tail_zero) != 7)
    162  0  stevel 		end_zero = B_TRUE;
    163  0  stevel 
    164  0  stevel 	for (hexdigits = 0; hexdigits < 8; hexdigits++) {
    165  0  stevel 
    166  0  stevel 		/* if entry is a 0 */
    167  0  stevel 
    168  0  stevel 		if (*addr_component == 0) {
    169  0  stevel 			if (!first && *(addr_component + 1) == 0) {
    170  0  stevel 				if (end_zero && (hexdigits < 4)) {
    171  0  stevel 					*ptr++ = '0';
    172  0  stevel 					*ptr++ = ':';
    173  0  stevel 				} else {
    174  0  stevel 					/*
    175  0  stevel 					 * address starts with 0s ..
    176  0  stevel 					 * stick in leading ':' of pair
    177  0  stevel 					 */
    178  0  stevel 					if (hexdigits == 0)
    179  0  stevel 						*ptr++ = ':';
    180  0  stevel 					/* add another */
    181  0  stevel 					*ptr++ = ':';
    182  0  stevel 					first = B_TRUE;
    183  0  stevel 					med_zero = B_TRUE;
    184  0  stevel 				}
    185  0  stevel 			} else if (first && med_zero) {
    186  0  stevel 				if (hexdigits == 7)
    187  0  stevel 					*ptr++ = ':';
    188  0  stevel 				addr_component++;
    189  0  stevel 				continue;
    190  0  stevel 			} else {
    191  0  stevel 				*ptr++ = '0';
    192  0  stevel 				*ptr++ = ':';
    193  0  stevel 			}
    194  0  stevel 			addr_component++;
    195  0  stevel 			continue;
    196  0  stevel 		}
    197  0  stevel 		if (med_zero)
    198  0  stevel 			med_zero = B_FALSE;
    199  0  stevel 
    200  0  stevel 		tempbuf[0] = '\0';
    201  0  stevel 		(void) sprintf(tempbuf, "%x:", ntohs(*addr_component) & 0xffff);
    202  0  stevel 		len = strlen(tempbuf);
    203  0  stevel 		bcopy(tempbuf, ptr, len);
    204  0  stevel 		ptr = ptr + len;
    205  0  stevel 		addr_component++;
    206  0  stevel 	}
    207  0  stevel 	*--ptr = '\0';
    208  0  stevel }
    209  0  stevel 
    210  0  stevel /*
    211  0  stevel  * search for char c, terminate on trailing white space
    212  0  stevel  */
    213  0  stevel static char *
    214  0  stevel strchr_w(const char *sp, int c)
    215  0  stevel {
    216  0  stevel 	/* skip leading white space */
    217  0  stevel 	while (*sp && (*sp == ' ' || *sp == '\t')) {
    218  0  stevel 		sp++;
    219  0  stevel 	}
    220  0  stevel 
    221  0  stevel 	do {
    222  0  stevel 		if (*sp == (char)c)
    223  0  stevel 			return ((char *)sp);
    224  0  stevel 		if (*sp == ' ' || *sp == '\t')
    225  0  stevel 			return (NULL);
    226  0  stevel 	} while (*sp++);
    227  0  stevel 	return (NULL);
    228  0  stevel }
    229  0  stevel 
    230  0  stevel static int
    231  0  stevel str2inet_addr(char *cp, ipaddr_t *addrp)
    232  0  stevel {
    233  0  stevel 	char *end;
    234  0  stevel 	long byte;
    235  0  stevel 	int i;
    236  0  stevel 	ipaddr_t addr = 0;
    237  0  stevel 
    238  0  stevel 	for (i = 0; i < 4; i++) {
    239  0  stevel 		if (ddi_strtol(cp, &end, 10, &byte) != 0 || byte < 0 ||
    240  0  stevel 		    byte > 255) {
    241  0  stevel 			return (0);
    242  0  stevel 		}
    243  0  stevel 		addr = (addr << 8) | (uint8_t)byte;
    244  0  stevel 		if (i < 3) {
    245  0  stevel 			if (*end != '.') {
    246  0  stevel 				return (0);
    247  0  stevel 			} else {
    248  0  stevel 				cp = end + 1;
    249  0  stevel 			}
    250  0  stevel 		} else {
    251  0  stevel 			cp = end;
    252  0  stevel 		}
    253  0  stevel 	}
    254  0  stevel 	*addrp = addr;
    255  0  stevel 	return (1);
    256  0  stevel }
    257  0  stevel 
    258  0  stevel /*
    259  0  stevel  * inet_pton: This function takes string format IPv4 or IPv6 address and
    260  0  stevel  * converts it to binary form. The format of this function corresponds to
    261  0  stevel  * inet_pton() in the socket library.
    262  0  stevel  * It returns 0 for invalid IPv4 and IPv6 address
    263  0  stevel  *            1 when successfully converts ascii to binary
    264  0  stevel  *            -1 when af is not AF_INET or AF_INET6
    265  0  stevel  */
    266  0  stevel int
    267  0  stevel inet_pton(int af, char *inp, void *outp)
    268  0  stevel {
    269  0  stevel 	int i;
    270  0  stevel 	long byte;
    271  0  stevel 	char *end;
    272  0  stevel 
    273  0  stevel 	switch (af) {
    274  0  stevel 	case AF_INET:
    275  0  stevel 		return (str2inet_addr(inp, (ipaddr_t *)outp));
    276  0  stevel 	case AF_INET6: {
    277  0  stevel 		union v6buf_u {
    278  0  stevel 			uint16_t v6words_u[8];
    279  0  stevel 			in6_addr_t v6addr_u;
    280  0  stevel 		} v6buf, *v6outp;
    281  0  stevel 		uint16_t	*dbl_col = NULL;
    282  0  stevel 		char lastbyte = NULL;
    283  0  stevel 
    284  0  stevel 		v6outp = (union v6buf_u *)outp;
    285  0  stevel 
    286  0  stevel 		if (strchr_w(inp, '.') != NULL) {
    287  0  stevel 			/* v4 mapped or v4 compatable */
    288  0  stevel 			if (strncmp(inp, "::ffff:", 7) == 0) {
    289  0  stevel 				ipaddr_t ipv4_all_zeroes = 0;
    290  0  stevel 				/* mapped - first init prefix and then fill */
    291  0  stevel 				IN6_IPADDR_TO_V4MAPPED(ipv4_all_zeroes,
    292  0  stevel 				    &v6outp->v6addr_u);
    293  0  stevel 				return (str2inet_addr(inp + 7,
    294  0  stevel 				    &(v6outp->v6addr_u.s6_addr32[3])));
    295  0  stevel 			} else if (strncmp(inp, "::", 2) == 0) {
    296  0  stevel 				/* v4 compatable - prefix all zeroes */
    297  0  stevel 				bzero(&v6outp->v6addr_u, sizeof (in6_addr_t));
    298  0  stevel 				return (str2inet_addr(inp + 2,
    299  0  stevel 				    &(v6outp->v6addr_u.s6_addr32[3])));
    300  0  stevel 			}
    301  0  stevel 			return (0);
    302  0  stevel 		}
    303  0  stevel 		for (i = 0; i < 8; i++) {
    304  0  stevel 			int error;
    305  0  stevel 			/*
    306  0  stevel 			 * if ddi_strtol() fails it could be because
    307  0  stevel 			 * the string is "::".  That is valid and
    308  0  stevel 			 * checked for below so just set the value to
    309  0  stevel 			 * 0 and continue.
    310  0  stevel 			 */
    311  0  stevel 			if ((error = ddi_strtol(inp, &end, 16, &byte)) != 0) {
    312  0  stevel 				if (error == ERANGE)
    313  0  stevel 					return (0);
    314  0  stevel 				byte = 0;
    315  0  stevel 			}
    316  0  stevel 			if (byte < 0 || byte > 0x0ffff) {
    317  0  stevel 				return (0);
    318  0  stevel 			}
    319  0  stevel 			v6buf.v6words_u[i] = (uint16_t)byte;
    320  0  stevel 			if (*end == NULL || i == 7) {
    321  0  stevel 				inp = end;
    322  0  stevel 				break;
    323  0  stevel 			}
    324  0  stevel 			if (inp == end) {	/* not a number must be */
    325  0  stevel 				if (*inp == ':' &&
    326  0  stevel 				    ((i == 0 && *(inp + 1) == ':') ||
    327  0  stevel 				    lastbyte == ':')) {
    328  0  stevel 					if (dbl_col) {
    329  0  stevel 						return (0);
    330  0  stevel 					}
    331  0  stevel 					if (byte != 0)
    332  0  stevel 						i++;
    333  0  stevel 					dbl_col = &v6buf.v6words_u[i];
    334  0  stevel 					if (i == 0)
    335  0  stevel 						inp++;
    336  0  stevel 				} else if (*inp == NULL || *inp == ' ' ||
    337  0  stevel 				    *inp == '\t') {
    338  0  stevel 					break;
    339  0  stevel 				} else {
    340  0  stevel 					return (0);
    341  0  stevel 				}
    342  0  stevel 			} else {
    343  0  stevel 				inp = end;
    344  0  stevel 			}
    345  0  stevel 			if (*inp != ':') {
    346  0  stevel 				return (0);
    347  0  stevel 			}
    348  0  stevel 			inp++;
    349  0  stevel 			if (*inp == NULL || *inp == ' ' || *inp == '\t') {
    350  0  stevel 				break;
    351  0  stevel 			}
    352  0  stevel 			lastbyte = *inp;
    353  0  stevel 		}
    354  0  stevel 		if (*inp != NULL && *inp != ' ' && *inp != '\t') {
    355  0  stevel 			return (0);
    356  0  stevel 		}
    357  0  stevel 		/*
    358  0  stevel 		 * v6words now contains the bytes we could translate
    359  0  stevel 		 * dbl_col points to the word (should be 0) where
    360  0  stevel 		 * a double colon was found
    361  0  stevel 		 */
    362  0  stevel 		if (i == 7) {
    363  0  stevel 			v6outp->v6addr_u = v6buf.v6addr_u;
    364  0  stevel 		} else {
    365  0  stevel 			int rem;
    366  0  stevel 			int word;
    367  0  stevel 			int next;
    368  0  stevel 			if (dbl_col == NULL) {
    369  0  stevel 				return (0);
    370  0  stevel 			}
    371  0  stevel 			bzero(&v6outp->v6addr_u, sizeof (in6_addr_t));
    372  0  stevel 			rem = dbl_col - &v6buf.v6words_u[0];
    373  0  stevel 			for (next = 0; next < rem; next++) {
    374  0  stevel 				v6outp->v6words_u[next] = v6buf.v6words_u[next];
    375  0  stevel 			}
    376  0  stevel 			next++;	/* skip dbl_col 0 */
    377  0  stevel 			rem = i - rem;
    378  0  stevel 			word = 8 - rem;
    379  0  stevel 			while (rem > 0) {
    380  0  stevel 				v6outp->v6words_u[word] = v6buf.v6words_u[next];
    381  0  stevel 				word++;
    382  0  stevel 				rem--;
    383  0  stevel 				next++;
    384  0  stevel 			}
    385  0  stevel 		}
    386  0  stevel 		return (1);	/* Success */
    387  0  stevel 	}
    388  0  stevel 	}	/* switch */
    389  0  stevel 	return (-1);	/* return -1 for default case */
    390  0  stevel }
    391