17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52a9459bdSsangeeta * Common Development and Distribution License (the "License").
62a9459bdSsangeeta * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
222a9459bdSsangeeta * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate *
257c478bd9Sstevel@tonic-gate * ipv4.c, Code implementing the IPv4 internet protocol.
267c478bd9Sstevel@tonic-gate */
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate #include <sys/types.h>
297c478bd9Sstevel@tonic-gate #include <socket_impl.h>
307c478bd9Sstevel@tonic-gate #include <socket_inet.h>
317c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
327c478bd9Sstevel@tonic-gate #include <sys/socket.h>
337c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h>
347c478bd9Sstevel@tonic-gate #include <netinet/in.h>
357c478bd9Sstevel@tonic-gate #include <netinet/ip.h>
367c478bd9Sstevel@tonic-gate #include <netinet/udp.h>
377c478bd9Sstevel@tonic-gate #include <net/if_arp.h>
387c478bd9Sstevel@tonic-gate #include <sys/promif.h>
397c478bd9Sstevel@tonic-gate #include <sys/bootconf.h>
407c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
417c478bd9Sstevel@tonic-gate #include <sys/salib.h>
427c478bd9Sstevel@tonic-gate
437c478bd9Sstevel@tonic-gate #include "icmp4.h"
447c478bd9Sstevel@tonic-gate #include "ipv4.h"
457c478bd9Sstevel@tonic-gate #include "ipv4_impl.h"
467c478bd9Sstevel@tonic-gate #include "mac.h"
477c478bd9Sstevel@tonic-gate #include "mac_impl.h"
487c478bd9Sstevel@tonic-gate #include "v4_sum_impl.h"
497c478bd9Sstevel@tonic-gate #include <sys/bootdebug.h>
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate static struct ip_frag fragment[FRAG_MAX]; /* ip fragment buffers */
527c478bd9Sstevel@tonic-gate static int fragments; /* Number of fragments */
537c478bd9Sstevel@tonic-gate static uint8_t ttl = MAXTTL; /* IP ttl */
547c478bd9Sstevel@tonic-gate static struct in_addr myip; /* our network-order IP addr */
557c478bd9Sstevel@tonic-gate static struct in_addr mynet; /* net-order netaddr */
567c478bd9Sstevel@tonic-gate static struct in_addr netmask =
577c478bd9Sstevel@tonic-gate { 0xff, 0xff, 0xff, 0xff }; /* our network-order netmask */
587c478bd9Sstevel@tonic-gate static boolean_t netmask_set = B_FALSE; /* has anyone set netmask? */
597c478bd9Sstevel@tonic-gate static struct in_addr defaultrouter; /* net-order defaultrouter */
607c478bd9Sstevel@tonic-gate static int promiscuous; /* promiscuous mode */
617c478bd9Sstevel@tonic-gate static struct routing table[IPV4_ROUTE_TABLE_SIZE];
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate static uint16_t g_ip_id;
647c478bd9Sstevel@tonic-gate
657c478bd9Sstevel@tonic-gate #ifdef DEBUG
667c478bd9Sstevel@tonic-gate #define FRAG_DEBUG
677c478bd9Sstevel@tonic-gate #endif /* DEBUG */
687c478bd9Sstevel@tonic-gate
697c478bd9Sstevel@tonic-gate #ifdef FRAG_DEBUG
707c478bd9Sstevel@tonic-gate /*
717c478bd9Sstevel@tonic-gate * display the fragment list. For debugging purposes.
727c478bd9Sstevel@tonic-gate */
737c478bd9Sstevel@tonic-gate static void
frag_disp(uint16_t size)747c478bd9Sstevel@tonic-gate frag_disp(uint16_t size)
757c478bd9Sstevel@tonic-gate {
767c478bd9Sstevel@tonic-gate int i;
777c478bd9Sstevel@tonic-gate uint_t total = 0;
787c478bd9Sstevel@tonic-gate
797c478bd9Sstevel@tonic-gate printf("Dumping fragment info: (%d)\n\n", fragments);
807c478bd9Sstevel@tonic-gate printf("More:\tOffset:\tDatap:\t\tIPid:\t\tIPlen:\tIPhlen:\n");
817c478bd9Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) {
827c478bd9Sstevel@tonic-gate if (fragment[i].mp == NULL)
837c478bd9Sstevel@tonic-gate continue;
847c478bd9Sstevel@tonic-gate printf("%d\t%d\t0x%x\t%d\t\t%d\t%d\n", fragment[i].more,
857c478bd9Sstevel@tonic-gate fragment[i].offset, fragment[i].mp->b_rptr,
867c478bd9Sstevel@tonic-gate fragment[i].ipid, fragment[i].iplen, fragment[i].iphlen);
877c478bd9Sstevel@tonic-gate total += (fragment[i].iplen - fragment[i].iphlen);
887c478bd9Sstevel@tonic-gate }
897c478bd9Sstevel@tonic-gate printf("Total length is: %d. It should be: %d\n\n", total, size);
907c478bd9Sstevel@tonic-gate }
917c478bd9Sstevel@tonic-gate #endif /* FRAG_DEBUG */
927c478bd9Sstevel@tonic-gate
937c478bd9Sstevel@tonic-gate /*
947c478bd9Sstevel@tonic-gate * This function returns index of fragment 0 of the current fragmented DGRAM
957c478bd9Sstevel@tonic-gate * (which would contain the transport header). Return the fragment number
967c478bd9Sstevel@tonic-gate * for success, -1 if we don't yet have the first fragment.
977c478bd9Sstevel@tonic-gate */
987c478bd9Sstevel@tonic-gate static int
frag_first(void)997c478bd9Sstevel@tonic-gate frag_first(void)
1007c478bd9Sstevel@tonic-gate {
1017c478bd9Sstevel@tonic-gate int i;
1027c478bd9Sstevel@tonic-gate
1037c478bd9Sstevel@tonic-gate if (fragments == 0)
1047c478bd9Sstevel@tonic-gate return (-1);
1057c478bd9Sstevel@tonic-gate
1067c478bd9Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) {
1077c478bd9Sstevel@tonic-gate if (fragment[i].mp != NULL && fragment[i].offset == 0)
1087c478bd9Sstevel@tonic-gate return (i);
1097c478bd9Sstevel@tonic-gate }
1107c478bd9Sstevel@tonic-gate return (-1);
1117c478bd9Sstevel@tonic-gate }
1127c478bd9Sstevel@tonic-gate
1137c478bd9Sstevel@tonic-gate /*
1147c478bd9Sstevel@tonic-gate * This function returns index of the last fragment of the current DGRAM.
1157c478bd9Sstevel@tonic-gate * Returns the fragment number for success, -1 if we don't yet have the
1167c478bd9Sstevel@tonic-gate * last fragment.
1177c478bd9Sstevel@tonic-gate */
1187c478bd9Sstevel@tonic-gate static int
frag_last(void)1197c478bd9Sstevel@tonic-gate frag_last(void)
1207c478bd9Sstevel@tonic-gate {
1217c478bd9Sstevel@tonic-gate int i;
1227c478bd9Sstevel@tonic-gate
1237c478bd9Sstevel@tonic-gate if (fragments == 0)
1247c478bd9Sstevel@tonic-gate return (-1);
1257c478bd9Sstevel@tonic-gate
1267c478bd9Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) {
1277c478bd9Sstevel@tonic-gate if (fragment[i].mp != NULL && !fragment[i].more)
1287c478bd9Sstevel@tonic-gate return (i);
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate return (-1);
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gate /*
1347c478bd9Sstevel@tonic-gate * This function adds a fragment to the current pkt fragment list. Returns
1357c478bd9Sstevel@tonic-gate * FRAG_NOSLOTS if there are no more slots, FRAG_DUP if the fragment is
1367c478bd9Sstevel@tonic-gate * a duplicate, or FRAG_SUCCESS if it is successful.
1377c478bd9Sstevel@tonic-gate */
1387c478bd9Sstevel@tonic-gate static int
frag_add(int16_t offset,mblk_t * mp,uint16_t ipid,int16_t iplen,int16_t iphlen,uint8_t ipp)1397c478bd9Sstevel@tonic-gate frag_add(int16_t offset, mblk_t *mp, uint16_t ipid,
1407c478bd9Sstevel@tonic-gate int16_t iplen, int16_t iphlen, uint8_t ipp)
1417c478bd9Sstevel@tonic-gate {
1427c478bd9Sstevel@tonic-gate int i;
1437c478bd9Sstevel@tonic-gate int16_t true_offset = IPV4_OFFSET(offset);
1447c478bd9Sstevel@tonic-gate
1457c478bd9Sstevel@tonic-gate /* first pass - look for duplicates */
1467c478bd9Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) {
1477c478bd9Sstevel@tonic-gate if (fragment[i].mp != NULL &&
1487c478bd9Sstevel@tonic-gate fragment[i].offset == true_offset)
1497c478bd9Sstevel@tonic-gate return (FRAG_DUP);
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate
1527c478bd9Sstevel@tonic-gate /* second pass - fill in empty slot */
1537c478bd9Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) {
1547c478bd9Sstevel@tonic-gate if (fragment[i].mp == NULL) {
1557c478bd9Sstevel@tonic-gate fragment[i].more = (offset & IP_MF);
1567c478bd9Sstevel@tonic-gate fragment[i].offset = true_offset;
1577c478bd9Sstevel@tonic-gate fragment[i].mp = mp;
1587c478bd9Sstevel@tonic-gate fragment[i].ipid = ipid;
1597c478bd9Sstevel@tonic-gate fragment[i].iplen = iplen;
1607c478bd9Sstevel@tonic-gate fragment[i].iphlen = iphlen;
1617c478bd9Sstevel@tonic-gate fragment[i].ipp = ipp;
1627c478bd9Sstevel@tonic-gate fragments++;
1637c478bd9Sstevel@tonic-gate return (FRAG_SUCCESS);
1647c478bd9Sstevel@tonic-gate }
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate return (FRAG_NOSLOTS);
1677c478bd9Sstevel@tonic-gate }
1687c478bd9Sstevel@tonic-gate
1697c478bd9Sstevel@tonic-gate /*
1707c478bd9Sstevel@tonic-gate * Nuke a fragment.
1717c478bd9Sstevel@tonic-gate */
1727c478bd9Sstevel@tonic-gate static void
frag_free(int index)1737c478bd9Sstevel@tonic-gate frag_free(int index)
1747c478bd9Sstevel@tonic-gate {
1757c478bd9Sstevel@tonic-gate if (fragment[index].mp != NULL) {
1767c478bd9Sstevel@tonic-gate freeb(fragment[index].mp);
1777c478bd9Sstevel@tonic-gate fragments--;
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate bzero((caddr_t)&fragment[index], sizeof (struct ip_frag));
1807c478bd9Sstevel@tonic-gate }
1817c478bd9Sstevel@tonic-gate
1827c478bd9Sstevel@tonic-gate /*
1837c478bd9Sstevel@tonic-gate * zero the frag list.
1847c478bd9Sstevel@tonic-gate */
1857c478bd9Sstevel@tonic-gate static void
frag_flush(void)1867c478bd9Sstevel@tonic-gate frag_flush(void)
1877c478bd9Sstevel@tonic-gate {
1887c478bd9Sstevel@tonic-gate int i;
1897c478bd9Sstevel@tonic-gate
1907c478bd9Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++)
1917c478bd9Sstevel@tonic-gate frag_free(i);
1927c478bd9Sstevel@tonic-gate
1937c478bd9Sstevel@tonic-gate fragments = 0;
1947c478bd9Sstevel@tonic-gate }
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate /*
1977c478bd9Sstevel@tonic-gate * Analyze the fragment list - see if we captured all our fragments.
1987c478bd9Sstevel@tonic-gate *
1997c478bd9Sstevel@tonic-gate * Returns TRUE if we've got all the fragments, and FALSE if we don't.
2007c478bd9Sstevel@tonic-gate */
2017c478bd9Sstevel@tonic-gate static int
frag_chk(void)2027c478bd9Sstevel@tonic-gate frag_chk(void)
2037c478bd9Sstevel@tonic-gate {
2047c478bd9Sstevel@tonic-gate int i, first_frag, last_frag;
2057c478bd9Sstevel@tonic-gate int16_t actual, total;
2067c478bd9Sstevel@tonic-gate uint16_t ip_id;
2077c478bd9Sstevel@tonic-gate uint8_t ipp;
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate if (fragments == 0 || (first_frag = frag_first()) < 0 ||
2107c478bd9Sstevel@tonic-gate (last_frag = frag_last()) < 0)
2117c478bd9Sstevel@tonic-gate return (FALSE);
2127c478bd9Sstevel@tonic-gate
2137c478bd9Sstevel@tonic-gate /*
2147c478bd9Sstevel@tonic-gate * Validate the ipid's of our fragments - nuke those that don't
2157c478bd9Sstevel@tonic-gate * match the id of the first fragment or don't match the IP
2167c478bd9Sstevel@tonic-gate * protocol of the first fragment.
2177c478bd9Sstevel@tonic-gate */
2187c478bd9Sstevel@tonic-gate ip_id = fragment[first_frag].ipid;
2197c478bd9Sstevel@tonic-gate ipp = fragment[first_frag].ipp;
2207c478bd9Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) {
2217c478bd9Sstevel@tonic-gate if (fragment[i].mp != NULL && ip_id != fragment[i].ipid &&
222*a963a5aaSToomas Soome fragment[i].ipp != ipp) {
2237c478bd9Sstevel@tonic-gate #ifdef FRAG_DEBUG
2247c478bd9Sstevel@tonic-gate printf("ipv4: Frag id mismatch: %x != %x\n",
2257c478bd9Sstevel@tonic-gate fragment[i].ipid, ip_id);
2267c478bd9Sstevel@tonic-gate #endif /* FRAG_DEBUG */
2277c478bd9Sstevel@tonic-gate frag_free(i);
2287c478bd9Sstevel@tonic-gate }
2297c478bd9Sstevel@tonic-gate }
2307c478bd9Sstevel@tonic-gate
2317c478bd9Sstevel@tonic-gate if (frag_last() < 0)
2327c478bd9Sstevel@tonic-gate return (FALSE);
2337c478bd9Sstevel@tonic-gate
2347c478bd9Sstevel@tonic-gate total = fragment[last_frag].offset + fragment[last_frag].iplen -
2357c478bd9Sstevel@tonic-gate fragment[last_frag].iphlen;
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate for (i = 0, actual = 0; i < FRAG_MAX; i++)
2387c478bd9Sstevel@tonic-gate actual += (fragment[i].iplen - fragment[i].iphlen);
2397c478bd9Sstevel@tonic-gate
2407c478bd9Sstevel@tonic-gate #ifdef FRAG_DEBUG
2417c478bd9Sstevel@tonic-gate frag_disp(total);
2427c478bd9Sstevel@tonic-gate #endif /* FRAG_DEBUG */
2437c478bd9Sstevel@tonic-gate
2447c478bd9Sstevel@tonic-gate return (total == actual);
2457c478bd9Sstevel@tonic-gate }
2467c478bd9Sstevel@tonic-gate
2477c478bd9Sstevel@tonic-gate /*
2487c478bd9Sstevel@tonic-gate * Load the assembled fragments into igp. Returns 0 for success, nonzero
2497c478bd9Sstevel@tonic-gate * otherwise.
2507c478bd9Sstevel@tonic-gate */
2517c478bd9Sstevel@tonic-gate static int
frag_load(struct inetgram * igp)2527c478bd9Sstevel@tonic-gate frag_load(struct inetgram *igp)
2537c478bd9Sstevel@tonic-gate {
2547c478bd9Sstevel@tonic-gate int i;
2557c478bd9Sstevel@tonic-gate int16_t len;
2567c478bd9Sstevel@tonic-gate uint_t total_len;
2577c478bd9Sstevel@tonic-gate boolean_t first_frag = B_FALSE;
2587c478bd9Sstevel@tonic-gate mblk_t *mp;
2597c478bd9Sstevel@tonic-gate struct ip *iph;
2607c478bd9Sstevel@tonic-gate int first_iph_len;
2617c478bd9Sstevel@tonic-gate
2627c478bd9Sstevel@tonic-gate if (fragments == 0)
2637c478bd9Sstevel@tonic-gate return (ENOENT);
2647c478bd9Sstevel@tonic-gate
2657c478bd9Sstevel@tonic-gate mp = igp->igm_mp;
2667c478bd9Sstevel@tonic-gate /* Get the IP header length of the first fragment. */
2677c478bd9Sstevel@tonic-gate i = frag_first();
2687c478bd9Sstevel@tonic-gate assert(i >= 0);
2697c478bd9Sstevel@tonic-gate first_iph_len = fragment[i].iphlen;
2707c478bd9Sstevel@tonic-gate for (i = 0, len = 0, total_len = 0; i < FRAG_MAX; i++) {
2717c478bd9Sstevel@tonic-gate if (fragment[i].mp != NULL) {
2727c478bd9Sstevel@tonic-gate /*
2737c478bd9Sstevel@tonic-gate * Copy just the data (omit the ip header of all
2747c478bd9Sstevel@tonic-gate * fragments except the first one which contains
2757c478bd9Sstevel@tonic-gate * all the info...)
2767c478bd9Sstevel@tonic-gate */
2777c478bd9Sstevel@tonic-gate if (fragment[i].offset == 0) {
2787c478bd9Sstevel@tonic-gate len = fragment[i].iplen;
2797c478bd9Sstevel@tonic-gate first_frag = B_TRUE;
2807c478bd9Sstevel@tonic-gate } else {
2817c478bd9Sstevel@tonic-gate len = fragment[i].iplen - fragment[i].iphlen;
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate total_len += len;
2847c478bd9Sstevel@tonic-gate if (total_len > mp->b_size)
2857c478bd9Sstevel@tonic-gate return (E2BIG);
2867c478bd9Sstevel@tonic-gate if (first_frag) {
2877c478bd9Sstevel@tonic-gate bcopy((caddr_t)(fragment[i].mp->b_rptr),
2887c478bd9Sstevel@tonic-gate (caddr_t)mp->b_rptr, len);
2897c478bd9Sstevel@tonic-gate first_frag = B_FALSE;
2907c478bd9Sstevel@tonic-gate } else {
2917c478bd9Sstevel@tonic-gate bcopy((caddr_t)(fragment[i].mp->b_rptr +
2927c478bd9Sstevel@tonic-gate fragment[i].iphlen),
2937c478bd9Sstevel@tonic-gate (caddr_t)(mp->b_rptr + first_iph_len +
2947c478bd9Sstevel@tonic-gate fragment[i].offset), len);
2957c478bd9Sstevel@tonic-gate }
2967c478bd9Sstevel@tonic-gate mp->b_wptr += len;
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate }
2997c478bd9Sstevel@tonic-gate /* Fix the total length in the IP header. */
3007c478bd9Sstevel@tonic-gate iph = (struct ip *)mp->b_rptr;
3017c478bd9Sstevel@tonic-gate iph->ip_len = htons(total_len);
3027c478bd9Sstevel@tonic-gate return (0);
3037c478bd9Sstevel@tonic-gate }
3047c478bd9Sstevel@tonic-gate
3057c478bd9Sstevel@tonic-gate /*
3067c478bd9Sstevel@tonic-gate * Locate a routing table entry based upon arguments. IP addresses expected
3077c478bd9Sstevel@tonic-gate * in network order. Returns index for success, -1 if entry not found.
3087c478bd9Sstevel@tonic-gate */
3097c478bd9Sstevel@tonic-gate static int
find_route(uint8_t * flagp,struct in_addr * destp,struct in_addr * gatewayp)3107c478bd9Sstevel@tonic-gate find_route(uint8_t *flagp, struct in_addr *destp, struct in_addr *gatewayp)
3117c478bd9Sstevel@tonic-gate {
3127c478bd9Sstevel@tonic-gate int i, table_entry = -1;
3137c478bd9Sstevel@tonic-gate
3147c478bd9Sstevel@tonic-gate for (i = 0; table_entry == -1 && i < IPV4_ROUTE_TABLE_SIZE; i++) {
3157c478bd9Sstevel@tonic-gate if (flagp != NULL) {
3167c478bd9Sstevel@tonic-gate if (*flagp & table[i].flag)
3177c478bd9Sstevel@tonic-gate table_entry = i;
3187c478bd9Sstevel@tonic-gate }
3197c478bd9Sstevel@tonic-gate if (destp != NULL) {
3207c478bd9Sstevel@tonic-gate if (destp->s_addr == table[i].dest.s_addr)
3217c478bd9Sstevel@tonic-gate table_entry = i;
3227c478bd9Sstevel@tonic-gate else
3237c478bd9Sstevel@tonic-gate table_entry = -1;
3247c478bd9Sstevel@tonic-gate }
3257c478bd9Sstevel@tonic-gate if (gatewayp != NULL) {
3267c478bd9Sstevel@tonic-gate if (gatewayp->s_addr == table[i].gateway.s_addr)
3277c478bd9Sstevel@tonic-gate table_entry = i;
3287c478bd9Sstevel@tonic-gate else
3297c478bd9Sstevel@tonic-gate table_entry = -1;
3307c478bd9Sstevel@tonic-gate }
3317c478bd9Sstevel@tonic-gate }
3327c478bd9Sstevel@tonic-gate return (table_entry);
3337c478bd9Sstevel@tonic-gate }
3347c478bd9Sstevel@tonic-gate
3357c478bd9Sstevel@tonic-gate /*
3367c478bd9Sstevel@tonic-gate * ADD or DEL a routing table entry. Returns 0 for success, -1 and errno
3377c478bd9Sstevel@tonic-gate * otherwise. IP addresses are expected in network order.
3387c478bd9Sstevel@tonic-gate */
3397c478bd9Sstevel@tonic-gate int
ipv4_route(int cmd,uint8_t flag,struct in_addr * destp,struct in_addr * gatewayp)3407c478bd9Sstevel@tonic-gate ipv4_route(int cmd, uint8_t flag, struct in_addr *destp,
3417c478bd9Sstevel@tonic-gate struct in_addr *gatewayp)
3427c478bd9Sstevel@tonic-gate {
3437c478bd9Sstevel@tonic-gate static int routing_table_initialized;
3447c478bd9Sstevel@tonic-gate int index;
345*a963a5aaSToomas Soome uint8_t tmp_flag;
3467c478bd9Sstevel@tonic-gate
3477c478bd9Sstevel@tonic-gate if (gatewayp == NULL) {
3487c478bd9Sstevel@tonic-gate errno = EINVAL;
3497c478bd9Sstevel@tonic-gate return (-1);
3507c478bd9Sstevel@tonic-gate }
3517c478bd9Sstevel@tonic-gate
3527c478bd9Sstevel@tonic-gate /* initialize routing table */
3537c478bd9Sstevel@tonic-gate if (routing_table_initialized == 0) {
3547c478bd9Sstevel@tonic-gate for (index = 0; index < IPV4_ROUTE_TABLE_SIZE; index++)
3557c478bd9Sstevel@tonic-gate table[index].flag = RT_UNUSED;
3567c478bd9Sstevel@tonic-gate routing_table_initialized = 1;
3577c478bd9Sstevel@tonic-gate }
3587c478bd9Sstevel@tonic-gate
3597c478bd9Sstevel@tonic-gate switch (cmd) {
3607c478bd9Sstevel@tonic-gate case IPV4_ADD_ROUTE:
3617c478bd9Sstevel@tonic-gate tmp_flag = (uint8_t)RT_UNUSED;
3627c478bd9Sstevel@tonic-gate if ((index = find_route(&tmp_flag, NULL, NULL)) == -1) {
3637c478bd9Sstevel@tonic-gate dprintf("ipv4_route: routing table full.\n");
3647c478bd9Sstevel@tonic-gate errno = ENOSPC;
3657c478bd9Sstevel@tonic-gate return (-1);
3667c478bd9Sstevel@tonic-gate }
3677c478bd9Sstevel@tonic-gate table[index].flag = flag;
3687c478bd9Sstevel@tonic-gate if (destp != NULL)
3697c478bd9Sstevel@tonic-gate table[index].dest.s_addr = destp->s_addr;
3707c478bd9Sstevel@tonic-gate else
3717c478bd9Sstevel@tonic-gate table[index].dest.s_addr = htonl(INADDR_ANY);
3727c478bd9Sstevel@tonic-gate table[index].gateway.s_addr = gatewayp->s_addr;
3737c478bd9Sstevel@tonic-gate break;
3747c478bd9Sstevel@tonic-gate case IPV4_BAD_ROUTE:
3757c478bd9Sstevel@tonic-gate /* FALLTHRU */
3767c478bd9Sstevel@tonic-gate case IPV4_DEL_ROUTE:
3777c478bd9Sstevel@tonic-gate if ((index = find_route(&flag, destp, gatewayp)) == -1) {
3787c478bd9Sstevel@tonic-gate dprintf("ipv4_route: No such routing entry.\n");
3797c478bd9Sstevel@tonic-gate errno = ENOENT;
3807c478bd9Sstevel@tonic-gate return (-1);
3817c478bd9Sstevel@tonic-gate }
3827c478bd9Sstevel@tonic-gate if (cmd == IPV4_DEL_ROUTE) {
3837c478bd9Sstevel@tonic-gate table[index].flag = RT_UNUSED;
3847c478bd9Sstevel@tonic-gate table[index].dest.s_addr = htonl(INADDR_ANY);
3857c478bd9Sstevel@tonic-gate table[index].gateway.s_addr = htonl(INADDR_ANY);
386*a963a5aaSToomas Soome } else {
3877c478bd9Sstevel@tonic-gate table[index].flag = RT_NG;
388*a963a5aaSToomas Soome }
389*a963a5aaSToomas Soome break;
3907c478bd9Sstevel@tonic-gate default:
3917c478bd9Sstevel@tonic-gate errno = EINVAL;
3927c478bd9Sstevel@tonic-gate return (-1);
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate return (0);
3957c478bd9Sstevel@tonic-gate }
3967c478bd9Sstevel@tonic-gate
3977c478bd9Sstevel@tonic-gate /*
3987c478bd9Sstevel@tonic-gate * Return gateway to destination. Returns gateway IP address in network order
3997c478bd9Sstevel@tonic-gate * for success, NULL if no route to destination exists.
4007c478bd9Sstevel@tonic-gate */
4017c478bd9Sstevel@tonic-gate struct in_addr *
ipv4_get_route(uint8_t flag,struct in_addr * destp,struct in_addr * gatewayp)4027c478bd9Sstevel@tonic-gate ipv4_get_route(uint8_t flag, struct in_addr *destp, struct in_addr *gatewayp)
4037c478bd9Sstevel@tonic-gate {
4047c478bd9Sstevel@tonic-gate int index;
4057c478bd9Sstevel@tonic-gate if ((index = find_route(&flag, destp, gatewayp)) == -1)
4067c478bd9Sstevel@tonic-gate return (NULL);
4077c478bd9Sstevel@tonic-gate return (&table[index].gateway);
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate
4107c478bd9Sstevel@tonic-gate /*
4117c478bd9Sstevel@tonic-gate * Initialize the IPv4 generic parts of the socket, as well as the routing
4127c478bd9Sstevel@tonic-gate * table.
4137c478bd9Sstevel@tonic-gate */
4147c478bd9Sstevel@tonic-gate void
ipv4_socket_init(struct inetboot_socket * isp)4157c478bd9Sstevel@tonic-gate ipv4_socket_init(struct inetboot_socket *isp)
4167c478bd9Sstevel@tonic-gate {
4177c478bd9Sstevel@tonic-gate isp->input[NETWORK_LVL] = ipv4_input;
4187c478bd9Sstevel@tonic-gate isp->output[NETWORK_LVL] = ipv4_output;
4197c478bd9Sstevel@tonic-gate isp->close[NETWORK_LVL] = NULL;
4207c478bd9Sstevel@tonic-gate isp->headerlen[NETWORK_LVL] = ipv4_header_len;
4217c478bd9Sstevel@tonic-gate }
4227c478bd9Sstevel@tonic-gate
4237c478bd9Sstevel@tonic-gate /*
4247c478bd9Sstevel@tonic-gate * Initialize a raw ipv4 socket.
4257c478bd9Sstevel@tonic-gate */
4267c478bd9Sstevel@tonic-gate void
ipv4_raw_socket(struct inetboot_socket * isp,uint8_t proto)4277c478bd9Sstevel@tonic-gate ipv4_raw_socket(struct inetboot_socket *isp, uint8_t proto)
4287c478bd9Sstevel@tonic-gate {
4297c478bd9Sstevel@tonic-gate isp->type = INETBOOT_RAW;
4307c478bd9Sstevel@tonic-gate if (proto == 0)
4317c478bd9Sstevel@tonic-gate isp->proto = IPPROTO_IP;
4327c478bd9Sstevel@tonic-gate else
4337c478bd9Sstevel@tonic-gate isp->proto = proto;
4347c478bd9Sstevel@tonic-gate isp->input[TRANSPORT_LVL] = NULL;
4357c478bd9Sstevel@tonic-gate isp->output[TRANSPORT_LVL] = NULL;
4367c478bd9Sstevel@tonic-gate isp->headerlen[TRANSPORT_LVL] = NULL;
4377c478bd9Sstevel@tonic-gate isp->ports = NULL;
4387c478bd9Sstevel@tonic-gate }
4397c478bd9Sstevel@tonic-gate
4407c478bd9Sstevel@tonic-gate /*
4417c478bd9Sstevel@tonic-gate * Return the size of an IPv4 header (no options)
4427c478bd9Sstevel@tonic-gate */
4437c478bd9Sstevel@tonic-gate /* ARGSUSED */
4447c478bd9Sstevel@tonic-gate int
ipv4_header_len(struct inetgram * igm)4457c478bd9Sstevel@tonic-gate ipv4_header_len(struct inetgram *igm)
4467c478bd9Sstevel@tonic-gate {
4477c478bd9Sstevel@tonic-gate return (sizeof (struct ip));
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate
4507c478bd9Sstevel@tonic-gate /*
4517c478bd9Sstevel@tonic-gate * Set our source address.
4527c478bd9Sstevel@tonic-gate * Argument is assumed to be host order.
4537c478bd9Sstevel@tonic-gate */
4547c478bd9Sstevel@tonic-gate void
ipv4_setipaddr(struct in_addr * ip)4557c478bd9Sstevel@tonic-gate ipv4_setipaddr(struct in_addr *ip)
4567c478bd9Sstevel@tonic-gate {
4577c478bd9Sstevel@tonic-gate myip.s_addr = htonl(ip->s_addr);
4587c478bd9Sstevel@tonic-gate }
4597c478bd9Sstevel@tonic-gate
4607c478bd9Sstevel@tonic-gate /*
4617c478bd9Sstevel@tonic-gate * Returns our current source address in host order.
4627c478bd9Sstevel@tonic-gate */
4637c478bd9Sstevel@tonic-gate void
ipv4_getipaddr(struct in_addr * ip)4647c478bd9Sstevel@tonic-gate ipv4_getipaddr(struct in_addr *ip)
4657c478bd9Sstevel@tonic-gate {
4667c478bd9Sstevel@tonic-gate ip->s_addr = ntohl(myip.s_addr);
4677c478bd9Sstevel@tonic-gate }
4687c478bd9Sstevel@tonic-gate
4697c478bd9Sstevel@tonic-gate /*
4707c478bd9Sstevel@tonic-gate * Set our netmask.
4717c478bd9Sstevel@tonic-gate * Argument is assumed to be host order.
4727c478bd9Sstevel@tonic-gate */
4737c478bd9Sstevel@tonic-gate void
ipv4_setnetmask(struct in_addr * ip)4747c478bd9Sstevel@tonic-gate ipv4_setnetmask(struct in_addr *ip)
4757c478bd9Sstevel@tonic-gate {
4767c478bd9Sstevel@tonic-gate netmask_set = B_TRUE;
4777c478bd9Sstevel@tonic-gate netmask.s_addr = htonl(ip->s_addr);
4787c478bd9Sstevel@tonic-gate mynet.s_addr = netmask.s_addr & myip.s_addr; /* implicit */
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate
4817c478bd9Sstevel@tonic-gate void
ipv4_getnetid(struct in_addr * my_netid)4827c478bd9Sstevel@tonic-gate ipv4_getnetid(struct in_addr *my_netid)
4837c478bd9Sstevel@tonic-gate {
4847c478bd9Sstevel@tonic-gate struct in_addr my_netmask;
4857c478bd9Sstevel@tonic-gate if (mynet.s_addr != 0)
4867c478bd9Sstevel@tonic-gate my_netid->s_addr = ntohl(mynet.s_addr);
4877c478bd9Sstevel@tonic-gate else {
4887c478bd9Sstevel@tonic-gate ipv4_getnetmask(&my_netmask);
4897c478bd9Sstevel@tonic-gate my_netid->s_addr = my_netmask.s_addr & ntohl(myip.s_addr);
4907c478bd9Sstevel@tonic-gate }
4917c478bd9Sstevel@tonic-gate }
4927c478bd9Sstevel@tonic-gate
4937c478bd9Sstevel@tonic-gate /*
4947c478bd9Sstevel@tonic-gate * Returns our current netmask in host order.
4957c478bd9Sstevel@tonic-gate * Neither OBP nor the standalone DHCP client mandate
4967c478bd9Sstevel@tonic-gate * that the netmask be specified, so in the absence of
4977c478bd9Sstevel@tonic-gate * a netmask, we attempt to derive it using class-based
4987c478bd9Sstevel@tonic-gate * heuristics.
4997c478bd9Sstevel@tonic-gate */
5007c478bd9Sstevel@tonic-gate void
ipv4_getnetmask(struct in_addr * ip)5017c478bd9Sstevel@tonic-gate ipv4_getnetmask(struct in_addr *ip)
5027c478bd9Sstevel@tonic-gate {
5037c478bd9Sstevel@tonic-gate if (netmask_set || (myip.s_addr == 0))
5047c478bd9Sstevel@tonic-gate ip->s_addr = ntohl(netmask.s_addr);
5057c478bd9Sstevel@tonic-gate else {
5067c478bd9Sstevel@tonic-gate /* base the netmask on our IP address */
5077c478bd9Sstevel@tonic-gate if (IN_CLASSA(ntohl(myip.s_addr)))
5087c478bd9Sstevel@tonic-gate ip->s_addr = ntohl(IN_CLASSA_NET);
5097c478bd9Sstevel@tonic-gate else if (IN_CLASSB(ntohl(myip.s_addr)))
5107c478bd9Sstevel@tonic-gate ip->s_addr = ntohl(IN_CLASSB_NET);
5112a9459bdSsangeeta else if (IN_CLASSC(ntohl(myip.s_addr)))
5127c478bd9Sstevel@tonic-gate ip->s_addr = ntohl(IN_CLASSC_NET);
5132a9459bdSsangeeta else
5142a9459bdSsangeeta ip->s_addr = ntohl(IN_CLASSE_NET);
5157c478bd9Sstevel@tonic-gate }
5167c478bd9Sstevel@tonic-gate }
5177c478bd9Sstevel@tonic-gate
5187c478bd9Sstevel@tonic-gate /*
5197c478bd9Sstevel@tonic-gate * Set our default router.
5207c478bd9Sstevel@tonic-gate * Argument is assumed to be host order, and *MUST* be on the same network
5217c478bd9Sstevel@tonic-gate * as our source IP address.
5227c478bd9Sstevel@tonic-gate */
5237c478bd9Sstevel@tonic-gate void
ipv4_setdefaultrouter(struct in_addr * ip)5247c478bd9Sstevel@tonic-gate ipv4_setdefaultrouter(struct in_addr *ip)
5257c478bd9Sstevel@tonic-gate {
5267c478bd9Sstevel@tonic-gate defaultrouter.s_addr = htonl(ip->s_addr);
5277c478bd9Sstevel@tonic-gate }
5287c478bd9Sstevel@tonic-gate
5297c478bd9Sstevel@tonic-gate /*
5307c478bd9Sstevel@tonic-gate * Returns our current default router in host order.
5317c478bd9Sstevel@tonic-gate */
5327c478bd9Sstevel@tonic-gate void
ipv4_getdefaultrouter(struct in_addr * ip)5337c478bd9Sstevel@tonic-gate ipv4_getdefaultrouter(struct in_addr *ip)
5347c478bd9Sstevel@tonic-gate {
5357c478bd9Sstevel@tonic-gate ip->s_addr = ntohl(defaultrouter.s_addr);
5367c478bd9Sstevel@tonic-gate }
5377c478bd9Sstevel@tonic-gate
5387c478bd9Sstevel@tonic-gate /*
5397c478bd9Sstevel@tonic-gate * Toggle promiscuous flag. If set, client disregards destination IP
5407c478bd9Sstevel@tonic-gate * address. Otherwise, only limited broadcast, network broadcast, and
5417c478bd9Sstevel@tonic-gate * unicast traffic get through. Returns previous setting.
5427c478bd9Sstevel@tonic-gate */
5437c478bd9Sstevel@tonic-gate int
ipv4_setpromiscuous(int toggle)5447c478bd9Sstevel@tonic-gate ipv4_setpromiscuous(int toggle)
5457c478bd9Sstevel@tonic-gate {
5467c478bd9Sstevel@tonic-gate int old = promiscuous;
5477c478bd9Sstevel@tonic-gate
5487c478bd9Sstevel@tonic-gate promiscuous = toggle;
5497c478bd9Sstevel@tonic-gate
5507c478bd9Sstevel@tonic-gate return (old);
5517c478bd9Sstevel@tonic-gate }
5527c478bd9Sstevel@tonic-gate
5537c478bd9Sstevel@tonic-gate /*
5547c478bd9Sstevel@tonic-gate * Set IP TTL.
5557c478bd9Sstevel@tonic-gate */
5567c478bd9Sstevel@tonic-gate void
ipv4_setmaxttl(uint8_t cttl)5577c478bd9Sstevel@tonic-gate ipv4_setmaxttl(uint8_t cttl)
5587c478bd9Sstevel@tonic-gate {
5597c478bd9Sstevel@tonic-gate ttl = cttl;
5607c478bd9Sstevel@tonic-gate }
5617c478bd9Sstevel@tonic-gate
5627c478bd9Sstevel@tonic-gate /*
5637c478bd9Sstevel@tonic-gate * Convert an ipv4 address to dotted notation.
5647c478bd9Sstevel@tonic-gate * Returns ptr to statically allocated buffer containing dotted string.
5657c478bd9Sstevel@tonic-gate */
5667c478bd9Sstevel@tonic-gate char *
inet_ntoa(struct in_addr ip)5677c478bd9Sstevel@tonic-gate inet_ntoa(struct in_addr ip)
5687c478bd9Sstevel@tonic-gate {
5697c478bd9Sstevel@tonic-gate uint8_t *p;
5707c478bd9Sstevel@tonic-gate static char ipaddr[16];
5717c478bd9Sstevel@tonic-gate
5727c478bd9Sstevel@tonic-gate p = (uint8_t *)&ip.s_addr;
5737c478bd9Sstevel@tonic-gate (void) sprintf(ipaddr, "%u.%u.%u.%u", p[0], p[1], p[2], p[3]);
5747c478bd9Sstevel@tonic-gate return (ipaddr);
5757c478bd9Sstevel@tonic-gate }
5767c478bd9Sstevel@tonic-gate
5777c478bd9Sstevel@tonic-gate /*
5787c478bd9Sstevel@tonic-gate * Construct a transport datagram from a series of IP fragments (igp == NULL)
5797c478bd9Sstevel@tonic-gate * or from a single IP datagram (igp != NULL). Return the address of the
5807c478bd9Sstevel@tonic-gate * contructed transport datagram.
5817c478bd9Sstevel@tonic-gate */
5827c478bd9Sstevel@tonic-gate struct inetgram *
make_trans_datagram(int index,struct inetgram * igp,struct in_addr ipsrc,struct in_addr ipdst,uint16_t iphlen)5837c478bd9Sstevel@tonic-gate make_trans_datagram(int index, struct inetgram *igp, struct in_addr ipsrc,
5847c478bd9Sstevel@tonic-gate struct in_addr ipdst, uint16_t iphlen)
5857c478bd9Sstevel@tonic-gate {
5867c478bd9Sstevel@tonic-gate uint16_t trans_len, *transp, new_len;
5877c478bd9Sstevel@tonic-gate int first_frag, last_frag;
5887c478bd9Sstevel@tonic-gate boolean_t fragmented;
5897c478bd9Sstevel@tonic-gate struct inetgram *ngp;
5907c478bd9Sstevel@tonic-gate struct ip *iph;
5917c478bd9Sstevel@tonic-gate
5927c478bd9Sstevel@tonic-gate fragmented = (igp == NULL);
5937c478bd9Sstevel@tonic-gate
5947c478bd9Sstevel@tonic-gate ngp = (struct inetgram *)bkmem_zalloc(sizeof (struct inetgram));
5957c478bd9Sstevel@tonic-gate if (ngp == NULL) {
5967c478bd9Sstevel@tonic-gate errno = ENOMEM;
5977c478bd9Sstevel@tonic-gate if (fragmented)
5987c478bd9Sstevel@tonic-gate frag_flush();
5997c478bd9Sstevel@tonic-gate return (NULL);
6007c478bd9Sstevel@tonic-gate }
6017c478bd9Sstevel@tonic-gate
6027c478bd9Sstevel@tonic-gate if (fragmented) {
6037c478bd9Sstevel@tonic-gate last_frag = frag_last();
6047c478bd9Sstevel@tonic-gate trans_len = fragment[last_frag].offset +
6057c478bd9Sstevel@tonic-gate fragment[last_frag].iplen - fragment[last_frag].iphlen;
6067c478bd9Sstevel@tonic-gate first_frag = frag_first();
6077c478bd9Sstevel@tonic-gate /*
6087c478bd9Sstevel@tonic-gate * The returned buffer contains the IP header of the
6097c478bd9Sstevel@tonic-gate * first fragment.
6107c478bd9Sstevel@tonic-gate */
6117c478bd9Sstevel@tonic-gate trans_len += fragment[first_frag].iphlen;
6127c478bd9Sstevel@tonic-gate transp = (uint16_t *)(fragment[first_frag].mp->b_rptr +
6137c478bd9Sstevel@tonic-gate fragment[first_frag].iphlen);
6147c478bd9Sstevel@tonic-gate } else {
6157c478bd9Sstevel@tonic-gate /*
6167c478bd9Sstevel@tonic-gate * Note that igm_len may not be the real length of an
6177c478bd9Sstevel@tonic-gate * IP packet because some network interface, such as
6187c478bd9Sstevel@tonic-gate * Ethernet, as a minimum frame size. So we should not
6197c478bd9Sstevel@tonic-gate * use the interface frame size to determine the
6207c478bd9Sstevel@tonic-gate * length of an IP packet. We should use the IP
6217c478bd9Sstevel@tonic-gate * length field in the IP header.
6227c478bd9Sstevel@tonic-gate */
6237c478bd9Sstevel@tonic-gate iph = (struct ip *)igp->igm_mp->b_rptr;
6247c478bd9Sstevel@tonic-gate trans_len = ntohs(iph->ip_len);
6257c478bd9Sstevel@tonic-gate transp = (uint16_t *)(igp->igm_mp->b_rptr + iphlen);
6267c478bd9Sstevel@tonic-gate }
6277c478bd9Sstevel@tonic-gate
6287c478bd9Sstevel@tonic-gate ngp->igm_saddr.sin_addr.s_addr = ipsrc.s_addr;
6297c478bd9Sstevel@tonic-gate ngp->igm_saddr.sin_port = sockets[index].ports(transp, SOURCE);
6307c478bd9Sstevel@tonic-gate ngp->igm_target.s_addr = ipdst.s_addr;
6317c478bd9Sstevel@tonic-gate ngp->igm_level = TRANSPORT_LVL;
6327c478bd9Sstevel@tonic-gate
6337c478bd9Sstevel@tonic-gate /*
6347c478bd9Sstevel@tonic-gate * Align to 16bit value. Checksum code may require an extra byte
6357c478bd9Sstevel@tonic-gate * for padding.
6367c478bd9Sstevel@tonic-gate */
6377c478bd9Sstevel@tonic-gate new_len = ((trans_len + sizeof (int16_t) - 1) &
6387c478bd9Sstevel@tonic-gate ~(sizeof (int16_t) - 1));
6397c478bd9Sstevel@tonic-gate if ((ngp->igm_mp = allocb(new_len, 0)) == NULL) {
6407c478bd9Sstevel@tonic-gate errno = ENOMEM;
6417c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)ngp, sizeof (struct inetgram));
6427c478bd9Sstevel@tonic-gate if (fragmented)
6437c478bd9Sstevel@tonic-gate frag_flush();
6447c478bd9Sstevel@tonic-gate return (NULL);
6457c478bd9Sstevel@tonic-gate }
6467c478bd9Sstevel@tonic-gate
6477c478bd9Sstevel@tonic-gate if (fragmented) {
6487c478bd9Sstevel@tonic-gate if (frag_load(ngp) != 0) {
6497c478bd9Sstevel@tonic-gate freeb(ngp->igm_mp);
6507c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)ngp, sizeof (struct inetgram));
6517c478bd9Sstevel@tonic-gate frag_flush();
6527c478bd9Sstevel@tonic-gate return (NULL);
6537c478bd9Sstevel@tonic-gate }
6547c478bd9Sstevel@tonic-gate frag_flush();
6557c478bd9Sstevel@tonic-gate } else {
6567c478bd9Sstevel@tonic-gate bcopy((caddr_t)(igp->igm_mp->b_rptr),
6577c478bd9Sstevel@tonic-gate (caddr_t)ngp->igm_mp->b_rptr, trans_len);
6587c478bd9Sstevel@tonic-gate ngp->igm_mp->b_wptr += trans_len;
6597c478bd9Sstevel@tonic-gate }
6607c478bd9Sstevel@tonic-gate return (ngp);
6617c478bd9Sstevel@tonic-gate }
6627c478bd9Sstevel@tonic-gate
6637c478bd9Sstevel@tonic-gate /*
6647c478bd9Sstevel@tonic-gate * ipv4_input: Pull in IPv4 datagrams addressed to us. Handle IP fragmentation
6657c478bd9Sstevel@tonic-gate * (fragments received in any order) and ICMP at this level.
6667c478bd9Sstevel@tonic-gate *
6677c478bd9Sstevel@tonic-gate * Note that because our network is serviced by polling when we expect
6687c478bd9Sstevel@tonic-gate * something (upon a referenced socket), we don't go through the work of
6697c478bd9Sstevel@tonic-gate * locating the appropriate socket a datagram is destined for. We'll only
6707c478bd9Sstevel@tonic-gate * accept data for the referenced socket. This means we don't have
6717c478bd9Sstevel@tonic-gate * asynchronous networking, but since we can't service the net using an
6727c478bd9Sstevel@tonic-gate * interrupt handler, it doesn't do us any good to try to service datagrams
6737c478bd9Sstevel@tonic-gate * destined for sockets other than the referenced one. Data is handled in
6747c478bd9Sstevel@tonic-gate * a fifo manner.
6757c478bd9Sstevel@tonic-gate *
6767c478bd9Sstevel@tonic-gate * The mac layer will grab all frames for us. If we find we don't have all
6777c478bd9Sstevel@tonic-gate * the necessary fragments to reassemble the datagram, we'll call the mac
6787c478bd9Sstevel@tonic-gate * layer again for FRAG_ATTEMPTS to see if it has any more frames.
6797c478bd9Sstevel@tonic-gate *
6807c478bd9Sstevel@tonic-gate * Supported protocols: IPPROTO_IP, IPPROTO_ICMP, IPPROTO_UDP.
6817c478bd9Sstevel@tonic-gate *
6827c478bd9Sstevel@tonic-gate * Returns: number of NETWORK_LVL datagrams placed on socket , -1 if error
6837c478bd9Sstevel@tonic-gate * occurred.
6847c478bd9Sstevel@tonic-gate *
6857c478bd9Sstevel@tonic-gate * Note: errno is set to ETIMEDOUT if fragment reassembly fails.
6867c478bd9Sstevel@tonic-gate */
6877c478bd9Sstevel@tonic-gate int
ipv4_input(int index)6887c478bd9Sstevel@tonic-gate ipv4_input(int index)
6897c478bd9Sstevel@tonic-gate {
6907c478bd9Sstevel@tonic-gate int datagrams = 0;
6917c478bd9Sstevel@tonic-gate int frag_stat, input_attempts = 0;
6927c478bd9Sstevel@tonic-gate uint16_t iphlen, iplen, ip_id;
6937c478bd9Sstevel@tonic-gate int16_t curr_off;
6947c478bd9Sstevel@tonic-gate struct ip *iphp;
6957c478bd9Sstevel@tonic-gate struct inetgram *igp, *newgp = NULL, *ipv4_listp = NULL;
6967c478bd9Sstevel@tonic-gate struct in_addr ipdst, ipsrc;
6977c478bd9Sstevel@tonic-gate mblk_t *mp;
6987c478bd9Sstevel@tonic-gate enum SockType type;
6997c478bd9Sstevel@tonic-gate
7007c478bd9Sstevel@tonic-gate #ifdef DEBUG
7017c478bd9Sstevel@tonic-gate printf("ipv4_input(%d): start ######################################\n",
7027c478bd9Sstevel@tonic-gate index);
7037c478bd9Sstevel@tonic-gate #endif /* DEBUG */
7047c478bd9Sstevel@tonic-gate
7057c478bd9Sstevel@tonic-gate frag_flush();
7067c478bd9Sstevel@tonic-gate
7077c478bd9Sstevel@tonic-gate ipv4_try_again:
7087c478bd9Sstevel@tonic-gate
7097c478bd9Sstevel@tonic-gate while ((igp = sockets[index].inq) != NULL) {
7107c478bd9Sstevel@tonic-gate if (igp->igm_level != NETWORK_LVL) {
7117c478bd9Sstevel@tonic-gate #ifdef DEBUG
7127c478bd9Sstevel@tonic-gate printf("ipv4_input(%d): unexpected frame type: %d\n",
7137c478bd9Sstevel@tonic-gate index, igp->igm_level);
7147c478bd9Sstevel@tonic-gate #endif /* DEBUG */
7157c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE);
7167c478bd9Sstevel@tonic-gate continue;
7177c478bd9Sstevel@tonic-gate }
7187c478bd9Sstevel@tonic-gate iphp = (struct ip *)igp->igm_mp->b_rptr;
7197c478bd9Sstevel@tonic-gate if (iphp->ip_v != IPVERSION) {
7207c478bd9Sstevel@tonic-gate dprintf("ipv4_input(%d): IPv%d datagram discarded\n",
721*a963a5aaSToomas Soome index, iphp->ip_v);
7227c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE);
7237c478bd9Sstevel@tonic-gate continue;
7247c478bd9Sstevel@tonic-gate }
7257c478bd9Sstevel@tonic-gate iphlen = iphp->ip_hl << 2;
7267c478bd9Sstevel@tonic-gate if (iphlen < sizeof (struct ip)) {
7277c478bd9Sstevel@tonic-gate dprintf("ipv4_input(%d): IP msg too short (%d < %u)\n",
7287c478bd9Sstevel@tonic-gate index, iphlen, (uint_t)sizeof (struct ip));
7297c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE);
7307c478bd9Sstevel@tonic-gate continue;
7317c478bd9Sstevel@tonic-gate }
7327c478bd9Sstevel@tonic-gate iplen = ntohs(iphp->ip_len);
7337c478bd9Sstevel@tonic-gate if (iplen > msgdsize(igp->igm_mp)) {
7347c478bd9Sstevel@tonic-gate dprintf("ipv4_input(%d): IP len/buffer mismatch "
7357c478bd9Sstevel@tonic-gate "(%d > %lu)\n", index, iplen, igp->igm_mp->b_size);
7367c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE);
7377c478bd9Sstevel@tonic-gate continue;
7387c478bd9Sstevel@tonic-gate }
7397c478bd9Sstevel@tonic-gate
7407c478bd9Sstevel@tonic-gate bcopy((caddr_t)&(iphp->ip_dst), (caddr_t)&ipdst,
7417c478bd9Sstevel@tonic-gate sizeof (ipdst));
7427c478bd9Sstevel@tonic-gate bcopy((caddr_t)&(iphp->ip_src), (caddr_t)&ipsrc,
7437c478bd9Sstevel@tonic-gate sizeof (ipsrc));
7447c478bd9Sstevel@tonic-gate
7457c478bd9Sstevel@tonic-gate /* igp->igm_mp->b_datap is guaranteed to be 64 bit aligned] */
7467c478bd9Sstevel@tonic-gate if (ipv4cksum((uint16_t *)iphp, iphlen) != 0) {
7477c478bd9Sstevel@tonic-gate dprintf("ipv4_input(%d): Bad IP header checksum "
7487c478bd9Sstevel@tonic-gate "(to %s)\n", index, inet_ntoa(ipdst));
7497c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE);
7507c478bd9Sstevel@tonic-gate continue;
7517c478bd9Sstevel@tonic-gate }
7527c478bd9Sstevel@tonic-gate
7537c478bd9Sstevel@tonic-gate if (!promiscuous) {
7547c478bd9Sstevel@tonic-gate /* validate destination address */
7557c478bd9Sstevel@tonic-gate if (ipdst.s_addr != htonl(INADDR_BROADCAST) &&
7567c478bd9Sstevel@tonic-gate ipdst.s_addr != (mynet.s_addr | ~netmask.s_addr) &&
7577c478bd9Sstevel@tonic-gate ipdst.s_addr != myip.s_addr) {
7587c478bd9Sstevel@tonic-gate #ifdef DEBUG
7597c478bd9Sstevel@tonic-gate printf("ipv4_input(%d): msg to %s discarded.\n",
7607c478bd9Sstevel@tonic-gate index, inet_ntoa(ipdst));
7617c478bd9Sstevel@tonic-gate #endif /* DEBUG */
7627c478bd9Sstevel@tonic-gate /* not ours */
7637c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE);
7647c478bd9Sstevel@tonic-gate continue;
7657c478bd9Sstevel@tonic-gate }
7667c478bd9Sstevel@tonic-gate }
7677c478bd9Sstevel@tonic-gate
7687c478bd9Sstevel@tonic-gate /* Intercept ICMP first */
7697c478bd9Sstevel@tonic-gate if (!promiscuous && (iphp->ip_p == IPPROTO_ICMP)) {
7707c478bd9Sstevel@tonic-gate icmp4(igp, iphp, iphlen, ipsrc);
7717c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE);
7727c478bd9Sstevel@tonic-gate continue;
7737c478bd9Sstevel@tonic-gate }
7747c478bd9Sstevel@tonic-gate
7757c478bd9Sstevel@tonic-gate #ifdef DEBUG
7767c478bd9Sstevel@tonic-gate printf("ipv4_input(%d): processing ID: 0x%x protocol %d "
7777c478bd9Sstevel@tonic-gate "(0x%x) (0x%x,%d)\n",
7787c478bd9Sstevel@tonic-gate index, ntohs(iphp->ip_id), iphp->ip_p, igp, igp->igm_mp,
7797c478bd9Sstevel@tonic-gate igp->igm_mp->b_size);
7807c478bd9Sstevel@tonic-gate #endif /* DEBUG */
7817c478bd9Sstevel@tonic-gate type = sockets[index].type;
7827c478bd9Sstevel@tonic-gate if (type == INETBOOT_RAW) {
7837c478bd9Sstevel@tonic-gate /* No fragmentation - Just the raw packet. */
7847c478bd9Sstevel@tonic-gate #ifdef DEBUG
7857c478bd9Sstevel@tonic-gate printf("ipv4_input(%d): Raw packet.\n", index);
7867c478bd9Sstevel@tonic-gate #endif /* DEBUG */
7877c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, FALSE);
7887c478bd9Sstevel@tonic-gate add_grams(&ipv4_listp, igp);
7897c478bd9Sstevel@tonic-gate igp->igm_mp->b_rptr += iphlen;
7907c478bd9Sstevel@tonic-gate igp->igm_mp->b_wptr = igp->igm_mp->b_rptr + iplen;
7917c478bd9Sstevel@tonic-gate datagrams++;
7927c478bd9Sstevel@tonic-gate continue;
7937c478bd9Sstevel@tonic-gate }
7947c478bd9Sstevel@tonic-gate
7957c478bd9Sstevel@tonic-gate if ((type == INETBOOT_DGRAM && iphp->ip_p != IPPROTO_UDP) ||
7967c478bd9Sstevel@tonic-gate (type == INETBOOT_STREAM && iphp->ip_p != IPPROTO_TCP)) {
7977c478bd9Sstevel@tonic-gate /* Wrong protocol. */
7987c478bd9Sstevel@tonic-gate dprintf("ipv4_input(%d): unexpected protocol: "
7997c478bd9Sstevel@tonic-gate "%d for socket type %d\n", index, iphp->ip_p, type);
8007c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE);
8017c478bd9Sstevel@tonic-gate continue;
8027c478bd9Sstevel@tonic-gate }
8037c478bd9Sstevel@tonic-gate
8047c478bd9Sstevel@tonic-gate /*
8057c478bd9Sstevel@tonic-gate * The following code is common to both STREAM and DATAGRAM
8067c478bd9Sstevel@tonic-gate * sockets.
8077c478bd9Sstevel@tonic-gate */
8087c478bd9Sstevel@tonic-gate
8097c478bd9Sstevel@tonic-gate /*
8107c478bd9Sstevel@tonic-gate * Once we process the first fragment, we won't have
8117c478bd9Sstevel@tonic-gate * the transport header, so we'll have to match on
8127c478bd9Sstevel@tonic-gate * IP id.
8137c478bd9Sstevel@tonic-gate */
8147c478bd9Sstevel@tonic-gate curr_off = ntohs(iphp->ip_off);
8157c478bd9Sstevel@tonic-gate if ((curr_off & ~(IP_DF | IP_MF)) == 0) {
8167c478bd9Sstevel@tonic-gate uint16_t *transp;
8177c478bd9Sstevel@tonic-gate
8187c478bd9Sstevel@tonic-gate /* Validate transport header. */
8197c478bd9Sstevel@tonic-gate mp = igp->igm_mp;
8207c478bd9Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr - iphlen) <
8217c478bd9Sstevel@tonic-gate sockets[index].headerlen[TRANSPORT_LVL](igp)) {
8227c478bd9Sstevel@tonic-gate dprintf("ipv4_input(%d): datagram 0 "
8237c478bd9Sstevel@tonic-gate "too small to hold transport header "
8247c478bd9Sstevel@tonic-gate "(from %s)\n", index, inet_ntoa(ipsrc));
8257c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE);
8267c478bd9Sstevel@tonic-gate continue;
8277c478bd9Sstevel@tonic-gate }
8287c478bd9Sstevel@tonic-gate
8297c478bd9Sstevel@tonic-gate /*
8307c478bd9Sstevel@tonic-gate * check alignment - transport elements are 16
8317c478bd9Sstevel@tonic-gate * bit aligned..
8327c478bd9Sstevel@tonic-gate */
8337c478bd9Sstevel@tonic-gate transp = (uint16_t *)(mp->b_rptr + iphlen);
8347c478bd9Sstevel@tonic-gate if ((uintptr_t)transp % sizeof (uint16_t)) {
8357c478bd9Sstevel@tonic-gate dprintf("ipv4_input(%d): Transport "
8367c478bd9Sstevel@tonic-gate "header is not 16-bit aligned "
8377c478bd9Sstevel@tonic-gate "(0x%lx, from %s)\n", index, (long)transp,
8387c478bd9Sstevel@tonic-gate inet_ntoa(ipsrc));
8397c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE);
8407c478bd9Sstevel@tonic-gate continue;
8417c478bd9Sstevel@tonic-gate }
8427c478bd9Sstevel@tonic-gate
8437c478bd9Sstevel@tonic-gate if (curr_off & IP_MF) {
8447c478bd9Sstevel@tonic-gate /* fragment 0 of fragmented datagram */
8457c478bd9Sstevel@tonic-gate ip_id = ntohs(iphp->ip_id);
8467c478bd9Sstevel@tonic-gate frag_stat = frag_add(curr_off, igp->igm_mp,
8477c478bd9Sstevel@tonic-gate ip_id, iplen, iphlen, iphp->ip_p);
8487c478bd9Sstevel@tonic-gate if (frag_stat != FRAG_SUCCESS) {
8497c478bd9Sstevel@tonic-gate #ifdef FRAG_DEBUG
8507c478bd9Sstevel@tonic-gate if (frag_stat == FRAG_DUP) {
8517c478bd9Sstevel@tonic-gate printf("ipv4_input"
8527c478bd9Sstevel@tonic-gate "(%d): Frag dup.\n", index);
8537c478bd9Sstevel@tonic-gate } else {
8547c478bd9Sstevel@tonic-gate printf("ipv4_input"
8557c478bd9Sstevel@tonic-gate "(%d): too many "
8567c478bd9Sstevel@tonic-gate "frags\n", index);
8577c478bd9Sstevel@tonic-gate }
8587c478bd9Sstevel@tonic-gate #endif /* FRAG_DEBUG */
8597c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq,
8607c478bd9Sstevel@tonic-gate igp, TRUE);
8617c478bd9Sstevel@tonic-gate continue;
8627c478bd9Sstevel@tonic-gate }
8637c478bd9Sstevel@tonic-gate
8647c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, FALSE);
8657c478bd9Sstevel@tonic-gate /* keep the data, lose the inetgram */
8667c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)igp,
8677c478bd9Sstevel@tonic-gate sizeof (struct inetgram));
8687c478bd9Sstevel@tonic-gate #ifdef FRAG_DEBUG
8697c478bd9Sstevel@tonic-gate printf("ipv4_input(%d): Frag/Off/Id "
8707c478bd9Sstevel@tonic-gate "(%d/%d/%x)\n", index, fragments,
8717c478bd9Sstevel@tonic-gate IPV4_OFFSET(curr_off), ip_id);
8727c478bd9Sstevel@tonic-gate #endif /* FRAG_DEBUG */
8737c478bd9Sstevel@tonic-gate } else {
8747c478bd9Sstevel@tonic-gate /* Single, unfragmented datagram */
8757c478bd9Sstevel@tonic-gate newgp = make_trans_datagram(index, igp,
8767c478bd9Sstevel@tonic-gate ipsrc, ipdst, iphlen);
8777c478bd9Sstevel@tonic-gate if (newgp != NULL) {
8787c478bd9Sstevel@tonic-gate add_grams(&ipv4_listp, newgp);
8797c478bd9Sstevel@tonic-gate datagrams++;
8807c478bd9Sstevel@tonic-gate }
8817c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp,
8827c478bd9Sstevel@tonic-gate TRUE);
8837c478bd9Sstevel@tonic-gate continue;
8847c478bd9Sstevel@tonic-gate }
8857c478bd9Sstevel@tonic-gate } else {
8867c478bd9Sstevel@tonic-gate /* fragments other than 0 */
8877c478bd9Sstevel@tonic-gate frag_stat = frag_add(curr_off, igp->igm_mp,
8887c478bd9Sstevel@tonic-gate ntohs(iphp->ip_id), iplen, iphlen, iphp->ip_p);
8897c478bd9Sstevel@tonic-gate
8907c478bd9Sstevel@tonic-gate if (frag_stat == FRAG_SUCCESS) {
8917c478bd9Sstevel@tonic-gate #ifdef FRAG_DEBUG
8927c478bd9Sstevel@tonic-gate printf("ipv4_input(%d): Frag(%d) "
8937c478bd9Sstevel@tonic-gate "off(%d) id(%x)\n", index,
8947c478bd9Sstevel@tonic-gate fragments, IPV4_OFFSET(curr_off),
8957c478bd9Sstevel@tonic-gate ntohs(iphp->ip_id));
8967c478bd9Sstevel@tonic-gate #endif /* FRAG_DEBUG */
8977c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, FALSE);
8987c478bd9Sstevel@tonic-gate /* keep the data, lose the inetgram */
8997c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)igp,
9007c478bd9Sstevel@tonic-gate sizeof (struct inetgram));
9017c478bd9Sstevel@tonic-gate } else {
9027c478bd9Sstevel@tonic-gate #ifdef FRAG_DEBUG
9037c478bd9Sstevel@tonic-gate if (frag_stat == FRAG_DUP)
9047c478bd9Sstevel@tonic-gate printf("ipv4_input(%d): Frag "
9057c478bd9Sstevel@tonic-gate "dup.\n", index);
9067c478bd9Sstevel@tonic-gate else {
9077c478bd9Sstevel@tonic-gate printf("ipv4_input(%d): too "
9087c478bd9Sstevel@tonic-gate "many frags\n", index);
9097c478bd9Sstevel@tonic-gate }
9107c478bd9Sstevel@tonic-gate #endif /* FRAG_DEBUG */
9117c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE);
9127c478bd9Sstevel@tonic-gate continue;
9137c478bd9Sstevel@tonic-gate }
9147c478bd9Sstevel@tonic-gate }
9157c478bd9Sstevel@tonic-gate
9167c478bd9Sstevel@tonic-gate /*
9177c478bd9Sstevel@tonic-gate * Determine if we have all of the fragments.
9187c478bd9Sstevel@tonic-gate *
9197c478bd9Sstevel@tonic-gate * NOTE: at this point, we've placed the data in the
9207c478bd9Sstevel@tonic-gate * fragment table, and the inetgram (igp) has been
9217c478bd9Sstevel@tonic-gate * deleted.
9227c478bd9Sstevel@tonic-gate */
9237c478bd9Sstevel@tonic-gate if (!frag_chk())
9247c478bd9Sstevel@tonic-gate continue;
9257c478bd9Sstevel@tonic-gate
9267c478bd9Sstevel@tonic-gate newgp = make_trans_datagram(index, NULL, ipsrc, ipdst, iphlen);
9277c478bd9Sstevel@tonic-gate if (newgp == NULL)
9287c478bd9Sstevel@tonic-gate continue;
9297c478bd9Sstevel@tonic-gate add_grams(&ipv4_listp, newgp);
9307c478bd9Sstevel@tonic-gate datagrams++;
9317c478bd9Sstevel@tonic-gate }
9327c478bd9Sstevel@tonic-gate if (ipv4_listp == NULL && fragments != 0) {
9337c478bd9Sstevel@tonic-gate if (++input_attempts > FRAG_ATTEMPTS) {
9347c478bd9Sstevel@tonic-gate dprintf("ipv4_input(%d): reassembly(%d) timed out in "
9357c478bd9Sstevel@tonic-gate "%d msecs.\n", index, fragments,
9367c478bd9Sstevel@tonic-gate sockets[index].in_timeout * input_attempts);
9377c478bd9Sstevel@tonic-gate frag_flush();
9387c478bd9Sstevel@tonic-gate errno = ETIMEDOUT;
9397c478bd9Sstevel@tonic-gate return (-1);
9407c478bd9Sstevel@tonic-gate } else {
9417c478bd9Sstevel@tonic-gate /*
9427c478bd9Sstevel@tonic-gate * Call the media layer again... there may be more
9437c478bd9Sstevel@tonic-gate * packets waiting.
9447c478bd9Sstevel@tonic-gate */
9457c478bd9Sstevel@tonic-gate if (sockets[index].input[MEDIA_LVL](index) < 0) {
9467c478bd9Sstevel@tonic-gate /* errno will be set appropriately */
9477c478bd9Sstevel@tonic-gate frag_flush();
9487c478bd9Sstevel@tonic-gate return (-1);
9497c478bd9Sstevel@tonic-gate }
9507c478bd9Sstevel@tonic-gate goto ipv4_try_again;
9517c478bd9Sstevel@tonic-gate }
9527c478bd9Sstevel@tonic-gate }
9537c478bd9Sstevel@tonic-gate
9547c478bd9Sstevel@tonic-gate add_grams(&sockets[index].inq, ipv4_listp);
9557c478bd9Sstevel@tonic-gate
9567c478bd9Sstevel@tonic-gate return (datagrams);
9577c478bd9Sstevel@tonic-gate }
9587c478bd9Sstevel@tonic-gate
9597c478bd9Sstevel@tonic-gate /*
9607c478bd9Sstevel@tonic-gate * ipv4_output: Generate IPv4 datagram(s) for the payload and deliver them.
9617c478bd9Sstevel@tonic-gate * Routing is handled here as well, by reusing the saddr field to hold the
9627c478bd9Sstevel@tonic-gate * router's IP address.
9637c478bd9Sstevel@tonic-gate *
9647c478bd9Sstevel@tonic-gate * We don't deal with fragmentation on the outgoing side.
9657c478bd9Sstevel@tonic-gate *
9667c478bd9Sstevel@tonic-gate * Arguments: index to socket, inetgram to send.
9677c478bd9Sstevel@tonic-gate *
9687c478bd9Sstevel@tonic-gate * Returns: 0 for success, -1 if error occurred.
9697c478bd9Sstevel@tonic-gate */
9707c478bd9Sstevel@tonic-gate int
ipv4_output(int index,struct inetgram * ogp)9717c478bd9Sstevel@tonic-gate ipv4_output(int index, struct inetgram *ogp)
9727c478bd9Sstevel@tonic-gate {
9737c478bd9Sstevel@tonic-gate struct ip *iphp;
9747c478bd9Sstevel@tonic-gate uint64_t iphbuffer[sizeof (struct ip)];
9757c478bd9Sstevel@tonic-gate
9767c478bd9Sstevel@tonic-gate #ifdef DEBUG
9777c478bd9Sstevel@tonic-gate printf("ipv4_output(%d): size %d\n", index,
9787c478bd9Sstevel@tonic-gate ogp->igm_mp->b_wptr - ogp->igm_mp->b_rptr);
9797c478bd9Sstevel@tonic-gate #endif /* DEBUG */
9807c478bd9Sstevel@tonic-gate
9817c478bd9Sstevel@tonic-gate /* we don't deal (yet) with fragmentation. Maybe never will */
9827c478bd9Sstevel@tonic-gate if ((ogp->igm_mp->b_wptr - ogp->igm_mp->b_rptr) > mac_get_mtu()) {
9837c478bd9Sstevel@tonic-gate dprintf("ipv4: datagram too big for MAC layer.\n");
9847c478bd9Sstevel@tonic-gate errno = E2BIG;
9857c478bd9Sstevel@tonic-gate return (-1);
9867c478bd9Sstevel@tonic-gate }
9877c478bd9Sstevel@tonic-gate
9887c478bd9Sstevel@tonic-gate if (ogp->igm_level != NETWORK_LVL) {
9897c478bd9Sstevel@tonic-gate #ifdef DEBUG
9907c478bd9Sstevel@tonic-gate printf("ipv4_output(%d): unexpected frame type: %d\n", index,
9917c478bd9Sstevel@tonic-gate ogp->igm_level);
9927c478bd9Sstevel@tonic-gate #endif /* DEBUG */
9937c478bd9Sstevel@tonic-gate errno = EINVAL;
9947c478bd9Sstevel@tonic-gate return (-1);
9957c478bd9Sstevel@tonic-gate }
9967c478bd9Sstevel@tonic-gate
9977c478bd9Sstevel@tonic-gate if (sockets[index].out_flags & SO_DONTROUTE)
9987c478bd9Sstevel@tonic-gate ogp->igm_oflags |= MSG_DONTROUTE;
9997c478bd9Sstevel@tonic-gate
10007c478bd9Sstevel@tonic-gate iphp = (struct ip *)&iphbuffer;
10017c478bd9Sstevel@tonic-gate iphp->ip_v = IPVERSION;
10027c478bd9Sstevel@tonic-gate iphp->ip_hl = sizeof (struct ip) / 4;
10037c478bd9Sstevel@tonic-gate iphp->ip_tos = 0;
10047c478bd9Sstevel@tonic-gate iphp->ip_len = htons(ogp->igm_mp->b_wptr - ogp->igm_mp->b_rptr +
10057c478bd9Sstevel@tonic-gate sizeof (struct ip));
10067c478bd9Sstevel@tonic-gate iphp->ip_id = htons(++g_ip_id);
10077c478bd9Sstevel@tonic-gate iphp->ip_off = htons(IP_DF);
10087c478bd9Sstevel@tonic-gate iphp->ip_p = sockets[index].proto;
10097c478bd9Sstevel@tonic-gate iphp->ip_sum = htons(0);
10107c478bd9Sstevel@tonic-gate iphp->ip_ttl = ttl;
10117c478bd9Sstevel@tonic-gate
10127c478bd9Sstevel@tonic-gate /* struct copies */
10137c478bd9Sstevel@tonic-gate iphp->ip_src = myip;
10147c478bd9Sstevel@tonic-gate iphp->ip_dst = ogp->igm_saddr.sin_addr;
10157c478bd9Sstevel@tonic-gate
10167c478bd9Sstevel@tonic-gate /*
10177c478bd9Sstevel@tonic-gate * On local / limited broadcasts, don't route. From a purist's
10187c478bd9Sstevel@tonic-gate * perspective, we should be setting the TTL to 1. But
10197c478bd9Sstevel@tonic-gate * operational experience has shown that some BOOTP relay agents
10207c478bd9Sstevel@tonic-gate * (ciscos) discard our packets. Furthermore, these devices also
10217c478bd9Sstevel@tonic-gate * *don't* reset the TTL to MAXTTL on the unicast side of the
10227c478bd9Sstevel@tonic-gate * BOOTP relay agent! Sigh. Thus to work correctly in these
10237c478bd9Sstevel@tonic-gate * environments, we leave the TTL as it has been been set by
10247c478bd9Sstevel@tonic-gate * the application layer, and simply don't check for a route.
10257c478bd9Sstevel@tonic-gate */
10267c478bd9Sstevel@tonic-gate if (iphp->ip_dst.s_addr == htonl(INADDR_BROADCAST) ||
10277c478bd9Sstevel@tonic-gate (netmask.s_addr != htonl(INADDR_BROADCAST) &&
10287c478bd9Sstevel@tonic-gate iphp->ip_dst.s_addr == (mynet.s_addr | ~netmask.s_addr))) {
10297c478bd9Sstevel@tonic-gate ogp->igm_oflags |= MSG_DONTROUTE;
10307c478bd9Sstevel@tonic-gate }
10317c478bd9Sstevel@tonic-gate
10327c478bd9Sstevel@tonic-gate /* Routing necessary? */
10337c478bd9Sstevel@tonic-gate if ((ogp->igm_oflags & MSG_DONTROUTE) == 0 &&
10347c478bd9Sstevel@tonic-gate ((iphp->ip_dst.s_addr & netmask.s_addr) != mynet.s_addr)) {
10357c478bd9Sstevel@tonic-gate struct in_addr *rip;
10367c478bd9Sstevel@tonic-gate if ((rip = ipv4_get_route(RT_HOST, &iphp->ip_dst,
10377c478bd9Sstevel@tonic-gate NULL)) == NULL) {
10387c478bd9Sstevel@tonic-gate rip = ipv4_get_route(RT_DEFAULT, NULL, NULL);
10397c478bd9Sstevel@tonic-gate }
10407c478bd9Sstevel@tonic-gate if (rip == NULL) {
10417c478bd9Sstevel@tonic-gate dprintf("ipv4(%d): No route to %s.\n",
10427c478bd9Sstevel@tonic-gate index, inet_ntoa(iphp->ip_dst));
10437c478bd9Sstevel@tonic-gate errno = EHOSTUNREACH;
10447c478bd9Sstevel@tonic-gate return (-1);
10457c478bd9Sstevel@tonic-gate }
10467c478bd9Sstevel@tonic-gate ogp->igm_router.s_addr = rip->s_addr;
10477c478bd9Sstevel@tonic-gate } else
10487c478bd9Sstevel@tonic-gate ogp->igm_router.s_addr = htonl(INADDR_ANY);
10497c478bd9Sstevel@tonic-gate
10507c478bd9Sstevel@tonic-gate iphp->ip_sum = ipv4cksum((uint16_t *)iphp, sizeof (struct ip));
10517c478bd9Sstevel@tonic-gate ogp->igm_mp->b_rptr -= sizeof (struct ip);
10527c478bd9Sstevel@tonic-gate bcopy((caddr_t)iphp, (caddr_t)(ogp->igm_mp->b_rptr),
10537c478bd9Sstevel@tonic-gate sizeof (struct ip));
10547c478bd9Sstevel@tonic-gate
10557c478bd9Sstevel@tonic-gate ogp->igm_level = MEDIA_LVL;
10567c478bd9Sstevel@tonic-gate
10577c478bd9Sstevel@tonic-gate return (0);
10587c478bd9Sstevel@tonic-gate }
10597c478bd9Sstevel@tonic-gate
10607c478bd9Sstevel@tonic-gate /*
10617c478bd9Sstevel@tonic-gate * Function to be called by TCP to send out a packet. This is used
10627c478bd9Sstevel@tonic-gate * when TCP wants to send out packets which it has already filled in
10637c478bd9Sstevel@tonic-gate * most of the header fields.
10647c478bd9Sstevel@tonic-gate */
10657c478bd9Sstevel@tonic-gate int
ipv4_tcp_output(int sock_id,mblk_t * pkt)10667c478bd9Sstevel@tonic-gate ipv4_tcp_output(int sock_id, mblk_t *pkt)
10677c478bd9Sstevel@tonic-gate {
10687c478bd9Sstevel@tonic-gate struct ip *iph;
10697c478bd9Sstevel@tonic-gate struct in_addr *rip = NULL;
10707c478bd9Sstevel@tonic-gate struct inetgram datagram;
10717c478bd9Sstevel@tonic-gate
10727c478bd9Sstevel@tonic-gate iph = (struct ip *)pkt->b_rptr;
10737c478bd9Sstevel@tonic-gate
10747c478bd9Sstevel@tonic-gate bzero(&datagram, sizeof (struct inetgram));
10757c478bd9Sstevel@tonic-gate
10767c478bd9Sstevel@tonic-gate /*
10777c478bd9Sstevel@tonic-gate * Bootparams doesn't know about subnet masks, so we need to
10787c478bd9Sstevel@tonic-gate * explicitly check for this flag.
10797c478bd9Sstevel@tonic-gate */
10807c478bd9Sstevel@tonic-gate if (sockets[sock_id].out_flags & SO_DONTROUTE)
10817c478bd9Sstevel@tonic-gate datagram.igm_oflags |= MSG_DONTROUTE;
10827c478bd9Sstevel@tonic-gate
10837c478bd9Sstevel@tonic-gate /* Routing necessary? */
10847c478bd9Sstevel@tonic-gate if (((datagram.igm_oflags & MSG_DONTROUTE) == 0) &&
1085*a963a5aaSToomas Soome ((iph->ip_dst.s_addr & netmask.s_addr) != mynet.s_addr)) {
10867c478bd9Sstevel@tonic-gate if ((rip = ipv4_get_route(RT_HOST, &iph->ip_dst,
10877c478bd9Sstevel@tonic-gate NULL)) == NULL) {
10887c478bd9Sstevel@tonic-gate rip = ipv4_get_route(RT_DEFAULT, NULL, NULL);
10897c478bd9Sstevel@tonic-gate }
10907c478bd9Sstevel@tonic-gate if (rip == NULL) {
10917c478bd9Sstevel@tonic-gate dprintf("ipv4(%d): No route to %s.\n",
10927c478bd9Sstevel@tonic-gate sock_id, inet_ntoa(iph->ip_dst));
10937c478bd9Sstevel@tonic-gate errno = EHOSTUNREACH;
10947c478bd9Sstevel@tonic-gate return (-1);
10957c478bd9Sstevel@tonic-gate }
10967c478bd9Sstevel@tonic-gate }
10977c478bd9Sstevel@tonic-gate
10987c478bd9Sstevel@tonic-gate iph->ip_id = htons(++g_ip_id);
10997c478bd9Sstevel@tonic-gate iph->ip_sum = ipv4cksum((uint16_t *)iph, sizeof (struct ip));
11007c478bd9Sstevel@tonic-gate #if DEBUG > 1
11017c478bd9Sstevel@tonic-gate printf("ipv4_tcp_output: dump IP packet(%d)\n", iph->ip_len);
11027c478bd9Sstevel@tonic-gate hexdump((char *)pkt->b_rptr, iph->ip_len);
11037c478bd9Sstevel@tonic-gate #endif
11047c478bd9Sstevel@tonic-gate /* Call the MAC layer output routine to send it out. */
11057c478bd9Sstevel@tonic-gate datagram.igm_mp = pkt;
11067c478bd9Sstevel@tonic-gate datagram.igm_level = MEDIA_LVL;
11077c478bd9Sstevel@tonic-gate if (rip != NULL)
11087c478bd9Sstevel@tonic-gate datagram.igm_router.s_addr = rip->s_addr;
11097c478bd9Sstevel@tonic-gate else
11107c478bd9Sstevel@tonic-gate datagram.igm_router.s_addr = 0;
11117c478bd9Sstevel@tonic-gate return (mac_state.mac_output(sock_id, &datagram));
11127c478bd9Sstevel@tonic-gate }
11137c478bd9Sstevel@tonic-gate
11147c478bd9Sstevel@tonic-gate /*
11157c478bd9Sstevel@tonic-gate * Internet address interpretation routine.
11167c478bd9Sstevel@tonic-gate * All the network library routines call this
11177c478bd9Sstevel@tonic-gate * routine to interpret entries in the data bases
11187c478bd9Sstevel@tonic-gate * which are expected to be an address.
11197c478bd9Sstevel@tonic-gate * The value returned is in network order.
11207c478bd9Sstevel@tonic-gate */
11217c478bd9Sstevel@tonic-gate in_addr_t
inet_addr(const char * cp)11227c478bd9Sstevel@tonic-gate inet_addr(const char *cp)
11237c478bd9Sstevel@tonic-gate {
11247c478bd9Sstevel@tonic-gate uint32_t val, base, n;
11257c478bd9Sstevel@tonic-gate char c;
11267c478bd9Sstevel@tonic-gate uint32_t parts[4], *pp = parts;
11277c478bd9Sstevel@tonic-gate
11287c478bd9Sstevel@tonic-gate if (*cp == '\0')
11297c478bd9Sstevel@tonic-gate return ((uint32_t)-1); /* disallow null string in cp */
11307c478bd9Sstevel@tonic-gate again:
11317c478bd9Sstevel@tonic-gate /*
11327c478bd9Sstevel@tonic-gate * Collect number up to ``.''.
11337c478bd9Sstevel@tonic-gate * Values are specified as for C:
11347c478bd9Sstevel@tonic-gate * 0x=hex, 0=octal, other=decimal.
11357c478bd9Sstevel@tonic-gate */
11367c478bd9Sstevel@tonic-gate val = 0; base = 10;
11377c478bd9Sstevel@tonic-gate if (*cp == '0') {
11387c478bd9Sstevel@tonic-gate if (*++cp == 'x' || *cp == 'X')
11397c478bd9Sstevel@tonic-gate base = 16, cp++;
11407c478bd9Sstevel@tonic-gate else
11417c478bd9Sstevel@tonic-gate base = 8;
11427c478bd9Sstevel@tonic-gate }
1143b531f6d1SToomas Soome while ((c = *cp) != '\0') {
11447c478bd9Sstevel@tonic-gate if (isdigit(c)) {
11457c478bd9Sstevel@tonic-gate if ((c - '0') >= base)
1146*a963a5aaSToomas Soome break;
11477c478bd9Sstevel@tonic-gate val = (val * base) + (c - '0');
11487c478bd9Sstevel@tonic-gate cp++;
11497c478bd9Sstevel@tonic-gate continue;
11507c478bd9Sstevel@tonic-gate }
11517c478bd9Sstevel@tonic-gate if (base == 16 && isxdigit(c)) {
11527c478bd9Sstevel@tonic-gate val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
11537c478bd9Sstevel@tonic-gate cp++;
11547c478bd9Sstevel@tonic-gate continue;
11557c478bd9Sstevel@tonic-gate }
11567c478bd9Sstevel@tonic-gate break;
11577c478bd9Sstevel@tonic-gate }
11587c478bd9Sstevel@tonic-gate if (*cp == '.') {
11597c478bd9Sstevel@tonic-gate /*
11607c478bd9Sstevel@tonic-gate * Internet format:
11617c478bd9Sstevel@tonic-gate * a.b.c.d
11627c478bd9Sstevel@tonic-gate * a.b.c (with c treated as 16-bits)
11637c478bd9