10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*5577Ssangeeta * Common Development and Distribution License (the "License").
6*5577Ssangeeta * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*5577Ssangeeta * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate *
250Sstevel@tonic-gate * ipv4.c, Code implementing the IPv4 internet protocol.
260Sstevel@tonic-gate */
270Sstevel@tonic-gate
280Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
290Sstevel@tonic-gate
300Sstevel@tonic-gate #include <sys/types.h>
310Sstevel@tonic-gate #include <socket_impl.h>
320Sstevel@tonic-gate #include <socket_inet.h>
330Sstevel@tonic-gate #include <sys/sysmacros.h>
340Sstevel@tonic-gate #include <sys/socket.h>
350Sstevel@tonic-gate #include <netinet/in_systm.h>
360Sstevel@tonic-gate #include <netinet/in.h>
370Sstevel@tonic-gate #include <netinet/ip.h>
380Sstevel@tonic-gate #include <netinet/udp.h>
390Sstevel@tonic-gate #include <net/if_arp.h>
400Sstevel@tonic-gate #include <sys/promif.h>
410Sstevel@tonic-gate #include <sys/bootconf.h>
420Sstevel@tonic-gate #include <sys/fcntl.h>
430Sstevel@tonic-gate #include <sys/salib.h>
440Sstevel@tonic-gate
450Sstevel@tonic-gate #include "icmp4.h"
460Sstevel@tonic-gate #include "ipv4.h"
470Sstevel@tonic-gate #include "ipv4_impl.h"
480Sstevel@tonic-gate #include "mac.h"
490Sstevel@tonic-gate #include "mac_impl.h"
500Sstevel@tonic-gate #include "v4_sum_impl.h"
510Sstevel@tonic-gate #include <sys/bootdebug.h>
520Sstevel@tonic-gate
530Sstevel@tonic-gate static struct ip_frag fragment[FRAG_MAX]; /* ip fragment buffers */
540Sstevel@tonic-gate static int fragments; /* Number of fragments */
550Sstevel@tonic-gate static uint8_t ttl = MAXTTL; /* IP ttl */
560Sstevel@tonic-gate static struct in_addr myip; /* our network-order IP addr */
570Sstevel@tonic-gate static struct in_addr mynet; /* net-order netaddr */
580Sstevel@tonic-gate static struct in_addr netmask =
590Sstevel@tonic-gate { 0xff, 0xff, 0xff, 0xff }; /* our network-order netmask */
600Sstevel@tonic-gate static boolean_t netmask_set = B_FALSE; /* has anyone set netmask? */
610Sstevel@tonic-gate static struct in_addr defaultrouter; /* net-order defaultrouter */
620Sstevel@tonic-gate static int promiscuous; /* promiscuous mode */
630Sstevel@tonic-gate static struct routing table[IPV4_ROUTE_TABLE_SIZE];
640Sstevel@tonic-gate
650Sstevel@tonic-gate static uint16_t g_ip_id;
660Sstevel@tonic-gate
670Sstevel@tonic-gate #ifdef DEBUG
680Sstevel@tonic-gate #define FRAG_DEBUG
690Sstevel@tonic-gate #endif /* DEBUG */
700Sstevel@tonic-gate
710Sstevel@tonic-gate #ifdef FRAG_DEBUG
720Sstevel@tonic-gate /*
730Sstevel@tonic-gate * display the fragment list. For debugging purposes.
740Sstevel@tonic-gate */
750Sstevel@tonic-gate static void
frag_disp(uint16_t size)760Sstevel@tonic-gate frag_disp(uint16_t size)
770Sstevel@tonic-gate {
780Sstevel@tonic-gate int i;
790Sstevel@tonic-gate uint_t total = 0;
800Sstevel@tonic-gate
810Sstevel@tonic-gate printf("Dumping fragment info: (%d)\n\n", fragments);
820Sstevel@tonic-gate printf("More:\tOffset:\tDatap:\t\tIPid:\t\tIPlen:\tIPhlen:\n");
830Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) {
840Sstevel@tonic-gate if (fragment[i].mp == NULL)
850Sstevel@tonic-gate continue;
860Sstevel@tonic-gate printf("%d\t%d\t0x%x\t%d\t\t%d\t%d\n", fragment[i].more,
870Sstevel@tonic-gate fragment[i].offset, fragment[i].mp->b_rptr,
880Sstevel@tonic-gate fragment[i].ipid, fragment[i].iplen, fragment[i].iphlen);
890Sstevel@tonic-gate total += (fragment[i].iplen - fragment[i].iphlen);
900Sstevel@tonic-gate }
910Sstevel@tonic-gate printf("Total length is: %d. It should be: %d\n\n", total, size);
920Sstevel@tonic-gate }
930Sstevel@tonic-gate #endif /* FRAG_DEBUG */
940Sstevel@tonic-gate
950Sstevel@tonic-gate /*
960Sstevel@tonic-gate * This function returns index of fragment 0 of the current fragmented DGRAM
970Sstevel@tonic-gate * (which would contain the transport header). Return the fragment number
980Sstevel@tonic-gate * for success, -1 if we don't yet have the first fragment.
990Sstevel@tonic-gate */
1000Sstevel@tonic-gate static int
frag_first(void)1010Sstevel@tonic-gate frag_first(void)
1020Sstevel@tonic-gate {
1030Sstevel@tonic-gate int i;
1040Sstevel@tonic-gate
1050Sstevel@tonic-gate if (fragments == 0)
1060Sstevel@tonic-gate return (-1);
1070Sstevel@tonic-gate
1080Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) {
1090Sstevel@tonic-gate if (fragment[i].mp != NULL && fragment[i].offset == 0)
1100Sstevel@tonic-gate return (i);
1110Sstevel@tonic-gate }
1120Sstevel@tonic-gate return (-1);
1130Sstevel@tonic-gate }
1140Sstevel@tonic-gate
1150Sstevel@tonic-gate /*
1160Sstevel@tonic-gate * This function returns index of the last fragment of the current DGRAM.
1170Sstevel@tonic-gate * Returns the fragment number for success, -1 if we don't yet have the
1180Sstevel@tonic-gate * last fragment.
1190Sstevel@tonic-gate */
1200Sstevel@tonic-gate static int
frag_last(void)1210Sstevel@tonic-gate frag_last(void)
1220Sstevel@tonic-gate {
1230Sstevel@tonic-gate int i;
1240Sstevel@tonic-gate
1250Sstevel@tonic-gate if (fragments == 0)
1260Sstevel@tonic-gate return (-1);
1270Sstevel@tonic-gate
1280Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) {
1290Sstevel@tonic-gate if (fragment[i].mp != NULL && !fragment[i].more)
1300Sstevel@tonic-gate return (i);
1310Sstevel@tonic-gate }
1320Sstevel@tonic-gate return (-1);
1330Sstevel@tonic-gate }
1340Sstevel@tonic-gate
1350Sstevel@tonic-gate /*
1360Sstevel@tonic-gate * This function adds a fragment to the current pkt fragment list. Returns
1370Sstevel@tonic-gate * FRAG_NOSLOTS if there are no more slots, FRAG_DUP if the fragment is
1380Sstevel@tonic-gate * a duplicate, or FRAG_SUCCESS if it is successful.
1390Sstevel@tonic-gate */
1400Sstevel@tonic-gate static int
frag_add(int16_t offset,mblk_t * mp,uint16_t ipid,int16_t iplen,int16_t iphlen,uint8_t ipp)1410Sstevel@tonic-gate frag_add(int16_t offset, mblk_t *mp, uint16_t ipid,
1420Sstevel@tonic-gate int16_t iplen, int16_t iphlen, uint8_t ipp)
1430Sstevel@tonic-gate {
1440Sstevel@tonic-gate int i;
1450Sstevel@tonic-gate int16_t true_offset = IPV4_OFFSET(offset);
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate /* first pass - look for duplicates */
1480Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) {
1490Sstevel@tonic-gate if (fragment[i].mp != NULL &&
1500Sstevel@tonic-gate fragment[i].offset == true_offset)
1510Sstevel@tonic-gate return (FRAG_DUP);
1520Sstevel@tonic-gate }
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate /* second pass - fill in empty slot */
1550Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) {
1560Sstevel@tonic-gate if (fragment[i].mp == NULL) {
1570Sstevel@tonic-gate fragment[i].more = (offset & IP_MF);
1580Sstevel@tonic-gate fragment[i].offset = true_offset;
1590Sstevel@tonic-gate fragment[i].mp = mp;
1600Sstevel@tonic-gate fragment[i].ipid = ipid;
1610Sstevel@tonic-gate fragment[i].iplen = iplen;
1620Sstevel@tonic-gate fragment[i].iphlen = iphlen;
1630Sstevel@tonic-gate fragment[i].ipp = ipp;
1640Sstevel@tonic-gate fragments++;
1650Sstevel@tonic-gate return (FRAG_SUCCESS);
1660Sstevel@tonic-gate }
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate return (FRAG_NOSLOTS);
1690Sstevel@tonic-gate }
1700Sstevel@tonic-gate
1710Sstevel@tonic-gate /*
1720Sstevel@tonic-gate * Nuke a fragment.
1730Sstevel@tonic-gate */
1740Sstevel@tonic-gate static void
frag_free(int index)1750Sstevel@tonic-gate frag_free(int index)
1760Sstevel@tonic-gate {
1770Sstevel@tonic-gate if (fragment[index].mp != NULL) {
1780Sstevel@tonic-gate freeb(fragment[index].mp);
1790Sstevel@tonic-gate fragments--;
1800Sstevel@tonic-gate }
1810Sstevel@tonic-gate bzero((caddr_t)&fragment[index], sizeof (struct ip_frag));
1820Sstevel@tonic-gate }
1830Sstevel@tonic-gate
1840Sstevel@tonic-gate /*
1850Sstevel@tonic-gate * zero the frag list.
1860Sstevel@tonic-gate */
1870Sstevel@tonic-gate static void
frag_flush(void)1880Sstevel@tonic-gate frag_flush(void)
1890Sstevel@tonic-gate {
1900Sstevel@tonic-gate int i;
1910Sstevel@tonic-gate
1920Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++)
1930Sstevel@tonic-gate frag_free(i);
1940Sstevel@tonic-gate
1950Sstevel@tonic-gate fragments = 0;
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate /*
1990Sstevel@tonic-gate * Analyze the fragment list - see if we captured all our fragments.
2000Sstevel@tonic-gate *
2010Sstevel@tonic-gate * Returns TRUE if we've got all the fragments, and FALSE if we don't.
2020Sstevel@tonic-gate */
2030Sstevel@tonic-gate static int
frag_chk(void)2040Sstevel@tonic-gate frag_chk(void)
2050Sstevel@tonic-gate {
2060Sstevel@tonic-gate int i, first_frag, last_frag;
2070Sstevel@tonic-gate int16_t actual, total;
2080Sstevel@tonic-gate uint16_t ip_id;
2090Sstevel@tonic-gate uint8_t ipp;
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate if (fragments == 0 || (first_frag = frag_first()) < 0 ||
2120Sstevel@tonic-gate (last_frag = frag_last()) < 0)
2130Sstevel@tonic-gate return (FALSE);
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate /*
2160Sstevel@tonic-gate * Validate the ipid's of our fragments - nuke those that don't
2170Sstevel@tonic-gate * match the id of the first fragment or don't match the IP
2180Sstevel@tonic-gate * protocol of the first fragment.
2190Sstevel@tonic-gate */
2200Sstevel@tonic-gate ip_id = fragment[first_frag].ipid;
2210Sstevel@tonic-gate ipp = fragment[first_frag].ipp;
2220Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) {
2230Sstevel@tonic-gate if (fragment[i].mp != NULL && ip_id != fragment[i].ipid &&
2240Sstevel@tonic-gate fragment[i].ipp != ipp) {
2250Sstevel@tonic-gate #ifdef FRAG_DEBUG
2260Sstevel@tonic-gate printf("ipv4: Frag id mismatch: %x != %x\n",
2270Sstevel@tonic-gate fragment[i].ipid, ip_id);
2280Sstevel@tonic-gate #endif /* FRAG_DEBUG */
2290Sstevel@tonic-gate frag_free(i);
2300Sstevel@tonic-gate }
2310Sstevel@tonic-gate }
2320Sstevel@tonic-gate
2330Sstevel@tonic-gate if (frag_last() < 0)
2340Sstevel@tonic-gate return (FALSE);
2350Sstevel@tonic-gate
2360Sstevel@tonic-gate total = fragment[last_frag].offset + fragment[last_frag].iplen -
2370Sstevel@tonic-gate fragment[last_frag].iphlen;
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate for (i = 0, actual = 0; i < FRAG_MAX; i++)
2400Sstevel@tonic-gate actual += (fragment[i].iplen - fragment[i].iphlen);
2410Sstevel@tonic-gate
2420Sstevel@tonic-gate #ifdef FRAG_DEBUG
2430Sstevel@tonic-gate frag_disp(total);
2440Sstevel@tonic-gate #endif /* FRAG_DEBUG */
2450Sstevel@tonic-gate
2460Sstevel@tonic-gate return (total == actual);
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate
2490Sstevel@tonic-gate /*
2500Sstevel@tonic-gate * Load the assembled fragments into igp. Returns 0 for success, nonzero
2510Sstevel@tonic-gate * otherwise.
2520Sstevel@tonic-gate */
2530Sstevel@tonic-gate static int
frag_load(struct inetgram * igp)2540Sstevel@tonic-gate frag_load(struct inetgram *igp)
2550Sstevel@tonic-gate {
2560Sstevel@tonic-gate int i;
2570Sstevel@tonic-gate int16_t len;
2580Sstevel@tonic-gate uint_t total_len;
2590Sstevel@tonic-gate boolean_t first_frag = B_FALSE;
2600Sstevel@tonic-gate mblk_t *mp;
2610Sstevel@tonic-gate struct ip *iph;
2620Sstevel@tonic-gate int first_iph_len;
2630Sstevel@tonic-gate
2640Sstevel@tonic-gate if (fragments == 0)
2650Sstevel@tonic-gate return (ENOENT);
2660Sstevel@tonic-gate
2670Sstevel@tonic-gate mp = igp->igm_mp;
2680Sstevel@tonic-gate /* Get the IP header length of the first fragment. */
2690Sstevel@tonic-gate i = frag_first();
2700Sstevel@tonic-gate assert(i >= 0);
2710Sstevel@tonic-gate first_iph_len = fragment[i].iphlen;
2720Sstevel@tonic-gate for (i = 0, len = 0, total_len = 0; i < FRAG_MAX; i++) {
2730Sstevel@tonic-gate if (fragment[i].mp != NULL) {
2740Sstevel@tonic-gate /*
2750Sstevel@tonic-gate * Copy just the data (omit the ip header of all
2760Sstevel@tonic-gate * fragments except the first one which contains
2770Sstevel@tonic-gate * all the info...)
2780Sstevel@tonic-gate */
2790Sstevel@tonic-gate if (fragment[i].offset == 0) {
2800Sstevel@tonic-gate len = fragment[i].iplen;
2810Sstevel@tonic-gate first_frag = B_TRUE;
2820Sstevel@tonic-gate } else {
2830Sstevel@tonic-gate len = fragment[i].iplen - fragment[i].iphlen;
2840Sstevel@tonic-gate }
2850Sstevel@tonic-gate total_len += len;
2860Sstevel@tonic-gate if (total_len > mp->b_size)
2870Sstevel@tonic-gate return (E2BIG);
2880Sstevel@tonic-gate if (first_frag) {
2890Sstevel@tonic-gate bcopy((caddr_t)(fragment[i].mp->b_rptr),
2900Sstevel@tonic-gate (caddr_t)mp->b_rptr, len);
2910Sstevel@tonic-gate first_frag = B_FALSE;
2920Sstevel@tonic-gate } else {
2930Sstevel@tonic-gate bcopy((caddr_t)(fragment[i].mp->b_rptr +
2940Sstevel@tonic-gate fragment[i].iphlen),
2950Sstevel@tonic-gate (caddr_t)(mp->b_rptr + first_iph_len +
2960Sstevel@tonic-gate fragment[i].offset), len);
2970Sstevel@tonic-gate }
2980Sstevel@tonic-gate mp->b_wptr += len;
2990Sstevel@tonic-gate }
3000Sstevel@tonic-gate }
3010Sstevel@tonic-gate /* Fix the total length in the IP header. */
3020Sstevel@tonic-gate iph = (struct ip *)mp->b_rptr;
3030Sstevel@tonic-gate iph->ip_len = htons(total_len);
3040Sstevel@tonic-gate return (0);
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate
3070Sstevel@tonic-gate /*
3080Sstevel@tonic-gate * Locate a routing table entry based upon arguments. IP addresses expected
3090Sstevel@tonic-gate * in network order. Returns index for success, -1 if entry not found.
3100Sstevel@tonic-gate */
3110Sstevel@tonic-gate static int
find_route(uint8_t * flagp,struct in_addr * destp,struct in_addr * gatewayp)3120Sstevel@tonic-gate find_route(uint8_t *flagp, struct in_addr *destp, struct in_addr *gatewayp)
3130Sstevel@tonic-gate {
3140Sstevel@tonic-gate int i, table_entry = -1;
3150Sstevel@tonic-gate
3160Sstevel@tonic-gate for (i = 0; table_entry == -1 && i < IPV4_ROUTE_TABLE_SIZE; i++) {
3170Sstevel@tonic-gate if (flagp != NULL) {
3180Sstevel@tonic-gate if (*flagp & table[i].flag)
3190Sstevel@tonic-gate table_entry = i;
3200Sstevel@tonic-gate }
3210Sstevel@tonic-gate if (destp != NULL) {
3220Sstevel@tonic-gate if (destp->s_addr == table[i].dest.s_addr)
3230Sstevel@tonic-gate table_entry = i;
3240Sstevel@tonic-gate else
3250Sstevel@tonic-gate table_entry = -1;
3260Sstevel@tonic-gate }
3270Sstevel@tonic-gate if (gatewayp != NULL) {
3280Sstevel@tonic-gate if (gatewayp->s_addr == table[i].gateway.s_addr)
3290Sstevel@tonic-gate table_entry = i;
3300Sstevel@tonic-gate else
3310Sstevel@tonic-gate table_entry = -1;
3320Sstevel@tonic-gate }
3330Sstevel@tonic-gate }
3340Sstevel@tonic-gate return (table_entry);
3350Sstevel@tonic-gate }
3360Sstevel@tonic-gate
3370Sstevel@tonic-gate /*
3380Sstevel@tonic-gate * ADD or DEL a routing table entry. Returns 0 for success, -1 and errno
3390Sstevel@tonic-gate * otherwise. IP addresses are expected in network order.
3400Sstevel@tonic-gate */
3410Sstevel@tonic-gate int
ipv4_route(int cmd,uint8_t flag,struct in_addr * destp,struct in_addr * gatewayp)3420Sstevel@tonic-gate ipv4_route(int cmd, uint8_t flag, struct in_addr *destp,
3430Sstevel@tonic-gate struct in_addr *gatewayp)
3440Sstevel@tonic-gate {
3450Sstevel@tonic-gate static int routing_table_initialized;
3460Sstevel@tonic-gate int index;
3470Sstevel@tonic-gate uint8_t tmp_flag;
3480Sstevel@tonic-gate
3490Sstevel@tonic-gate if (gatewayp == NULL) {
3500Sstevel@tonic-gate errno = EINVAL;
3510Sstevel@tonic-gate return (-1);
3520Sstevel@tonic-gate }
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate /* initialize routing table */
3550Sstevel@tonic-gate if (routing_table_initialized == 0) {
3560Sstevel@tonic-gate for (index = 0; index < IPV4_ROUTE_TABLE_SIZE; index++)
3570Sstevel@tonic-gate table[index].flag = RT_UNUSED;
3580Sstevel@tonic-gate routing_table_initialized = 1;
3590Sstevel@tonic-gate }
3600Sstevel@tonic-gate
3610Sstevel@tonic-gate switch (cmd) {
3620Sstevel@tonic-gate case IPV4_ADD_ROUTE:
3630Sstevel@tonic-gate tmp_flag = (uint8_t)RT_UNUSED;
3640Sstevel@tonic-gate if ((index = find_route(&tmp_flag, NULL, NULL)) == -1) {
3650Sstevel@tonic-gate dprintf("ipv4_route: routing table full.\n");
3660Sstevel@tonic-gate errno = ENOSPC;
3670Sstevel@tonic-gate return (-1);
3680Sstevel@tonic-gate }
3690Sstevel@tonic-gate table[index].flag = flag;
3700Sstevel@tonic-gate if (destp != NULL)
3710Sstevel@tonic-gate table[index].dest.s_addr = destp->s_addr;
3720Sstevel@tonic-gate else
3730Sstevel@tonic-gate table[index].dest.s_addr = htonl(INADDR_ANY);
3740Sstevel@tonic-gate table[index].gateway.s_addr = gatewayp->s_addr;
3750Sstevel@tonic-gate break;
3760Sstevel@tonic-gate case IPV4_BAD_ROUTE:
3770Sstevel@tonic-gate /* FALLTHRU */
3780Sstevel@tonic-gate case IPV4_DEL_ROUTE:
3790Sstevel@tonic-gate if ((index = find_route(&flag, destp, gatewayp)) == -1) {
3800Sstevel@tonic-gate dprintf("ipv4_route: No such routing entry.\n");
3810Sstevel@tonic-gate errno = ENOENT;
3820Sstevel@tonic-gate return (-1);
3830Sstevel@tonic-gate }
3840Sstevel@tonic-gate if (cmd == IPV4_DEL_ROUTE) {
3850Sstevel@tonic-gate table[index].flag = RT_UNUSED;
3860Sstevel@tonic-gate table[index].dest.s_addr = htonl(INADDR_ANY);
3870Sstevel@tonic-gate table[index].gateway.s_addr = htonl(INADDR_ANY);
3880Sstevel@tonic-gate } else
3890Sstevel@tonic-gate table[index].flag = RT_NG;
3900Sstevel@tonic-gate default:
3910Sstevel@tonic-gate errno = EINVAL;
3920Sstevel@tonic-gate return (-1);
3930Sstevel@tonic-gate }
3940Sstevel@tonic-gate return (0);
3950Sstevel@tonic-gate }
3960Sstevel@tonic-gate
3970Sstevel@tonic-gate /*
3980Sstevel@tonic-gate * Return gateway to destination. Returns gateway IP address in network order
3990Sstevel@tonic-gate * for success, NULL if no route to destination exists.
4000Sstevel@tonic-gate */
4010Sstevel@tonic-gate struct in_addr *
ipv4_get_route(uint8_t flag,struct in_addr * destp,struct in_addr * gatewayp)4020Sstevel@tonic-gate ipv4_get_route(uint8_t flag, struct in_addr *destp, struct in_addr *gatewayp)
4030Sstevel@tonic-gate {
4040Sstevel@tonic-gate int index;
4050Sstevel@tonic-gate if ((index = find_route(&flag, destp, gatewayp)) == -1)
4060Sstevel@tonic-gate return (NULL);
4070Sstevel@tonic-gate return (&table[index].gateway);
4080Sstevel@tonic-gate }
4090Sstevel@tonic-gate
4100Sstevel@tonic-gate /*
4110Sstevel@tonic-gate * Initialize the IPv4 generic parts of the socket, as well as the routing
4120Sstevel@tonic-gate * table.
4130Sstevel@tonic-gate */
4140Sstevel@tonic-gate void
ipv4_socket_init(struct inetboot_socket * isp)4150Sstevel@tonic-gate ipv4_socket_init(struct inetboot_socket *isp)
4160Sstevel@tonic-gate {
4170Sstevel@tonic-gate isp->input[NETWORK_LVL] = ipv4_input;
4180Sstevel@tonic-gate isp->output[NETWORK_LVL] = ipv4_output;
4190Sstevel@tonic-gate isp->close[NETWORK_LVL] = NULL;
4200Sstevel@tonic-gate isp->headerlen[NETWORK_LVL] = ipv4_header_len;
4210Sstevel@tonic-gate }
4220Sstevel@tonic-gate
4230Sstevel@tonic-gate /*
4240Sstevel@tonic-gate * Initialize a raw ipv4 socket.
4250Sstevel@tonic-gate */
4260Sstevel@tonic-gate void
ipv4_raw_socket(struct inetboot_socket * isp,uint8_t proto)4270Sstevel@tonic-gate ipv4_raw_socket(struct inetboot_socket *isp, uint8_t proto)
4280Sstevel@tonic-gate {
4290Sstevel@tonic-gate isp->type = INETBOOT_RAW;
4300Sstevel@tonic-gate if (proto == 0)
4310Sstevel@tonic-gate isp->proto = IPPROTO_IP;
4320Sstevel@tonic-gate else
4330Sstevel@tonic-gate isp->proto = proto;
4340Sstevel@tonic-gate isp->input[TRANSPORT_LVL] = NULL;
4350Sstevel@tonic-gate isp->output[TRANSPORT_LVL] = NULL;
4360Sstevel@tonic-gate isp->headerlen[TRANSPORT_LVL] = NULL;
4370Sstevel@tonic-gate isp->ports = NULL;
4380Sstevel@tonic-gate }
4390Sstevel@tonic-gate
4400Sstevel@tonic-gate /*
4410Sstevel@tonic-gate * Return the size of an IPv4 header (no options)
4420Sstevel@tonic-gate */
4430Sstevel@tonic-gate /* ARGSUSED */
4440Sstevel@tonic-gate int
ipv4_header_len(struct inetgram * igm)4450Sstevel@tonic-gate ipv4_header_len(struct inetgram *igm)
4460Sstevel@tonic-gate {
4470Sstevel@tonic-gate return (sizeof (struct ip));
4480Sstevel@tonic-gate }
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate /*
4510Sstevel@tonic-gate * Set our source address.
4520Sstevel@tonic-gate * Argument is assumed to be host order.
4530Sstevel@tonic-gate */
4540Sstevel@tonic-gate void
ipv4_setipaddr(struct in_addr * ip)4550Sstevel@tonic-gate ipv4_setipaddr(struct in_addr *ip)
4560Sstevel@tonic-gate {
4570Sstevel@tonic-gate myip.s_addr = htonl(ip->s_addr);
4580Sstevel@tonic-gate }
4590Sstevel@tonic-gate
4600Sstevel@tonic-gate /*
4610Sstevel@tonic-gate * Returns our current source address in host order.
4620Sstevel@tonic-gate */
4630Sstevel@tonic-gate void
ipv4_getipaddr(struct in_addr * ip)4640Sstevel@tonic-gate ipv4_getipaddr(struct in_addr *ip)
4650Sstevel@tonic-gate {
4660Sstevel@tonic-gate ip->s_addr = ntohl(myip.s_addr);
4670Sstevel@tonic-gate }
4680Sstevel@tonic-gate
4690Sstevel@tonic-gate /*
4700Sstevel@tonic-gate * Set our netmask.
4710Sstevel@tonic-gate * Argument is assumed to be host order.
4720Sstevel@tonic-gate */
4730Sstevel@tonic-gate void
ipv4_setnetmask(struct in_addr * ip)4740Sstevel@tonic-gate ipv4_setnetmask(struct in_addr *ip)
4750Sstevel@tonic-gate {
4760Sstevel@tonic-gate netmask_set = B_TRUE;
4770Sstevel@tonic-gate netmask.s_addr = htonl(ip->s_addr);
4780Sstevel@tonic-gate mynet.s_addr = netmask.s_addr & myip.s_addr; /* implicit */
4790Sstevel@tonic-gate }
4800Sstevel@tonic-gate
4810Sstevel@tonic-gate void
ipv4_getnetid(struct in_addr * my_netid)4820Sstevel@tonic-gate ipv4_getnetid(struct in_addr *my_netid)
4830Sstevel@tonic-gate {
4840Sstevel@tonic-gate struct in_addr my_netmask;
4850Sstevel@tonic-gate if (mynet.s_addr != 0)
4860Sstevel@tonic-gate my_netid->s_addr = ntohl(mynet.s_addr);
4870Sstevel@tonic-gate else {
4880Sstevel@tonic-gate ipv4_getnetmask(&my_netmask);
4890Sstevel@tonic-gate my_netid->s_addr = my_netmask.s_addr & ntohl(myip.s_addr);
4900Sstevel@tonic-gate }
4910Sstevel@tonic-gate }
4920Sstevel@tonic-gate
4930Sstevel@tonic-gate /*
4940Sstevel@tonic-gate * Returns our current netmask in host order.
4950Sstevel@tonic-gate * Neither OBP nor the standalone DHCP client mandate
4960Sstevel@tonic-gate * that the netmask be specified, so in the absence of
4970Sstevel@tonic-gate * a netmask, we attempt to derive it using class-based
4980Sstevel@tonic-gate * heuristics.
4990Sstevel@tonic-gate */
5000Sstevel@tonic-gate void
ipv4_getnetmask(struct in_addr * ip)5010Sstevel@tonic-gate ipv4_getnetmask(struct in_addr *ip)
5020Sstevel@tonic-gate {
5030Sstevel@tonic-gate if (netmask_set || (myip.s_addr == 0))
5040Sstevel@tonic-gate ip->s_addr = ntohl(netmask.s_addr);
5050Sstevel@tonic-gate else {
5060Sstevel@tonic-gate /* base the netmask on our IP address */
5070Sstevel@tonic-gate if (IN_CLASSA(ntohl(myip.s_addr)))
5080Sstevel@tonic-gate ip->s_addr = ntohl(IN_CLASSA_NET);
5090Sstevel@tonic-gate else if (IN_CLASSB(ntohl(myip.s_addr)))
5100Sstevel@tonic-gate ip->s_addr = ntohl(IN_CLASSB_NET);
511*5577Ssangeeta else if (IN_CLASSC(ntohl(myip.s_addr)))
512*5577Ssangeeta ip->s_addr = ntohl(IN_CLASSC_NET);
5130Sstevel@tonic-gate else
514*5577Ssangeeta ip->s_addr = ntohl(IN_CLASSE_NET);
5150Sstevel@tonic-gate }
5160Sstevel@tonic-gate }
5170Sstevel@tonic-gate
5180Sstevel@tonic-gate /*
5190Sstevel@tonic-gate * Set our default router.
5200Sstevel@tonic-gate * Argument is assumed to be host order, and *MUST* be on the same network
5210Sstevel@tonic-gate * as our source IP address.
5220Sstevel@tonic-gate */
5230Sstevel@tonic-gate void
ipv4_setdefaultrouter(struct in_addr * ip)5240Sstevel@tonic-gate ipv4_setdefaultrouter(struct in_addr *ip)
5250Sstevel@tonic-gate {
5260Sstevel@tonic-gate defaultrouter.s_addr = htonl(ip->s_addr);
5270Sstevel@tonic-gate }
5280Sstevel@tonic-gate
5290Sstevel@tonic-gate /*
5300Sstevel@tonic-gate * Returns our current default router in host order.
5310Sstevel@tonic-gate */
5320Sstevel@tonic-gate void
ipv4_getdefaultrouter(struct in_addr * ip)5330Sstevel@tonic-gate ipv4_getdefaultrouter(struct in_addr *ip)
5340Sstevel@tonic-gate {
5350Sstevel@tonic-gate ip->s_addr = ntohl(defaultrouter.s_addr);
5360Sstevel@tonic-gate }
5370Sstevel@tonic-gate
5380Sstevel@tonic-gate /*
5390Sstevel@tonic-gate * Toggle promiscuous flag. If set, client disregards destination IP
5400Sstevel@tonic-gate * address. Otherwise, only limited broadcast, network broadcast, and
5410Sstevel@tonic-gate * unicast traffic get through. Returns previous setting.
5420Sstevel@tonic-gate */
5430Sstevel@tonic-gate int
ipv4_setpromiscuous(int toggle)5440Sstevel@tonic-gate ipv4_setpromiscuous(int toggle)
5450Sstevel@tonic-gate {
5460Sstevel@tonic-gate int old = promiscuous;
5470Sstevel@tonic-gate
5480Sstevel@tonic-gate promiscuous = toggle;
5490Sstevel@tonic-gate
5500Sstevel@tonic-gate return (old);
5510Sstevel@tonic-gate }
5520Sstevel@tonic-gate
5530Sstevel@tonic-gate /*
5540Sstevel@tonic-gate * Set IP TTL.
5550Sstevel@tonic-gate */
5560Sstevel@tonic-gate void
ipv4_setmaxttl(uint8_t cttl)5570Sstevel@tonic-gate ipv4_setmaxttl(uint8_t cttl)
5580Sstevel@tonic-gate {
5590Sstevel@tonic-gate ttl = cttl;
5600Sstevel@tonic-gate }
5610Sstevel@tonic-gate
5620Sstevel@tonic-gate /*
5630Sstevel@tonic-gate * Convert an ipv4 address to dotted notation.
5640Sstevel@tonic-gate * Returns ptr to statically allocated buffer containing dotted string.
5650Sstevel@tonic-gate */
5660Sstevel@tonic-gate char *
inet_ntoa(struct in_addr ip)5670Sstevel@tonic-gate inet_ntoa(struct in_addr ip)
5680Sstevel@tonic-gate {
5690Sstevel@tonic-gate uint8_t *p;
5700Sstevel@tonic-gate static char ipaddr[16];
5710Sstevel@tonic-gate
5720Sstevel@tonic-gate p = (uint8_t *)&ip.s_addr;
5730Sstevel@tonic-gate (void) sprintf(ipaddr, "%u.%u.%u.%u", p[0], p[1], p[2], p[3]);
5740Sstevel@tonic-gate return (ipaddr);
5750Sstevel@tonic-gate }
5760Sstevel@tonic-gate
5770Sstevel@tonic-gate /*
5780Sstevel@tonic-gate * Construct a transport datagram from a series of IP fragments (igp == NULL)
5790Sstevel@tonic-gate * or from a single IP datagram (igp != NULL). Return the address of the
5800Sstevel@tonic-gate * contructed transport datagram.
5810Sstevel@tonic-gate */
5820Sstevel@tonic-gate struct inetgram *
make_trans_datagram(int index,struct inetgram * igp,struct in_addr ipsrc,struct in_addr ipdst,uint16_t iphlen)5830Sstevel@tonic-gate make_trans_datagram(int index, struct inetgram *igp, struct in_addr ipsrc,
5840Sstevel@tonic-gate struct in_addr ipdst, uint16_t iphlen)
5850Sstevel@tonic-gate {
5860Sstevel@tonic-gate uint16_t trans_len, *transp, new_len;
5870Sstevel@tonic-gate int first_frag, last_frag;
5880Sstevel@tonic-gate boolean_t fragmented;
5890Sstevel@tonic-gate struct inetgram *ngp;
5900Sstevel@tonic-gate struct ip *iph;
5910Sstevel@tonic-gate
5920Sstevel@tonic-gate fragmented = (igp == NULL);
5930Sstevel@tonic-gate
5940Sstevel@tonic-gate ngp = (struct inetgram *)bkmem_zalloc(sizeof (struct inetgram));
5950Sstevel@tonic-gate if (ngp == NULL) {
5960Sstevel@tonic-gate errno = ENOMEM;
5970Sstevel@tonic-gate if (fragmented)
5980Sstevel@tonic-gate frag_flush();
5990Sstevel@tonic-gate return (NULL);
6000Sstevel@tonic-gate }
6010Sstevel@tonic-gate
6020Sstevel@tonic-gate if (fragmented) {
6030Sstevel@tonic-gate last_frag = frag_last();
6040Sstevel@tonic-gate trans_len = fragment[last_frag].offset +
6050Sstevel@tonic-gate fragment[last_frag].iplen - fragment[last_frag].iphlen;
6060Sstevel@tonic-gate first_frag = frag_first();
6070Sstevel@tonic-gate /*
6080Sstevel@tonic-gate * The returned buffer contains the IP header of the
6090Sstevel@tonic-gate * first fragment.
6100Sstevel@tonic-gate */
6110Sstevel@tonic-gate trans_len += fragment[first_frag].iphlen;
6120Sstevel@tonic-gate transp = (uint16_t *)(fragment[first_frag].mp->b_rptr +
6130Sstevel@tonic-gate fragment[first_frag].iphlen);
6140Sstevel@tonic-gate } else {
6150Sstevel@tonic-gate /*
6160Sstevel@tonic-gate * Note that igm_len may not be the real length of an
6170Sstevel@tonic-gate * IP packet because some network interface, such as
6180Sstevel@tonic-gate * Ethernet, as a minimum frame size. So we should not
6190Sstevel@tonic-gate * use the interface frame size to determine the
6200Sstevel@tonic-gate * length of an IP packet. We should use the IP
6210Sstevel@tonic-gate * length field in the IP header.
6220Sstevel@tonic-gate */
6230Sstevel@tonic-gate iph = (struct ip *)igp->igm_mp->b_rptr;
6240Sstevel@tonic-gate trans_len = ntohs(iph->ip_len);
6250Sstevel@tonic-gate transp = (uint16_t *)(igp->igm_mp->b_rptr + iphlen);
6260Sstevel@tonic-gate }
6270Sstevel@tonic-gate
6280Sstevel@tonic-gate ngp->igm_saddr.sin_addr.s_addr = ipsrc.s_addr;
6290Sstevel@tonic-gate ngp->igm_saddr.sin_port = sockets[index].ports(transp, SOURCE);
6300Sstevel@tonic-gate ngp->igm_target.s_addr = ipdst.s_addr;
6310Sstevel@tonic-gate ngp->igm_level = TRANSPORT_LVL;
6320Sstevel@tonic-gate
6330Sstevel@tonic-gate /*
6340Sstevel@tonic-gate * Align to 16bit value. Checksum code may require an extra byte
6350Sstevel@tonic-gate * for padding.
6360Sstevel@tonic-gate */
6370Sstevel@tonic-gate new_len = ((trans_len + sizeof (int16_t) - 1) &
6380Sstevel@tonic-gate ~(sizeof (int16_t) - 1));
6390Sstevel@tonic-gate if ((ngp->igm_mp = allocb(new_len, 0)) == NULL) {
6400Sstevel@tonic-gate errno = ENOMEM;
6410Sstevel@tonic-gate bkmem_free((caddr_t)ngp, sizeof (struct inetgram));
6420Sstevel@tonic-gate if (fragmented)
6430Sstevel@tonic-gate frag_flush();
6440Sstevel@tonic-gate return (NULL);
6450Sstevel@tonic-gate }
6460Sstevel@tonic-gate
6470Sstevel@tonic-gate if (fragmented) {
6480Sstevel@tonic-gate if (frag_load(ngp) != 0) {
6490Sstevel@tonic-gate freeb(ngp->igm_mp);
6500Sstevel@tonic-gate bkmem_free((caddr_t)ngp, sizeof (struct inetgram));
6510Sstevel@tonic-gate frag_flush();
6520Sstevel@tonic-gate return (NULL);
6530Sstevel@tonic-gate }
6540Sstevel@tonic-gate frag_flush();
6550Sstevel@tonic-gate } else {
6560Sstevel@tonic-gate bcopy((caddr_t)(igp->igm_mp->b_rptr),
6570Sstevel@tonic-gate (caddr_t)ngp->igm_mp->b_rptr, trans_len);
6580Sstevel@tonic-gate ngp->igm_mp->b_wptr += trans_len;
6590Sstevel@tonic-gate }
6600Sstevel@tonic-gate return (ngp);
6610Sstevel@tonic-gate }
6620Sstevel@tonic-gate
6630Sstevel@tonic-gate /*
6640Sstevel@tonic-gate * ipv4_input: Pull in IPv4 datagrams addressed to us. Handle IP fragmentation
6650Sstevel@tonic-gate * (fragments received in any order) and ICMP at this level.
6660Sstevel@tonic-gate *
6670Sstevel@tonic-gate * Note that because our network is serviced by polling when we expect
6680Sstevel@tonic-gate * something (upon a referenced socket), we don't go through the work of
6690Sstevel@tonic-gate * locating the appropriate socket a datagram is destined for. We'll only
6700Sstevel@tonic-gate * accept data for the referenced socket. This means we don't have
6710Sstevel@tonic-gate * asynchronous networking, but since we can't service the net using an
6720Sstevel@tonic-gate * interrupt handler, it doesn't do us any good to try to service datagrams
6730Sstevel@tonic-gate * destined for sockets other than the referenced one. Data is handled in
6740Sstevel@tonic-gate * a fifo manner.
6750Sstevel@tonic-gate *
6760Sstevel@tonic-gate * The mac layer will grab all frames for us. If we find we don't have all
6770Sstevel@tonic-gate * the necessary fragments to reassemble the datagram, we'll call the mac
6780Sstevel@tonic-gate * layer again for FRAG_ATTEMPTS to see if it has any more frames.
6790Sstevel@tonic-gate *
6800Sstevel@tonic-gate * Supported protocols: IPPROTO_IP, IPPROTO_ICMP, IPPROTO_UDP.
6810Sstevel@tonic-gate *
6820Sstevel@tonic-gate * Returns: number of NETWORK_LVL datagrams placed on socket , -1 if error
6830Sstevel@tonic-gate * occurred.
6840Sstevel@tonic-gate *
6850Sstevel@tonic-gate * Note: errno is set to ETIMEDOUT if fragment reassembly fails.
6860Sstevel@tonic-gate */
6870Sstevel@tonic-gate int
ipv4_input(int index)6880Sstevel@tonic-gate ipv4_input(int index)
6890Sstevel@tonic-gate {
6900Sstevel@tonic-gate int datagrams = 0;
6910Sstevel@tonic-gate int frag_stat, input_attempts = 0;
6920Sstevel@tonic-gate uint16_t iphlen, iplen, ip_id;
6930Sstevel@tonic-gate int16_t curr_off;
6940Sstevel@tonic-gate struct ip *iphp;
6950Sstevel@tonic-gate struct inetgram *igp, *newgp = NULL, *ipv4_listp = NULL;
6960Sstevel@tonic-gate struct in_addr ipdst, ipsrc;
6970Sstevel@tonic-gate mblk_t *mp;
6980Sstevel@tonic-gate enum SockType type;
6990Sstevel@tonic-gate
7000Sstevel@tonic-gate #ifdef DEBUG
7010Sstevel@tonic-gate printf("ipv4_input(%d): start ######################################\n",
7020Sstevel@tonic-gate index);
7030Sstevel@tonic-gate #endif /* DEBUG */
7040Sstevel@tonic-gate
7050Sstevel@tonic-gate frag_flush();
7060Sstevel@tonic-gate
7070Sstevel@tonic-gate ipv4_try_again:
7080Sstevel@tonic-gate
7090Sstevel@tonic-gate while ((igp = sockets[index].inq) != NULL) {
7100Sstevel@tonic-gate if (igp->igm_level != NETWORK_LVL) {
7110Sstevel@tonic-gate #ifdef DEBUG
7120Sstevel@tonic-gate printf("ipv4_input(%d): unexpected frame type: %d\n",
7130Sstevel@tonic-gate index, igp->igm_level);
7140Sstevel@tonic-gate #endif /* DEBUG */
7150Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE);
7160Sstevel@tonic-gate continue;
7170Sstevel@tonic-gate }
7180Sstevel@tonic-gate iphp = (struct ip *)igp->igm_mp->b_rptr;
7190Sstevel@tonic-gate if (iphp->ip_v != IPVERSION) {
7200Sstevel@tonic-gate dprintf("ipv4_input(%d): IPv%d datagram discarded\n",
7210Sstevel@tonic-gate index, iphp->ip_v);
7220Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE);
7230Sstevel@tonic-gate continue;
7240Sstevel@tonic-gate }
7250Sstevel@tonic-gate iphlen = iphp->ip_hl << 2;
7260Sstevel@tonic-gate if (iphlen < sizeof (struct ip)) {
7270Sstevel@tonic-gate dprintf("ipv4_input(%d): IP msg too short (%d < %u)\n",
7280Sstevel@tonic-gate index, iphlen, (uint_t)sizeof (struct ip));
7290Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE);
7300Sstevel@tonic-gate continue;
7310Sstevel@tonic-gate }
7320Sstevel@tonic-gate iplen = ntohs(iphp->ip_len);
7330Sstevel@tonic-gate if (iplen > msgdsize(igp->igm_mp)) {
7340Sstevel@tonic-gate dprintf("ipv4_input(%d): IP len/buffer mismatch "
7350Sstevel@tonic-gate "(%d > %lu)\n", index, iplen, igp->igm_mp->b_size);
7360Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE);
7370Sstevel@tonic-gate continue;
7380Sstevel@tonic-gate }
7390Sstevel@tonic-gate
7400Sstevel@tonic-gate bcopy((caddr_t)&(iphp->ip_dst), (caddr_t)&ipdst,
7410Sstevel@tonic-gate sizeof (ipdst));
7420Sstevel@tonic-gate bcopy((caddr_t)&(iphp->ip_src), (caddr_t)&ipsrc,
7430Sstevel@tonic-gate sizeof (ipsrc));
7440Sstevel@tonic-gate
7450Sstevel@tonic-gate /* igp->igm_mp->b_datap is guaranteed to be 64 bit aligned] */
7460Sstevel@tonic-gate if (ipv4cksum((uint16_t *)iphp, iphlen) != 0) {
7470Sstevel@tonic-gate dprintf("ipv4_input(%d): Bad IP header checksum "
7480Sstevel@tonic-gate "(to %s)\n", index, inet_ntoa(ipdst));
7490Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE);
7500Sstevel@tonic-gate continue;
7510Sstevel@tonic-gate }
7520Sstevel@tonic-gate
7530Sstevel@tonic-gate if (!promiscuous) {
7540Sstevel@tonic-gate /* validate destination address */
7550Sstevel@tonic-gate if (ipdst.s_addr != htonl(INADDR_BROADCAST) &&
7560Sstevel@tonic-gate ipdst.s_addr != (mynet.s_addr | ~netmask.s_addr) &&
7570Sstevel@tonic-gate ipdst.s_addr != myip.s_addr) {
7580Sstevel@tonic-gate #ifdef DEBUG
7590Sstevel@tonic-gate printf("ipv4_input(%d): msg to %s discarded.\n",
7600Sstevel@tonic-gate index, inet_ntoa(ipdst));
7610Sstevel@tonic-gate #endif /* DEBUG */
7620Sstevel@tonic-gate /* not ours */
7630Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE);
7640Sstevel@tonic-gate continue;
7650Sstevel@tonic-gate }
7660Sstevel@tonic-gate }
7670Sstevel@tonic-gate
7680Sstevel@tonic-gate /* Intercept ICMP first */
7690Sstevel@tonic-gate if (!promiscuous && (iphp->ip_p == IPPROTO_ICMP)) {
7700Sstevel@tonic-gate icmp4(igp, iphp, iphlen, ipsrc);
7710Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE);
7720Sstevel@tonic-gate continue;
7730Sstevel@tonic-gate }
7740Sstevel@tonic-gate
7750Sstevel@tonic-gate #ifdef DEBUG
7760Sstevel@tonic-gate printf("ipv4_input(%d): processing ID: 0x%x protocol %d "
7770Sstevel@tonic-gate "(0x%x) (0x%x,%d)\n",
7780Sstevel@tonic-gate index, ntohs(iphp->ip_id), iphp->ip_p, igp, igp->igm_mp,
7790Sstevel@tonic-gate igp->igm_mp->b_size);
7800Sstevel@tonic-gate #endif /* DEBUG */
7810Sstevel@tonic-gate type = sockets[index].type;
7820Sstevel@tonic-gate if (type == INETBOOT_RAW) {
7830Sstevel@tonic-gate /* No fragmentation - Just the raw packet. */
7840Sstevel@tonic-gate #ifdef DEBUG
7850Sstevel@tonic-gate printf("ipv4_input(%d): Raw packet.\n", index);
7860Sstevel@tonic-gate #endif /* DEBUG */
7870Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, FALSE);
7880Sstevel@tonic-gate add_grams(&ipv4_listp, igp);
7890Sstevel@tonic-gate igp->igm_mp->b_rptr += iphlen;
7900Sstevel@tonic-gate igp->igm_mp->b_wptr = igp->igm_mp->b_rptr + iplen;
7910Sstevel@tonic-gate datagrams++;
7920Sstevel@tonic-gate continue;
7930Sstevel@tonic-gate }
7940Sstevel@tonic-gate
7950Sstevel@tonic-gate if ((type == INETBOOT_DGRAM && iphp->ip_p != IPPROTO_UDP) ||
7960Sstevel@tonic-gate (type == INETBOOT_STREAM && iphp->ip_p != IPPROTO_TCP)) {
7970Sstevel@tonic-gate /* Wrong protocol. */
7980Sstevel@tonic-gate dprintf("ipv4_input(%d): unexpected protocol: "
7990Sstevel@tonic-gate "%d for socket type %d\n", index, iphp->ip_p, type);
8000Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE);
8010Sstevel@tonic-gate continue;
8020Sstevel@tonic-gate }
8030Sstevel@tonic-gate
8040Sstevel@tonic-gate /*
8050Sstevel@tonic-gate * The following code is common to both STREAM and DATAGRAM
8060Sstevel@tonic-gate * sockets.
8070Sstevel@tonic-gate */
8080Sstevel@tonic-gate
8090Sstevel@tonic-gate /*
8100Sstevel@tonic-gate * Once we process the first fragment, we won't have
8110Sstevel@tonic-gate * the transport header, so we'll have to match on
8120Sstevel@tonic-gate * IP id.
8130Sstevel@tonic-gate */
8140Sstevel@tonic-gate curr_off = ntohs(iphp->ip_off);
8150Sstevel@tonic-gate if ((curr_off & ~(IP_DF | IP_MF)) == 0) {
8160Sstevel@tonic-gate uint16_t *transp;
8170Sstevel@tonic-gate
8180Sstevel@tonic-gate /* Validate transport header. */
8190Sstevel@tonic-gate mp = igp->igm_mp;
8200Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr - iphlen) <
8210Sstevel@tonic-gate sockets[index].headerlen[TRANSPORT_LVL](igp)) {
8220Sstevel@tonic-gate dprintf("ipv4_input(%d): datagram 0 "
8230Sstevel@tonic-gate "too small to hold transport header "
8240Sstevel@tonic-gate "(from %s)\n", index, inet_ntoa(ipsrc));
8250Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE);
8260Sstevel@tonic-gate continue;
8270Sstevel@tonic-gate }
8280Sstevel@tonic-gate
8290Sstevel@tonic-gate /*
8300Sstevel@tonic-gate * check alignment - transport elements are 16
8310Sstevel@tonic-gate * bit aligned..
8320Sstevel@tonic-gate */
8330Sstevel@tonic-gate transp = (uint16_t *)(mp->b_rptr + iphlen);
8340Sstevel@tonic-gate if ((uintptr_t)transp % sizeof (uint16_t)) {
8350Sstevel@tonic-gate dprintf("ipv4_input(%d): Transport "
8360Sstevel@tonic-gate "header is not 16-bit aligned "
8370Sstevel@tonic-gate "(0x%lx, from %s)\n", index, (long)transp,
8380Sstevel@tonic-gate inet_ntoa(ipsrc));
8390Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE);
8400Sstevel@tonic-gate continue;
8410Sstevel@tonic-gate }
8420Sstevel@tonic-gate
8430Sstevel@tonic-gate if (curr_off & IP_MF) {
8440Sstevel@tonic-gate /* fragment 0 of fragmented datagram */
8450Sstevel@tonic-gate ip_id = ntohs(iphp->ip_id);
8460Sstevel@tonic-gate frag_stat = frag_add(curr_off, igp->igm_mp,
8470Sstevel@tonic-gate ip_id, iplen, iphlen, iphp->ip_p);
8480Sstevel@tonic-gate if (frag_stat != FRAG_SUCCESS) {
8490Sstevel@tonic-gate #ifdef FRAG_DEBUG
8500Sstevel@tonic-gate if (frag_stat == FRAG_DUP) {
8510Sstevel@tonic-gate printf("ipv4_input"
8520Sstevel@tonic-gate "(%d): Frag dup.\n", index);
8530Sstevel@tonic-gate } else {
8540Sstevel@tonic-gate printf("ipv4_input"
8550Sstevel@tonic-gate "(%d): too many "
8560Sstevel@tonic-gate "frags\n", index);
8570Sstevel@tonic-gate }
8580Sstevel@tonic-gate #endif /* FRAG_DEBUG */
8590Sstevel@tonic-gate del_gram(&sockets[index].inq,
8600Sstevel@tonic-gate igp, TRUE);
8610Sstevel@tonic-gate continue;
8620Sstevel@tonic-gate }
8630Sstevel@tonic-gate
8640Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, FALSE);
8650Sstevel@tonic-gate /* keep the data, lose the inetgram */
8660Sstevel@tonic-gate bkmem_free((caddr_t)igp,
8670Sstevel@tonic-gate sizeof (struct inetgram));
8680Sstevel@tonic-gate #ifdef FRAG_DEBUG
8690Sstevel@tonic-gate printf("ipv4_input(%d): Frag/Off/Id "
8700Sstevel@tonic-gate "(%d/%d/%x)\n", index, fragments,
8710Sstevel@tonic-gate IPV4_OFFSET(curr_off), ip_id);
8720Sstevel@tonic-gate #endif /* FRAG_DEBUG */
8730Sstevel@tonic-gate } else {
8740Sstevel@tonic-gate /* Single, unfragmented datagram */
8750Sstevel@tonic-gate newgp = make_trans_datagram(index, igp,
8760Sstevel@tonic-gate ipsrc, ipdst, iphlen);
8770Sstevel@tonic-gate if (newgp != NULL) {
8780Sstevel@tonic-gate add_grams(&ipv4_listp, newgp);
8790Sstevel@tonic-gate datagrams++;
8800Sstevel@tonic-gate }
8810Sstevel@tonic-gate del_gram(&sockets[index].inq, igp,
8820Sstevel@tonic-gate TRUE);
8830Sstevel@tonic-gate continue;
8840Sstevel@tonic-gate }
8850Sstevel@tonic-gate } else {
8860Sstevel@tonic-gate /* fragments other than 0 */
8870Sstevel@tonic-gate frag_stat = frag_add(curr_off, igp->igm_mp,
8880Sstevel@tonic-gate ntohs(iphp->ip_id), iplen, iphlen, iphp->ip_p);
8890Sstevel@tonic-gate
8900Sstevel@tonic-gate if (frag_stat == FRAG_SUCCESS) {
8910Sstevel@tonic-gate #ifdef FRAG_DEBUG
8920Sstevel@tonic-gate printf("ipv4_input(%d): Frag(%d) "
8930Sstevel@tonic-gate "off(%d) id(%x)\n", index,
8940Sstevel@tonic-gate fragments, IPV4_OFFSET(curr_off),
8950Sstevel@tonic-gate ntohs(iphp->ip_id));
8960Sstevel@tonic-gate #endif /* FRAG_DEBUG */
8970Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, FALSE);
8980Sstevel@tonic-gate /* keep the data, lose the inetgram */
8990Sstevel@tonic-gate bkmem_free((caddr_t)igp,
9000Sstevel@tonic-gate sizeof (struct inetgram));
9010Sstevel@tonic-gate } else {
9020Sstevel@tonic-gate #ifdef FRAG_DEBUG
9030Sstevel@tonic-gate if (frag_stat == FRAG_DUP)
9040Sstevel@tonic-gate printf("ipv4_input(%d): Frag "
9050Sstevel@tonic-gate "dup.\n", index);
9060Sstevel@tonic-gate else {
9070Sstevel@tonic-gate printf("ipv4_input(%d): too "
9080Sstevel@tonic-gate "many frags\n", index);
9090Sstevel@tonic-gate }
9100Sstevel@tonic-gate #endif /* FRAG_DEBUG */
9110Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE);
9120Sstevel@tonic-gate continue;
9130Sstevel@tonic-gate }
9140Sstevel@tonic-gate }
9150Sstevel@tonic-gate
9160Sstevel@tonic-gate /*
9170Sstevel@tonic-gate * Determine if we have all of the fragments.
9180Sstevel@tonic-gate *
9190Sstevel@tonic-gate * NOTE: at this point, we've placed the data in the
9200Sstevel@tonic-gate * fragment table, and the inetgram (igp) has been
9210Sstevel@tonic-gate * deleted.
9220Sstevel@tonic-gate */
9230Sstevel@tonic-gate if (!frag_chk())
9240Sstevel@tonic-gate continue;
9250Sstevel@tonic-gate
9260Sstevel@tonic-gate newgp = make_trans_datagram(index, NULL, ipsrc, ipdst, iphlen);
9270Sstevel@tonic-gate if (newgp == NULL)
9280Sstevel@tonic-gate continue;
9290Sstevel@tonic-gate add_grams(&ipv4_listp, newgp);
9300Sstevel@tonic-gate datagrams++;
9310Sstevel@tonic-gate }
9320Sstevel@tonic-gate if (ipv4_listp == NULL && fragments != 0) {
9330Sstevel@tonic-gate if (++input_attempts > FRAG_ATTEMPTS) {
9340Sstevel@tonic-gate dprintf("ipv4_input(%d): reassembly(%d) timed out in "
9350Sstevel@tonic-gate "%d msecs.\n", index, fragments,
9360Sstevel@tonic-gate sockets[index].in_timeout * input_attempts);
9370Sstevel@tonic-gate frag_flush();
9380Sstevel@tonic-gate errno = ETIMEDOUT;
9390Sstevel@tonic-gate return (-1);
9400Sstevel@tonic-gate } else {
9410Sstevel@tonic-gate /*
9420Sstevel@tonic-gate * Call the media layer again... there may be more
9430Sstevel@tonic-gate * packets waiting.
9440Sstevel@tonic-gate */
9450Sstevel@tonic-gate if (sockets[index].input[MEDIA_LVL](index) < 0) {
9460Sstevel@tonic-gate /* errno will be set appropriately */
9470Sstevel@tonic-gate frag_flush();
9480Sstevel@tonic-gate return (-1);
9490Sstevel@tonic-gate }
9500Sstevel@tonic-gate goto ipv4_try_again;
9510Sstevel@tonic-gate }
9520Sstevel@tonic-gate }
9530Sstevel@tonic-gate
9540Sstevel@tonic-gate add_grams(&sockets[index].inq, ipv4_listp);
9550Sstevel@tonic-gate
9560Sstevel@tonic-gate return (datagrams);
9570Sstevel@tonic-gate }
9580Sstevel@tonic-gate
9590Sstevel@tonic-gate /*
9600Sstevel@tonic-gate * ipv4_output: Generate IPv4 datagram(s) for the payload and deliver them.
9610Sstevel@tonic-gate * Routing is handled here as well, by reusing the saddr field to hold the
9620Sstevel@tonic-gate * router's IP address.
9630Sstevel@tonic-gate *
9640Sstevel@tonic-gate * We don't deal with fragmentation on the outgoing side.
9650Sstevel@tonic-gate *
9660Sstevel@tonic-gate * Arguments: index to socket, inetgram to send.
9670Sstevel@tonic-gate *
9680Sstevel@tonic-gate * Returns: 0 for success, -1 if error occurred.
9690Sstevel@tonic-gate */
9700Sstevel@tonic-gate int
ipv4_output(int index,struct inetgram * ogp)9710Sstevel@tonic-gate ipv4_output(int index, struct inetgram *ogp)
9720Sstevel@tonic-gate {
9730Sstevel@tonic-gate struct ip *iphp;
9740Sstevel@tonic-gate uint64_t iphbuffer[sizeof (struct ip)];
9750Sstevel@tonic-gate
9760Sstevel@tonic-gate #ifdef DEBUG
9770Sstevel@tonic-gate printf("ipv4_output(%d): size %d\n", index,
9780Sstevel@tonic-gate ogp->igm_mp->b_wptr - ogp->igm_mp->b_rptr);
9790Sstevel@tonic-gate #endif /* DEBUG */
9800Sstevel@tonic-gate
9810Sstevel@tonic-gate /* we don't deal (yet) with fragmentation. Maybe never will */
9820Sstevel@tonic-gate if ((ogp->igm_mp->b_wptr - ogp->igm_mp->b_rptr) > mac_get_mtu()) {
9830Sstevel@tonic-gate dprintf("ipv4: datagram too big for MAC layer.\n");
9840Sstevel@tonic-gate errno = E2BIG;
9850Sstevel@tonic-gate return (-1);
9860Sstevel@tonic-gate }
9870Sstevel@tonic-gate
9880Sstevel@tonic-gate if (ogp->igm_level != NETWORK_LVL) {
9890Sstevel@tonic-gate #ifdef DEBUG
9900Sstevel@tonic-gate printf("ipv4_output(%d): unexpected frame type: %d\n", index,
9910Sstevel@tonic-gate ogp->igm_level);
9920Sstevel@tonic-gate #endif /* DEBUG */
9930Sstevel@tonic-gate errno = EINVAL;
9940Sstevel@tonic-gate return (-1);
9950Sstevel@tonic-gate }
9960Sstevel@tonic-gate
9970Sstevel@tonic-gate if (sockets[index].out_flags & SO_DONTROUTE)
9980Sstevel@tonic-gate ogp->igm_oflags |= MSG_DONTROUTE;
9990Sstevel@tonic-gate
10000Sstevel@tonic-gate iphp = (struct ip *)&iphbuffer;
10010Sstevel@tonic-gate iphp->ip_v = IPVERSION;
10020Sstevel@tonic-gate iphp->ip_hl = sizeof (struct ip) / 4;
10030Sstevel@tonic-gate iphp->ip_tos = 0;
10040Sstevel@tonic-gate iphp->ip_len = htons(ogp->igm_mp->b_wptr - ogp->igm_mp->b_rptr +
10050Sstevel@tonic-gate sizeof (struct ip));
10060Sstevel@tonic-gate iphp->ip_id = htons(++g_ip_id);
10070Sstevel@tonic-gate iphp->ip_off = htons(IP_DF);
10080Sstevel@tonic-gate iphp->ip_p = sockets[index].proto;
10090Sstevel@tonic-gate iphp->ip_sum = htons(0);
10100Sstevel@tonic-gate iphp->ip_ttl = ttl;
10110Sstevel@tonic-gate
10120Sstevel@tonic-gate /* struct copies */
10130Sstevel@tonic-gate iphp->ip_src = myip;
10140Sstevel@tonic-gate iphp->ip_dst = ogp->igm_saddr.sin_addr;
10150Sstevel@tonic-gate
10160Sstevel@tonic-gate /*
10170Sstevel@tonic-gate * On local / limited broadcasts, don't route. From a purist's
10180Sstevel@tonic-gate * perspective, we should be setting the TTL to 1. But
10190Sstevel@tonic-gate * operational experience has shown that some BOOTP relay agents
10200Sstevel@tonic-gate * (ciscos) discard our packets. Furthermore, these devices also
10210Sstevel@tonic-gate * *don't* reset the TTL to MAXTTL on the unicast side of the
10220Sstevel@tonic-gate * BOOTP relay agent! Sigh. Thus to work correctly in these
10230Sstevel@tonic-gate * environments, we leave the TTL as it has been been set by
10240Sstevel@tonic-gate * the application layer, and simply don't check for a route.
10250Sstevel@tonic-gate */
10260Sstevel@tonic-gate if (iphp->ip_dst.s_addr == htonl(INADDR_BROADCAST) ||
10270Sstevel@tonic-gate (netmask.s_addr != htonl(INADDR_BROADCAST) &&
10280Sstevel@tonic-gate iphp->ip_dst.s_addr == (mynet.s_addr | ~netmask.s_addr))) {
10290Sstevel@tonic-gate ogp->igm_oflags |= MSG_DONTROUTE;
10300Sstevel@tonic-gate }
10310Sstevel@tonic-gate
10320Sstevel@tonic-gate /* Routing necessary? */
10330Sstevel@tonic-gate if ((ogp->igm_oflags & MSG_DONTROUTE) == 0 &&
10340Sstevel@tonic-gate ((iphp->ip_dst.s_addr & netmask.s_addr) != mynet.s_addr)) {
10350Sstevel@tonic-gate struct in_addr *rip;
10360Sstevel@tonic-gate if ((rip = ipv4_get_route(RT_HOST, &iphp->ip_dst,
10370Sstevel@tonic-gate NULL)) == NULL) {
10380Sstevel@tonic-gate rip = ipv4_get_route(RT_DEFAULT, NULL, NULL);
10390Sstevel@tonic-gate }
10400Sstevel@tonic-gate if (rip == NULL) {
10410Sstevel@tonic-gate dprintf("ipv4(%d): No route to %s.\n",
10420Sstevel@tonic-gate index, inet_ntoa(iphp->ip_dst));
10430Sstevel@tonic-gate errno = EHOSTUNREACH;
10440Sstevel@tonic-gate return (-1);
10450Sstevel@tonic-gate }
10460Sstevel@tonic-gate ogp->igm_router.s_addr = rip->s_addr;
10470Sstevel@tonic-gate } else
10480Sstevel@tonic-gate ogp->igm_router.s_addr = htonl(INADDR_ANY);
10490Sstevel@tonic-gate
10500Sstevel@tonic-gate iphp->ip_sum = ipv4cksum((uint16_t *)iphp, sizeof (struct ip));
10510Sstevel@tonic-gate ogp->igm_mp->b_rptr -= sizeof (struct ip);
10520Sstevel@tonic-gate bcopy((caddr_t)iphp, (caddr_t)(ogp->igm_mp->b_rptr),
10530Sstevel@tonic-gate sizeof (struct ip));
10540Sstevel@tonic-gate
10550Sstevel@tonic-gate ogp->igm_level = MEDIA_LVL;
10560Sstevel@tonic-gate
10570Sstevel@tonic-gate return (0);
10580Sstevel@tonic-gate }
10590Sstevel@tonic-gate
10600Sstevel@tonic-gate /*
10610Sstevel@tonic-gate * Function to be called by TCP to send out a packet. This is used
10620Sstevel@tonic-gate * when TCP wants to send out packets which it has already filled in
10630Sstevel@tonic-gate * most of the header fields.
10640Sstevel@tonic-gate */
10650Sstevel@tonic-gate int
ipv4_tcp_output(int sock_id,mblk_t * pkt)10660Sstevel@tonic-gate ipv4_tcp_output(int sock_id, mblk_t *pkt)
10670Sstevel@tonic-gate {
10680Sstevel@tonic-gate struct ip *iph;
10690Sstevel@tonic-gate struct in_addr *rip = NULL;
10700Sstevel@tonic-gate struct inetgram datagram;
10710Sstevel@tonic-gate
10720Sstevel@tonic-gate iph = (struct ip *)pkt->b_rptr;
10730Sstevel@tonic-gate
10740Sstevel@tonic-gate bzero(&datagram, sizeof (struct inetgram));
10750Sstevel@tonic-gate
10760Sstevel@tonic-gate /*
10770Sstevel@tonic-gate * Bootparams doesn't know about subnet masks, so we need to
10780Sstevel@tonic-gate * explicitly check for this flag.
10790Sstevel@tonic-gate */
10800Sstevel@tonic-gate if (sockets[sock_id].out_flags & SO_DONTROUTE)
10810Sstevel@tonic-gate datagram.igm_oflags |= MSG_DONTROUTE;
10820Sstevel@tonic-gate
10830Sstevel@tonic-gate /* Routing necessary? */
10840Sstevel@tonic-gate if (((datagram.igm_oflags & MSG_DONTROUTE) == 0) &&
10850Sstevel@tonic-gate ((iph->ip_dst.s_addr & netmask.s_addr) != mynet.s_addr)) {
10860Sstevel@tonic-gate if ((rip = ipv4_get_route(RT_HOST, &iph->ip_dst,
10870Sstevel@tonic-gate NULL)) == NULL) {
10880Sstevel@tonic-gate rip = ipv4_get_route(RT_DEFAULT, NULL, NULL);
10890Sstevel@tonic-gate }
10900Sstevel@tonic-gate if (rip == NULL) {
10910Sstevel@tonic-gate dprintf("ipv4(%d): No route to %s.\n",
10920Sstevel@tonic-gate sock_id, inet_ntoa(iph->ip_dst));
10930Sstevel@tonic-gate errno = EHOSTUNREACH;
10940Sstevel@tonic-gate return (-1);
10950Sstevel@tonic-gate }
10960Sstevel@tonic-gate }
10970Sstevel@tonic-gate
10980Sstevel@tonic-gate iph->ip_id = htons(++g_ip_id);
10990Sstevel@tonic-gate iph->ip_sum = ipv4cksum((uint16_t *)iph, sizeof (struct ip));
11000Sstevel@tonic-gate #if DEBUG > 1
11010Sstevel@tonic-gate printf("ipv4_tcp_output: dump IP packet(%d)\n", iph->ip_len);
11020Sstevel@tonic-gate hexdump((char *)pkt->b_rptr, iph->ip_len);
11030Sstevel@tonic-gate #endif
11040Sstevel@tonic-gate /* Call the MAC layer output routine to send it out. */
11050Sstevel@tonic-gate datagram.igm_mp = pkt;
11060Sstevel@tonic-gate datagram.igm_level = MEDIA_LVL;
11070Sstevel@tonic-gate if (rip != NULL)
11080Sstevel@tonic-gate datagram.igm_router.s_addr = rip->s_addr;
11090Sstevel@tonic-gate else
11100Sstevel@tonic-gate datagram.igm_router.s_addr = 0;
11110Sstevel@tonic-gate return (mac_state.mac_output(sock_id, &datagram));
11120Sstevel@tonic-gate }
11130Sstevel@tonic-gate
11140Sstevel@tonic-gate /*
11150Sstevel@tonic-gate * Internet address interpretation routine.
11160Sstevel@tonic-gate * All the network library routines call this
11170Sstevel@tonic-gate * routine to interpret entries in the data bases
11180Sstevel@tonic-gate * which are expected to be an address.
11190Sstevel@tonic-gate * The value returned is in network order.
11200Sstevel@tonic-gate */
11210Sstevel@tonic-gate in_addr_t
inet_addr(const char * cp)11220Sstevel@tonic-gate inet_addr(const char *cp)
11230Sstevel@tonic-gate {
11240Sstevel@tonic-gate uint32_t val, base, n;
11250Sstevel@tonic-gate char c;
11260Sstevel@tonic-gate uint32_t parts[4], *pp = parts;
11270Sstevel@tonic-gate
11280Sstevel@tonic-gate if (*cp == '\0')
11290Sstevel@tonic-gate return ((uint32_t)-1); /* disallow null string in cp */
11300Sstevel@tonic-gate again:
11310Sstevel@tonic-gate /*
11320Sstevel@tonic-gate * Collect number up to ``.''.
11330Sstevel@tonic-gate * Values are specified as for C:
11340Sstevel@tonic-gate * 0x=hex, 0=octal, other=decimal.
11350Sstevel@tonic-gate */
11360Sstevel@tonic-gate val = 0; base = 10;
11370Sstevel@tonic-gate if (*cp == '0') {
11380Sstevel@tonic-gate if (*++cp == 'x' || *cp == 'X')
11390Sstevel@tonic-gate base = 16, cp++;
11400Sstevel@tonic-gate else
11410Sstevel@tonic-gate base = 8;
11420Sstevel@tonic-gate }
11430Sstevel@tonic-gate while ((c = *cp) != NULL) {
11440Sstevel@tonic-gate if (isdigit(c)) {
11450Sstevel@tonic-gate if ((c - '0') >= base)
11460Sstevel@tonic-gate break;
11470Sstevel@tonic-gate val = (val * base) + (c - '0');
11480Sstevel@tonic-gate cp++;
11490Sstevel@tonic-gate continue;
11500Sstevel@tonic-gate }
11510Sstevel@tonic-gate if (base == 16 && isxdigit(c)) {
11520Sstevel@tonic-gate val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
11530Sstevel@tonic-gate cp++;
11540Sstevel@tonic-gate continue;
11550Sstevel@tonic-gate }
11560Sstevel@tonic-gate break;
11570Sstevel@tonic-gate }
11580Sstevel@tonic-gate if (*cp == '.') {
11590Sstevel@tonic-gate /*
11600Sstevel@tonic-gate * Internet format:
11610Sstevel@tonic-gate * a.b.c.d
11620Sstevel@tonic-gate * a.b.c (with c treated as 16-bits)
11630Sstevel@tonic-gate * a.b (with b treated as 24 bits)
11640Sstevel@tonic-gate */
11650Sstevel@tonic-gate if ((pp >= parts + 3) || (val > 0xff)) {
11660Sstevel@tonic-gate return ((uint32_t)-1);
11670Sstevel@tonic-gate }
11680Sstevel@tonic-gate *pp++ = val, cp++;
11690Sstevel@tonic-gate goto again;
11700Sstevel@tonic-gate }
11710Sstevel@tonic-gate /*
11720Sstevel@tonic-gate * Check for trailing characters.
11730Sstevel@tonic-gate */
11740Sstevel@tonic-gate if (*cp && !isspace(*cp)) {
11750Sstevel@tonic-gate return ((uint32_t)-1);
11760Sstevel@tonic-gate }
11770Sstevel@tonic-gate *pp++ = val;
11780Sstevel@tonic-gate /*
11790Sstevel@tonic-gate * Concoct the address according to
11800Sstevel@tonic-gate * the number of parts specified.
11810Sstevel@tonic-gate */
11820Sstevel@tonic-gate n = pp - parts;
11830Sstevel@tonic-gate switch (n) {
11840Sstevel@tonic-gate
11850Sstevel@tonic-gate case 1: /* a -- 32 bits */
11860Sstevel@tonic-gate val = parts[0];
11870Sstevel@tonic-gate break;
11880Sstevel@tonic-gate
11890Sstevel@tonic-gate case 2: /* a.b -- 8.24 bits */
11900Sstevel@tonic-gate if (parts[1] > 0xffffff)
11910Sstevel@tonic-gate return ((uint32_t)-1);
11920Sstevel@tonic-gate val = (parts[0] << 24) | (parts[1] & 0xffffff);
11930Sstevel@tonic-gate break;
11940Sstevel@tonic-gate
11950Sstevel@tonic-gate case 3: /* a.b.c -- 8.8.16 bits */
11960Sstevel@tonic-gate if (parts[2] > 0xffff)
11970Sstevel@tonic-gate return ((uint32_t)-1);
11980Sstevel@tonic-gate val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
11990Sstevel@tonic-gate (parts[2] & 0xffff);
12000Sstevel@tonic-gate break;
12010Sstevel@tonic-gate
12020Sstevel@tonic-gate case 4: /* a.b.c.d -- 8.8.8.8 bits */
12030Sstevel@tonic-gate if (parts[3] > 0xff)
12040Sstevel@tonic-gate return ((uint32_t)-1);
12050Sstevel@tonic-gate val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
12060Sstevel@tonic-gate ((parts[2] & 0xff) << 8) | (parts[3] & 0xff);
12070Sstevel@tonic-gate break;
12080Sstevel@tonic-gate
12090Sstevel@tonic-gate default:
12100Sstevel@tonic-gate return ((uint32_t)-1);
12110Sstevel@tonic-gate }
12120Sstevel@tonic-gate val = htonl(val);
12130Sstevel@tonic-gate return (val);
12140Sstevel@tonic-gate }
12150Sstevel@tonic-gate
12160Sstevel@tonic-gate void
hexdump(char * data,int datalen)12170Sstevel@tonic-gate hexdump(char *data, int datalen)
12180Sstevel@tonic-gate {
12190Sstevel@tonic-gate char *p;
12200Sstevel@tonic-gate ushort_t *p16 = (ushort_t *)data;
12210Sstevel@tonic-gate char *p8 = data;
12220Sstevel@tonic-gate int i, left, len;
12230Sstevel@tonic-gate int chunk = 16; /* 16 bytes per line */
12240Sstevel@tonic-gate
12250Sstevel@tonic-gate printf("\n");
12260Sstevel@tonic-gate
12270Sstevel@tonic-gate for (p = data; p < data + datalen; p += chunk) {
12280Sstevel@tonic-gate printf("\t%4d: ", (int)(p - data));
12290Sstevel@tonic-gate left = (data + datalen) - p;
12300Sstevel@tonic-gate len = MIN(chunk, left);
12310Sstevel@tonic-gate for (i = 0; i < (len / 2); i++)
12320Sstevel@tonic-gate printf("%04x ", ntohs(*p16++) & 0xffff);
12330Sstevel@tonic-gate if (len % 2) {
12340Sstevel@tonic-gate printf("%02x ", *((unsigned char *)p16));
12350Sstevel@tonic-gate }
12360Sstevel@tonic-gate for (i = 0; i < (chunk - left) / 2; i++)
12370Sstevel@tonic-gate printf(" ");
12380Sstevel@tonic-gate
12390Sstevel@tonic-gate printf(" ");
12400Sstevel@tonic-gate for (i = 0; i < len; i++, p8++)
12410Sstevel@tonic-gate printf("%c", isprint(*p8) ? *p8 : '.');
12420Sstevel@tonic-gate printf("\n");
12430Sstevel@tonic-gate }
12440Sstevel@tonic-gate
12450Sstevel@tonic-gate printf("\n");
12460Sstevel@tonic-gate }
1247