1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * Ethernet routines. Includes ARP and Reverse ARP. Used for ethernet-like 31*0Sstevel@tonic-gate * media also - so be sure NOT to use ETHERMTU as a mtu limit. macinit() 32*0Sstevel@tonic-gate * will set this appropriately. 33*0Sstevel@tonic-gate */ 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gate #include <sys/types.h> 36*0Sstevel@tonic-gate #include <socket_impl.h> 37*0Sstevel@tonic-gate #include <socket_inet.h> 38*0Sstevel@tonic-gate #include <sys/time.h> 39*0Sstevel@tonic-gate #include <sys/socket.h> 40*0Sstevel@tonic-gate #include <net/if.h> 41*0Sstevel@tonic-gate #include <net/if_arp.h> 42*0Sstevel@tonic-gate #include <netinet/in_systm.h> 43*0Sstevel@tonic-gate #include <netinet/in.h> 44*0Sstevel@tonic-gate #include <netinet/ip.h> 45*0Sstevel@tonic-gate #include <netinet/if_ether.h> 46*0Sstevel@tonic-gate #include <sys/promif.h> 47*0Sstevel@tonic-gate #include <sys/prom_plat.h> 48*0Sstevel@tonic-gate #include <sys/salib.h> 49*0Sstevel@tonic-gate #include <sys/bootdebug.h> 50*0Sstevel@tonic-gate 51*0Sstevel@tonic-gate #include "ipv4.h" 52*0Sstevel@tonic-gate #include "ipv4_impl.h" 53*0Sstevel@tonic-gate #include "mac.h" 54*0Sstevel@tonic-gate #include "mac_impl.h" 55*0Sstevel@tonic-gate #include "ethernet_inet.h" 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate ether_addr_t etherbroadcastaddr = { 58*0Sstevel@tonic-gate 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF 59*0Sstevel@tonic-gate }; 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate struct arp_packet { 62*0Sstevel@tonic-gate struct ether_header arp_eh; 63*0Sstevel@tonic-gate struct ether_arp arp_ea; 64*0Sstevel@tonic-gate #define USED_SIZE (sizeof (struct ether_header) + sizeof (struct ether_arp)) 65*0Sstevel@tonic-gate char filler[ETHERMIN - sizeof (struct ether_arp)]; 66*0Sstevel@tonic-gate }; 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate static char * 69*0Sstevel@tonic-gate ether_print(ether_addr_t ea) 70*0Sstevel@tonic-gate { 71*0Sstevel@tonic-gate static char eprintbuf[20]; 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate (void) sprintf(eprintbuf, "%x:%x:%x:%x:%x:%x", ea[0], ea[1], ea[2], 74*0Sstevel@tonic-gate ea[3], ea[4], ea[5]); 75*0Sstevel@tonic-gate return (eprintbuf); 76*0Sstevel@tonic-gate } 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate /* 79*0Sstevel@tonic-gate * Common ARP code. Broadcast the packet and wait for the right response. 80*0Sstevel@tonic-gate * 81*0Sstevel@tonic-gate * If rarp is called for, caller expects an IPv4 address in the target 82*0Sstevel@tonic-gate * protocol address (tpa) field of the "out" argument. 83*0Sstevel@tonic-gate * 84*0Sstevel@tonic-gate * If arp is called for, caller expects a hardware address in the 85*0Sstevel@tonic-gate * source hardware address (sha) field of the "out" argument. 86*0Sstevel@tonic-gate * 87*0Sstevel@tonic-gate * Returns TRUE if transaction succeeded, FALSE otherwise. 88*0Sstevel@tonic-gate * 89*0Sstevel@tonic-gate * The timeout argument is the number of milliseconds to wait for a 90*0Sstevel@tonic-gate * response. An infinite timeout can be specified as 0xffffffff. 91*0Sstevel@tonic-gate */ 92*0Sstevel@tonic-gate static int 93*0Sstevel@tonic-gate ether_comarp(struct arp_packet *out, uint32_t timeout) 94*0Sstevel@tonic-gate { 95*0Sstevel@tonic-gate struct arp_packet *in = (struct arp_packet *)mac_state.mac_buf; 96*0Sstevel@tonic-gate int count, time, feedback, len, delay = 2; 97*0Sstevel@tonic-gate char *ind = "-\\|/"; 98*0Sstevel@tonic-gate struct in_addr tmp_ia; 99*0Sstevel@tonic-gate uint32_t wait_time; 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate bcopy((caddr_t)etherbroadcastaddr, (caddr_t)&out->arp_eh.ether_dhost, 102*0Sstevel@tonic-gate sizeof (ether_addr_t)); 103*0Sstevel@tonic-gate bcopy((caddr_t)mac_state.mac_addr_buf, 104*0Sstevel@tonic-gate (caddr_t)&out->arp_eh.ether_shost, sizeof (ether_addr_t)); 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gate out->arp_ea.arp_hrd = htons(ARPHRD_ETHER); 107*0Sstevel@tonic-gate out->arp_ea.arp_pro = htons(ETHERTYPE_IP); 108*0Sstevel@tonic-gate out->arp_ea.arp_hln = sizeof (ether_addr_t); 109*0Sstevel@tonic-gate out->arp_ea.arp_pln = sizeof (struct in_addr); 110*0Sstevel@tonic-gate bcopy(mac_state.mac_addr_buf, (caddr_t)&out->arp_ea.arp_sha, 111*0Sstevel@tonic-gate sizeof (ether_addr_t)); 112*0Sstevel@tonic-gate ipv4_getipaddr(&tmp_ia); 113*0Sstevel@tonic-gate tmp_ia.s_addr = htonl(tmp_ia.s_addr); 114*0Sstevel@tonic-gate bcopy((caddr_t)&tmp_ia, (caddr_t)out->arp_ea.arp_spa, 115*0Sstevel@tonic-gate sizeof (struct in_addr)); 116*0Sstevel@tonic-gate feedback = 0; 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate wait_time = prom_gettime() + timeout; 119*0Sstevel@tonic-gate for (count = 0; timeout == ~0U || prom_gettime() < wait_time; count++) { 120*0Sstevel@tonic-gate if (count == ETHER_WAITCNT) { 121*0Sstevel@tonic-gate if (out->arp_ea.arp_op == ARPOP_REQUEST) { 122*0Sstevel@tonic-gate bcopy((caddr_t)out->arp_ea.arp_tpa, 123*0Sstevel@tonic-gate (caddr_t)&tmp_ia, sizeof (struct in_addr)); 124*0Sstevel@tonic-gate printf( 125*0Sstevel@tonic-gate "\nRequesting Ethernet address for: %s\n", 126*0Sstevel@tonic-gate inet_ntoa(tmp_ia)); 127*0Sstevel@tonic-gate } else { 128*0Sstevel@tonic-gate printf("\nRequesting Internet address for %s\n", 129*0Sstevel@tonic-gate ether_print(out->arp_ea.arp_tha)); 130*0Sstevel@tonic-gate } 131*0Sstevel@tonic-gate } 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate (void) prom_write(mac_state.mac_dev, (caddr_t)out, 134*0Sstevel@tonic-gate sizeof (*out), 0, NETWORK); 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate if (count >= ETHER_WAITCNT) 137*0Sstevel@tonic-gate printf("%c\b", ind[feedback++ % 4]); /* activity */ 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate time = prom_gettime() + (delay * 1000); /* broadcast delay */ 140*0Sstevel@tonic-gate while (prom_gettime() <= time) { 141*0Sstevel@tonic-gate len = prom_read(mac_state.mac_dev, mac_state.mac_buf, 142*0Sstevel@tonic-gate mac_state.mac_mtu, 0, NETWORK); 143*0Sstevel@tonic-gate if (len < USED_SIZE) 144*0Sstevel@tonic-gate continue; 145*0Sstevel@tonic-gate if (in->arp_ea.arp_pro != ntohs(ETHERTYPE_IP)) 146*0Sstevel@tonic-gate continue; 147*0Sstevel@tonic-gate if (out->arp_ea.arp_op == ntohs(ARPOP_REQUEST)) { 148*0Sstevel@tonic-gate if (in->arp_eh.ether_type != 149*0Sstevel@tonic-gate ntohs(ETHERTYPE_ARP)) 150*0Sstevel@tonic-gate continue; 151*0Sstevel@tonic-gate if (in->arp_ea.arp_op != ntohs(ARPOP_REPLY)) 152*0Sstevel@tonic-gate continue; 153*0Sstevel@tonic-gate if (bcmp((caddr_t)in->arp_ea.arp_spa, 154*0Sstevel@tonic-gate (caddr_t)out->arp_ea.arp_tpa, 155*0Sstevel@tonic-gate sizeof (struct in_addr)) != 0) 156*0Sstevel@tonic-gate continue; 157*0Sstevel@tonic-gate if (boothowto & RB_VERBOSE) { 158*0Sstevel@tonic-gate bcopy((caddr_t)in->arp_ea.arp_spa, 159*0Sstevel@tonic-gate (caddr_t)&tmp_ia, 160*0Sstevel@tonic-gate sizeof (struct in_addr)); 161*0Sstevel@tonic-gate printf("Found %s @ %s\n", 162*0Sstevel@tonic-gate inet_ntoa(tmp_ia), 163*0Sstevel@tonic-gate ether_print(in->arp_ea.arp_sha)); 164*0Sstevel@tonic-gate } 165*0Sstevel@tonic-gate /* copy hardware addr into "out" for caller */ 166*0Sstevel@tonic-gate bcopy((caddr_t)&in->arp_ea.arp_sha, 167*0Sstevel@tonic-gate (caddr_t)&out->arp_ea.arp_sha, 168*0Sstevel@tonic-gate sizeof (ether_addr_t)); 169*0Sstevel@tonic-gate return (TRUE); 170*0Sstevel@tonic-gate } else { /* Reverse ARP */ 171*0Sstevel@tonic-gate if (in->arp_eh.ether_type != 172*0Sstevel@tonic-gate ntohs(ETHERTYPE_REVARP)) 173*0Sstevel@tonic-gate continue; 174*0Sstevel@tonic-gate if (in->arp_ea.arp_op != ntohs(REVARP_REPLY)) 175*0Sstevel@tonic-gate continue; 176*0Sstevel@tonic-gate if (bcmp((caddr_t)in->arp_ea.arp_tha, 177*0Sstevel@tonic-gate (caddr_t)out->arp_ea.arp_tha, 178*0Sstevel@tonic-gate sizeof (ether_addr_t)) != 0) 179*0Sstevel@tonic-gate continue; 180*0Sstevel@tonic-gate if (boothowto & RB_VERBOSE) { 181*0Sstevel@tonic-gate bcopy((caddr_t)in->arp_ea.arp_tpa, 182*0Sstevel@tonic-gate (caddr_t)&tmp_ia, 183*0Sstevel@tonic-gate sizeof (struct in_addr)); 184*0Sstevel@tonic-gate printf("Internet address is: %s\n", 185*0Sstevel@tonic-gate inet_ntoa(tmp_ia)); 186*0Sstevel@tonic-gate } 187*0Sstevel@tonic-gate /* copy IP address into "out" for caller */ 188*0Sstevel@tonic-gate bcopy((caddr_t)in->arp_ea.arp_tpa, 189*0Sstevel@tonic-gate (caddr_t)out->arp_ea.arp_tpa, 190*0Sstevel@tonic-gate sizeof (struct in_addr)); 191*0Sstevel@tonic-gate return (TRUE); 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate } 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate delay = delay * 2; /* Double the request delay */ 196*0Sstevel@tonic-gate if (delay > 64) /* maximum delay is 64 seconds */ 197*0Sstevel@tonic-gate delay = 64; 198*0Sstevel@tonic-gate } 199*0Sstevel@tonic-gate return (FALSE); 200*0Sstevel@tonic-gate } 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate /* 203*0Sstevel@tonic-gate * ARP client side 204*0Sstevel@tonic-gate * Broadcasts to determine MAC address given network order IP address. 205*0Sstevel@tonic-gate * See RFC 826 206*0Sstevel@tonic-gate * 207*0Sstevel@tonic-gate * Returns TRUE if successful, FALSE otherwise. 208*0Sstevel@tonic-gate */ 209*0Sstevel@tonic-gate int 210*0Sstevel@tonic-gate ether_arp(struct in_addr *ip, void *hap, uint32_t timeout) 211*0Sstevel@tonic-gate { 212*0Sstevel@tonic-gate ether_addr_t *ep = (ether_addr_t *)hap; 213*0Sstevel@tonic-gate struct arp_packet out; 214*0Sstevel@tonic-gate int result; 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate if (!initialized) 217*0Sstevel@tonic-gate prom_panic("Ethernet device is not initialized."); 218*0Sstevel@tonic-gate 219*0Sstevel@tonic-gate bzero((char *)&out, sizeof (struct arp_packet)); 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate out.arp_eh.ether_type = htons(ETHERTYPE_ARP); 222*0Sstevel@tonic-gate out.arp_ea.arp_op = htons(ARPOP_REQUEST); 223*0Sstevel@tonic-gate bcopy((caddr_t)etherbroadcastaddr, (caddr_t)&out.arp_ea.arp_tha, 224*0Sstevel@tonic-gate sizeof (ether_addr_t)); 225*0Sstevel@tonic-gate bcopy((caddr_t)ip, (caddr_t)out.arp_ea.arp_tpa, 226*0Sstevel@tonic-gate sizeof (struct in_addr)); 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate result = ether_comarp(&out, timeout); 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate if (result && (ep != NULL)) { 231*0Sstevel@tonic-gate bcopy((caddr_t)&out.arp_ea.arp_sha, (caddr_t)ep, 232*0Sstevel@tonic-gate sizeof (ether_addr_t)); 233*0Sstevel@tonic-gate } 234*0Sstevel@tonic-gate return (result); 235*0Sstevel@tonic-gate } 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gate /* 238*0Sstevel@tonic-gate * Reverse ARP client side 239*0Sstevel@tonic-gate * Determine our Internet address given our MAC address 240*0Sstevel@tonic-gate * See RFC 903 241*0Sstevel@tonic-gate */ 242*0Sstevel@tonic-gate void 243*0Sstevel@tonic-gate ether_revarp(void) 244*0Sstevel@tonic-gate { 245*0Sstevel@tonic-gate struct in_addr ip; 246*0Sstevel@tonic-gate struct arp_packet out; 247*0Sstevel@tonic-gate 248*0Sstevel@tonic-gate if (!initialized) 249*0Sstevel@tonic-gate prom_panic("Ethernet device is not initialized."); 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate bzero((char *)&out, sizeof (struct arp_packet)); 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate out.arp_eh.ether_type = htons(ETHERTYPE_REVARP); 254*0Sstevel@tonic-gate out.arp_ea.arp_op = htons(REVARP_REQUEST); 255*0Sstevel@tonic-gate bcopy(mac_state.mac_addr_buf, (caddr_t)&out.arp_ea.arp_tha, 256*0Sstevel@tonic-gate sizeof (ether_addr_t)); 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate /* Wait forever */ 259*0Sstevel@tonic-gate (void) ether_comarp(&out, 0xffffffff); 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate bcopy((caddr_t)&out.arp_ea.arp_tpa, (caddr_t)&ip, 262*0Sstevel@tonic-gate sizeof (struct in_addr)); 263*0Sstevel@tonic-gate 264*0Sstevel@tonic-gate ip.s_addr = ntohl(ip.s_addr); 265*0Sstevel@tonic-gate ipv4_setipaddr(&ip); 266*0Sstevel@tonic-gate } 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate /* ARGSUSED */ 269*0Sstevel@tonic-gate int 270*0Sstevel@tonic-gate ether_header_len(struct inetgram *igm) 271*0Sstevel@tonic-gate { 272*0Sstevel@tonic-gate return (sizeof (struct ether_header)); 273*0Sstevel@tonic-gate } 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gate /* 276*0Sstevel@tonic-gate * Handle a IP datagram addressed to our ethernet address or to the 277*0Sstevel@tonic-gate * ethernet broadcast address. Also respond to ARP requests. Generates 278*0Sstevel@tonic-gate * inetgrams as long as there's data and the mac level IP timeout timer 279*0Sstevel@tonic-gate * hasn't expired. As soon as there is no data, we try for 280*0Sstevel@tonic-gate * ETHER_INPUT_ATTEMPTS for more, then exit the loop, even if there is time 281*0Sstevel@tonic-gate * left, since we expect to have data waiting for us when we're called, we just 282*0Sstevel@tonic-gate * don't know how much. 283*0Sstevel@tonic-gate * 284*0Sstevel@tonic-gate * We workaround slow proms (some proms have hard sleeps for as much as 3msec) 285*0Sstevel@tonic-gate * even though there are is data waiting. 286*0Sstevel@tonic-gate * 287*0Sstevel@tonic-gate * Returns the total number of MEDIA_LVL frames placed on the socket. 288*0Sstevel@tonic-gate * Caller is expected to free up the inetgram resources. 289*0Sstevel@tonic-gate */ 290*0Sstevel@tonic-gate int 291*0Sstevel@tonic-gate ether_input(int index) 292*0Sstevel@tonic-gate { 293*0Sstevel@tonic-gate struct inetgram *inp; 294*0Sstevel@tonic-gate struct ether_header *eh; 295*0Sstevel@tonic-gate int frames = 0; /* successful frames */ 296*0Sstevel@tonic-gate int attempts = 0; /* failed attempts after success */ 297*0Sstevel@tonic-gate int16_t len = 0, data_len; 298*0Sstevel@tonic-gate uint32_t timeout, reltime; 299*0Sstevel@tonic-gate uint32_t pre_pr, post_pr; /* prom_read interval */ 300*0Sstevel@tonic-gate 301*0Sstevel@tonic-gate #ifdef DEBUG 302*0Sstevel@tonic-gate int failures = 0; /* total failures */ 303*0Sstevel@tonic-gate int total_attempts = 0; /* total prom_read */ 304*0Sstevel@tonic-gate int no_data = 0; /* no data in prom */ 305*0Sstevel@tonic-gate int arps = 0; /* arp requests processed */ 306*0Sstevel@tonic-gate uint32_t tot_pr = 0; /* prom_read time */ 307*0Sstevel@tonic-gate uint32_t tot_pc = 0; /* inetgram creation time */ 308*0Sstevel@tonic-gate uint32_t pre_pc; 309*0Sstevel@tonic-gate uint32_t now; 310*0Sstevel@tonic-gate #endif /* DEBUG */ 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate if (!initialized) 313*0Sstevel@tonic-gate prom_panic("Ethernet device is not initialized."); 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gate if ((reltime = sockets[index].in_timeout) == 0) 316*0Sstevel@tonic-gate reltime = mac_state.mac_in_timeout; 317*0Sstevel@tonic-gate timeout = prom_gettime() + reltime; 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate do { 320*0Sstevel@tonic-gate if (frames > ETHER_MAX_FRAMES) { 321*0Sstevel@tonic-gate /* someone is trying a denial of service attack */ 322*0Sstevel@tonic-gate break; 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate /* 326*0Sstevel@tonic-gate * The following is a workaround for a calvin prom (V2) bug 327*0Sstevel@tonic-gate * where prom_read() returns a nonzero length, even when it's 328*0Sstevel@tonic-gate * not read a packet. So we zero out the header to compensate. 329*0Sstevel@tonic-gate */ 330*0Sstevel@tonic-gate bzero(mac_state.mac_buf, sizeof (struct ether_header)); 331*0Sstevel@tonic-gate 332*0Sstevel@tonic-gate /* 333*0Sstevel@tonic-gate * Prom_read() will return 0 or -2 if no data is present. A 334*0Sstevel@tonic-gate * return value of -1 means an error has occurred. We adjust 335*0Sstevel@tonic-gate * the timeout by calling the time spent in prom_read() "free". 336*0Sstevel@tonic-gate * prom_read() returns the number of bytes actually read, but 337*0Sstevel@tonic-gate * will only copy "len" bytes into our buffer. Adjust in 338*0Sstevel@tonic-gate * case the MTU is wrong. 339*0Sstevel@tonic-gate */ 340*0Sstevel@tonic-gate pre_pr = prom_gettime(); 341*0Sstevel@tonic-gate len = prom_read(mac_state.mac_dev, mac_state.mac_buf, 342*0Sstevel@tonic-gate mac_state.mac_mtu, 0, NETWORK); 343*0Sstevel@tonic-gate post_pr = prom_gettime(); 344*0Sstevel@tonic-gate timeout += (post_pr - pre_pr); 345*0Sstevel@tonic-gate #ifdef DEBUG 346*0Sstevel@tonic-gate tot_pr += (post_pr - pre_pr); 347*0Sstevel@tonic-gate total_attempts++; 348*0Sstevel@tonic-gate #endif /* DEBUG */ 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate if (len > mac_state.mac_mtu) { 351*0Sstevel@tonic-gate dprintf("ether_input: adjusting MTU %d -> %d\n", 352*0Sstevel@tonic-gate mac_state.mac_mtu, len); 353*0Sstevel@tonic-gate bkmem_free(mac_state.mac_buf, mac_state.mac_mtu); 354*0Sstevel@tonic-gate mac_state.mac_mtu = len; 355*0Sstevel@tonic-gate mac_state.mac_buf = bkmem_alloc(mac_state.mac_mtu); 356*0Sstevel@tonic-gate if (mac_state.mac_buf == NULL) { 357*0Sstevel@tonic-gate prom_panic("ether_input: Cannot reallocate " 358*0Sstevel@tonic-gate "netbuf memory."); 359*0Sstevel@tonic-gate } 360*0Sstevel@tonic-gate len = 0; /* pretend there was no data */ 361*0Sstevel@tonic-gate } 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate if (len == -1) { 364*0Sstevel@tonic-gate #ifdef DEBUG 365*0Sstevel@tonic-gate failures++; 366*0Sstevel@tonic-gate #endif /* DEBUG */ 367*0Sstevel@tonic-gate break; 368*0Sstevel@tonic-gate } 369*0Sstevel@tonic-gate if (len == 0 || len == -2) { 370*0Sstevel@tonic-gate if (frames != 0) 371*0Sstevel@tonic-gate attempts++; 372*0Sstevel@tonic-gate #ifdef DEBUG 373*0Sstevel@tonic-gate no_data++; 374*0Sstevel@tonic-gate #endif /* DEBUG */ 375*0Sstevel@tonic-gate continue; 376*0Sstevel@tonic-gate } 377*0Sstevel@tonic-gate 378*0Sstevel@tonic-gate eh = (struct ether_header *)mac_state.mac_buf; 379*0Sstevel@tonic-gate if (eh->ether_type == ntohs(ETHERTYPE_IP) && 380*0Sstevel@tonic-gate len >= (sizeof (struct ether_header) + 381*0Sstevel@tonic-gate sizeof (struct ip))) { 382*0Sstevel@tonic-gate 383*0Sstevel@tonic-gate int offset; 384*0Sstevel@tonic-gate #ifdef DEBUG 385*0Sstevel@tonic-gate pre_pc = prom_gettime(); 386*0Sstevel@tonic-gate #endif /* DEBUG */ 387*0Sstevel@tonic-gate 388*0Sstevel@tonic-gate inp = (struct inetgram *)bkmem_zalloc( 389*0Sstevel@tonic-gate sizeof (struct inetgram)); 390*0Sstevel@tonic-gate if (inp == NULL) { 391*0Sstevel@tonic-gate errno = ENOMEM; 392*0Sstevel@tonic-gate return (frames == 0 ? -1 : frames); 393*0Sstevel@tonic-gate } 394*0Sstevel@tonic-gate offset = sizeof (struct ether_header); 395*0Sstevel@tonic-gate data_len = len - offset; 396*0Sstevel@tonic-gate inp->igm_mp = allocb(data_len, 0); 397*0Sstevel@tonic-gate if (inp->igm_mp == NULL) { 398*0Sstevel@tonic-gate errno = ENOMEM; 399*0Sstevel@tonic-gate bkmem_free((caddr_t)inp, 400*0Sstevel@tonic-gate sizeof (struct inetgram)); 401*0Sstevel@tonic-gate return (frames == 0 ? -1 : frames); 402*0Sstevel@tonic-gate } 403*0Sstevel@tonic-gate bcopy((caddr_t)(mac_state.mac_buf + offset), 404*0Sstevel@tonic-gate inp->igm_mp->b_rptr, data_len); 405*0Sstevel@tonic-gate inp->igm_mp->b_wptr += data_len; 406*0Sstevel@tonic-gate inp->igm_level = NETWORK_LVL; 407*0Sstevel@tonic-gate add_grams(&sockets[index].inq, inp); 408*0Sstevel@tonic-gate frames++; 409*0Sstevel@tonic-gate attempts = 0; 410*0Sstevel@tonic-gate #ifdef DEBUG 411*0Sstevel@tonic-gate tot_pc += prom_gettime() - pre_pc; 412*0Sstevel@tonic-gate #endif /* DEBUG */ 413*0Sstevel@tonic-gate continue; 414*0Sstevel@tonic-gate } 415*0Sstevel@tonic-gate 416*0Sstevel@tonic-gate if (eh->ether_type == ntohs(ETHERTYPE_ARP) && 417*0Sstevel@tonic-gate len >= (sizeof (struct ether_header) + 418*0Sstevel@tonic-gate sizeof (struct ether_arp))) { 419*0Sstevel@tonic-gate 420*0Sstevel@tonic-gate struct in_addr ip; 421*0Sstevel@tonic-gate struct ether_arp *ea; 422*0Sstevel@tonic-gate 423*0Sstevel@tonic-gate #ifdef DEBUG 424*0Sstevel@tonic-gate printf("ether_input: ARP message received\n"); 425*0Sstevel@tonic-gate arps++; 426*0Sstevel@tonic-gate #endif /* DEBUG */ 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate ea = (struct ether_arp *)(mac_state.mac_buf + 429*0Sstevel@tonic-gate sizeof (struct ether_header)); 430*0Sstevel@tonic-gate if (ea->arp_pro != ntohs(ETHERTYPE_IP)) 431*0Sstevel@tonic-gate continue; 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate ipv4_getipaddr(&ip); 434*0Sstevel@tonic-gate ip.s_addr = ntohl(ip.s_addr); 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate if (ea->arp_op == ntohs(ARPOP_REQUEST) && 437*0Sstevel@tonic-gate ip.s_addr != INADDR_ANY && 438*0Sstevel@tonic-gate (bcmp((caddr_t)ea->arp_tpa, (caddr_t)&ip, 439*0Sstevel@tonic-gate sizeof (struct in_addr)) == 0)) { 440*0Sstevel@tonic-gate ea->arp_op = htons(ARPOP_REPLY); 441*0Sstevel@tonic-gate bcopy((caddr_t)ea->arp_sha, 442*0Sstevel@tonic-gate (caddr_t)&eh->ether_dhost, 443*0Sstevel@tonic-gate sizeof (ether_addr_t)); 444*0Sstevel@tonic-gate bcopy(mac_state.mac_addr_buf, 445*0Sstevel@tonic-gate (caddr_t)&eh->ether_shost, 446*0Sstevel@tonic-gate mac_state.mac_addr_len); 447*0Sstevel@tonic-gate bcopy((caddr_t)ea->arp_sha, 448*0Sstevel@tonic-gate (caddr_t)ea->arp_tha, 449*0Sstevel@tonic-gate sizeof (ether_addr_t)); 450*0Sstevel@tonic-gate bcopy((caddr_t)ea->arp_spa, 451*0Sstevel@tonic-gate (caddr_t)ea->arp_tpa, 452*0Sstevel@tonic-gate sizeof (struct in_addr)); 453*0Sstevel@tonic-gate bcopy(mac_state.mac_addr_buf, 454*0Sstevel@tonic-gate (caddr_t)ea->arp_sha, 455*0Sstevel@tonic-gate mac_state.mac_addr_len); 456*0Sstevel@tonic-gate bcopy((caddr_t)&ip, (caddr_t)ea->arp_spa, 457*0Sstevel@tonic-gate sizeof (struct in_addr)); 458*0Sstevel@tonic-gate (void) prom_write(mac_state.mac_dev, 459*0Sstevel@tonic-gate mac_state.mac_buf, 460*0Sstevel@tonic-gate sizeof (struct arp_packet), 461*0Sstevel@tonic-gate 0, NETWORK); 462*0Sstevel@tonic-gate /* don't charge for ARP replies */ 463*0Sstevel@tonic-gate timeout += reltime; 464*0Sstevel@tonic-gate } 465*0Sstevel@tonic-gate } 466*0Sstevel@tonic-gate } while (attempts < ETHER_INPUT_ATTEMPTS && 467*0Sstevel@tonic-gate #ifdef DEBUG 468*0Sstevel@tonic-gate (now = prom_gettime()) < timeout); 469*0Sstevel@tonic-gate #else 470*0Sstevel@tonic-gate prom_gettime() < timeout); 471*0Sstevel@tonic-gate #endif /* DEBUG */ 472*0Sstevel@tonic-gate 473*0Sstevel@tonic-gate #ifdef DEBUG 474*0Sstevel@tonic-gate printf("ether_input(%d): T/S/N/A/F/P/M: %d/%d/%d/%d/%d/%d/%d " 475*0Sstevel@tonic-gate "T/O: %d < %d = %s\n", index, total_attempts, frames, no_data, 476*0Sstevel@tonic-gate arps, failures, tot_pr, tot_pc, now, timeout, 477*0Sstevel@tonic-gate (now < timeout) ? "TRUE" : "FALSE"); 478*0Sstevel@tonic-gate #endif /* DEBUG */ 479*0Sstevel@tonic-gate return (frames); 480*0Sstevel@tonic-gate } 481*0Sstevel@tonic-gate 482*0Sstevel@tonic-gate /* 483*0Sstevel@tonic-gate * Send out an ethernet datagram. We expect a IP frame appropriately fragmented 484*0Sstevel@tonic-gate * at this level. 485*0Sstevel@tonic-gate * 486*0Sstevel@tonic-gate * Errno is set and -1 is returned if an error occurs. Number of bytes sent 487*0Sstevel@tonic-gate * is returned on success. 488*0Sstevel@tonic-gate */ 489*0Sstevel@tonic-gate /* ARGSUSED */ 490*0Sstevel@tonic-gate int 491*0Sstevel@tonic-gate ether_output(int index, struct inetgram *ogp) 492*0Sstevel@tonic-gate { 493*0Sstevel@tonic-gate int header_len, result; 494*0Sstevel@tonic-gate struct ether_header eh; 495*0Sstevel@tonic-gate struct ip *ip; 496*0Sstevel@tonic-gate struct in_addr tmpip, ipdst, netid; 497*0Sstevel@tonic-gate int broadcast = FALSE; 498*0Sstevel@tonic-gate int size; 499*0Sstevel@tonic-gate mblk_t *mp; 500*0Sstevel@tonic-gate 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate #ifdef DEBUG 503*0Sstevel@tonic-gate printf("ether_output (%d): size %d\n", index, 504*0Sstevel@tonic-gate ogp->igm_mp->b_wptr - ogp->igm_mp->b_rptr); 505*0Sstevel@tonic-gate #endif 506*0Sstevel@tonic-gate if (!initialized) 507*0Sstevel@tonic-gate prom_panic("Ethernet device is not initialized."); 508*0Sstevel@tonic-gate 509*0Sstevel@tonic-gate if (ogp->igm_level != MEDIA_LVL) { 510*0Sstevel@tonic-gate dprintf("ether_output: frame type wrong: socket: %d\n", 511*0Sstevel@tonic-gate index * SOCKETTYPE); 512*0Sstevel@tonic-gate errno = EINVAL; 513*0Sstevel@tonic-gate return (-1); 514*0Sstevel@tonic-gate } 515*0Sstevel@tonic-gate 516*0Sstevel@tonic-gate header_len = sizeof (struct ether_header); 517*0Sstevel@tonic-gate mp = ogp->igm_mp; 518*0Sstevel@tonic-gate size = mp->b_wptr - mp->b_rptr; 519*0Sstevel@tonic-gate if (size > mac_state.mac_mtu) { 520*0Sstevel@tonic-gate dprintf("ether_output: frame size too big: %d\n", size); 521*0Sstevel@tonic-gate errno = E2BIG; 522*0Sstevel@tonic-gate return (-1); 523*0Sstevel@tonic-gate } 524*0Sstevel@tonic-gate 525*0Sstevel@tonic-gate size += header_len; 526*0Sstevel@tonic-gate ip = (struct ip *)(mp->b_rptr); 527*0Sstevel@tonic-gate 528*0Sstevel@tonic-gate eh.ether_type = htons(ETHERTYPE_IP); 529*0Sstevel@tonic-gate bcopy(mac_state.mac_addr_buf, (caddr_t)&eh.ether_shost, 530*0Sstevel@tonic-gate mac_state.mac_addr_len); 531*0Sstevel@tonic-gate bcopy((caddr_t)&ip->ip_dst, (caddr_t)&ipdst, sizeof (ipdst)); 532*0Sstevel@tonic-gate 533*0Sstevel@tonic-gate if (ipdst.s_addr == htonl(INADDR_BROADCAST)) 534*0Sstevel@tonic-gate broadcast = TRUE; /* limited broadcast */ 535*0Sstevel@tonic-gate 536*0Sstevel@tonic-gate if (!broadcast) { 537*0Sstevel@tonic-gate struct in_addr mask; 538*0Sstevel@tonic-gate 539*0Sstevel@tonic-gate ipv4_getnetid(&netid); 540*0Sstevel@tonic-gate ipv4_getnetmask(&mask); 541*0Sstevel@tonic-gate mask.s_addr = htonl(mask.s_addr); 542*0Sstevel@tonic-gate netid.s_addr = htonl(netid.s_addr); 543*0Sstevel@tonic-gate if (mask.s_addr != htonl(INADDR_BROADCAST) && 544*0Sstevel@tonic-gate (ipdst.s_addr & mask.s_addr) == netid.s_addr) { 545*0Sstevel@tonic-gate broadcast = TRUE; /* directed broadcast */ 546*0Sstevel@tonic-gate } else { 547*0Sstevel@tonic-gate if (ogp->igm_router.s_addr != htonl(INADDR_ANY)) 548*0Sstevel@tonic-gate tmpip.s_addr = ogp->igm_router.s_addr; 549*0Sstevel@tonic-gate else 550*0Sstevel@tonic-gate tmpip.s_addr = ipdst.s_addr; 551*0Sstevel@tonic-gate 552*0Sstevel@tonic-gate result = mac_get_arp(&tmpip, (void *)&eh.ether_dhost, 553*0Sstevel@tonic-gate sizeof (ether_addr_t), mac_state.mac_arp_timeout); 554*0Sstevel@tonic-gate if (!result) { 555*0Sstevel@tonic-gate errno = ETIMEDOUT; 556*0Sstevel@tonic-gate dprintf("ether_output: ARP request for %s " 557*0Sstevel@tonic-gate "timed out.\n", inet_ntoa(tmpip)); 558*0Sstevel@tonic-gate return (-1); 559*0Sstevel@tonic-gate } 560*0Sstevel@tonic-gate } 561*0Sstevel@tonic-gate } 562*0Sstevel@tonic-gate 563*0Sstevel@tonic-gate if (broadcast) { 564*0Sstevel@tonic-gate bcopy((caddr_t)etherbroadcastaddr, 565*0Sstevel@tonic-gate (caddr_t)&eh.ether_dhost, sizeof (ether_addr_t)); 566*0Sstevel@tonic-gate } 567*0Sstevel@tonic-gate 568*0Sstevel@tonic-gate /* add the ethernet header */ 569*0Sstevel@tonic-gate mp->b_rptr -= sizeof (eh); 570*0Sstevel@tonic-gate bcopy((caddr_t)&eh, mp->b_rptr, sizeof (eh)); 571*0Sstevel@tonic-gate #ifdef DEBUG 572*0Sstevel@tonic-gate printf("ether_output(%d): level(%d) frame(0x%x) len(%d)\n", 573*0Sstevel@tonic-gate index, ogp->igm_level, mp->b_rptr, size); 574*0Sstevel@tonic-gate #if DEBUG > 1 575*0Sstevel@tonic-gate printf("Dump ethernet (%d): \n", size); 576*0Sstevel@tonic-gate hexdump((char *)mp->b_rptr, size); 577*0Sstevel@tonic-gate printf("\n"); 578*0Sstevel@tonic-gate #endif /* DEBUG > 1 */ 579*0Sstevel@tonic-gate #endif /* DEBUG */ 580*0Sstevel@tonic-gate return (prom_write(mac_state.mac_dev, (char *)mp->b_rptr, size, 581*0Sstevel@tonic-gate 0, NETWORK)); 582*0Sstevel@tonic-gate } 583