#include <sys/types.h>
#include <sys/cmn_err.h>
#include <sys/systm.h>
#include <sys/socket.h>
#include <sys/sunddi.h>
#include <netinet/in.h>
#include <inet/led.h>
static void
convert2ascii(char *buf, const in6_addr_t *addr)
{
int hexdigits;
int head_zero = 0;
int tail_zero = 0;
char tempbuf[6];
char *ptr;
uint16_t *addr_component;
size_t len;
boolean_t first = B_FALSE;
boolean_t med_zero = B_FALSE;
boolean_t end_zero = B_FALSE;
addr_component = (uint16_t *)addr;
ptr = buf;
for (hexdigits = 0; hexdigits < 8; hexdigits++) {
if (*addr_component == 0) {
if (hexdigits < 4)
head_zero++;
else
tail_zero++;
}
addr_component++;
}
addr_component = (uint16_t *)addr;
if (tail_zero > head_zero && (head_zero + tail_zero) != 7)
end_zero = B_TRUE;
for (hexdigits = 0; hexdigits < 8; hexdigits++) {
if (*addr_component == 0) {
if (!first && *(addr_component + 1) == 0) {
if (end_zero && (hexdigits < 4)) {
*ptr++ = '0';
*ptr++ = ':';
} else {
if (hexdigits == 0)
*ptr++ = ':';
*ptr++ = ':';
first = B_TRUE;
med_zero = B_TRUE;
}
} else if (first && med_zero) {
if (hexdigits == 7)
*ptr++ = ':';
addr_component++;
continue;
} else {
*ptr++ = '0';
*ptr++ = ':';
}
addr_component++;
continue;
}
if (med_zero)
med_zero = B_FALSE;
tempbuf[0] = '\0';
(void) sprintf(tempbuf, "%x:", ntohs(*addr_component) & 0xffff);
len = strlen(tempbuf);
bcopy(tempbuf, ptr, len);
ptr = ptr + len;
addr_component++;
}
*--ptr = '\0';
}
static char *
strchr_w(const char *sp, int c)
{
while (*sp && (*sp == ' ' || *sp == '\t')) {
sp++;
}
do {
if (*sp == (char)c)
return ((char *)sp);
if (*sp == ' ' || *sp == '\t')
return (NULL);
} while (*sp++);
return (NULL);
}
static int
str2inet_addr(char *cp, ipaddr_t *addrp)
{
char *end;
long byte;
int i;
ipaddr_t addr = 0;
for (i = 0; i < 4; i++) {
if (ddi_strtol(cp, &end, 10, &byte) != 0 || byte < 0 ||
byte > 255) {
return (0);
}
addr = (addr << 8) | (uint8_t)byte;
if (i < 3) {
if (*end != '.') {
return (0);
} else {
cp = end + 1;
}
} else {
cp = end;
}
}
*addrp = addr;
return (1);
}
static char *
__inet_ntop(int af, const void *addr, char *buf, int addrlen, int compat)
{
static char *badaf = "<badfamily>";
in6_addr_t *v6addr;
uchar_t *v4addr;
char *caddr;
VERIFY(addr != NULL);
VERIFY(OK_32PTR(addr));
VERIFY(buf != NULL);
buf[0] = '\0';
#define UC(b) (((int)b) & 0xff)
switch (af) {
case AF_INET:
ASSERT(addrlen >= INET_ADDRSTRLEN);
v4addr = (uchar_t *)addr;
(void) sprintf(buf,
(compat) ? "%03d.%03d.%03d.%03d" : "%d.%d.%d.%d",
UC(v4addr[0]), UC(v4addr[1]), UC(v4addr[2]), UC(v4addr[3]));
return (buf);
case AF_INET6:
ASSERT(addrlen >= INET6_ADDRSTRLEN);
v6addr = (in6_addr_t *)addr;
if (IN6_IS_ADDR_V4MAPPED(v6addr)) {
caddr = (char *)addr;
(void) sprintf(buf, "::ffff:%d.%d.%d.%d",
UC(caddr[12]), UC(caddr[13]),
UC(caddr[14]), UC(caddr[15]));
} else if (IN6_IS_ADDR_V4COMPAT(v6addr)) {
caddr = (char *)addr;
(void) sprintf(buf, "::%d.%d.%d.%d",
UC(caddr[12]), UC(caddr[13]), UC(caddr[14]),
UC(caddr[15]));
} else if (IN6_IS_ADDR_UNSPECIFIED(v6addr)) {
(void) sprintf(buf, "::");
} else {
convert2ascii(buf, v6addr);
}
return (buf);
default:
return (badaf);
}
#undef UC
}
char *
_inet_ntop(int af, const void *addr, char *buf, int addrlen)
{
return (__inet_ntop(af, addr, buf, addrlen, 0));
}
char *
inet_ntop(int af, const void *addr, char *buf, int addrlen)
{
static char local_buf[INET6_ADDRSTRLEN];
static char *badaddr = "<badaddr>";
if (addr == NULL || !(OK_32PTR(addr)))
return (badaddr);
if (buf == NULL) {
buf = local_buf;
addrlen = sizeof (local_buf);
}
return (__inet_ntop(af, addr, buf, addrlen, 1));
}
static int
__inet_pton(int af, char *inp, void *outp, int compat)
{
int i;
long byte;
char *end;
switch (af) {
case AF_INET:
if (str2inet_addr(inp, (ipaddr_t *)outp) != 0) {
if (!compat)
*(uint32_t *)outp = htonl(*(uint32_t *)outp);
return (1);
} else {
return (0);
}
case AF_INET6: {
union v6buf_u {
uint16_t v6words_u[8];
in6_addr_t v6addr_u;
} v6buf, *v6outp;
uint16_t *dbl_col = NULL;
char lastbyte = '\0';
v6outp = (union v6buf_u *)outp;
if (strchr_w(inp, '.') != NULL) {
int ret = 0;
if (strncmp(inp, "::ffff:", 7) == 0) {
ipaddr_t ipv4_all_zeroes = 0;
IN6_IPADDR_TO_V4MAPPED(ipv4_all_zeroes,
&v6outp->v6addr_u);
ret = str2inet_addr(inp + 7,
&(v6outp->v6addr_u.s6_addr32[3]));
} else if (strncmp(inp, "::", 2) == 0) {
bzero(&v6outp->v6addr_u, sizeof (in6_addr_t));
ret = str2inet_addr(inp + 2,
&(v6outp->v6addr_u.s6_addr32[3]));
}
if (ret > 0 && !compat) {
v6outp->v6addr_u.s6_addr32[3] =
htonl(v6outp->v6addr_u.s6_addr32[3]);
}
return (ret);
}
for (i = 0; i < 8; i++) {
int error;
if ((error = ddi_strtol(inp, &end, 16, &byte)) != 0) {
if (error == ERANGE)
return (0);
byte = 0;
}
if (byte < 0 || byte > 0x0ffff) {
return (0);
}
if (compat) {
v6buf.v6words_u[i] = (uint16_t)byte;
} else {
v6buf.v6words_u[i] = htons((uint16_t)byte);
}
if (*end == '\0' || i == 7) {
inp = end;
break;
}
if (inp == end) {
if (*inp == ':' &&
((i == 0 && *(inp + 1) == ':') ||
lastbyte == ':')) {
if (dbl_col) {
return (0);
}
if (byte != 0)
i++;
dbl_col = &v6buf.v6words_u[i];
if (i == 0)
inp++;
} else if (*inp == '\0' || *inp == ' ' ||
*inp == '\t') {
break;
} else {
return (0);
}
} else {
inp = end;
}
if (*inp != ':') {
return (0);
}
inp++;
if (*inp == '\0' || *inp == ' ' || *inp == '\t') {
break;
}
lastbyte = *inp;
}
if (*inp != '\0' && *inp != ' ' && *inp != '\t') {
return (0);
}
if (i == 7) {
v6outp->v6addr_u = v6buf.v6addr_u;
} else {
int rem;
int word;
int next;
if (dbl_col == NULL) {
return (0);
}
bzero(&v6outp->v6addr_u, sizeof (in6_addr_t));
rem = dbl_col - &v6buf.v6words_u[0];
for (next = 0; next < rem; next++) {
v6outp->v6words_u[next] = v6buf.v6words_u[next];
}
next++;
rem = i - rem;
word = 8 - rem;
while (rem > 0) {
v6outp->v6words_u[word] = v6buf.v6words_u[next];
word++;
rem--;
next++;
}
}
return (1);
}
}
return (-1);
}
int
_inet_pton(int af, char *inp, void *outp)
{
return (__inet_pton(af, inp, outp, 0));
}
int
inet_pton(int af, char *inp, void *outp)
{
return (__inet_pton(af, inp, outp, 1));
}