sl@0: /* ARPA.C
sl@0:  * 
sl@0:  * Portions Copyright (c) 1997-1999 Nokia Corporation and/or its subsidiary(-ies).
sl@0:  * All rights reserved.
sl@0:  */
sl@0: 
sl@0: /*
sl@0:  * Implementation of the ARPA/INET.H functions, based on FreeBSD.
sl@0:  */
sl@0: 
sl@0: /*
sl@0:  * Copyright (c) 1983, 1993
sl@0:  *      The Regents of the University of California.  All rights reserved.
sl@0:  *
sl@0:  * Redistribution and use in source and binary forms, with or without
sl@0:  * modification, are permitted provided that the following conditions
sl@0:  * are met:
sl@0:  * 1. Redistributions of source code must retain the above copyright
sl@0:  *    notice, this list of conditions and the following disclaimer.
sl@0:  * 2. Redistributions in binary form must reproduce the above copyright
sl@0:  *    notice, this list of conditions and the following disclaimer in the
sl@0:  *    documentation and/or other materials provided with the distribution.
sl@0:  * 3. All advertising materials mentioning features or use of this software
sl@0:  *    must display the following acknowledgement:
sl@0:  *      This product includes software developed by the University of
sl@0:  *      California, Berkeley and its contributors.
sl@0:  * 4. Neither the name of the University nor the names of its contributors
sl@0:  *    may be used to endorse or promote products derived from this software
sl@0:  *    without specific prior written permission.
sl@0:  *
sl@0:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
sl@0:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
sl@0:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
sl@0:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
sl@0:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
sl@0:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
sl@0:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
sl@0:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
sl@0:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
sl@0:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
sl@0:  * SUCH DAMAGE.
sl@0:  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
sl@0:  * 
sl@0:  * Permission to use, copy, modify, and distribute this software for any
sl@0:  * purpose with or without fee is hereby granted, provided that the above
sl@0:  * copyright notice and this permission notice appear in all copies, and that
sl@0:  * the name of Digital Equipment Corporation not be used in advertising or
sl@0:  * publicity pertaining to distribution of the document or software without
sl@0:  * specific, written prior permission.
sl@0:  * 
sl@0:  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
sl@0:  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
sl@0:  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
sl@0:  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
sl@0:  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
sl@0:  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
sl@0:  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
sl@0:  * SOFTWARE.
sl@0:  * -
sl@0:  * --Copyright--
sl@0:  */
sl@0: 
sl@0: #include <stdio_r.h>
sl@0: #include <netdb_r.h>
sl@0: #include <ctype.h>
sl@0: #include <sys/types.h>
sl@0: #include <libc/netinet/in.h>
sl@0: #include <libc/arpa/inet.h>
sl@0: 
sl@0: 
sl@0: /**
sl@0: Ascii internet address interpretation routine.
sl@0: @return The value returned is in network order.
sl@0: @param cp ascii representation of an Internet address
sl@0: */
sl@0: EXPORT_C unsigned long inet_addr(const char *cp)
sl@0: {
sl@0:         struct in_addr val;
sl@0: 
sl@0:         if (inet_aton(cp, &val))
sl@0:                 return (val.s_addr);
sl@0:         return (INADDR_NONE);
sl@0: }
sl@0: 
sl@0: /**
sl@0: Check whether "cp" is a valid ascii representation
sl@0: of an Internet address and convert to a binary address.
sl@0: This replaces inet_addr, the return value from which
sl@0: cannot distinguish between failure and a local broadcast address.
sl@0: @return 1 if the address is valid, 0 if not.
sl@0: @param cp ascii representation of an Internet address
sl@0: @param addr internet address
sl@0: */
sl@0: EXPORT_C int inet_aton(const char* cp, struct in_addr* addr)
sl@0: {
sl@0:         unsigned long val;
sl@0:         int base, n;
sl@0:         char c;
sl@0:         unsigned int parts[4];
sl@0:         unsigned int *pp = parts;
sl@0: 
sl@0:         c = *cp;
sl@0:         for (;;) {
sl@0:                 /*
sl@0:                  * Collect number up to ``.''.
sl@0:                  * Values are specified as for C:
sl@0:                  * 0x=hex, 0=octal, isdigit=decimal.
sl@0:                  */
sl@0:                 if (!isdigit(c))
sl@0:                         return (0);
sl@0:                 val = 0; base = 10;
sl@0:                 if (c == '0') {
sl@0:                         c = *++cp;
sl@0:                         if (c == 'x' || c == 'X')
sl@0:                                 base = 16, c = *++cp;
sl@0:                         else
sl@0:                                 base = 8;
sl@0:                 }
sl@0:                 for (;;) {
sl@0:                         if (isascii(c) && isdigit(c)) {
sl@0:                                 val = (val * base) + (c - '0');
sl@0:                                 c = *++cp;
sl@0:                         } else if (base == 16 && isascii(c) && isxdigit(c)) {
sl@0:                                 val = (val << 4) |
sl@0:                                         (c + 10 - (islower(c) ? 'a' : 'A'));
sl@0:                                 c = *++cp;
sl@0:                         } else
sl@0:                                 break;
sl@0:                 }
sl@0:                 if (c == '.') {
sl@0:                         /*
sl@0:                          * Internet format:
sl@0:                          *      a.b.c.d
sl@0:                          *      a.b.c   (with c treated as 16 bits)
sl@0:                          *      a.b     (with b treated as 24 bits)
sl@0:                          */
sl@0:                         if (pp >= parts + 3)
sl@0:                                 return (0);
sl@0: 		                if (val > 0xff) /* Check 8-bit a, b, c */
sl@0: 		                        return (0);
sl@0:                         *pp++ = val;
sl@0:                         c = *++cp;
sl@0:                 } else
sl@0:                         break;
sl@0:         }
sl@0:         /*
sl@0:          * Check for trailing characters.
sl@0:          */
sl@0:         if (c != '\0' && (!isascii(c) || !isspace(c)))
sl@0:                 return (0);
sl@0:         /*
sl@0:          * Concoct the address according to
sl@0:          * the number of parts specified.
sl@0:          */
sl@0:         n = pp - parts + 1;
sl@0:         switch (n) {
sl@0: 
sl@0:         case 0:
sl@0:                 return (0);             /* initial nondigit */
sl@0: 
sl@0:         case 1:                         /* a -- 32 bits */
sl@0:                 break;
sl@0: 
sl@0:         case 2:                         /* a.b -- 8.24 bits */
sl@0:                 if (val > 0xffffff)
sl@0:                         return (0);
sl@0:                 val |= parts[0] << 24;
sl@0:                 break;
sl@0: 
sl@0:         case 3:                         /* a.b.c -- 8.8.16 bits */
sl@0:                 if (val > 0xffff)
sl@0:                         return (0);
sl@0:                 val |= (parts[0] << 24) | (parts[1] << 16);
sl@0:                 break;
sl@0: 
sl@0:         case 4:                         /* a.b.c.d -- 8.8.8.8 bits */
sl@0:                 if (val > 0xff)
sl@0:                         return (0);
sl@0:                 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
sl@0:                 break;
sl@0:         }
sl@0:         if (addr)
sl@0:                 addr->s_addr = htonl(val);
sl@0:         return (1);
sl@0: }
sl@0: 
sl@0: /*
sl@0:  * Convert network-format internet address
sl@0:  * to base 256 d.d.d.d representation.
sl@0:  */
sl@0: EXPORT_C char* _inet_ntoa_r(struct _reent* rp, struct in_addr in)
sl@0: {
sl@0:         unsigned char* p = (unsigned char *)&in;
sl@0:         _sprintf_r(rp, rp->_tmpnam, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
sl@0:         return rp->_tmpnam;
sl@0: }
sl@0: 
sl@0: #ifndef _REENT_ONLY
sl@0: 
sl@0: EXPORT_C char* inet_ntoa(struct in_addr in)
sl@0: {
sl@0: 	return _inet_ntoa_r(_REENT,in);
sl@0: }
sl@0: 
sl@0: #endif /* _REENT_ONLY */
sl@0: 
sl@0: /**
sl@0: Return the local network address portion of an
sl@0: internet address; handles class a/b/c network
sl@0: number formats.
sl@0: @return the local network address portion of an
sl@0: internet address
sl@0: @param in 
sl@0: */ 
sl@0: EXPORT_C unsigned long inet_lnaof(struct in_addr in)
sl@0: {
sl@0:         register unsigned long i = ntohl(in.s_addr);
sl@0: 
sl@0:         if (IN_CLASSA(i))
sl@0:                 return ((i)&IN_CLASSA_HOST);
sl@0:         else if (IN_CLASSB(i))
sl@0:                 return ((i)&IN_CLASSB_HOST);
sl@0:         else
sl@0:                 return ((i)&IN_CLASSC_HOST);
sl@0: }
sl@0: 
sl@0: /**
sl@0: @return the network number from an internet
sl@0: address; handles class a/b/c network #'s.
sl@0: @param in
sl@0: */
sl@0: EXPORT_C unsigned long inet_netof(struct in_addr in)
sl@0: {
sl@0:         unsigned long i = ntohl(in.s_addr);
sl@0: 
sl@0:         if (IN_CLASSA(i))
sl@0:                 return (((i)&IN_CLASSA_NET) >> IN_CLASSA_NSHIFT);
sl@0:         else if (IN_CLASSB(i))
sl@0:                 return (((i)&IN_CLASSB_NET) >> IN_CLASSB_NSHIFT);
sl@0:         else
sl@0:                 return (((i)&IN_CLASSC_NET) >> IN_CLASSC_NSHIFT);
sl@0: }
sl@0: 
sl@0: /** Formulate an Internet address from network + host.
sl@0: */
sl@0: EXPORT_C struct in_addr inet_makeaddr(unsigned long net, unsigned long host)
sl@0: {
sl@0:         unsigned long addr;
sl@0: 
sl@0:         if (net < IN_CLASSA_MAX)
sl@0:                 addr = (net << IN_CLASSA_NSHIFT) | (host & IN_CLASSA_HOST);
sl@0:         else if (net < IN_CLASSB_MAX)
sl@0:                 addr = (net << IN_CLASSB_NSHIFT) | (host & IN_CLASSB_HOST);
sl@0:         else if (net < IN_CLASSC_MAX)
sl@0:                 addr = (net << IN_CLASSC_NSHIFT) | (host & IN_CLASSC_HOST);
sl@0:         else
sl@0:                 addr = net | host;
sl@0:         addr = htonl(addr);
sl@0:         return (*(struct in_addr *)&addr);
sl@0: }
sl@0: