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 5*2a9459bdSsangeeta * Common Development and Distribution License (the "License"). 6*2a9459bdSsangeeta * 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 /* 22*2a9459bdSsangeeta * 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 #pragma ident "%Z%%M% %I% %E% SMI" 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <sys/types.h> 317c478bd9Sstevel@tonic-gate #include <socket_impl.h> 327c478bd9Sstevel@tonic-gate #include <socket_inet.h> 337c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 347c478bd9Sstevel@tonic-gate #include <sys/socket.h> 357c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h> 367c478bd9Sstevel@tonic-gate #include <netinet/in.h> 377c478bd9Sstevel@tonic-gate #include <netinet/ip.h> 387c478bd9Sstevel@tonic-gate #include <netinet/udp.h> 397c478bd9Sstevel@tonic-gate #include <net/if_arp.h> 407c478bd9Sstevel@tonic-gate #include <sys/promif.h> 417c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 427c478bd9Sstevel@tonic-gate #include <sys/fcntl.h> 437c478bd9Sstevel@tonic-gate #include <sys/salib.h> 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate #include "icmp4.h" 467c478bd9Sstevel@tonic-gate #include "ipv4.h" 477c478bd9Sstevel@tonic-gate #include "ipv4_impl.h" 487c478bd9Sstevel@tonic-gate #include "mac.h" 497c478bd9Sstevel@tonic-gate #include "mac_impl.h" 507c478bd9Sstevel@tonic-gate #include "v4_sum_impl.h" 517c478bd9Sstevel@tonic-gate #include <sys/bootdebug.h> 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate static struct ip_frag fragment[FRAG_MAX]; /* ip fragment buffers */ 547c478bd9Sstevel@tonic-gate static int fragments; /* Number of fragments */ 557c478bd9Sstevel@tonic-gate static uint8_t ttl = MAXTTL; /* IP ttl */ 567c478bd9Sstevel@tonic-gate static struct in_addr myip; /* our network-order IP addr */ 577c478bd9Sstevel@tonic-gate static struct in_addr mynet; /* net-order netaddr */ 587c478bd9Sstevel@tonic-gate static struct in_addr netmask = 597c478bd9Sstevel@tonic-gate { 0xff, 0xff, 0xff, 0xff }; /* our network-order netmask */ 607c478bd9Sstevel@tonic-gate static boolean_t netmask_set = B_FALSE; /* has anyone set netmask? */ 617c478bd9Sstevel@tonic-gate static struct in_addr defaultrouter; /* net-order defaultrouter */ 627c478bd9Sstevel@tonic-gate static int promiscuous; /* promiscuous mode */ 637c478bd9Sstevel@tonic-gate static struct routing table[IPV4_ROUTE_TABLE_SIZE]; 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate static uint16_t g_ip_id; 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate #ifdef DEBUG 687c478bd9Sstevel@tonic-gate #define FRAG_DEBUG 697c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate #ifdef FRAG_DEBUG 727c478bd9Sstevel@tonic-gate /* 737c478bd9Sstevel@tonic-gate * display the fragment list. For debugging purposes. 747c478bd9Sstevel@tonic-gate */ 757c478bd9Sstevel@tonic-gate static void 767c478bd9Sstevel@tonic-gate frag_disp(uint16_t size) 777c478bd9Sstevel@tonic-gate { 787c478bd9Sstevel@tonic-gate int i; 797c478bd9Sstevel@tonic-gate uint_t total = 0; 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate printf("Dumping fragment info: (%d)\n\n", fragments); 827c478bd9Sstevel@tonic-gate printf("More:\tOffset:\tDatap:\t\tIPid:\t\tIPlen:\tIPhlen:\n"); 837c478bd9Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) { 847c478bd9Sstevel@tonic-gate if (fragment[i].mp == NULL) 857c478bd9Sstevel@tonic-gate continue; 867c478bd9Sstevel@tonic-gate printf("%d\t%d\t0x%x\t%d\t\t%d\t%d\n", fragment[i].more, 877c478bd9Sstevel@tonic-gate fragment[i].offset, fragment[i].mp->b_rptr, 887c478bd9Sstevel@tonic-gate fragment[i].ipid, fragment[i].iplen, fragment[i].iphlen); 897c478bd9Sstevel@tonic-gate total += (fragment[i].iplen - fragment[i].iphlen); 907c478bd9Sstevel@tonic-gate } 917c478bd9Sstevel@tonic-gate printf("Total length is: %d. It should be: %d\n\n", total, size); 927c478bd9Sstevel@tonic-gate } 937c478bd9Sstevel@tonic-gate #endif /* FRAG_DEBUG */ 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate /* 967c478bd9Sstevel@tonic-gate * This function returns index of fragment 0 of the current fragmented DGRAM 977c478bd9Sstevel@tonic-gate * (which would contain the transport header). Return the fragment number 987c478bd9Sstevel@tonic-gate * for success, -1 if we don't yet have the first fragment. 997c478bd9Sstevel@tonic-gate */ 1007c478bd9Sstevel@tonic-gate static int 1017c478bd9Sstevel@tonic-gate frag_first(void) 1027c478bd9Sstevel@tonic-gate { 1037c478bd9Sstevel@tonic-gate int i; 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate if (fragments == 0) 1067c478bd9Sstevel@tonic-gate return (-1); 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) { 1097c478bd9Sstevel@tonic-gate if (fragment[i].mp != NULL && fragment[i].offset == 0) 1107c478bd9Sstevel@tonic-gate return (i); 1117c478bd9Sstevel@tonic-gate } 1127c478bd9Sstevel@tonic-gate return (-1); 1137c478bd9Sstevel@tonic-gate } 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate /* 1167c478bd9Sstevel@tonic-gate * This function returns index of the last fragment of the current DGRAM. 1177c478bd9Sstevel@tonic-gate * Returns the fragment number for success, -1 if we don't yet have the 1187c478bd9Sstevel@tonic-gate * last fragment. 1197c478bd9Sstevel@tonic-gate */ 1207c478bd9Sstevel@tonic-gate static int 1217c478bd9Sstevel@tonic-gate frag_last(void) 1227c478bd9Sstevel@tonic-gate { 1237c478bd9Sstevel@tonic-gate int i; 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate if (fragments == 0) 1267c478bd9Sstevel@tonic-gate return (-1); 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) { 1297c478bd9Sstevel@tonic-gate if (fragment[i].mp != NULL && !fragment[i].more) 1307c478bd9Sstevel@tonic-gate return (i); 1317c478bd9Sstevel@tonic-gate } 1327c478bd9Sstevel@tonic-gate return (-1); 1337c478bd9Sstevel@tonic-gate } 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate /* 1367c478bd9Sstevel@tonic-gate * This function adds a fragment to the current pkt fragment list. Returns 1377c478bd9Sstevel@tonic-gate * FRAG_NOSLOTS if there are no more slots, FRAG_DUP if the fragment is 1387c478bd9Sstevel@tonic-gate * a duplicate, or FRAG_SUCCESS if it is successful. 1397c478bd9Sstevel@tonic-gate */ 1407c478bd9Sstevel@tonic-gate static int 1417c478bd9Sstevel@tonic-gate frag_add(int16_t offset, mblk_t *mp, uint16_t ipid, 1427c478bd9Sstevel@tonic-gate int16_t iplen, int16_t iphlen, uint8_t ipp) 1437c478bd9Sstevel@tonic-gate { 1447c478bd9Sstevel@tonic-gate int i; 1457c478bd9Sstevel@tonic-gate int16_t true_offset = IPV4_OFFSET(offset); 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate /* first pass - look for duplicates */ 1487c478bd9Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) { 1497c478bd9Sstevel@tonic-gate if (fragment[i].mp != NULL && 1507c478bd9Sstevel@tonic-gate fragment[i].offset == true_offset) 1517c478bd9Sstevel@tonic-gate return (FRAG_DUP); 1527c478bd9Sstevel@tonic-gate } 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate /* second pass - fill in empty slot */ 1557c478bd9Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) { 1567c478bd9Sstevel@tonic-gate if (fragment[i].mp == NULL) { 1577c478bd9Sstevel@tonic-gate fragment[i].more = (offset & IP_MF); 1587c478bd9Sstevel@tonic-gate fragment[i].offset = true_offset; 1597c478bd9Sstevel@tonic-gate fragment[i].mp = mp; 1607c478bd9Sstevel@tonic-gate fragment[i].ipid = ipid; 1617c478bd9Sstevel@tonic-gate fragment[i].iplen = iplen; 1627c478bd9Sstevel@tonic-gate fragment[i].iphlen = iphlen; 1637c478bd9Sstevel@tonic-gate fragment[i].ipp = ipp; 1647c478bd9Sstevel@tonic-gate fragments++; 1657c478bd9Sstevel@tonic-gate return (FRAG_SUCCESS); 1667c478bd9Sstevel@tonic-gate } 1677c478bd9Sstevel@tonic-gate } 1687c478bd9Sstevel@tonic-gate return (FRAG_NOSLOTS); 1697c478bd9Sstevel@tonic-gate } 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate /* 1727c478bd9Sstevel@tonic-gate * Nuke a fragment. 1737c478bd9Sstevel@tonic-gate */ 1747c478bd9Sstevel@tonic-gate static void 1757c478bd9Sstevel@tonic-gate frag_free(int index) 1767c478bd9Sstevel@tonic-gate { 1777c478bd9Sstevel@tonic-gate if (fragment[index].mp != NULL) { 1787c478bd9Sstevel@tonic-gate freeb(fragment[index].mp); 1797c478bd9Sstevel@tonic-gate fragments--; 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate bzero((caddr_t)&fragment[index], sizeof (struct ip_frag)); 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate /* 1857c478bd9Sstevel@tonic-gate * zero the frag list. 1867c478bd9Sstevel@tonic-gate */ 1877c478bd9Sstevel@tonic-gate static void 1887c478bd9Sstevel@tonic-gate frag_flush(void) 1897c478bd9Sstevel@tonic-gate { 1907c478bd9Sstevel@tonic-gate int i; 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) 1937c478bd9Sstevel@tonic-gate frag_free(i); 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate fragments = 0; 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate /* 1997c478bd9Sstevel@tonic-gate * Analyze the fragment list - see if we captured all our fragments. 2007c478bd9Sstevel@tonic-gate * 2017c478bd9Sstevel@tonic-gate * Returns TRUE if we've got all the fragments, and FALSE if we don't. 2027c478bd9Sstevel@tonic-gate */ 2037c478bd9Sstevel@tonic-gate static int 2047c478bd9Sstevel@tonic-gate frag_chk(void) 2057c478bd9Sstevel@tonic-gate { 2067c478bd9Sstevel@tonic-gate int i, first_frag, last_frag; 2077c478bd9Sstevel@tonic-gate int16_t actual, total; 2087c478bd9Sstevel@tonic-gate uint16_t ip_id; 2097c478bd9Sstevel@tonic-gate uint8_t ipp; 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate if (fragments == 0 || (first_frag = frag_first()) < 0 || 2127c478bd9Sstevel@tonic-gate (last_frag = frag_last()) < 0) 2137c478bd9Sstevel@tonic-gate return (FALSE); 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate /* 2167c478bd9Sstevel@tonic-gate * Validate the ipid's of our fragments - nuke those that don't 2177c478bd9Sstevel@tonic-gate * match the id of the first fragment or don't match the IP 2187c478bd9Sstevel@tonic-gate * protocol of the first fragment. 2197c478bd9Sstevel@tonic-gate */ 2207c478bd9Sstevel@tonic-gate ip_id = fragment[first_frag].ipid; 2217c478bd9Sstevel@tonic-gate ipp = fragment[first_frag].ipp; 2227c478bd9Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) { 2237c478bd9Sstevel@tonic-gate if (fragment[i].mp != NULL && ip_id != fragment[i].ipid && 2247c478bd9Sstevel@tonic-gate fragment[i].ipp != ipp) { 2257c478bd9Sstevel@tonic-gate #ifdef FRAG_DEBUG 2267c478bd9Sstevel@tonic-gate printf("ipv4: Frag id mismatch: %x != %x\n", 2277c478bd9Sstevel@tonic-gate fragment[i].ipid, ip_id); 2287c478bd9Sstevel@tonic-gate #endif /* FRAG_DEBUG */ 2297c478bd9Sstevel@tonic-gate frag_free(i); 2307c478bd9Sstevel@tonic-gate } 2317c478bd9Sstevel@tonic-gate } 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate if (frag_last() < 0) 2347c478bd9Sstevel@tonic-gate return (FALSE); 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate total = fragment[last_frag].offset + fragment[last_frag].iplen - 2377c478bd9Sstevel@tonic-gate fragment[last_frag].iphlen; 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate for (i = 0, actual = 0; i < FRAG_MAX; i++) 2407c478bd9Sstevel@tonic-gate actual += (fragment[i].iplen - fragment[i].iphlen); 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate #ifdef FRAG_DEBUG 2437c478bd9Sstevel@tonic-gate frag_disp(total); 2447c478bd9Sstevel@tonic-gate #endif /* FRAG_DEBUG */ 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate return (total == actual); 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate /* 2507c478bd9Sstevel@tonic-gate * Load the assembled fragments into igp. Returns 0 for success, nonzero 2517c478bd9Sstevel@tonic-gate * otherwise. 2527c478bd9Sstevel@tonic-gate */ 2537c478bd9Sstevel@tonic-gate static int 2547c478bd9Sstevel@tonic-gate frag_load(struct inetgram *igp) 2557c478bd9Sstevel@tonic-gate { 2567c478bd9Sstevel@tonic-gate int i; 2577c478bd9Sstevel@tonic-gate int16_t len; 2587c478bd9Sstevel@tonic-gate uint_t total_len; 2597c478bd9Sstevel@tonic-gate boolean_t first_frag = B_FALSE; 2607c478bd9Sstevel@tonic-gate mblk_t *mp; 2617c478bd9Sstevel@tonic-gate struct ip *iph; 2627c478bd9Sstevel@tonic-gate int first_iph_len; 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate if (fragments == 0) 2657c478bd9Sstevel@tonic-gate return (ENOENT); 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate mp = igp->igm_mp; 2687c478bd9Sstevel@tonic-gate /* Get the IP header length of the first fragment. */ 2697c478bd9Sstevel@tonic-gate i = frag_first(); 2707c478bd9Sstevel@tonic-gate assert(i >= 0); 2717c478bd9Sstevel@tonic-gate first_iph_len = fragment[i].iphlen; 2727c478bd9Sstevel@tonic-gate for (i = 0, len = 0, total_len = 0; i < FRAG_MAX; i++) { 2737c478bd9Sstevel@tonic-gate if (fragment[i].mp != NULL) { 2747c478bd9Sstevel@tonic-gate /* 2757c478bd9Sstevel@tonic-gate * Copy just the data (omit the ip header of all 2767c478bd9Sstevel@tonic-gate * fragments except the first one which contains 2777c478bd9Sstevel@tonic-gate * all the info...) 2787c478bd9Sstevel@tonic-gate */ 2797c478bd9Sstevel@tonic-gate if (fragment[i].offset == 0) { 2807c478bd9Sstevel@tonic-gate len = fragment[i].iplen; 2817c478bd9Sstevel@tonic-gate first_frag = B_TRUE; 2827c478bd9Sstevel@tonic-gate } else { 2837c478bd9Sstevel@tonic-gate len = fragment[i].iplen - fragment[i].iphlen; 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate total_len += len; 2867c478bd9Sstevel@tonic-gate if (total_len > mp->b_size) 2877c478bd9Sstevel@tonic-gate return (E2BIG); 2887c478bd9Sstevel@tonic-gate if (first_frag) { 2897c478bd9Sstevel@tonic-gate bcopy((caddr_t)(fragment[i].mp->b_rptr), 2907c478bd9Sstevel@tonic-gate (caddr_t)mp->b_rptr, len); 2917c478bd9Sstevel@tonic-gate first_frag = B_FALSE; 2927c478bd9Sstevel@tonic-gate } else { 2937c478bd9Sstevel@tonic-gate bcopy((caddr_t)(fragment[i].mp->b_rptr + 2947c478bd9Sstevel@tonic-gate fragment[i].iphlen), 2957c478bd9Sstevel@tonic-gate (caddr_t)(mp->b_rptr + first_iph_len + 2967c478bd9Sstevel@tonic-gate fragment[i].offset), len); 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate mp->b_wptr += len; 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate /* Fix the total length in the IP header. */ 3027c478bd9Sstevel@tonic-gate iph = (struct ip *)mp->b_rptr; 3037c478bd9Sstevel@tonic-gate iph->ip_len = htons(total_len); 3047c478bd9Sstevel@tonic-gate return (0); 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate /* 3087c478bd9Sstevel@tonic-gate * Locate a routing table entry based upon arguments. IP addresses expected 3097c478bd9Sstevel@tonic-gate * in network order. Returns index for success, -1 if entry not found. 3107c478bd9Sstevel@tonic-gate */ 3117c478bd9Sstevel@tonic-gate static int 3127c478bd9Sstevel@tonic-gate find_route(uint8_t *flagp, struct in_addr *destp, struct in_addr *gatewayp) 3137c478bd9Sstevel@tonic-gate { 3147c478bd9Sstevel@tonic-gate int i, table_entry = -1; 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate for (i = 0; table_entry == -1 && i < IPV4_ROUTE_TABLE_SIZE; i++) { 3177c478bd9Sstevel@tonic-gate if (flagp != NULL) { 3187c478bd9Sstevel@tonic-gate if (*flagp & table[i].flag) 3197c478bd9Sstevel@tonic-gate table_entry = i; 3207c478bd9Sstevel@tonic-gate } 3217c478bd9Sstevel@tonic-gate if (destp != NULL) { 3227c478bd9Sstevel@tonic-gate if (destp->s_addr == table[i].dest.s_addr) 3237c478bd9Sstevel@tonic-gate table_entry = i; 3247c478bd9Sstevel@tonic-gate else 3257c478bd9Sstevel@tonic-gate table_entry = -1; 3267c478bd9Sstevel@tonic-gate } 3277c478bd9Sstevel@tonic-gate if (gatewayp != NULL) { 3287c478bd9Sstevel@tonic-gate if (gatewayp->s_addr == table[i].gateway.s_addr) 3297c478bd9Sstevel@tonic-gate table_entry = i; 3307c478bd9Sstevel@tonic-gate else 3317c478bd9Sstevel@tonic-gate table_entry = -1; 3327c478bd9Sstevel@tonic-gate } 3337c478bd9Sstevel@tonic-gate } 3347c478bd9Sstevel@tonic-gate return (table_entry); 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate /* 3387c478bd9Sstevel@tonic-gate * ADD or DEL a routing table entry. Returns 0 for success, -1 and errno 3397c478bd9Sstevel@tonic-gate * otherwise. IP addresses are expected in network order. 3407c478bd9Sstevel@tonic-gate */ 3417c478bd9Sstevel@tonic-gate int 3427c478bd9Sstevel@tonic-gate ipv4_route(int cmd, uint8_t flag, struct in_addr *destp, 3437c478bd9Sstevel@tonic-gate struct in_addr *gatewayp) 3447c478bd9Sstevel@tonic-gate { 3457c478bd9Sstevel@tonic-gate static int routing_table_initialized; 3467c478bd9Sstevel@tonic-gate int index; 3477c478bd9Sstevel@tonic-gate uint8_t tmp_flag; 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate if (gatewayp == NULL) { 3507c478bd9Sstevel@tonic-gate errno = EINVAL; 3517c478bd9Sstevel@tonic-gate return (-1); 3527c478bd9Sstevel@tonic-gate } 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate /* initialize routing table */ 3557c478bd9Sstevel@tonic-gate if (routing_table_initialized == 0) { 3567c478bd9Sstevel@tonic-gate for (index = 0; index < IPV4_ROUTE_TABLE_SIZE; index++) 3577c478bd9Sstevel@tonic-gate table[index].flag = RT_UNUSED; 3587c478bd9Sstevel@tonic-gate routing_table_initialized = 1; 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate switch (cmd) { 3627c478bd9Sstevel@tonic-gate case IPV4_ADD_ROUTE: 3637c478bd9Sstevel@tonic-gate tmp_flag = (uint8_t)RT_UNUSED; 3647c478bd9Sstevel@tonic-gate if ((index = find_route(&tmp_flag, NULL, NULL)) == -1) { 3657c478bd9Sstevel@tonic-gate dprintf("ipv4_route: routing table full.\n"); 3667c478bd9Sstevel@tonic-gate errno = ENOSPC; 3677c478bd9Sstevel@tonic-gate return (-1); 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate table[index].flag = flag; 3707c478bd9Sstevel@tonic-gate if (destp != NULL) 3717c478bd9Sstevel@tonic-gate table[index].dest.s_addr = destp->s_addr; 3727c478bd9Sstevel@tonic-gate else 3737c478bd9Sstevel@tonic-gate table[index].dest.s_addr = htonl(INADDR_ANY); 3747c478bd9Sstevel@tonic-gate table[index].gateway.s_addr = gatewayp->s_addr; 3757c478bd9Sstevel@tonic-gate break; 3767c478bd9Sstevel@tonic-gate case IPV4_BAD_ROUTE: 3777c478bd9Sstevel@tonic-gate /* FALLTHRU */ 3787c478bd9Sstevel@tonic-gate case IPV4_DEL_ROUTE: 3797c478bd9Sstevel@tonic-gate if ((index = find_route(&flag, destp, gatewayp)) == -1) { 3807c478bd9Sstevel@tonic-gate dprintf("ipv4_route: No such routing entry.\n"); 3817c478bd9Sstevel@tonic-gate errno = ENOENT; 3827c478bd9Sstevel@tonic-gate return (-1); 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate if (cmd == IPV4_DEL_ROUTE) { 3857c478bd9Sstevel@tonic-gate table[index].flag = RT_UNUSED; 3867c478bd9Sstevel@tonic-gate table[index].dest.s_addr = htonl(INADDR_ANY); 3877c478bd9Sstevel@tonic-gate table[index].gateway.s_addr = htonl(INADDR_ANY); 3887c478bd9Sstevel@tonic-gate } else 3897c478bd9Sstevel@tonic-gate table[index].flag = RT_NG; 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 * 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 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 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 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 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 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 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 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 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); 511*2a9459bdSsangeeta else if (IN_CLASSC(ntohl(myip.s_addr))) 5127c478bd9Sstevel@tonic-gate ip->s_addr = ntohl(IN_CLASSC_NET); 513*2a9459bdSsangeeta else 514*2a9459bdSsangeeta 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 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 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 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 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 * 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 * 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 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", 7217c478bd9Sstevel@tonic-gate 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 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 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) && 10857c478bd9Sstevel@tonic-gate ((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 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 } 11437c478bd9Sstevel@tonic-gate while ((c = *cp) != NULL) { 11447c478bd9Sstevel@tonic-gate if (isdigit(c)) { 11457c478bd9Sstevel@tonic-gate if ((c - '0') >= base) 11467c478bd9Sstevel@tonic-gate 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) 11637c478bd9Sstevel@tonic-gate * a.b (with b treated as 24 bits) 11647c478bd9Sstevel@tonic-gate */ 11657c478bd9Sstevel@tonic-gate if ((pp >= parts + 3) || (val > 0xff)) { 11667c478bd9Sstevel@tonic-gate return ((uint32_t)-1); 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate *pp++ = val, cp++; 11697c478bd9Sstevel@tonic-gate goto again; 11707c478bd9Sstevel@tonic-gate } 11717c478bd9Sstevel@tonic-gate /* 11727c478bd9Sstevel@tonic-gate * Check for trailing characters. 11737c478bd9Sstevel@tonic-gate */ 11747c478bd9Sstevel@tonic-gate if (*cp && !isspace(*cp)) { 11757c478bd9Sstevel@tonic-gate return ((uint32_t)-1); 11767c478bd9Sstevel@tonic-gate } 11777c478bd9Sstevel@tonic-gate *pp++ = val; 11787c478bd9Sstevel@tonic-gate /* 11797c478bd9Sstevel@tonic-gate * Concoct the address according to 11807c478bd9Sstevel@tonic-gate * the number of parts specified. 11817c478bd9Sstevel@tonic-gate */ 11827c478bd9Sstevel@tonic-gate n = pp - parts; 11837c478bd9Sstevel@tonic-gate switch (n) { 11847c478bd9Sstevel@tonic-gate 11857c478bd9Sstevel@tonic-gate case 1: /* a -- 32 bits */ 11867c478bd9Sstevel@tonic-gate val = parts[0]; 11877c478bd9Sstevel@tonic-gate break; 11887c478bd9Sstevel@tonic-gate 11897c478bd9Sstevel@tonic-gate case 2: /* a.b -- 8.24 bits */ 11907c478bd9Sstevel@tonic-gate if (parts[1] > 0xffffff) 11917c478bd9Sstevel@tonic-gate return ((uint32_t)-1); 11927c478bd9Sstevel@tonic-gate val = (parts[0] << 24) | (parts[1] & 0xffffff); 11937c478bd9Sstevel@tonic-gate break; 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate case 3: /* a.b.c -- 8.8.16 bits */ 11967c478bd9Sstevel@tonic-gate if (parts[2] > 0xffff) 11977c478bd9Sstevel@tonic-gate return ((uint32_t)-1); 11987c478bd9Sstevel@tonic-gate val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) | 11997c478bd9Sstevel@tonic-gate (parts[2] & 0xffff); 12007c478bd9Sstevel@tonic-gate break; 12017c478bd9Sstevel@tonic-gate 12027c478bd9Sstevel@tonic-gate case 4: /* a.b.c.d -- 8.8.8.8 bits */ 12037c478bd9Sstevel@tonic-gate if (parts[3] > 0xff) 12047c478bd9Sstevel@tonic-gate return ((uint32_t)-1); 12057c478bd9Sstevel@tonic-gate val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) | 12067c478bd9Sstevel@tonic-gate ((parts[2] & 0xff) << 8) | (parts[3] & 0xff); 12077c478bd9Sstevel@tonic-gate break; 12087c478bd9Sstevel@tonic-gate 12097c478bd9Sstevel@tonic-gate default: 12107c478bd9Sstevel@tonic-gate return ((uint32_t)-1); 12117c478bd9Sstevel@tonic-gate } 12127c478bd9Sstevel@tonic-gate val = htonl(val); 12137c478bd9Sstevel@tonic-gate return (val); 12147c478bd9Sstevel@tonic-gate } 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate void 12177c478bd9Sstevel@tonic-gate hexdump(char *data, int datalen) 12187c478bd9Sstevel@tonic-gate { 12197c478bd9Sstevel@tonic-gate char *p; 12207c478bd9Sstevel@tonic-gate ushort_t *p16 = (ushort_t *)data; 12217c478bd9Sstevel@tonic-gate char *p8 = data; 12227c478bd9Sstevel@tonic-gate int i, left, len; 12237c478bd9Sstevel@tonic-gate int chunk = 16; /* 16 bytes per line */ 12247c478bd9Sstevel@tonic-gate 12257c478bd9Sstevel@tonic-gate printf("\n"); 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate for (p = data; p < data + datalen; p += chunk) { 12287c478bd9Sstevel@tonic-gate printf("\t%4d: ", (int)(p - data)); 12297c478bd9Sstevel@tonic-gate left = (data + datalen) - p; 12307c478bd9Sstevel@tonic-gate len = MIN(chunk, left); 12317c478bd9Sstevel@tonic-gate for (i = 0; i < (len / 2); i++) 12327c478bd9Sstevel@tonic-gate printf("%04x ", ntohs(*p16++) & 0xffff); 12337c478bd9Sstevel@tonic-gate if (len % 2) { 12347c478bd9Sstevel@tonic-gate printf("%02x ", *((unsigned char *)p16)); 12357c478bd9Sstevel@tonic-gate } 12367c478bd9Sstevel@tonic-gate for (i = 0; i < (chunk - left) / 2; i++) 12377c478bd9Sstevel@tonic-gate printf(" "); 12387c478bd9Sstevel@tonic-gate 12397c478bd9Sstevel@tonic-gate printf(" "); 12407c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++, p8++) 12417c478bd9Sstevel@tonic-gate printf("%c", isprint(*p8) ? *p8 : '.'); 12427c478bd9Sstevel@tonic-gate printf("\n"); 12437c478bd9Sstevel@tonic-gate } 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate printf("\n"); 12467c478bd9Sstevel@tonic-gate } 1247