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