1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate * 26*7c478bd9Sstevel@tonic-gate * ipv4.c, Code implementing the IPv4 internet protocol. 27*7c478bd9Sstevel@tonic-gate */ 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 32*7c478bd9Sstevel@tonic-gate #include <socket_impl.h> 33*7c478bd9Sstevel@tonic-gate #include <socket_inet.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 36*7c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h> 37*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 38*7c478bd9Sstevel@tonic-gate #include <netinet/ip.h> 39*7c478bd9Sstevel@tonic-gate #include <netinet/udp.h> 40*7c478bd9Sstevel@tonic-gate #include <net/if_arp.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/promif.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/fcntl.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/salib.h> 45*7c478bd9Sstevel@tonic-gate 46*7c478bd9Sstevel@tonic-gate #include "icmp4.h" 47*7c478bd9Sstevel@tonic-gate #include "ipv4.h" 48*7c478bd9Sstevel@tonic-gate #include "ipv4_impl.h" 49*7c478bd9Sstevel@tonic-gate #include "mac.h" 50*7c478bd9Sstevel@tonic-gate #include "mac_impl.h" 51*7c478bd9Sstevel@tonic-gate #include "v4_sum_impl.h" 52*7c478bd9Sstevel@tonic-gate #include <sys/bootdebug.h> 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate static struct ip_frag fragment[FRAG_MAX]; /* ip fragment buffers */ 55*7c478bd9Sstevel@tonic-gate static int fragments; /* Number of fragments */ 56*7c478bd9Sstevel@tonic-gate static uint8_t ttl = MAXTTL; /* IP ttl */ 57*7c478bd9Sstevel@tonic-gate static struct in_addr myip; /* our network-order IP addr */ 58*7c478bd9Sstevel@tonic-gate static struct in_addr mynet; /* net-order netaddr */ 59*7c478bd9Sstevel@tonic-gate static struct in_addr netmask = 60*7c478bd9Sstevel@tonic-gate { 0xff, 0xff, 0xff, 0xff }; /* our network-order netmask */ 61*7c478bd9Sstevel@tonic-gate static boolean_t netmask_set = B_FALSE; /* has anyone set netmask? */ 62*7c478bd9Sstevel@tonic-gate static struct in_addr defaultrouter; /* net-order defaultrouter */ 63*7c478bd9Sstevel@tonic-gate static int promiscuous; /* promiscuous mode */ 64*7c478bd9Sstevel@tonic-gate static struct routing table[IPV4_ROUTE_TABLE_SIZE]; 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate static uint16_t g_ip_id; 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 69*7c478bd9Sstevel@tonic-gate #define FRAG_DEBUG 70*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate #ifdef FRAG_DEBUG 73*7c478bd9Sstevel@tonic-gate /* 74*7c478bd9Sstevel@tonic-gate * display the fragment list. For debugging purposes. 75*7c478bd9Sstevel@tonic-gate */ 76*7c478bd9Sstevel@tonic-gate static void 77*7c478bd9Sstevel@tonic-gate frag_disp(uint16_t size) 78*7c478bd9Sstevel@tonic-gate { 79*7c478bd9Sstevel@tonic-gate int i; 80*7c478bd9Sstevel@tonic-gate uint_t total = 0; 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate printf("Dumping fragment info: (%d)\n\n", fragments); 83*7c478bd9Sstevel@tonic-gate printf("More:\tOffset:\tDatap:\t\tIPid:\t\tIPlen:\tIPhlen:\n"); 84*7c478bd9Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) { 85*7c478bd9Sstevel@tonic-gate if (fragment[i].mp == NULL) 86*7c478bd9Sstevel@tonic-gate continue; 87*7c478bd9Sstevel@tonic-gate printf("%d\t%d\t0x%x\t%d\t\t%d\t%d\n", fragment[i].more, 88*7c478bd9Sstevel@tonic-gate fragment[i].offset, fragment[i].mp->b_rptr, 89*7c478bd9Sstevel@tonic-gate fragment[i].ipid, fragment[i].iplen, fragment[i].iphlen); 90*7c478bd9Sstevel@tonic-gate total += (fragment[i].iplen - fragment[i].iphlen); 91*7c478bd9Sstevel@tonic-gate } 92*7c478bd9Sstevel@tonic-gate printf("Total length is: %d. It should be: %d\n\n", total, size); 93*7c478bd9Sstevel@tonic-gate } 94*7c478bd9Sstevel@tonic-gate #endif /* FRAG_DEBUG */ 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate /* 97*7c478bd9Sstevel@tonic-gate * This function returns index of fragment 0 of the current fragmented DGRAM 98*7c478bd9Sstevel@tonic-gate * (which would contain the transport header). Return the fragment number 99*7c478bd9Sstevel@tonic-gate * for success, -1 if we don't yet have the first fragment. 100*7c478bd9Sstevel@tonic-gate */ 101*7c478bd9Sstevel@tonic-gate static int 102*7c478bd9Sstevel@tonic-gate frag_first(void) 103*7c478bd9Sstevel@tonic-gate { 104*7c478bd9Sstevel@tonic-gate int i; 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate if (fragments == 0) 107*7c478bd9Sstevel@tonic-gate return (-1); 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) { 110*7c478bd9Sstevel@tonic-gate if (fragment[i].mp != NULL && fragment[i].offset == 0) 111*7c478bd9Sstevel@tonic-gate return (i); 112*7c478bd9Sstevel@tonic-gate } 113*7c478bd9Sstevel@tonic-gate return (-1); 114*7c478bd9Sstevel@tonic-gate } 115*7c478bd9Sstevel@tonic-gate 116*7c478bd9Sstevel@tonic-gate /* 117*7c478bd9Sstevel@tonic-gate * This function returns index of the last fragment of the current DGRAM. 118*7c478bd9Sstevel@tonic-gate * Returns the fragment number for success, -1 if we don't yet have the 119*7c478bd9Sstevel@tonic-gate * last fragment. 120*7c478bd9Sstevel@tonic-gate */ 121*7c478bd9Sstevel@tonic-gate static int 122*7c478bd9Sstevel@tonic-gate frag_last(void) 123*7c478bd9Sstevel@tonic-gate { 124*7c478bd9Sstevel@tonic-gate int i; 125*7c478bd9Sstevel@tonic-gate 126*7c478bd9Sstevel@tonic-gate if (fragments == 0) 127*7c478bd9Sstevel@tonic-gate return (-1); 128*7c478bd9Sstevel@tonic-gate 129*7c478bd9Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) { 130*7c478bd9Sstevel@tonic-gate if (fragment[i].mp != NULL && !fragment[i].more) 131*7c478bd9Sstevel@tonic-gate return (i); 132*7c478bd9Sstevel@tonic-gate } 133*7c478bd9Sstevel@tonic-gate return (-1); 134*7c478bd9Sstevel@tonic-gate } 135*7c478bd9Sstevel@tonic-gate 136*7c478bd9Sstevel@tonic-gate /* 137*7c478bd9Sstevel@tonic-gate * This function adds a fragment to the current pkt fragment list. Returns 138*7c478bd9Sstevel@tonic-gate * FRAG_NOSLOTS if there are no more slots, FRAG_DUP if the fragment is 139*7c478bd9Sstevel@tonic-gate * a duplicate, or FRAG_SUCCESS if it is successful. 140*7c478bd9Sstevel@tonic-gate */ 141*7c478bd9Sstevel@tonic-gate static int 142*7c478bd9Sstevel@tonic-gate frag_add(int16_t offset, mblk_t *mp, uint16_t ipid, 143*7c478bd9Sstevel@tonic-gate int16_t iplen, int16_t iphlen, uint8_t ipp) 144*7c478bd9Sstevel@tonic-gate { 145*7c478bd9Sstevel@tonic-gate int i; 146*7c478bd9Sstevel@tonic-gate int16_t true_offset = IPV4_OFFSET(offset); 147*7c478bd9Sstevel@tonic-gate 148*7c478bd9Sstevel@tonic-gate /* first pass - look for duplicates */ 149*7c478bd9Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) { 150*7c478bd9Sstevel@tonic-gate if (fragment[i].mp != NULL && 151*7c478bd9Sstevel@tonic-gate fragment[i].offset == true_offset) 152*7c478bd9Sstevel@tonic-gate return (FRAG_DUP); 153*7c478bd9Sstevel@tonic-gate } 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate /* second pass - fill in empty slot */ 156*7c478bd9Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) { 157*7c478bd9Sstevel@tonic-gate if (fragment[i].mp == NULL) { 158*7c478bd9Sstevel@tonic-gate fragment[i].more = (offset & IP_MF); 159*7c478bd9Sstevel@tonic-gate fragment[i].offset = true_offset; 160*7c478bd9Sstevel@tonic-gate fragment[i].mp = mp; 161*7c478bd9Sstevel@tonic-gate fragment[i].ipid = ipid; 162*7c478bd9Sstevel@tonic-gate fragment[i].iplen = iplen; 163*7c478bd9Sstevel@tonic-gate fragment[i].iphlen = iphlen; 164*7c478bd9Sstevel@tonic-gate fragment[i].ipp = ipp; 165*7c478bd9Sstevel@tonic-gate fragments++; 166*7c478bd9Sstevel@tonic-gate return (FRAG_SUCCESS); 167*7c478bd9Sstevel@tonic-gate } 168*7c478bd9Sstevel@tonic-gate } 169*7c478bd9Sstevel@tonic-gate return (FRAG_NOSLOTS); 170*7c478bd9Sstevel@tonic-gate } 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate /* 173*7c478bd9Sstevel@tonic-gate * Nuke a fragment. 174*7c478bd9Sstevel@tonic-gate */ 175*7c478bd9Sstevel@tonic-gate static void 176*7c478bd9Sstevel@tonic-gate frag_free(int index) 177*7c478bd9Sstevel@tonic-gate { 178*7c478bd9Sstevel@tonic-gate if (fragment[index].mp != NULL) { 179*7c478bd9Sstevel@tonic-gate freeb(fragment[index].mp); 180*7c478bd9Sstevel@tonic-gate fragments--; 181*7c478bd9Sstevel@tonic-gate } 182*7c478bd9Sstevel@tonic-gate bzero((caddr_t)&fragment[index], sizeof (struct ip_frag)); 183*7c478bd9Sstevel@tonic-gate } 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate /* 186*7c478bd9Sstevel@tonic-gate * zero the frag list. 187*7c478bd9Sstevel@tonic-gate */ 188*7c478bd9Sstevel@tonic-gate static void 189*7c478bd9Sstevel@tonic-gate frag_flush(void) 190*7c478bd9Sstevel@tonic-gate { 191*7c478bd9Sstevel@tonic-gate int i; 192*7c478bd9Sstevel@tonic-gate 193*7c478bd9Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) 194*7c478bd9Sstevel@tonic-gate frag_free(i); 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate fragments = 0; 197*7c478bd9Sstevel@tonic-gate } 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate /* 200*7c478bd9Sstevel@tonic-gate * Analyze the fragment list - see if we captured all our fragments. 201*7c478bd9Sstevel@tonic-gate * 202*7c478bd9Sstevel@tonic-gate * Returns TRUE if we've got all the fragments, and FALSE if we don't. 203*7c478bd9Sstevel@tonic-gate */ 204*7c478bd9Sstevel@tonic-gate static int 205*7c478bd9Sstevel@tonic-gate frag_chk(void) 206*7c478bd9Sstevel@tonic-gate { 207*7c478bd9Sstevel@tonic-gate int i, first_frag, last_frag; 208*7c478bd9Sstevel@tonic-gate int16_t actual, total; 209*7c478bd9Sstevel@tonic-gate uint16_t ip_id; 210*7c478bd9Sstevel@tonic-gate uint8_t ipp; 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate if (fragments == 0 || (first_frag = frag_first()) < 0 || 213*7c478bd9Sstevel@tonic-gate (last_frag = frag_last()) < 0) 214*7c478bd9Sstevel@tonic-gate return (FALSE); 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate /* 217*7c478bd9Sstevel@tonic-gate * Validate the ipid's of our fragments - nuke those that don't 218*7c478bd9Sstevel@tonic-gate * match the id of the first fragment or don't match the IP 219*7c478bd9Sstevel@tonic-gate * protocol of the first fragment. 220*7c478bd9Sstevel@tonic-gate */ 221*7c478bd9Sstevel@tonic-gate ip_id = fragment[first_frag].ipid; 222*7c478bd9Sstevel@tonic-gate ipp = fragment[first_frag].ipp; 223*7c478bd9Sstevel@tonic-gate for (i = 0; i < FRAG_MAX; i++) { 224*7c478bd9Sstevel@tonic-gate if (fragment[i].mp != NULL && ip_id != fragment[i].ipid && 225*7c478bd9Sstevel@tonic-gate fragment[i].ipp != ipp) { 226*7c478bd9Sstevel@tonic-gate #ifdef FRAG_DEBUG 227*7c478bd9Sstevel@tonic-gate printf("ipv4: Frag id mismatch: %x != %x\n", 228*7c478bd9Sstevel@tonic-gate fragment[i].ipid, ip_id); 229*7c478bd9Sstevel@tonic-gate #endif /* FRAG_DEBUG */ 230*7c478bd9Sstevel@tonic-gate frag_free(i); 231*7c478bd9Sstevel@tonic-gate } 232*7c478bd9Sstevel@tonic-gate } 233*7c478bd9Sstevel@tonic-gate 234*7c478bd9Sstevel@tonic-gate if (frag_last() < 0) 235*7c478bd9Sstevel@tonic-gate return (FALSE); 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate total = fragment[last_frag].offset + fragment[last_frag].iplen - 238*7c478bd9Sstevel@tonic-gate fragment[last_frag].iphlen; 239*7c478bd9Sstevel@tonic-gate 240*7c478bd9Sstevel@tonic-gate for (i = 0, actual = 0; i < FRAG_MAX; i++) 241*7c478bd9Sstevel@tonic-gate actual += (fragment[i].iplen - fragment[i].iphlen); 242*7c478bd9Sstevel@tonic-gate 243*7c478bd9Sstevel@tonic-gate #ifdef FRAG_DEBUG 244*7c478bd9Sstevel@tonic-gate frag_disp(total); 245*7c478bd9Sstevel@tonic-gate #endif /* FRAG_DEBUG */ 246*7c478bd9Sstevel@tonic-gate 247*7c478bd9Sstevel@tonic-gate return (total == actual); 248*7c478bd9Sstevel@tonic-gate } 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate /* 251*7c478bd9Sstevel@tonic-gate * Load the assembled fragments into igp. Returns 0 for success, nonzero 252*7c478bd9Sstevel@tonic-gate * otherwise. 253*7c478bd9Sstevel@tonic-gate */ 254*7c478bd9Sstevel@tonic-gate static int 255*7c478bd9Sstevel@tonic-gate frag_load(struct inetgram *igp) 256*7c478bd9Sstevel@tonic-gate { 257*7c478bd9Sstevel@tonic-gate int i; 258*7c478bd9Sstevel@tonic-gate int16_t len; 259*7c478bd9Sstevel@tonic-gate uint_t total_len; 260*7c478bd9Sstevel@tonic-gate boolean_t first_frag = B_FALSE; 261*7c478bd9Sstevel@tonic-gate mblk_t *mp; 262*7c478bd9Sstevel@tonic-gate struct ip *iph; 263*7c478bd9Sstevel@tonic-gate int first_iph_len; 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate if (fragments == 0) 266*7c478bd9Sstevel@tonic-gate return (ENOENT); 267*7c478bd9Sstevel@tonic-gate 268*7c478bd9Sstevel@tonic-gate mp = igp->igm_mp; 269*7c478bd9Sstevel@tonic-gate /* Get the IP header length of the first fragment. */ 270*7c478bd9Sstevel@tonic-gate i = frag_first(); 271*7c478bd9Sstevel@tonic-gate assert(i >= 0); 272*7c478bd9Sstevel@tonic-gate first_iph_len = fragment[i].iphlen; 273*7c478bd9Sstevel@tonic-gate for (i = 0, len = 0, total_len = 0; i < FRAG_MAX; i++) { 274*7c478bd9Sstevel@tonic-gate if (fragment[i].mp != NULL) { 275*7c478bd9Sstevel@tonic-gate /* 276*7c478bd9Sstevel@tonic-gate * Copy just the data (omit the ip header of all 277*7c478bd9Sstevel@tonic-gate * fragments except the first one which contains 278*7c478bd9Sstevel@tonic-gate * all the info...) 279*7c478bd9Sstevel@tonic-gate */ 280*7c478bd9Sstevel@tonic-gate if (fragment[i].offset == 0) { 281*7c478bd9Sstevel@tonic-gate len = fragment[i].iplen; 282*7c478bd9Sstevel@tonic-gate first_frag = B_TRUE; 283*7c478bd9Sstevel@tonic-gate } else { 284*7c478bd9Sstevel@tonic-gate len = fragment[i].iplen - fragment[i].iphlen; 285*7c478bd9Sstevel@tonic-gate } 286*7c478bd9Sstevel@tonic-gate total_len += len; 287*7c478bd9Sstevel@tonic-gate if (total_len > mp->b_size) 288*7c478bd9Sstevel@tonic-gate return (E2BIG); 289*7c478bd9Sstevel@tonic-gate if (first_frag) { 290*7c478bd9Sstevel@tonic-gate bcopy((caddr_t)(fragment[i].mp->b_rptr), 291*7c478bd9Sstevel@tonic-gate (caddr_t)mp->b_rptr, len); 292*7c478bd9Sstevel@tonic-gate first_frag = B_FALSE; 293*7c478bd9Sstevel@tonic-gate } else { 294*7c478bd9Sstevel@tonic-gate bcopy((caddr_t)(fragment[i].mp->b_rptr + 295*7c478bd9Sstevel@tonic-gate fragment[i].iphlen), 296*7c478bd9Sstevel@tonic-gate (caddr_t)(mp->b_rptr + first_iph_len + 297*7c478bd9Sstevel@tonic-gate fragment[i].offset), len); 298*7c478bd9Sstevel@tonic-gate } 299*7c478bd9Sstevel@tonic-gate mp->b_wptr += len; 300*7c478bd9Sstevel@tonic-gate } 301*7c478bd9Sstevel@tonic-gate } 302*7c478bd9Sstevel@tonic-gate /* Fix the total length in the IP header. */ 303*7c478bd9Sstevel@tonic-gate iph = (struct ip *)mp->b_rptr; 304*7c478bd9Sstevel@tonic-gate iph->ip_len = htons(total_len); 305*7c478bd9Sstevel@tonic-gate return (0); 306*7c478bd9Sstevel@tonic-gate } 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate /* 309*7c478bd9Sstevel@tonic-gate * Locate a routing table entry based upon arguments. IP addresses expected 310*7c478bd9Sstevel@tonic-gate * in network order. Returns index for success, -1 if entry not found. 311*7c478bd9Sstevel@tonic-gate */ 312*7c478bd9Sstevel@tonic-gate static int 313*7c478bd9Sstevel@tonic-gate find_route(uint8_t *flagp, struct in_addr *destp, struct in_addr *gatewayp) 314*7c478bd9Sstevel@tonic-gate { 315*7c478bd9Sstevel@tonic-gate int i, table_entry = -1; 316*7c478bd9Sstevel@tonic-gate 317*7c478bd9Sstevel@tonic-gate for (i = 0; table_entry == -1 && i < IPV4_ROUTE_TABLE_SIZE; i++) { 318*7c478bd9Sstevel@tonic-gate if (flagp != NULL) { 319*7c478bd9Sstevel@tonic-gate if (*flagp & table[i].flag) 320*7c478bd9Sstevel@tonic-gate table_entry = i; 321*7c478bd9Sstevel@tonic-gate } 322*7c478bd9Sstevel@tonic-gate if (destp != NULL) { 323*7c478bd9Sstevel@tonic-gate if (destp->s_addr == table[i].dest.s_addr) 324*7c478bd9Sstevel@tonic-gate table_entry = i; 325*7c478bd9Sstevel@tonic-gate else 326*7c478bd9Sstevel@tonic-gate table_entry = -1; 327*7c478bd9Sstevel@tonic-gate } 328*7c478bd9Sstevel@tonic-gate if (gatewayp != NULL) { 329*7c478bd9Sstevel@tonic-gate if (gatewayp->s_addr == table[i].gateway.s_addr) 330*7c478bd9Sstevel@tonic-gate table_entry = i; 331*7c478bd9Sstevel@tonic-gate else 332*7c478bd9Sstevel@tonic-gate table_entry = -1; 333*7c478bd9Sstevel@tonic-gate } 334*7c478bd9Sstevel@tonic-gate } 335*7c478bd9Sstevel@tonic-gate return (table_entry); 336*7c478bd9Sstevel@tonic-gate } 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate /* 339*7c478bd9Sstevel@tonic-gate * ADD or DEL a routing table entry. Returns 0 for success, -1 and errno 340*7c478bd9Sstevel@tonic-gate * otherwise. IP addresses are expected in network order. 341*7c478bd9Sstevel@tonic-gate */ 342*7c478bd9Sstevel@tonic-gate int 343*7c478bd9Sstevel@tonic-gate ipv4_route(int cmd, uint8_t flag, struct in_addr *destp, 344*7c478bd9Sstevel@tonic-gate struct in_addr *gatewayp) 345*7c478bd9Sstevel@tonic-gate { 346*7c478bd9Sstevel@tonic-gate static int routing_table_initialized; 347*7c478bd9Sstevel@tonic-gate int index; 348*7c478bd9Sstevel@tonic-gate uint8_t tmp_flag; 349*7c478bd9Sstevel@tonic-gate 350*7c478bd9Sstevel@tonic-gate if (gatewayp == NULL) { 351*7c478bd9Sstevel@tonic-gate errno = EINVAL; 352*7c478bd9Sstevel@tonic-gate return (-1); 353*7c478bd9Sstevel@tonic-gate } 354*7c478bd9Sstevel@tonic-gate 355*7c478bd9Sstevel@tonic-gate /* initialize routing table */ 356*7c478bd9Sstevel@tonic-gate if (routing_table_initialized == 0) { 357*7c478bd9Sstevel@tonic-gate for (index = 0; index < IPV4_ROUTE_TABLE_SIZE; index++) 358*7c478bd9Sstevel@tonic-gate table[index].flag = RT_UNUSED; 359*7c478bd9Sstevel@tonic-gate routing_table_initialized = 1; 360*7c478bd9Sstevel@tonic-gate } 361*7c478bd9Sstevel@tonic-gate 362*7c478bd9Sstevel@tonic-gate switch (cmd) { 363*7c478bd9Sstevel@tonic-gate case IPV4_ADD_ROUTE: 364*7c478bd9Sstevel@tonic-gate tmp_flag = (uint8_t)RT_UNUSED; 365*7c478bd9Sstevel@tonic-gate if ((index = find_route(&tmp_flag, NULL, NULL)) == -1) { 366*7c478bd9Sstevel@tonic-gate dprintf("ipv4_route: routing table full.\n"); 367*7c478bd9Sstevel@tonic-gate errno = ENOSPC; 368*7c478bd9Sstevel@tonic-gate return (-1); 369*7c478bd9Sstevel@tonic-gate } 370*7c478bd9Sstevel@tonic-gate table[index].flag = flag; 371*7c478bd9Sstevel@tonic-gate if (destp != NULL) 372*7c478bd9Sstevel@tonic-gate table[index].dest.s_addr = destp->s_addr; 373*7c478bd9Sstevel@tonic-gate else 374*7c478bd9Sstevel@tonic-gate table[index].dest.s_addr = htonl(INADDR_ANY); 375*7c478bd9Sstevel@tonic-gate table[index].gateway.s_addr = gatewayp->s_addr; 376*7c478bd9Sstevel@tonic-gate break; 377*7c478bd9Sstevel@tonic-gate case IPV4_BAD_ROUTE: 378*7c478bd9Sstevel@tonic-gate /* FALLTHRU */ 379*7c478bd9Sstevel@tonic-gate case IPV4_DEL_ROUTE: 380*7c478bd9Sstevel@tonic-gate if ((index = find_route(&flag, destp, gatewayp)) == -1) { 381*7c478bd9Sstevel@tonic-gate dprintf("ipv4_route: No such routing entry.\n"); 382*7c478bd9Sstevel@tonic-gate errno = ENOENT; 383*7c478bd9Sstevel@tonic-gate return (-1); 384*7c478bd9Sstevel@tonic-gate } 385*7c478bd9Sstevel@tonic-gate if (cmd == IPV4_DEL_ROUTE) { 386*7c478bd9Sstevel@tonic-gate table[index].flag = RT_UNUSED; 387*7c478bd9Sstevel@tonic-gate table[index].dest.s_addr = htonl(INADDR_ANY); 388*7c478bd9Sstevel@tonic-gate table[index].gateway.s_addr = htonl(INADDR_ANY); 389*7c478bd9Sstevel@tonic-gate } else 390*7c478bd9Sstevel@tonic-gate table[index].flag = RT_NG; 391*7c478bd9Sstevel@tonic-gate default: 392*7c478bd9Sstevel@tonic-gate errno = EINVAL; 393*7c478bd9Sstevel@tonic-gate return (-1); 394*7c478bd9Sstevel@tonic-gate } 395*7c478bd9Sstevel@tonic-gate return (0); 396*7c478bd9Sstevel@tonic-gate } 397*7c478bd9Sstevel@tonic-gate 398*7c478bd9Sstevel@tonic-gate /* 399*7c478bd9Sstevel@tonic-gate * Return gateway to destination. Returns gateway IP address in network order 400*7c478bd9Sstevel@tonic-gate * for success, NULL if no route to destination exists. 401*7c478bd9Sstevel@tonic-gate */ 402*7c478bd9Sstevel@tonic-gate struct in_addr * 403*7c478bd9Sstevel@tonic-gate ipv4_get_route(uint8_t flag, struct in_addr *destp, struct in_addr *gatewayp) 404*7c478bd9Sstevel@tonic-gate { 405*7c478bd9Sstevel@tonic-gate int index; 406*7c478bd9Sstevel@tonic-gate if ((index = find_route(&flag, destp, gatewayp)) == -1) 407*7c478bd9Sstevel@tonic-gate return (NULL); 408*7c478bd9Sstevel@tonic-gate return (&table[index].gateway); 409*7c478bd9Sstevel@tonic-gate } 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate /* 412*7c478bd9Sstevel@tonic-gate * Initialize the IPv4 generic parts of the socket, as well as the routing 413*7c478bd9Sstevel@tonic-gate * table. 414*7c478bd9Sstevel@tonic-gate */ 415*7c478bd9Sstevel@tonic-gate void 416*7c478bd9Sstevel@tonic-gate ipv4_socket_init(struct inetboot_socket *isp) 417*7c478bd9Sstevel@tonic-gate { 418*7c478bd9Sstevel@tonic-gate isp->input[NETWORK_LVL] = ipv4_input; 419*7c478bd9Sstevel@tonic-gate isp->output[NETWORK_LVL] = ipv4_output; 420*7c478bd9Sstevel@tonic-gate isp->close[NETWORK_LVL] = NULL; 421*7c478bd9Sstevel@tonic-gate isp->headerlen[NETWORK_LVL] = ipv4_header_len; 422*7c478bd9Sstevel@tonic-gate } 423*7c478bd9Sstevel@tonic-gate 424*7c478bd9Sstevel@tonic-gate /* 425*7c478bd9Sstevel@tonic-gate * Initialize a raw ipv4 socket. 426*7c478bd9Sstevel@tonic-gate */ 427*7c478bd9Sstevel@tonic-gate void 428*7c478bd9Sstevel@tonic-gate ipv4_raw_socket(struct inetboot_socket *isp, uint8_t proto) 429*7c478bd9Sstevel@tonic-gate { 430*7c478bd9Sstevel@tonic-gate isp->type = INETBOOT_RAW; 431*7c478bd9Sstevel@tonic-gate if (proto == 0) 432*7c478bd9Sstevel@tonic-gate isp->proto = IPPROTO_IP; 433*7c478bd9Sstevel@tonic-gate else 434*7c478bd9Sstevel@tonic-gate isp->proto = proto; 435*7c478bd9Sstevel@tonic-gate isp->input[TRANSPORT_LVL] = NULL; 436*7c478bd9Sstevel@tonic-gate isp->output[TRANSPORT_LVL] = NULL; 437*7c478bd9Sstevel@tonic-gate isp->headerlen[TRANSPORT_LVL] = NULL; 438*7c478bd9Sstevel@tonic-gate isp->ports = NULL; 439*7c478bd9Sstevel@tonic-gate } 440*7c478bd9Sstevel@tonic-gate 441*7c478bd9Sstevel@tonic-gate /* 442*7c478bd9Sstevel@tonic-gate * Return the size of an IPv4 header (no options) 443*7c478bd9Sstevel@tonic-gate */ 444*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 445*7c478bd9Sstevel@tonic-gate int 446*7c478bd9Sstevel@tonic-gate ipv4_header_len(struct inetgram *igm) 447*7c478bd9Sstevel@tonic-gate { 448*7c478bd9Sstevel@tonic-gate return (sizeof (struct ip)); 449*7c478bd9Sstevel@tonic-gate } 450*7c478bd9Sstevel@tonic-gate 451*7c478bd9Sstevel@tonic-gate /* 452*7c478bd9Sstevel@tonic-gate * Set our source address. 453*7c478bd9Sstevel@tonic-gate * Argument is assumed to be host order. 454*7c478bd9Sstevel@tonic-gate */ 455*7c478bd9Sstevel@tonic-gate void 456*7c478bd9Sstevel@tonic-gate ipv4_setipaddr(struct in_addr *ip) 457*7c478bd9Sstevel@tonic-gate { 458*7c478bd9Sstevel@tonic-gate myip.s_addr = htonl(ip->s_addr); 459*7c478bd9Sstevel@tonic-gate } 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate /* 462*7c478bd9Sstevel@tonic-gate * Returns our current source address in host order. 463*7c478bd9Sstevel@tonic-gate */ 464*7c478bd9Sstevel@tonic-gate void 465*7c478bd9Sstevel@tonic-gate ipv4_getipaddr(struct in_addr *ip) 466*7c478bd9Sstevel@tonic-gate { 467*7c478bd9Sstevel@tonic-gate ip->s_addr = ntohl(myip.s_addr); 468*7c478bd9Sstevel@tonic-gate } 469*7c478bd9Sstevel@tonic-gate 470*7c478bd9Sstevel@tonic-gate /* 471*7c478bd9Sstevel@tonic-gate * Set our netmask. 472*7c478bd9Sstevel@tonic-gate * Argument is assumed to be host order. 473*7c478bd9Sstevel@tonic-gate */ 474*7c478bd9Sstevel@tonic-gate void 475*7c478bd9Sstevel@tonic-gate ipv4_setnetmask(struct in_addr *ip) 476*7c478bd9Sstevel@tonic-gate { 477*7c478bd9Sstevel@tonic-gate netmask_set = B_TRUE; 478*7c478bd9Sstevel@tonic-gate netmask.s_addr = htonl(ip->s_addr); 479*7c478bd9Sstevel@tonic-gate mynet.s_addr = netmask.s_addr & myip.s_addr; /* implicit */ 480*7c478bd9Sstevel@tonic-gate } 481*7c478bd9Sstevel@tonic-gate 482*7c478bd9Sstevel@tonic-gate void 483*7c478bd9Sstevel@tonic-gate ipv4_getnetid(struct in_addr *my_netid) 484*7c478bd9Sstevel@tonic-gate { 485*7c478bd9Sstevel@tonic-gate struct in_addr my_netmask; 486*7c478bd9Sstevel@tonic-gate if (mynet.s_addr != 0) 487*7c478bd9Sstevel@tonic-gate my_netid->s_addr = ntohl(mynet.s_addr); 488*7c478bd9Sstevel@tonic-gate else { 489*7c478bd9Sstevel@tonic-gate ipv4_getnetmask(&my_netmask); 490*7c478bd9Sstevel@tonic-gate my_netid->s_addr = my_netmask.s_addr & ntohl(myip.s_addr); 491*7c478bd9Sstevel@tonic-gate } 492*7c478bd9Sstevel@tonic-gate } 493*7c478bd9Sstevel@tonic-gate 494*7c478bd9Sstevel@tonic-gate /* 495*7c478bd9Sstevel@tonic-gate * Returns our current netmask in host order. 496*7c478bd9Sstevel@tonic-gate * Neither OBP nor the standalone DHCP client mandate 497*7c478bd9Sstevel@tonic-gate * that the netmask be specified, so in the absence of 498*7c478bd9Sstevel@tonic-gate * a netmask, we attempt to derive it using class-based 499*7c478bd9Sstevel@tonic-gate * heuristics. 500*7c478bd9Sstevel@tonic-gate */ 501*7c478bd9Sstevel@tonic-gate void 502*7c478bd9Sstevel@tonic-gate ipv4_getnetmask(struct in_addr *ip) 503*7c478bd9Sstevel@tonic-gate { 504*7c478bd9Sstevel@tonic-gate if (netmask_set || (myip.s_addr == 0)) 505*7c478bd9Sstevel@tonic-gate ip->s_addr = ntohl(netmask.s_addr); 506*7c478bd9Sstevel@tonic-gate else { 507*7c478bd9Sstevel@tonic-gate /* base the netmask on our IP address */ 508*7c478bd9Sstevel@tonic-gate if (IN_CLASSA(ntohl(myip.s_addr))) 509*7c478bd9Sstevel@tonic-gate ip->s_addr = ntohl(IN_CLASSA_NET); 510*7c478bd9Sstevel@tonic-gate else if (IN_CLASSB(ntohl(myip.s_addr))) 511*7c478bd9Sstevel@tonic-gate ip->s_addr = ntohl(IN_CLASSB_NET); 512*7c478bd9Sstevel@tonic-gate else 513*7c478bd9Sstevel@tonic-gate ip->s_addr = ntohl(IN_CLASSC_NET); 514*7c478bd9Sstevel@tonic-gate } 515*7c478bd9Sstevel@tonic-gate } 516*7c478bd9Sstevel@tonic-gate 517*7c478bd9Sstevel@tonic-gate /* 518*7c478bd9Sstevel@tonic-gate * Set our default router. 519*7c478bd9Sstevel@tonic-gate * Argument is assumed to be host order, and *MUST* be on the same network 520*7c478bd9Sstevel@tonic-gate * as our source IP address. 521*7c478bd9Sstevel@tonic-gate */ 522*7c478bd9Sstevel@tonic-gate void 523*7c478bd9Sstevel@tonic-gate ipv4_setdefaultrouter(struct in_addr *ip) 524*7c478bd9Sstevel@tonic-gate { 525*7c478bd9Sstevel@tonic-gate defaultrouter.s_addr = htonl(ip->s_addr); 526*7c478bd9Sstevel@tonic-gate } 527*7c478bd9Sstevel@tonic-gate 528*7c478bd9Sstevel@tonic-gate /* 529*7c478bd9Sstevel@tonic-gate * Returns our current default router in host order. 530*7c478bd9Sstevel@tonic-gate */ 531*7c478bd9Sstevel@tonic-gate void 532*7c478bd9Sstevel@tonic-gate ipv4_getdefaultrouter(struct in_addr *ip) 533*7c478bd9Sstevel@tonic-gate { 534*7c478bd9Sstevel@tonic-gate ip->s_addr = ntohl(defaultrouter.s_addr); 535*7c478bd9Sstevel@tonic-gate } 536*7c478bd9Sstevel@tonic-gate 537*7c478bd9Sstevel@tonic-gate /* 538*7c478bd9Sstevel@tonic-gate * Toggle promiscuous flag. If set, client disregards destination IP 539*7c478bd9Sstevel@tonic-gate * address. Otherwise, only limited broadcast, network broadcast, and 540*7c478bd9Sstevel@tonic-gate * unicast traffic get through. Returns previous setting. 541*7c478bd9Sstevel@tonic-gate */ 542*7c478bd9Sstevel@tonic-gate int 543*7c478bd9Sstevel@tonic-gate ipv4_setpromiscuous(int toggle) 544*7c478bd9Sstevel@tonic-gate { 545*7c478bd9Sstevel@tonic-gate int old = promiscuous; 546*7c478bd9Sstevel@tonic-gate 547*7c478bd9Sstevel@tonic-gate promiscuous = toggle; 548*7c478bd9Sstevel@tonic-gate 549*7c478bd9Sstevel@tonic-gate return (old); 550*7c478bd9Sstevel@tonic-gate } 551*7c478bd9Sstevel@tonic-gate 552*7c478bd9Sstevel@tonic-gate /* 553*7c478bd9Sstevel@tonic-gate * Set IP TTL. 554*7c478bd9Sstevel@tonic-gate */ 555*7c478bd9Sstevel@tonic-gate void 556*7c478bd9Sstevel@tonic-gate ipv4_setmaxttl(uint8_t cttl) 557*7c478bd9Sstevel@tonic-gate { 558*7c478bd9Sstevel@tonic-gate ttl = cttl; 559*7c478bd9Sstevel@tonic-gate } 560*7c478bd9Sstevel@tonic-gate 561*7c478bd9Sstevel@tonic-gate /* 562*7c478bd9Sstevel@tonic-gate * Convert an ipv4 address to dotted notation. 563*7c478bd9Sstevel@tonic-gate * Returns ptr to statically allocated buffer containing dotted string. 564*7c478bd9Sstevel@tonic-gate */ 565*7c478bd9Sstevel@tonic-gate char * 566*7c478bd9Sstevel@tonic-gate inet_ntoa(struct in_addr ip) 567*7c478bd9Sstevel@tonic-gate { 568*7c478bd9Sstevel@tonic-gate uint8_t *p; 569*7c478bd9Sstevel@tonic-gate static char ipaddr[16]; 570*7c478bd9Sstevel@tonic-gate 571*7c478bd9Sstevel@tonic-gate p = (uint8_t *)&ip.s_addr; 572*7c478bd9Sstevel@tonic-gate (void) sprintf(ipaddr, "%u.%u.%u.%u", p[0], p[1], p[2], p[3]); 573*7c478bd9Sstevel@tonic-gate return (ipaddr); 574*7c478bd9Sstevel@tonic-gate } 575*7c478bd9Sstevel@tonic-gate 576*7c478bd9Sstevel@tonic-gate /* 577*7c478bd9Sstevel@tonic-gate * Construct a transport datagram from a series of IP fragments (igp == NULL) 578*7c478bd9Sstevel@tonic-gate * or from a single IP datagram (igp != NULL). Return the address of the 579*7c478bd9Sstevel@tonic-gate * contructed transport datagram. 580*7c478bd9Sstevel@tonic-gate */ 581*7c478bd9Sstevel@tonic-gate struct inetgram * 582*7c478bd9Sstevel@tonic-gate make_trans_datagram(int index, struct inetgram *igp, struct in_addr ipsrc, 583*7c478bd9Sstevel@tonic-gate struct in_addr ipdst, uint16_t iphlen) 584*7c478bd9Sstevel@tonic-gate { 585*7c478bd9Sstevel@tonic-gate uint16_t trans_len, *transp, new_len; 586*7c478bd9Sstevel@tonic-gate int first_frag, last_frag; 587*7c478bd9Sstevel@tonic-gate boolean_t fragmented; 588*7c478bd9Sstevel@tonic-gate struct inetgram *ngp; 589*7c478bd9Sstevel@tonic-gate struct ip *iph; 590*7c478bd9Sstevel@tonic-gate 591*7c478bd9Sstevel@tonic-gate fragmented = (igp == NULL); 592*7c478bd9Sstevel@tonic-gate 593*7c478bd9Sstevel@tonic-gate ngp = (struct inetgram *)bkmem_zalloc(sizeof (struct inetgram)); 594*7c478bd9Sstevel@tonic-gate if (ngp == NULL) { 595*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 596*7c478bd9Sstevel@tonic-gate if (fragmented) 597*7c478bd9Sstevel@tonic-gate frag_flush(); 598*7c478bd9Sstevel@tonic-gate return (NULL); 599*7c478bd9Sstevel@tonic-gate } 600*7c478bd9Sstevel@tonic-gate 601*7c478bd9Sstevel@tonic-gate if (fragmented) { 602*7c478bd9Sstevel@tonic-gate last_frag = frag_last(); 603*7c478bd9Sstevel@tonic-gate trans_len = fragment[last_frag].offset + 604*7c478bd9Sstevel@tonic-gate fragment[last_frag].iplen - fragment[last_frag].iphlen; 605*7c478bd9Sstevel@tonic-gate first_frag = frag_first(); 606*7c478bd9Sstevel@tonic-gate /* 607*7c478bd9Sstevel@tonic-gate * The returned buffer contains the IP header of the 608*7c478bd9Sstevel@tonic-gate * first fragment. 609*7c478bd9Sstevel@tonic-gate */ 610*7c478bd9Sstevel@tonic-gate trans_len += fragment[first_frag].iphlen; 611*7c478bd9Sstevel@tonic-gate transp = (uint16_t *)(fragment[first_frag].mp->b_rptr + 612*7c478bd9Sstevel@tonic-gate fragment[first_frag].iphlen); 613*7c478bd9Sstevel@tonic-gate } else { 614*7c478bd9Sstevel@tonic-gate /* 615*7c478bd9Sstevel@tonic-gate * Note that igm_len may not be the real length of an 616*7c478bd9Sstevel@tonic-gate * IP packet because some network interface, such as 617*7c478bd9Sstevel@tonic-gate * Ethernet, as a minimum frame size. So we should not 618*7c478bd9Sstevel@tonic-gate * use the interface frame size to determine the 619*7c478bd9Sstevel@tonic-gate * length of an IP packet. We should use the IP 620*7c478bd9Sstevel@tonic-gate * length field in the IP header. 621*7c478bd9Sstevel@tonic-gate */ 622*7c478bd9Sstevel@tonic-gate iph = (struct ip *)igp->igm_mp->b_rptr; 623*7c478bd9Sstevel@tonic-gate trans_len = ntohs(iph->ip_len); 624*7c478bd9Sstevel@tonic-gate transp = (uint16_t *)(igp->igm_mp->b_rptr + iphlen); 625*7c478bd9Sstevel@tonic-gate } 626*7c478bd9Sstevel@tonic-gate 627*7c478bd9Sstevel@tonic-gate ngp->igm_saddr.sin_addr.s_addr = ipsrc.s_addr; 628*7c478bd9Sstevel@tonic-gate ngp->igm_saddr.sin_port = sockets[index].ports(transp, SOURCE); 629*7c478bd9Sstevel@tonic-gate ngp->igm_target.s_addr = ipdst.s_addr; 630*7c478bd9Sstevel@tonic-gate ngp->igm_level = TRANSPORT_LVL; 631*7c478bd9Sstevel@tonic-gate 632*7c478bd9Sstevel@tonic-gate /* 633*7c478bd9Sstevel@tonic-gate * Align to 16bit value. Checksum code may require an extra byte 634*7c478bd9Sstevel@tonic-gate * for padding. 635*7c478bd9Sstevel@tonic-gate */ 636*7c478bd9Sstevel@tonic-gate new_len = ((trans_len + sizeof (int16_t) - 1) & 637*7c478bd9Sstevel@tonic-gate ~(sizeof (int16_t) - 1)); 638*7c478bd9Sstevel@tonic-gate if ((ngp->igm_mp = allocb(new_len, 0)) == NULL) { 639*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 640*7c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)ngp, sizeof (struct inetgram)); 641*7c478bd9Sstevel@tonic-gate if (fragmented) 642*7c478bd9Sstevel@tonic-gate frag_flush(); 643*7c478bd9Sstevel@tonic-gate return (NULL); 644*7c478bd9Sstevel@tonic-gate } 645*7c478bd9Sstevel@tonic-gate 646*7c478bd9Sstevel@tonic-gate if (fragmented) { 647*7c478bd9Sstevel@tonic-gate if (frag_load(ngp) != 0) { 648*7c478bd9Sstevel@tonic-gate freeb(ngp->igm_mp); 649*7c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)ngp, sizeof (struct inetgram)); 650*7c478bd9Sstevel@tonic-gate frag_flush(); 651*7c478bd9Sstevel@tonic-gate return (NULL); 652*7c478bd9Sstevel@tonic-gate } 653*7c478bd9Sstevel@tonic-gate frag_flush(); 654*7c478bd9Sstevel@tonic-gate } else { 655*7c478bd9Sstevel@tonic-gate bcopy((caddr_t)(igp->igm_mp->b_rptr), 656*7c478bd9Sstevel@tonic-gate (caddr_t)ngp->igm_mp->b_rptr, trans_len); 657*7c478bd9Sstevel@tonic-gate ngp->igm_mp->b_wptr += trans_len; 658*7c478bd9Sstevel@tonic-gate } 659*7c478bd9Sstevel@tonic-gate return (ngp); 660*7c478bd9Sstevel@tonic-gate } 661*7c478bd9Sstevel@tonic-gate 662*7c478bd9Sstevel@tonic-gate /* 663*7c478bd9Sstevel@tonic-gate * ipv4_input: Pull in IPv4 datagrams addressed to us. Handle IP fragmentation 664*7c478bd9Sstevel@tonic-gate * (fragments received in any order) and ICMP at this level. 665*7c478bd9Sstevel@tonic-gate * 666*7c478bd9Sstevel@tonic-gate * Note that because our network is serviced by polling when we expect 667*7c478bd9Sstevel@tonic-gate * something (upon a referenced socket), we don't go through the work of 668*7c478bd9Sstevel@tonic-gate * locating the appropriate socket a datagram is destined for. We'll only 669*7c478bd9Sstevel@tonic-gate * accept data for the referenced socket. This means we don't have 670*7c478bd9Sstevel@tonic-gate * asynchronous networking, but since we can't service the net using an 671*7c478bd9Sstevel@tonic-gate * interrupt handler, it doesn't do us any good to try to service datagrams 672*7c478bd9Sstevel@tonic-gate * destined for sockets other than the referenced one. Data is handled in 673*7c478bd9Sstevel@tonic-gate * a fifo manner. 674*7c478bd9Sstevel@tonic-gate * 675*7c478bd9Sstevel@tonic-gate * The mac layer will grab all frames for us. If we find we don't have all 676*7c478bd9Sstevel@tonic-gate * the necessary fragments to reassemble the datagram, we'll call the mac 677*7c478bd9Sstevel@tonic-gate * layer again for FRAG_ATTEMPTS to see if it has any more frames. 678*7c478bd9Sstevel@tonic-gate * 679*7c478bd9Sstevel@tonic-gate * Supported protocols: IPPROTO_IP, IPPROTO_ICMP, IPPROTO_UDP. 680*7c478bd9Sstevel@tonic-gate * 681*7c478bd9Sstevel@tonic-gate * Returns: number of NETWORK_LVL datagrams placed on socket , -1 if error 682*7c478bd9Sstevel@tonic-gate * occurred. 683*7c478bd9Sstevel@tonic-gate * 684*7c478bd9Sstevel@tonic-gate * Note: errno is set to ETIMEDOUT if fragment reassembly fails. 685*7c478bd9Sstevel@tonic-gate */ 686*7c478bd9Sstevel@tonic-gate int 687*7c478bd9Sstevel@tonic-gate ipv4_input(int index) 688*7c478bd9Sstevel@tonic-gate { 689*7c478bd9Sstevel@tonic-gate int datagrams = 0; 690*7c478bd9Sstevel@tonic-gate int frag_stat, input_attempts = 0; 691*7c478bd9Sstevel@tonic-gate uint16_t iphlen, iplen, ip_id; 692*7c478bd9Sstevel@tonic-gate int16_t curr_off; 693*7c478bd9Sstevel@tonic-gate struct ip *iphp; 694*7c478bd9Sstevel@tonic-gate struct inetgram *igp, *newgp = NULL, *ipv4_listp = NULL; 695*7c478bd9Sstevel@tonic-gate struct in_addr ipdst, ipsrc; 696*7c478bd9Sstevel@tonic-gate mblk_t *mp; 697*7c478bd9Sstevel@tonic-gate enum SockType type; 698*7c478bd9Sstevel@tonic-gate 699*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 700*7c478bd9Sstevel@tonic-gate printf("ipv4_input(%d): start ######################################\n", 701*7c478bd9Sstevel@tonic-gate index); 702*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 703*7c478bd9Sstevel@tonic-gate 704*7c478bd9Sstevel@tonic-gate frag_flush(); 705*7c478bd9Sstevel@tonic-gate 706*7c478bd9Sstevel@tonic-gate ipv4_try_again: 707*7c478bd9Sstevel@tonic-gate 708*7c478bd9Sstevel@tonic-gate while ((igp = sockets[index].inq) != NULL) { 709*7c478bd9Sstevel@tonic-gate if (igp->igm_level != NETWORK_LVL) { 710*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 711*7c478bd9Sstevel@tonic-gate printf("ipv4_input(%d): unexpected frame type: %d\n", 712*7c478bd9Sstevel@tonic-gate index, igp->igm_level); 713*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 714*7c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE); 715*7c478bd9Sstevel@tonic-gate continue; 716*7c478bd9Sstevel@tonic-gate } 717*7c478bd9Sstevel@tonic-gate iphp = (struct ip *)igp->igm_mp->b_rptr; 718*7c478bd9Sstevel@tonic-gate if (iphp->ip_v != IPVERSION) { 719*7c478bd9Sstevel@tonic-gate dprintf("ipv4_input(%d): IPv%d datagram discarded\n", 720*7c478bd9Sstevel@tonic-gate index, iphp->ip_v); 721*7c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE); 722*7c478bd9Sstevel@tonic-gate continue; 723*7c478bd9Sstevel@tonic-gate } 724*7c478bd9Sstevel@tonic-gate iphlen = iphp->ip_hl << 2; 725*7c478bd9Sstevel@tonic-gate if (iphlen < sizeof (struct ip)) { 726*7c478bd9Sstevel@tonic-gate dprintf("ipv4_input(%d): IP msg too short (%d < %u)\n", 727*7c478bd9Sstevel@tonic-gate index, iphlen, (uint_t)sizeof (struct ip)); 728*7c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE); 729*7c478bd9Sstevel@tonic-gate continue; 730*7c478bd9Sstevel@tonic-gate } 731*7c478bd9Sstevel@tonic-gate iplen = ntohs(iphp->ip_len); 732*7c478bd9Sstevel@tonic-gate if (iplen > msgdsize(igp->igm_mp)) { 733*7c478bd9Sstevel@tonic-gate dprintf("ipv4_input(%d): IP len/buffer mismatch " 734*7c478bd9Sstevel@tonic-gate "(%d > %lu)\n", index, iplen, igp->igm_mp->b_size); 735*7c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE); 736*7c478bd9Sstevel@tonic-gate continue; 737*7c478bd9Sstevel@tonic-gate } 738*7c478bd9Sstevel@tonic-gate 739*7c478bd9Sstevel@tonic-gate bcopy((caddr_t)&(iphp->ip_dst), (caddr_t)&ipdst, 740*7c478bd9Sstevel@tonic-gate sizeof (ipdst)); 741*7c478bd9Sstevel@tonic-gate bcopy((caddr_t)&(iphp->ip_src), (caddr_t)&ipsrc, 742*7c478bd9Sstevel@tonic-gate sizeof (ipsrc)); 743*7c478bd9Sstevel@tonic-gate 744*7c478bd9Sstevel@tonic-gate /* igp->igm_mp->b_datap is guaranteed to be 64 bit aligned] */ 745*7c478bd9Sstevel@tonic-gate if (ipv4cksum((uint16_t *)iphp, iphlen) != 0) { 746*7c478bd9Sstevel@tonic-gate dprintf("ipv4_input(%d): Bad IP header checksum " 747*7c478bd9Sstevel@tonic-gate "(to %s)\n", index, inet_ntoa(ipdst)); 748*7c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE); 749*7c478bd9Sstevel@tonic-gate continue; 750*7c478bd9Sstevel@tonic-gate } 751*7c478bd9Sstevel@tonic-gate 752*7c478bd9Sstevel@tonic-gate if (!promiscuous) { 753*7c478bd9Sstevel@tonic-gate /* validate destination address */ 754*7c478bd9Sstevel@tonic-gate if (ipdst.s_addr != htonl(INADDR_BROADCAST) && 755*7c478bd9Sstevel@tonic-gate ipdst.s_addr != (mynet.s_addr | ~netmask.s_addr) && 756*7c478bd9Sstevel@tonic-gate ipdst.s_addr != myip.s_addr) { 757*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 758*7c478bd9Sstevel@tonic-gate printf("ipv4_input(%d): msg to %s discarded.\n", 759*7c478bd9Sstevel@tonic-gate index, inet_ntoa(ipdst)); 760*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 761*7c478bd9Sstevel@tonic-gate /* not ours */ 762*7c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE); 763*7c478bd9Sstevel@tonic-gate continue; 764*7c478bd9Sstevel@tonic-gate } 765*7c478bd9Sstevel@tonic-gate } 766*7c478bd9Sstevel@tonic-gate 767*7c478bd9Sstevel@tonic-gate /* Intercept ICMP first */ 768*7c478bd9Sstevel@tonic-gate if (!promiscuous && (iphp->ip_p == IPPROTO_ICMP)) { 769*7c478bd9Sstevel@tonic-gate icmp4(igp, iphp, iphlen, ipsrc); 770*7c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE); 771*7c478bd9Sstevel@tonic-gate continue; 772*7c478bd9Sstevel@tonic-gate } 773*7c478bd9Sstevel@tonic-gate 774*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 775*7c478bd9Sstevel@tonic-gate printf("ipv4_input(%d): processing ID: 0x%x protocol %d " 776*7c478bd9Sstevel@tonic-gate "(0x%x) (0x%x,%d)\n", 777*7c478bd9Sstevel@tonic-gate index, ntohs(iphp->ip_id), iphp->ip_p, igp, igp->igm_mp, 778*7c478bd9Sstevel@tonic-gate igp->igm_mp->b_size); 779*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 780*7c478bd9Sstevel@tonic-gate type = sockets[index].type; 781*7c478bd9Sstevel@tonic-gate if (type == INETBOOT_RAW) { 782*7c478bd9Sstevel@tonic-gate /* No fragmentation - Just the raw packet. */ 783*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 784*7c478bd9Sstevel@tonic-gate printf("ipv4_input(%d): Raw packet.\n", index); 785*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 786*7c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, FALSE); 787*7c478bd9Sstevel@tonic-gate add_grams(&ipv4_listp, igp); 788*7c478bd9Sstevel@tonic-gate igp->igm_mp->b_rptr += iphlen; 789*7c478bd9Sstevel@tonic-gate igp->igm_mp->b_wptr = igp->igm_mp->b_rptr + iplen; 790*7c478bd9Sstevel@tonic-gate datagrams++; 791*7c478bd9Sstevel@tonic-gate continue; 792*7c478bd9Sstevel@tonic-gate } 793*7c478bd9Sstevel@tonic-gate 794*7c478bd9Sstevel@tonic-gate if ((type == INETBOOT_DGRAM && iphp->ip_p != IPPROTO_UDP) || 795*7c478bd9Sstevel@tonic-gate (type == INETBOOT_STREAM && iphp->ip_p != IPPROTO_TCP)) { 796*7c478bd9Sstevel@tonic-gate /* Wrong protocol. */ 797*7c478bd9Sstevel@tonic-gate dprintf("ipv4_input(%d): unexpected protocol: " 798*7c478bd9Sstevel@tonic-gate "%d for socket type %d\n", index, iphp->ip_p, type); 799*7c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE); 800*7c478bd9Sstevel@tonic-gate continue; 801*7c478bd9Sstevel@tonic-gate } 802*7c478bd9Sstevel@tonic-gate 803*7c478bd9Sstevel@tonic-gate /* 804*7c478bd9Sstevel@tonic-gate * The following code is common to both STREAM and DATAGRAM 805*7c478bd9Sstevel@tonic-gate * sockets. 806*7c478bd9Sstevel@tonic-gate */ 807*7c478bd9Sstevel@tonic-gate 808*7c478bd9Sstevel@tonic-gate /* 809*7c478bd9Sstevel@tonic-gate * Once we process the first fragment, we won't have 810*7c478bd9Sstevel@tonic-gate * the transport header, so we'll have to match on 811*7c478bd9Sstevel@tonic-gate * IP id. 812*7c478bd9Sstevel@tonic-gate */ 813*7c478bd9Sstevel@tonic-gate curr_off = ntohs(iphp->ip_off); 814*7c478bd9Sstevel@tonic-gate if ((curr_off & ~(IP_DF | IP_MF)) == 0) { 815*7c478bd9Sstevel@tonic-gate uint16_t *transp; 816*7c478bd9Sstevel@tonic-gate 817*7c478bd9Sstevel@tonic-gate /* Validate transport header. */ 818*7c478bd9Sstevel@tonic-gate mp = igp->igm_mp; 819*7c478bd9Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr - iphlen) < 820*7c478bd9Sstevel@tonic-gate sockets[index].headerlen[TRANSPORT_LVL](igp)) { 821*7c478bd9Sstevel@tonic-gate dprintf("ipv4_input(%d): datagram 0 " 822*7c478bd9Sstevel@tonic-gate "too small to hold transport header " 823*7c478bd9Sstevel@tonic-gate "(from %s)\n", index, inet_ntoa(ipsrc)); 824*7c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE); 825*7c478bd9Sstevel@tonic-gate continue; 826*7c478bd9Sstevel@tonic-gate } 827*7c478bd9Sstevel@tonic-gate 828*7c478bd9Sstevel@tonic-gate /* 829*7c478bd9Sstevel@tonic-gate * check alignment - transport elements are 16 830*7c478bd9Sstevel@tonic-gate * bit aligned.. 831*7c478bd9Sstevel@tonic-gate */ 832*7c478bd9Sstevel@tonic-gate transp = (uint16_t *)(mp->b_rptr + iphlen); 833*7c478bd9Sstevel@tonic-gate if ((uintptr_t)transp % sizeof (uint16_t)) { 834*7c478bd9Sstevel@tonic-gate dprintf("ipv4_input(%d): Transport " 835*7c478bd9Sstevel@tonic-gate "header is not 16-bit aligned " 836*7c478bd9Sstevel@tonic-gate "(0x%lx, from %s)\n", index, (long)transp, 837*7c478bd9Sstevel@tonic-gate inet_ntoa(ipsrc)); 838*7c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE); 839*7c478bd9Sstevel@tonic-gate continue; 840*7c478bd9Sstevel@tonic-gate } 841*7c478bd9Sstevel@tonic-gate 842*7c478bd9Sstevel@tonic-gate if (curr_off & IP_MF) { 843*7c478bd9Sstevel@tonic-gate /* fragment 0 of fragmented datagram */ 844*7c478bd9Sstevel@tonic-gate ip_id = ntohs(iphp->ip_id); 845*7c478bd9Sstevel@tonic-gate frag_stat = frag_add(curr_off, igp->igm_mp, 846*7c478bd9Sstevel@tonic-gate ip_id, iplen, iphlen, iphp->ip_p); 847*7c478bd9Sstevel@tonic-gate if (frag_stat != FRAG_SUCCESS) { 848*7c478bd9Sstevel@tonic-gate #ifdef FRAG_DEBUG 849*7c478bd9Sstevel@tonic-gate if (frag_stat == FRAG_DUP) { 850*7c478bd9Sstevel@tonic-gate printf("ipv4_input" 851*7c478bd9Sstevel@tonic-gate "(%d): Frag dup.\n", index); 852*7c478bd9Sstevel@tonic-gate } else { 853*7c478bd9Sstevel@tonic-gate printf("ipv4_input" 854*7c478bd9Sstevel@tonic-gate "(%d): too many " 855*7c478bd9Sstevel@tonic-gate "frags\n", index); 856*7c478bd9Sstevel@tonic-gate } 857*7c478bd9Sstevel@tonic-gate #endif /* FRAG_DEBUG */ 858*7c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, 859*7c478bd9Sstevel@tonic-gate igp, TRUE); 860*7c478bd9Sstevel@tonic-gate continue; 861*7c478bd9Sstevel@tonic-gate } 862*7c478bd9Sstevel@tonic-gate 863*7c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, FALSE); 864*7c478bd9Sstevel@tonic-gate /* keep the data, lose the inetgram */ 865*7c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)igp, 866*7c478bd9Sstevel@tonic-gate sizeof (struct inetgram)); 867*7c478bd9Sstevel@tonic-gate #ifdef FRAG_DEBUG 868*7c478bd9Sstevel@tonic-gate printf("ipv4_input(%d): Frag/Off/Id " 869*7c478bd9Sstevel@tonic-gate "(%d/%d/%x)\n", index, fragments, 870*7c478bd9Sstevel@tonic-gate IPV4_OFFSET(curr_off), ip_id); 871*7c478bd9Sstevel@tonic-gate #endif /* FRAG_DEBUG */ 872*7c478bd9Sstevel@tonic-gate } else { 873*7c478bd9Sstevel@tonic-gate /* Single, unfragmented datagram */ 874*7c478bd9Sstevel@tonic-gate newgp = make_trans_datagram(index, igp, 875*7c478bd9Sstevel@tonic-gate ipsrc, ipdst, iphlen); 876*7c478bd9Sstevel@tonic-gate if (newgp != NULL) { 877*7c478bd9Sstevel@tonic-gate add_grams(&ipv4_listp, newgp); 878*7c478bd9Sstevel@tonic-gate datagrams++; 879*7c478bd9Sstevel@tonic-gate } 880*7c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, 881*7c478bd9Sstevel@tonic-gate TRUE); 882*7c478bd9Sstevel@tonic-gate continue; 883*7c478bd9Sstevel@tonic-gate } 884*7c478bd9Sstevel@tonic-gate } else { 885*7c478bd9Sstevel@tonic-gate /* fragments other than 0 */ 886*7c478bd9Sstevel@tonic-gate frag_stat = frag_add(curr_off, igp->igm_mp, 887*7c478bd9Sstevel@tonic-gate ntohs(iphp->ip_id), iplen, iphlen, iphp->ip_p); 888*7c478bd9Sstevel@tonic-gate 889*7c478bd9Sstevel@tonic-gate if (frag_stat == FRAG_SUCCESS) { 890*7c478bd9Sstevel@tonic-gate #ifdef FRAG_DEBUG 891*7c478bd9Sstevel@tonic-gate printf("ipv4_input(%d): Frag(%d) " 892*7c478bd9Sstevel@tonic-gate "off(%d) id(%x)\n", index, 893*7c478bd9Sstevel@tonic-gate fragments, IPV4_OFFSET(curr_off), 894*7c478bd9Sstevel@tonic-gate ntohs(iphp->ip_id)); 895*7c478bd9Sstevel@tonic-gate #endif /* FRAG_DEBUG */ 896*7c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, FALSE); 897*7c478bd9Sstevel@tonic-gate /* keep the data, lose the inetgram */ 898*7c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)igp, 899*7c478bd9Sstevel@tonic-gate sizeof (struct inetgram)); 900*7c478bd9Sstevel@tonic-gate } else { 901*7c478bd9Sstevel@tonic-gate #ifdef FRAG_DEBUG 902*7c478bd9Sstevel@tonic-gate if (frag_stat == FRAG_DUP) 903*7c478bd9Sstevel@tonic-gate printf("ipv4_input(%d): Frag " 904*7c478bd9Sstevel@tonic-gate "dup.\n", index); 905*7c478bd9Sstevel@tonic-gate else { 906*7c478bd9Sstevel@tonic-gate printf("ipv4_input(%d): too " 907*7c478bd9Sstevel@tonic-gate "many frags\n", index); 908*7c478bd9Sstevel@tonic-gate } 909*7c478bd9Sstevel@tonic-gate #endif /* FRAG_DEBUG */ 910*7c478bd9Sstevel@tonic-gate del_gram(&sockets[index].inq, igp, TRUE); 911*7c478bd9Sstevel@tonic-gate continue; 912*7c478bd9Sstevel@tonic-gate } 913*7c478bd9Sstevel@tonic-gate } 914*7c478bd9Sstevel@tonic-gate 915*7c478bd9Sstevel@tonic-gate /* 916*7c478bd9Sstevel@tonic-gate * Determine if we have all of the fragments. 917*7c478bd9Sstevel@tonic-gate * 918*7c478bd9Sstevel@tonic-gate * NOTE: at this point, we've placed the data in the 919*7c478bd9Sstevel@tonic-gate * fragment table, and the inetgram (igp) has been 920*7c478bd9Sstevel@tonic-gate * deleted. 921*7c478bd9Sstevel@tonic-gate */ 922*7c478bd9Sstevel@tonic-gate if (!frag_chk()) 923*7c478bd9Sstevel@tonic-gate continue; 924*7c478bd9Sstevel@tonic-gate 925*7c478bd9Sstevel@tonic-gate newgp = make_trans_datagram(index, NULL, ipsrc, ipdst, iphlen); 926*7c478bd9Sstevel@tonic-gate if (newgp == NULL) 927*7c478bd9Sstevel@tonic-gate continue; 928*7c478bd9Sstevel@tonic-gate add_grams(&ipv4_listp, newgp); 929*7c478bd9Sstevel@tonic-gate datagrams++; 930*7c478bd9Sstevel@tonic-gate } 931*7c478bd9Sstevel@tonic-gate if (ipv4_listp == NULL && fragments != 0) { 932*7c478bd9Sstevel@tonic-gate if (++input_attempts > FRAG_ATTEMPTS) { 933*7c478bd9Sstevel@tonic-gate dprintf("ipv4_input(%d): reassembly(%d) timed out in " 934*7c478bd9Sstevel@tonic-gate "%d msecs.\n", index, fragments, 935*7c478bd9Sstevel@tonic-gate sockets[index].in_timeout * input_attempts); 936*7c478bd9Sstevel@tonic-gate frag_flush(); 937*7c478bd9Sstevel@tonic-gate errno = ETIMEDOUT; 938*7c478bd9Sstevel@tonic-gate return (-1); 939*7c478bd9Sstevel@tonic-gate } else { 940*7c478bd9Sstevel@tonic-gate /* 941*7c478bd9Sstevel@tonic-gate * Call the media layer again... there may be more 942*7c478bd9Sstevel@tonic-gate * packets waiting. 943*7c478bd9Sstevel@tonic-gate */ 944*7c478bd9Sstevel@tonic-gate if (sockets[index].input[MEDIA_LVL](index) < 0) { 945*7c478bd9Sstevel@tonic-gate /* errno will be set appropriately */ 946*7c478bd9Sstevel@tonic-gate frag_flush(); 947*7c478bd9Sstevel@tonic-gate return (-1); 948*7c478bd9Sstevel@tonic-gate } 949*7c478bd9Sstevel@tonic-gate goto ipv4_try_again; 950*7c478bd9Sstevel@tonic-gate } 951*7c478bd9Sstevel@tonic-gate } 952*7c478bd9Sstevel@tonic-gate 953*7c478bd9Sstevel@tonic-gate add_grams(&sockets[index].inq, ipv4_listp); 954*7c478bd9Sstevel@tonic-gate 955*7c478bd9Sstevel@tonic-gate return (datagrams); 956*7c478bd9Sstevel@tonic-gate } 957*7c478bd9Sstevel@tonic-gate 958*7c478bd9Sstevel@tonic-gate /* 959*7c478bd9Sstevel@tonic-gate * ipv4_output: Generate IPv4 datagram(s) for the payload and deliver them. 960*7c478bd9Sstevel@tonic-gate * Routing is handled here as well, by reusing the saddr field to hold the 961*7c478bd9Sstevel@tonic-gate * router's IP address. 962*7c478bd9Sstevel@tonic-gate * 963*7c478bd9Sstevel@tonic-gate * We don't deal with fragmentation on the outgoing side. 964*7c478bd9Sstevel@tonic-gate * 965*7c478bd9Sstevel@tonic-gate * Arguments: index to socket, inetgram to send. 966*7c478bd9Sstevel@tonic-gate * 967*7c478bd9Sstevel@tonic-gate * Returns: 0 for success, -1 if error occurred. 968*7c478bd9Sstevel@tonic-gate */ 969*7c478bd9Sstevel@tonic-gate int 970*7c478bd9Sstevel@tonic-gate ipv4_output(int index, struct inetgram *ogp) 971*7c478bd9Sstevel@tonic-gate { 972*7c478bd9Sstevel@tonic-gate struct ip *iphp; 973*7c478bd9Sstevel@tonic-gate uint64_t iphbuffer[sizeof (struct ip)]; 974*7c478bd9Sstevel@tonic-gate 975*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 976*7c478bd9Sstevel@tonic-gate printf("ipv4_output(%d): size %d\n", index, 977*7c478bd9Sstevel@tonic-gate ogp->igm_mp->b_wptr - ogp->igm_mp->b_rptr); 978*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 979*7c478bd9Sstevel@tonic-gate 980*7c478bd9Sstevel@tonic-gate /* we don't deal (yet) with fragmentation. Maybe never will */ 981*7c478bd9Sstevel@tonic-gate if ((ogp->igm_mp->b_wptr - ogp->igm_mp->b_rptr) > mac_get_mtu()) { 982*7c478bd9Sstevel@tonic-gate dprintf("ipv4: datagram too big for MAC layer.\n"); 983*7c478bd9Sstevel@tonic-gate errno = E2BIG; 984*7c478bd9Sstevel@tonic-gate return (-1); 985*7c478bd9Sstevel@tonic-gate } 986*7c478bd9Sstevel@tonic-gate 987*7c478bd9Sstevel@tonic-gate if (ogp->igm_level != NETWORK_LVL) { 988*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 989*7c478bd9Sstevel@tonic-gate printf("ipv4_output(%d): unexpected frame type: %d\n", index, 990*7c478bd9Sstevel@tonic-gate ogp->igm_level); 991*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 992*7c478bd9Sstevel@tonic-gate errno = EINVAL; 993*7c478bd9Sstevel@tonic-gate return (-1); 994*7c478bd9Sstevel@tonic-gate } 995*7c478bd9Sstevel@tonic-gate 996*7c478bd9Sstevel@tonic-gate if (sockets[index].out_flags & SO_DONTROUTE) 997*7c478bd9Sstevel@tonic-gate ogp->igm_oflags |= MSG_DONTROUTE; 998*7c478bd9Sstevel@tonic-gate 999*7c478bd9Sstevel@tonic-gate iphp = (struct ip *)&iphbuffer; 1000*7c478bd9Sstevel@tonic-gate iphp->ip_v = IPVERSION; 1001*7c478bd9Sstevel@tonic-gate iphp->ip_hl = sizeof (struct ip) / 4; 1002*7c478bd9Sstevel@tonic-gate iphp->ip_tos = 0; 1003*7c478bd9Sstevel@tonic-gate iphp->ip_len = htons(ogp->igm_mp->b_wptr - ogp->igm_mp->b_rptr + 1004*7c478bd9Sstevel@tonic-gate sizeof (struct ip)); 1005*7c478bd9Sstevel@tonic-gate iphp->ip_id = htons(++g_ip_id); 1006*7c478bd9Sstevel@tonic-gate iphp->ip_off = htons(IP_DF); 1007*7c478bd9Sstevel@tonic-gate iphp->ip_p = sockets[index].proto; 1008*7c478bd9Sstevel@tonic-gate iphp->ip_sum = htons(0); 1009*7c478bd9Sstevel@tonic-gate iphp->ip_ttl = ttl; 1010*7c478bd9Sstevel@tonic-gate 1011*7c478bd9Sstevel@tonic-gate /* struct copies */ 1012*7c478bd9Sstevel@tonic-gate iphp->ip_src = myip; 1013*7c478bd9Sstevel@tonic-gate iphp->ip_dst = ogp->igm_saddr.sin_addr; 1014*7c478bd9Sstevel@tonic-gate 1015*7c478bd9Sstevel@tonic-gate /* 1016*7c478bd9Sstevel@tonic-gate * On local / limited broadcasts, don't route. From a purist's 1017*7c478bd9Sstevel@tonic-gate * perspective, we should be setting the TTL to 1. But 1018*7c478bd9Sstevel@tonic-gate * operational experience has shown that some BOOTP relay agents 1019*7c478bd9Sstevel@tonic-gate * (ciscos) discard our packets. Furthermore, these devices also 1020*7c478bd9Sstevel@tonic-gate * *don't* reset the TTL to MAXTTL on the unicast side of the 1021*7c478bd9Sstevel@tonic-gate * BOOTP relay agent! Sigh. Thus to work correctly in these 1022*7c478bd9Sstevel@tonic-gate * environments, we leave the TTL as it has been been set by 1023*7c478bd9Sstevel@tonic-gate * the application layer, and simply don't check for a route. 1024*7c478bd9Sstevel@tonic-gate */ 1025*7c478bd9Sstevel@tonic-gate if (iphp->ip_dst.s_addr == htonl(INADDR_BROADCAST) || 1026*7c478bd9Sstevel@tonic-gate (netmask.s_addr != htonl(INADDR_BROADCAST) && 1027*7c478bd9Sstevel@tonic-gate iphp->ip_dst.s_addr == (mynet.s_addr | ~netmask.s_addr))) { 1028*7c478bd9Sstevel@tonic-gate ogp->igm_oflags |= MSG_DONTROUTE; 1029*7c478bd9Sstevel@tonic-gate } 1030*7c478bd9Sstevel@tonic-gate 1031*7c478bd9Sstevel@tonic-gate /* Routing necessary? */ 1032*7c478bd9Sstevel@tonic-gate if ((ogp->igm_oflags & MSG_DONTROUTE) == 0 && 1033*7c478bd9Sstevel@tonic-gate ((iphp->ip_dst.s_addr & netmask.s_addr) != mynet.s_addr)) { 1034*7c478bd9Sstevel@tonic-gate struct in_addr *rip; 1035*7c478bd9Sstevel@tonic-gate if ((rip = ipv4_get_route(RT_HOST, &iphp->ip_dst, 1036*7c478bd9Sstevel@tonic-gate NULL)) == NULL) { 1037*7c478bd9Sstevel@tonic-gate rip = ipv4_get_route(RT_DEFAULT, NULL, NULL); 1038*7c478bd9Sstevel@tonic-gate } 1039*7c478bd9Sstevel@tonic-gate if (rip == NULL) { 1040*7c478bd9Sstevel@tonic-gate dprintf("ipv4(%d): No route to %s.\n", 1041*7c478bd9Sstevel@tonic-gate index, inet_ntoa(iphp->ip_dst)); 1042*7c478bd9Sstevel@tonic-gate errno = EHOSTUNREACH; 1043*7c478bd9Sstevel@tonic-gate return (-1); 1044*7c478bd9Sstevel@tonic-gate } 1045*7c478bd9Sstevel@tonic-gate ogp->igm_router.s_addr = rip->s_addr; 1046*7c478bd9Sstevel@tonic-gate } else 1047*7c478bd9Sstevel@tonic-gate ogp->igm_router.s_addr = htonl(INADDR_ANY); 1048*7c478bd9Sstevel@tonic-gate 1049*7c478bd9Sstevel@tonic-gate iphp->ip_sum = ipv4cksum((uint16_t *)iphp, sizeof (struct ip)); 1050*7c478bd9Sstevel@tonic-gate ogp->igm_mp->b_rptr -= sizeof (struct ip); 1051*7c478bd9Sstevel@tonic-gate bcopy((caddr_t)iphp, (caddr_t)(ogp->igm_mp->b_rptr), 1052*7c478bd9Sstevel@tonic-gate sizeof (struct ip)); 1053*7c478bd9Sstevel@tonic-gate 1054*7c478bd9Sstevel@tonic-gate ogp->igm_level = MEDIA_LVL; 1055*7c478bd9Sstevel@tonic-gate 1056*7c478bd9Sstevel@tonic-gate return (0); 1057*7c478bd9Sstevel@tonic-gate } 1058*7c478bd9Sstevel@tonic-gate 1059*7c478bd9Sstevel@tonic-gate /* 1060*7c478bd9Sstevel@tonic-gate * Function to be called by TCP to send out a packet. This is used 1061*7c478bd9Sstevel@tonic-gate * when TCP wants to send out packets which it has already filled in 1062*7c478bd9Sstevel@tonic-gate * most of the header fields. 1063*7c478bd9Sstevel@tonic-gate */ 1064*7c478bd9Sstevel@tonic-gate int 1065*7c478bd9Sstevel@tonic-gate ipv4_tcp_output(int sock_id, mblk_t *pkt) 1066*7c478bd9Sstevel@tonic-gate { 1067*7c478bd9Sstevel@tonic-gate struct ip *iph; 1068*7c478bd9Sstevel@tonic-gate struct in_addr *rip = NULL; 1069*7c478bd9Sstevel@tonic-gate struct inetgram datagram; 1070*7c478bd9Sstevel@tonic-gate 1071*7c478bd9Sstevel@tonic-gate iph = (struct ip *)pkt->b_rptr; 1072*7c478bd9Sstevel@tonic-gate 1073*7c478bd9Sstevel@tonic-gate bzero(&datagram, sizeof (struct inetgram)); 1074*7c478bd9Sstevel@tonic-gate 1075*7c478bd9Sstevel@tonic-gate /* 1076*7c478bd9Sstevel@tonic-gate * Bootparams doesn't know about subnet masks, so we need to 1077*7c478bd9Sstevel@tonic-gate * explicitly check for this flag. 1078*7c478bd9Sstevel@tonic-gate */ 1079*7c478bd9Sstevel@tonic-gate if (sockets[sock_id].out_flags & SO_DONTROUTE) 1080*7c478bd9Sstevel@tonic-gate datagram.igm_oflags |= MSG_DONTROUTE; 1081*7c478bd9Sstevel@tonic-gate 1082*7c478bd9Sstevel@tonic-gate /* Routing necessary? */ 1083*7c478bd9Sstevel@tonic-gate if (((datagram.igm_oflags & MSG_DONTROUTE) == 0) && 1084*7c478bd9Sstevel@tonic-gate ((iph->ip_dst.s_addr & netmask.s_addr) != mynet.s_addr)) { 1085*7c478bd9Sstevel@tonic-gate if ((rip = ipv4_get_route(RT_HOST, &iph->ip_dst, 1086*7c478bd9Sstevel@tonic-gate NULL)) == NULL) { 1087*7c478bd9Sstevel@tonic-gate rip = ipv4_get_route(RT_DEFAULT, NULL, NULL); 1088*7c478bd9Sstevel@tonic-gate } 1089*7c478bd9Sstevel@tonic-gate if (rip == NULL) { 1090*7c478bd9Sstevel@tonic-gate dprintf("ipv4(%d): No route to %s.\n", 1091*7c478bd9Sstevel@tonic-gate sock_id, inet_ntoa(iph->ip_dst)); 1092*7c478bd9Sstevel@tonic-gate errno = EHOSTUNREACH; 1093*7c478bd9Sstevel@tonic-gate return (-1); 1094*7c478bd9Sstevel@tonic-gate } 1095*7c478bd9Sstevel@tonic-gate } 1096*7c478bd9Sstevel@tonic-gate 1097*7c478bd9Sstevel@tonic-gate iph->ip_id = htons(++g_ip_id); 1098*7c478bd9Sstevel@tonic-gate iph->ip_sum = ipv4cksum((uint16_t *)iph, sizeof (struct ip)); 1099*7c478bd9Sstevel@tonic-gate #if DEBUG > 1 1100*7c478bd9Sstevel@tonic-gate printf("ipv4_tcp_output: dump IP packet(%d)\n", iph->ip_len); 1101*7c478bd9Sstevel@tonic-gate hexdump((char *)pkt->b_rptr, iph->ip_len); 1102*7c478bd9Sstevel@tonic-gate #endif 1103*7c478bd9Sstevel@tonic-gate /* Call the MAC layer output routine to send it out. */ 1104*7c478bd9Sstevel@tonic-gate datagram.igm_mp = pkt; 1105*7c478bd9Sstevel@tonic-gate datagram.igm_level = MEDIA_LVL; 1106*7c478bd9Sstevel@tonic-gate if (rip != NULL) 1107*7c478bd9Sstevel@tonic-gate datagram.igm_router.s_addr = rip->s_addr; 1108*7c478bd9Sstevel@tonic-gate else 1109*7c478bd9Sstevel@tonic-gate datagram.igm_router.s_addr = 0; 1110*7c478bd9Sstevel@tonic-gate return (mac_state.mac_output(sock_id, &datagram)); 1111*7c478bd9Sstevel@tonic-gate } 1112*7c478bd9Sstevel@tonic-gate 1113*7c478bd9Sstevel@tonic-gate /* 1114*7c478bd9Sstevel@tonic-gate * Internet address interpretation routine. 1115*7c478bd9Sstevel@tonic-gate * All the network library routines call this 1116*7c478bd9Sstevel@tonic-gate * routine to interpret entries in the data bases 1117*7c478bd9Sstevel@tonic-gate * which are expected to be an address. 1118*7c478bd9Sstevel@tonic-gate * The value returned is in network order. 1119*7c478bd9Sstevel@tonic-gate */ 1120*7c478bd9Sstevel@tonic-gate in_addr_t 1121*7c478bd9Sstevel@tonic-gate inet_addr(const char *cp) 1122*7c478bd9Sstevel@tonic-gate { 1123*7c478bd9Sstevel@tonic-gate uint32_t val, base, n; 1124*7c478bd9Sstevel@tonic-gate char c; 1125*7c478bd9Sstevel@tonic-gate uint32_t parts[4], *pp = parts; 1126*7c478bd9Sstevel@tonic-gate 1127*7c478bd9Sstevel@tonic-gate if (*cp == '\0') 1128*7c478bd9Sstevel@tonic-gate return ((uint32_t)-1); /* disallow null string in cp */ 1129*7c478bd9Sstevel@tonic-gate again: 1130*7c478bd9Sstevel@tonic-gate /* 1131*7c478bd9Sstevel@tonic-gate * Collect number up to ``.''. 1132*7c478bd9Sstevel@tonic-gate * Values are specified as for C: 1133*7c478bd9Sstevel@tonic-gate * 0x=hex, 0=octal, other=decimal. 1134*7c478bd9Sstevel@tonic-gate */ 1135*7c478bd9Sstevel@tonic-gate val = 0; base = 10; 1136*7c478bd9Sstevel@tonic-gate if (*cp == '0') { 1137*7c478bd9Sstevel@tonic-gate if (*++cp == 'x' || *cp == 'X') 1138*7c478bd9Sstevel@tonic-gate base = 16, cp++; 1139*7c478bd9Sstevel@tonic-gate else 1140*7c478bd9Sstevel@tonic-gate base = 8; 1141*7c478bd9Sstevel@tonic-gate } 1142*7c478bd9Sstevel@tonic-gate while ((c = *cp) != NULL) { 1143*7c478bd9Sstevel@tonic-gate if (isdigit(c)) { 1144*7c478bd9Sstevel@tonic-gate if ((c - '0') >= base) 1145*7c478bd9Sstevel@tonic-gate break; 1146*7c478bd9Sstevel@tonic-gate val = (val * base) + (c - '0'); 1147*7c478bd9Sstevel@tonic-gate cp++; 1148*7c478bd9Sstevel@tonic-gate continue; 1149*7c478bd9Sstevel@tonic-gate } 1150*7c478bd9Sstevel@tonic-gate if (base == 16 && isxdigit(c)) { 1151*7c478bd9Sstevel@tonic-gate val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A')); 1152*7c478bd9Sstevel@tonic-gate cp++; 1153*7c478bd9Sstevel@tonic-gate continue; 1154*7c478bd9Sstevel@tonic-gate } 1155*7c478bd9Sstevel@tonic-gate break; 1156*7c478bd9Sstevel@tonic-gate } 1157*7c478bd9Sstevel@tonic-gate if (*cp == '.') { 1158*7c478bd9Sstevel@tonic-gate /* 1159*7c478bd9Sstevel@tonic-gate * Internet format: 1160*7c478bd9Sstevel@tonic-gate * a.b.c.d 1161*7c478bd9Sstevel@tonic-gate * a.b.c (with c treated as 16-bits) 1162*7c478bd9Sstevel@tonic-gate * a.b (with b treated as 24 bits) 1163*7c478bd9Sstevel@tonic-gate */ 1164*7c478bd9Sstevel@tonic-gate if ((pp >= parts + 3) || (val > 0xff)) { 1165*7c478bd9Sstevel@tonic-gate return ((uint32_t)-1); 1166*7c478bd9Sstevel@tonic-gate } 1167*7c478bd9Sstevel@tonic-gate *pp++ = val, cp++; 1168*7c478bd9Sstevel@tonic-gate goto again; 1169*7c478bd9Sstevel@tonic-gate } 1170*7c478bd9Sstevel@tonic-gate /* 1171*7c478bd9Sstevel@tonic-gate * Check for trailing characters. 1172*7c478bd9Sstevel@tonic-gate */ 1173*7c478bd9Sstevel@tonic-gate if (*cp && !isspace(*cp)) { 1174*7c478bd9Sstevel@tonic-gate return ((uint32_t)-1); 1175*7c478bd9Sstevel@tonic-gate } 1176*7c478bd9Sstevel@tonic-gate *pp++ = val; 1177*7c478bd9Sstevel@tonic-gate /* 1178*7c478bd9Sstevel@tonic-gate * Concoct the address according to 1179*7c478bd9Sstevel@tonic-gate * the number of parts specified. 1180*7c478bd9Sstevel@tonic-gate */ 1181*7c478bd9Sstevel@tonic-gate n = pp - parts; 1182*7c478bd9Sstevel@tonic-gate switch (n) { 1183*7c478bd9Sstevel@tonic-gate 1184*7c478bd9Sstevel@tonic-gate case 1: /* a -- 32 bits */ 1185*7c478bd9Sstevel@tonic-gate val = parts[0]; 1186*7c478bd9Sstevel@tonic-gate break; 1187*7c478bd9Sstevel@tonic-gate 1188*7c478bd9Sstevel@tonic-gate case 2: /* a.b -- 8.24 bits */ 1189*7c478bd9Sstevel@tonic-gate if (parts[1] > 0xffffff) 1190*7c478bd9Sstevel@tonic-gate return ((uint32_t)-1); 1191*7c478bd9Sstevel@tonic-gate val = (parts[0] << 24) | (parts[1] & 0xffffff); 1192*7c478bd9Sstevel@tonic-gate break; 1193*7c478bd9Sstevel@tonic-gate 1194*7c478bd9Sstevel@tonic-gate case 3: /* a.b.c -- 8.8.16 bits */ 1195*7c478bd9Sstevel@tonic-gate if (parts[2] > 0xffff) 1196*7c478bd9Sstevel@tonic-gate return ((uint32_t)-1); 1197*7c478bd9Sstevel@tonic-gate val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) | 1198*7c478bd9Sstevel@tonic-gate (parts[2] & 0xffff); 1199*7c478bd9Sstevel@tonic-gate break; 1200*7c478bd9Sstevel@tonic-gate 1201*7c478bd9Sstevel@tonic-gate case 4: /* a.b.c.d -- 8.8.8.8 bits */ 1202*7c478bd9Sstevel@tonic-gate if (parts[3] > 0xff) 1203*7c478bd9Sstevel@tonic-gate return ((uint32_t)-1); 1204*7c478bd9Sstevel@tonic-gate val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) | 1205*7c478bd9Sstevel@tonic-gate ((parts[2] & 0xff) << 8) | (parts[3] & 0xff); 1206*7c478bd9Sstevel@tonic-gate break; 1207*7c478bd9Sstevel@tonic-gate 1208*7c478bd9Sstevel@tonic-gate default: 1209*7c478bd9Sstevel@tonic-gate return ((uint32_t)-1); 1210*7c478bd9Sstevel@tonic-gate } 1211*7c478bd9Sstevel@tonic-gate val = htonl(val); 1212*7c478bd9Sstevel@tonic-gate return (val); 1213*7c478bd9Sstevel@tonic-gate } 1214*7c478bd9Sstevel@tonic-gate 1215*7c478bd9Sstevel@tonic-gate void 1216*7c478bd9Sstevel@tonic-gate hexdump(char *data, int datalen) 1217*7c478bd9Sstevel@tonic-gate { 1218*7c478bd9Sstevel@tonic-gate char *p; 1219*7c478bd9Sstevel@tonic-gate ushort_t *p16 = (ushort_t *)data; 1220*7c478bd9Sstevel@tonic-gate char *p8 = data; 1221*7c478bd9Sstevel@tonic-gate int i, left, len; 1222*7c478bd9Sstevel@tonic-gate int chunk = 16; /* 16 bytes per line */ 1223*7c478bd9Sstevel@tonic-gate 1224*7c478bd9Sstevel@tonic-gate printf("\n"); 1225*7c478bd9Sstevel@tonic-gate 1226*7c478bd9Sstevel@tonic-gate for (p = data; p < data + datalen; p += chunk) { 1227*7c478bd9Sstevel@tonic-gate printf("\t%4d: ", (int)(p - data)); 1228*7c478bd9Sstevel@tonic-gate left = (data + datalen) - p; 1229*7c478bd9Sstevel@tonic-gate len = MIN(chunk, left); 1230*7c478bd9Sstevel@tonic-gate for (i = 0; i < (len / 2); i++) 1231*7c478bd9Sstevel@tonic-gate printf("%04x ", ntohs(*p16++) & 0xffff); 1232*7c478bd9Sstevel@tonic-gate if (len % 2) { 1233*7c478bd9Sstevel@tonic-gate printf("%02x ", *((unsigned char *)p16)); 1234*7c478bd9Sstevel@tonic-gate } 1235*7c478bd9Sstevel@tonic-gate for (i = 0; i < (chunk - left) / 2; i++) 1236*7c478bd9Sstevel@tonic-gate printf(" "); 1237*7c478bd9Sstevel@tonic-gate 1238*7c478bd9Sstevel@tonic-gate printf(" "); 1239*7c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++, p8++) 1240*7c478bd9Sstevel@tonic-gate printf("%c", isprint(*p8) ? *p8 : '.'); 1241*7c478bd9Sstevel@tonic-gate printf("\n"); 1242*7c478bd9Sstevel@tonic-gate } 1243*7c478bd9Sstevel@tonic-gate 1244*7c478bd9Sstevel@tonic-gate printf("\n"); 1245*7c478bd9Sstevel@tonic-gate } 1246