xref: /onnv-gate/usr/src/stand/lib/inet/ethernet.c (revision 627:8f27c35e7d30)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * Ethernet routines. Includes ARP and Reverse ARP. Used for ethernet-like
310Sstevel@tonic-gate  * media also - so be sure NOT to use ETHERMTU as a mtu limit. macinit()
320Sstevel@tonic-gate  * will set this appropriately.
330Sstevel@tonic-gate  */
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include <sys/types.h>
360Sstevel@tonic-gate #include <socket_impl.h>
370Sstevel@tonic-gate #include <socket_inet.h>
380Sstevel@tonic-gate #include <sys/time.h>
390Sstevel@tonic-gate #include <sys/socket.h>
400Sstevel@tonic-gate #include <net/if.h>
410Sstevel@tonic-gate #include <net/if_arp.h>
420Sstevel@tonic-gate #include <netinet/in_systm.h>
430Sstevel@tonic-gate #include <netinet/in.h>
440Sstevel@tonic-gate #include <netinet/ip.h>
450Sstevel@tonic-gate #include <netinet/if_ether.h>
460Sstevel@tonic-gate #include <sys/promif.h>
470Sstevel@tonic-gate #include <sys/prom_plat.h>
480Sstevel@tonic-gate #include <sys/salib.h>
490Sstevel@tonic-gate #include <sys/bootdebug.h>
500Sstevel@tonic-gate 
510Sstevel@tonic-gate #include "ipv4.h"
520Sstevel@tonic-gate #include "ipv4_impl.h"
530Sstevel@tonic-gate #include "mac.h"
540Sstevel@tonic-gate #include "mac_impl.h"
550Sstevel@tonic-gate #include "ethernet_inet.h"
560Sstevel@tonic-gate 
570Sstevel@tonic-gate ether_addr_t etherbroadcastaddr = {
580Sstevel@tonic-gate 	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
590Sstevel@tonic-gate };
600Sstevel@tonic-gate 
610Sstevel@tonic-gate struct arp_packet {
620Sstevel@tonic-gate 	struct ether_header	arp_eh;
630Sstevel@tonic-gate 	struct ether_arp	arp_ea;
640Sstevel@tonic-gate #define	USED_SIZE (sizeof (struct ether_header) + sizeof (struct ether_arp))
650Sstevel@tonic-gate 	char	filler[ETHERMIN - sizeof (struct ether_arp)];
660Sstevel@tonic-gate };
670Sstevel@tonic-gate 
680Sstevel@tonic-gate static char *
ether_print(ether_addr_t ea)690Sstevel@tonic-gate ether_print(ether_addr_t ea)
700Sstevel@tonic-gate {
710Sstevel@tonic-gate 	static char eprintbuf[20];
720Sstevel@tonic-gate 
730Sstevel@tonic-gate 	(void) sprintf(eprintbuf, "%x:%x:%x:%x:%x:%x", ea[0], ea[1], ea[2],
740Sstevel@tonic-gate 	    ea[3], ea[4], ea[5]);
750Sstevel@tonic-gate 	return (eprintbuf);
760Sstevel@tonic-gate }
770Sstevel@tonic-gate 
780Sstevel@tonic-gate /*
790Sstevel@tonic-gate  * Common ARP code. Broadcast the packet and wait for the right response.
800Sstevel@tonic-gate  *
810Sstevel@tonic-gate  * If rarp is called for, caller expects an IPv4 address in the target
820Sstevel@tonic-gate  * protocol address (tpa) field of the "out" argument.
830Sstevel@tonic-gate  *
840Sstevel@tonic-gate  * If arp is called for, caller expects a hardware address in the
850Sstevel@tonic-gate  * source hardware address (sha) field of the "out" argument.
860Sstevel@tonic-gate  *
870Sstevel@tonic-gate  * Returns TRUE if transaction succeeded, FALSE otherwise.
880Sstevel@tonic-gate  *
890Sstevel@tonic-gate  * The timeout argument is the number of milliseconds to wait for a
900Sstevel@tonic-gate  * response. An infinite timeout can be specified as 0xffffffff.
910Sstevel@tonic-gate  */
920Sstevel@tonic-gate static int
ether_comarp(struct arp_packet * out,uint32_t timeout)930Sstevel@tonic-gate ether_comarp(struct arp_packet *out, uint32_t timeout)
940Sstevel@tonic-gate {
950Sstevel@tonic-gate 	struct arp_packet *in = (struct arp_packet *)mac_state.mac_buf;
960Sstevel@tonic-gate 	int count, time, feedback, len, delay = 2;
970Sstevel@tonic-gate 	char    *ind = "-\\|/";
980Sstevel@tonic-gate 	struct in_addr tmp_ia;
990Sstevel@tonic-gate 	uint32_t wait_time;
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 	bcopy((caddr_t)etherbroadcastaddr, (caddr_t)&out->arp_eh.ether_dhost,
1020Sstevel@tonic-gate 	    sizeof (ether_addr_t));
1030Sstevel@tonic-gate 	bcopy((caddr_t)mac_state.mac_addr_buf,
1040Sstevel@tonic-gate 	    (caddr_t)&out->arp_eh.ether_shost, sizeof (ether_addr_t));
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate 	out->arp_ea.arp_hrd =  htons(ARPHRD_ETHER);
1070Sstevel@tonic-gate 	out->arp_ea.arp_pro = htons(ETHERTYPE_IP);
1080Sstevel@tonic-gate 	out->arp_ea.arp_hln = sizeof (ether_addr_t);
1090Sstevel@tonic-gate 	out->arp_ea.arp_pln = sizeof (struct in_addr);
1100Sstevel@tonic-gate 	bcopy(mac_state.mac_addr_buf, (caddr_t)&out->arp_ea.arp_sha,
1110Sstevel@tonic-gate 	    sizeof (ether_addr_t));
1120Sstevel@tonic-gate 	ipv4_getipaddr(&tmp_ia);
1130Sstevel@tonic-gate 	tmp_ia.s_addr = htonl(tmp_ia.s_addr);
1140Sstevel@tonic-gate 	bcopy((caddr_t)&tmp_ia, (caddr_t)out->arp_ea.arp_spa,
1150Sstevel@tonic-gate 	    sizeof (struct in_addr));
1160Sstevel@tonic-gate 	feedback = 0;
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 	wait_time = prom_gettime() + timeout;
1190Sstevel@tonic-gate 	for (count = 0; timeout == ~0U || prom_gettime() < wait_time; count++) {
1200Sstevel@tonic-gate 		if (count == ETHER_WAITCNT) {
1210Sstevel@tonic-gate 			if (out->arp_ea.arp_op == ARPOP_REQUEST) {
1220Sstevel@tonic-gate 				bcopy((caddr_t)out->arp_ea.arp_tpa,
1230Sstevel@tonic-gate 				    (caddr_t)&tmp_ia, sizeof (struct in_addr));
1240Sstevel@tonic-gate 				printf(
1250Sstevel@tonic-gate 				    "\nRequesting Ethernet address for: %s\n",
1260Sstevel@tonic-gate 				    inet_ntoa(tmp_ia));
1270Sstevel@tonic-gate 			} else {
1280Sstevel@tonic-gate 				printf("\nRequesting Internet address for %s\n",
1290Sstevel@tonic-gate 				    ether_print(out->arp_ea.arp_tha));
1300Sstevel@tonic-gate 			}
1310Sstevel@tonic-gate 		}
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 		(void) prom_write(mac_state.mac_dev, (caddr_t)out,
1340Sstevel@tonic-gate 		    sizeof (*out), 0, NETWORK);
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 		if (count >= ETHER_WAITCNT)
1370Sstevel@tonic-gate 			printf("%c\b", ind[feedback++ % 4]); /* activity */
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 		time = prom_gettime() + (delay * 1000);	/* broadcast delay */
1400Sstevel@tonic-gate 		while (prom_gettime() <= time) {
1410Sstevel@tonic-gate 			len = prom_read(mac_state.mac_dev, mac_state.mac_buf,
1420Sstevel@tonic-gate 			    mac_state.mac_mtu, 0, NETWORK);
1430Sstevel@tonic-gate 			if (len < USED_SIZE)
1440Sstevel@tonic-gate 				continue;
1450Sstevel@tonic-gate 			if (in->arp_ea.arp_pro != ntohs(ETHERTYPE_IP))
1460Sstevel@tonic-gate 				continue;
1470Sstevel@tonic-gate 			if (out->arp_ea.arp_op == ntohs(ARPOP_REQUEST)) {
1480Sstevel@tonic-gate 				if (in->arp_eh.ether_type !=
1490Sstevel@tonic-gate 				    ntohs(ETHERTYPE_ARP))
1500Sstevel@tonic-gate 					continue;
1510Sstevel@tonic-gate 				if (in->arp_ea.arp_op != ntohs(ARPOP_REPLY))
1520Sstevel@tonic-gate 					continue;
1530Sstevel@tonic-gate 				if (bcmp((caddr_t)in->arp_ea.arp_spa,
1540Sstevel@tonic-gate 				    (caddr_t)out->arp_ea.arp_tpa,
1550Sstevel@tonic-gate 				    sizeof (struct in_addr)) != 0)
1560Sstevel@tonic-gate 					continue;
1570Sstevel@tonic-gate 				if (boothowto & RB_VERBOSE) {
1580Sstevel@tonic-gate 					bcopy((caddr_t)in->arp_ea.arp_spa,
1590Sstevel@tonic-gate 					    (caddr_t)&tmp_ia,
1600Sstevel@tonic-gate 					    sizeof (struct in_addr));
1610Sstevel@tonic-gate 					printf("Found %s @ %s\n",
1620Sstevel@tonic-gate 					    inet_ntoa(tmp_ia),
1630Sstevel@tonic-gate 					    ether_print(in->arp_ea.arp_sha));
1640Sstevel@tonic-gate 				}
1650Sstevel@tonic-gate 				/* copy hardware addr into "out" for caller */
1660Sstevel@tonic-gate 				bcopy((caddr_t)&in->arp_ea.arp_sha,
1670Sstevel@tonic-gate 				    (caddr_t)&out->arp_ea.arp_sha,
1680Sstevel@tonic-gate 				    sizeof (ether_addr_t));
1690Sstevel@tonic-gate 				return (TRUE);
1700Sstevel@tonic-gate 			} else {		/* Reverse ARP */
1710Sstevel@tonic-gate 				if (in->arp_eh.ether_type !=
1720Sstevel@tonic-gate 				    ntohs(ETHERTYPE_REVARP))
1730Sstevel@tonic-gate 					continue;
1740Sstevel@tonic-gate 				if (in->arp_ea.arp_op != ntohs(REVARP_REPLY))
1750Sstevel@tonic-gate 					continue;
1760Sstevel@tonic-gate 				if (bcmp((caddr_t)in->arp_ea.arp_tha,
1770Sstevel@tonic-gate 				    (caddr_t)out->arp_ea.arp_tha,
1780Sstevel@tonic-gate 				    sizeof (ether_addr_t)) != 0)
1790Sstevel@tonic-gate 					continue;
1800Sstevel@tonic-gate 				if (boothowto & RB_VERBOSE) {
1810Sstevel@tonic-gate 					bcopy((caddr_t)in->arp_ea.arp_tpa,
1820Sstevel@tonic-gate 					    (caddr_t)&tmp_ia,
1830Sstevel@tonic-gate 					    sizeof (struct in_addr));
1840Sstevel@tonic-gate 					printf("Internet address is: %s\n",
1850Sstevel@tonic-gate 					    inet_ntoa(tmp_ia));
1860Sstevel@tonic-gate 				}
1870Sstevel@tonic-gate 				/* copy IP address into "out" for caller */
1880Sstevel@tonic-gate 				bcopy((caddr_t)in->arp_ea.arp_tpa,
1890Sstevel@tonic-gate 				    (caddr_t)out->arp_ea.arp_tpa,
1900Sstevel@tonic-gate 				    sizeof (struct in_addr));
1910Sstevel@tonic-gate 				return (TRUE);
1920Sstevel@tonic-gate 			}
1930Sstevel@tonic-gate 		}
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 		delay = delay * 2;	/* Double the request delay */
1960Sstevel@tonic-gate 		if (delay > 64)		/* maximum delay is 64 seconds */
1970Sstevel@tonic-gate 			delay = 64;
1980Sstevel@tonic-gate 	}
1990Sstevel@tonic-gate 	return (FALSE);
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate /*
2030Sstevel@tonic-gate  * ARP client side
2040Sstevel@tonic-gate  * Broadcasts to determine MAC address given network order IP address.
2050Sstevel@tonic-gate  * See RFC 826
2060Sstevel@tonic-gate  *
2070Sstevel@tonic-gate  * Returns TRUE if successful, FALSE otherwise.
2080Sstevel@tonic-gate  */
2090Sstevel@tonic-gate int
ether_arp(struct in_addr * ip,void * hap,uint32_t timeout)2100Sstevel@tonic-gate ether_arp(struct in_addr *ip, void *hap, uint32_t timeout)
2110Sstevel@tonic-gate {
2120Sstevel@tonic-gate 	ether_addr_t *ep = (ether_addr_t *)hap;
2130Sstevel@tonic-gate 	struct arp_packet out;
2140Sstevel@tonic-gate 	int result;
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	if (!initialized)
2170Sstevel@tonic-gate 		prom_panic("Ethernet device is not initialized.");
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	bzero((char *)&out, sizeof (struct arp_packet));
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	out.arp_eh.ether_type = htons(ETHERTYPE_ARP);
2220Sstevel@tonic-gate 	out.arp_ea.arp_op = htons(ARPOP_REQUEST);
2230Sstevel@tonic-gate 	bcopy((caddr_t)etherbroadcastaddr, (caddr_t)&out.arp_ea.arp_tha,
2240Sstevel@tonic-gate 	    sizeof (ether_addr_t));
2250Sstevel@tonic-gate 	bcopy((caddr_t)ip, (caddr_t)out.arp_ea.arp_tpa,
2260Sstevel@tonic-gate 	    sizeof (struct in_addr));
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	result = ether_comarp(&out, timeout);
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	if (result && (ep != NULL)) {
2310Sstevel@tonic-gate 		bcopy((caddr_t)&out.arp_ea.arp_sha, (caddr_t)ep,
2320Sstevel@tonic-gate 		    sizeof (ether_addr_t));
2330Sstevel@tonic-gate 	}
2340Sstevel@tonic-gate 	return (result);
2350Sstevel@tonic-gate }
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate /*
2380Sstevel@tonic-gate  * Reverse ARP client side
2390Sstevel@tonic-gate  * Determine our Internet address given our MAC address
2400Sstevel@tonic-gate  * See RFC 903
2410Sstevel@tonic-gate  */
2420Sstevel@tonic-gate void
ether_revarp(void)2430Sstevel@tonic-gate ether_revarp(void)
2440Sstevel@tonic-gate {
2450Sstevel@tonic-gate 	struct in_addr	ip;
2460Sstevel@tonic-gate 	struct arp_packet out;
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	if (!initialized)
2490Sstevel@tonic-gate 		prom_panic("Ethernet device is not initialized.");
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	bzero((char *)&out, sizeof (struct arp_packet));
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 	out.arp_eh.ether_type = htons(ETHERTYPE_REVARP);
2540Sstevel@tonic-gate 	out.arp_ea.arp_op = htons(REVARP_REQUEST);
2550Sstevel@tonic-gate 	bcopy(mac_state.mac_addr_buf, (caddr_t)&out.arp_ea.arp_tha,
2560Sstevel@tonic-gate 	    sizeof (ether_addr_t));
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	/* Wait forever */
2590Sstevel@tonic-gate 	(void) ether_comarp(&out, 0xffffffff);
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	bcopy((caddr_t)&out.arp_ea.arp_tpa, (caddr_t)&ip,
2620Sstevel@tonic-gate 	    sizeof (struct in_addr));
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 	ip.s_addr = ntohl(ip.s_addr);
2650Sstevel@tonic-gate 	ipv4_setipaddr(&ip);
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate /* ARGSUSED */
2690Sstevel@tonic-gate int
ether_header_len(struct inetgram * igm)2700Sstevel@tonic-gate ether_header_len(struct inetgram *igm)
2710Sstevel@tonic-gate {
2720Sstevel@tonic-gate 	return (sizeof (struct ether_header));
2730Sstevel@tonic-gate }
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate /*
2760Sstevel@tonic-gate  * Handle a IP datagram addressed to our ethernet address or to the
2770Sstevel@tonic-gate  * ethernet broadcast address. Also respond to ARP requests. Generates
2780Sstevel@tonic-gate  * inetgrams as long as there's data and the mac level IP timeout timer
2790Sstevel@tonic-gate  * hasn't expired. As soon as there is no data, we try for
2800Sstevel@tonic-gate  * ETHER_INPUT_ATTEMPTS for more, then exit the loop, even if there is time
2810Sstevel@tonic-gate  * left, since we expect to have data waiting for us when we're called, we just
2820Sstevel@tonic-gate  * don't know how much.
2830Sstevel@tonic-gate  *
2840Sstevel@tonic-gate  * We workaround slow proms (some proms have hard sleeps for as much as 3msec)
2850Sstevel@tonic-gate  * even though there are is data waiting.
2860Sstevel@tonic-gate  *
2870Sstevel@tonic-gate  * Returns the total number of MEDIA_LVL frames placed on the socket.
2880Sstevel@tonic-gate  * Caller is expected to free up the inetgram resources.
2890Sstevel@tonic-gate  */
2900Sstevel@tonic-gate int
ether_input(int index)2910Sstevel@tonic-gate ether_input(int index)
2920Sstevel@tonic-gate {
2930Sstevel@tonic-gate 	struct inetgram		*inp;
2940Sstevel@tonic-gate 	struct ether_header	*eh;
2950Sstevel@tonic-gate 	int		frames = 0;	/* successful frames */
2960Sstevel@tonic-gate 	int		attempts = 0;	/* failed attempts after success */
2970Sstevel@tonic-gate 	int16_t		len = 0, data_len;
2980Sstevel@tonic-gate 	uint32_t	timeout, reltime;
2990Sstevel@tonic-gate 	uint32_t	pre_pr, post_pr; /* prom_read interval */
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate #ifdef	DEBUG
3020Sstevel@tonic-gate 	int		failures = 0;		/* total failures */
3030Sstevel@tonic-gate 	int		total_attempts = 0;	/* total prom_read */
3040Sstevel@tonic-gate 	int		no_data = 0;		/* no data in prom */
3050Sstevel@tonic-gate 	int		arps = 0;		/* arp requests processed */
3060Sstevel@tonic-gate 	uint32_t	tot_pr = 0;		/* prom_read time */
3070Sstevel@tonic-gate 	uint32_t	tot_pc = 0;		/* inetgram creation time */
3080Sstevel@tonic-gate 	uint32_t	pre_pc;
3090Sstevel@tonic-gate 	uint32_t	now;
3100Sstevel@tonic-gate #endif	/* DEBUG */
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	if (!initialized)
3130Sstevel@tonic-gate 		prom_panic("Ethernet device is not initialized.");
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	if ((reltime = sockets[index].in_timeout) == 0)
3160Sstevel@tonic-gate 		reltime = mac_state.mac_in_timeout;
3170Sstevel@tonic-gate 	timeout = prom_gettime() + reltime;
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	do {
3200Sstevel@tonic-gate 		if (frames > ETHER_MAX_FRAMES) {
3210Sstevel@tonic-gate 			/* someone is trying a denial of service attack */
3220Sstevel@tonic-gate 			break;
3230Sstevel@tonic-gate 		}
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 		/*
3260Sstevel@tonic-gate 		 * The following is a workaround for a calvin prom (V2) bug
3270Sstevel@tonic-gate 		 * where prom_read() returns a nonzero length, even when it's
3280Sstevel@tonic-gate 		 * not read a packet. So we zero out the header to compensate.
3290Sstevel@tonic-gate 		 */
3300Sstevel@tonic-gate 		bzero(mac_state.mac_buf, sizeof (struct ether_header));
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 		/*
3330Sstevel@tonic-gate 		 * Prom_read() will return 0 or -2 if no data is present. A
3340Sstevel@tonic-gate 		 * return value of -1 means an error has occurred. We adjust
3350Sstevel@tonic-gate 		 * the timeout by calling the time spent in prom_read() "free".
3360Sstevel@tonic-gate 		 * prom_read() returns the number of bytes actually read, but
3370Sstevel@tonic-gate 		 * will only copy "len" bytes into our buffer. Adjust in
3380Sstevel@tonic-gate 		 * case the MTU is wrong.
3390Sstevel@tonic-gate 		 */
3400Sstevel@tonic-gate 		pre_pr = prom_gettime();
3410Sstevel@tonic-gate 		len = prom_read(mac_state.mac_dev, mac_state.mac_buf,
3420Sstevel@tonic-gate 		    mac_state.mac_mtu, 0, NETWORK);
3430Sstevel@tonic-gate 		post_pr = prom_gettime();
3440Sstevel@tonic-gate 		timeout += (post_pr - pre_pr);
3450Sstevel@tonic-gate #ifdef	DEBUG
3460Sstevel@tonic-gate 		tot_pr += (post_pr - pre_pr);
3470Sstevel@tonic-gate 		total_attempts++;
3480Sstevel@tonic-gate #endif	/* DEBUG */
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 		if (len > mac_state.mac_mtu) {
3510Sstevel@tonic-gate 			dprintf("ether_input: adjusting MTU %d -> %d\n",
3520Sstevel@tonic-gate 			    mac_state.mac_mtu, len);
3530Sstevel@tonic-gate 			bkmem_free(mac_state.mac_buf, mac_state.mac_mtu);
3540Sstevel@tonic-gate 			mac_state.mac_mtu = len;
3550Sstevel@tonic-gate 			mac_state.mac_buf = bkmem_alloc(mac_state.mac_mtu);
3560Sstevel@tonic-gate 			if (mac_state.mac_buf == NULL) {
3570Sstevel@tonic-gate 				prom_panic("ether_input: Cannot reallocate "
3580Sstevel@tonic-gate 				    "netbuf memory.");
3590Sstevel@tonic-gate 			}
3600Sstevel@tonic-gate 			len = 0; /* pretend there was no data */
3610Sstevel@tonic-gate 		}
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 		if (len == -1) {
3640Sstevel@tonic-gate #ifdef	DEBUG
3650Sstevel@tonic-gate 			failures++;
3660Sstevel@tonic-gate #endif	/* DEBUG */
3670Sstevel@tonic-gate 			break;
3680Sstevel@tonic-gate 		}
3690Sstevel@tonic-gate 		if (len == 0 || len == -2) {
3700Sstevel@tonic-gate 			if (frames != 0)
3710Sstevel@tonic-gate 				attempts++;
3720Sstevel@tonic-gate #ifdef	DEBUG
3730Sstevel@tonic-gate 			no_data++;
3740Sstevel@tonic-gate #endif	/* DEBUG */
3750Sstevel@tonic-gate 			continue;
3760Sstevel@tonic-gate 		}
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 		eh = (struct ether_header *)mac_state.mac_buf;
3790Sstevel@tonic-gate 		if (eh->ether_type == ntohs(ETHERTYPE_IP) &&
3800Sstevel@tonic-gate 		    len >= (sizeof (struct ether_header) +
3810Sstevel@tonic-gate 		    sizeof (struct ip))) {
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 			int offset;
3840Sstevel@tonic-gate #ifdef	DEBUG
3850Sstevel@tonic-gate 			pre_pc = prom_gettime();
3860Sstevel@tonic-gate #endif	/* DEBUG */
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 			inp = (struct inetgram *)bkmem_zalloc(
3890Sstevel@tonic-gate 			    sizeof (struct inetgram));
3900Sstevel@tonic-gate 			if (inp == NULL) {
3910Sstevel@tonic-gate 				errno = ENOMEM;
3920Sstevel@tonic-gate 				return (frames == 0 ? -1 : frames);
3930Sstevel@tonic-gate 			}
3940Sstevel@tonic-gate 			offset = sizeof (struct ether_header);
3950Sstevel@tonic-gate 			data_len = len - offset;
3960Sstevel@tonic-gate 			inp->igm_mp = allocb(data_len, 0);
3970Sstevel@tonic-gate 			if (inp->igm_mp == NULL) {
3980Sstevel@tonic-gate 				errno = ENOMEM;
3990Sstevel@tonic-gate 				bkmem_free((caddr_t)inp,
4000Sstevel@tonic-gate 				    sizeof (struct inetgram));
4010Sstevel@tonic-gate 				return (frames == 0 ? -1 : frames);
4020Sstevel@tonic-gate 			}
4030Sstevel@tonic-gate 			bcopy((caddr_t)(mac_state.mac_buf + offset),
4040Sstevel@tonic-gate 			    inp->igm_mp->b_rptr, data_len);
4050Sstevel@tonic-gate 			inp->igm_mp->b_wptr += data_len;
4060Sstevel@tonic-gate 			inp->igm_level = NETWORK_LVL;
4070Sstevel@tonic-gate 			add_grams(&sockets[index].inq, inp);
4080Sstevel@tonic-gate 			frames++;
4090Sstevel@tonic-gate 			attempts = 0;
4100Sstevel@tonic-gate #ifdef	DEBUG
4110Sstevel@tonic-gate 			tot_pc += prom_gettime() - pre_pc;
4120Sstevel@tonic-gate #endif	/* DEBUG */
4130Sstevel@tonic-gate 			continue;
4140Sstevel@tonic-gate 		}
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 		if (eh->ether_type == ntohs(ETHERTYPE_ARP) &&
4170Sstevel@tonic-gate 		    len >= (sizeof (struct ether_header) +
4180Sstevel@tonic-gate 		    sizeof (struct ether_arp))) {
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 			struct in_addr		ip;
4210Sstevel@tonic-gate 			struct ether_arp	*ea;
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate #ifdef	DEBUG
4240Sstevel@tonic-gate 			printf("ether_input: ARP message received\n");
4250Sstevel@tonic-gate 			arps++;
4260Sstevel@tonic-gate #endif	/* DEBUG */
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 			ea = (struct ether_arp *)(mac_state.mac_buf +
4290Sstevel@tonic-gate 			    sizeof (struct ether_header));
4300Sstevel@tonic-gate 			if (ea->arp_pro != ntohs(ETHERTYPE_IP))
4310Sstevel@tonic-gate 				continue;
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 			ipv4_getipaddr(&ip);
4340Sstevel@tonic-gate 			ip.s_addr = ntohl(ip.s_addr);
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 			if (ea->arp_op == ntohs(ARPOP_REQUEST) &&
4370Sstevel@tonic-gate 			    ip.s_addr != INADDR_ANY &&
4380Sstevel@tonic-gate 			    (bcmp((caddr_t)ea->arp_tpa, (caddr_t)&ip,
4390Sstevel@tonic-gate 			    sizeof (struct in_addr)) == 0)) {
4400Sstevel@tonic-gate 				ea->arp_op = htons(ARPOP_REPLY);
4410Sstevel@tonic-gate 				bcopy((caddr_t)ea->arp_sha,
4420Sstevel@tonic-gate 				    (caddr_t)&eh->ether_dhost,
4430Sstevel@tonic-gate 				    sizeof (ether_addr_t));
4440Sstevel@tonic-gate 				bcopy(mac_state.mac_addr_buf,
4450Sstevel@tonic-gate 				    (caddr_t)&eh->ether_shost,
4460Sstevel@tonic-gate 				    mac_state.mac_addr_len);
4470Sstevel@tonic-gate 				bcopy((caddr_t)ea->arp_sha,
4480Sstevel@tonic-gate 				    (caddr_t)ea->arp_tha,
4490Sstevel@tonic-gate 				    sizeof (ether_addr_t));
4500Sstevel@tonic-gate 				bcopy((caddr_t)ea->arp_spa,
4510Sstevel@tonic-gate 				    (caddr_t)ea->arp_tpa,
4520Sstevel@tonic-gate 				    sizeof (struct in_addr));
4530Sstevel@tonic-gate 				bcopy(mac_state.mac_addr_buf,
4540Sstevel@tonic-gate 				    (caddr_t)ea->arp_sha,
4550Sstevel@tonic-gate 				    mac_state.mac_addr_len);
4560Sstevel@tonic-gate 				bcopy((caddr_t)&ip, (caddr_t)ea->arp_spa,
4570Sstevel@tonic-gate 				    sizeof (struct in_addr));
4580Sstevel@tonic-gate 				(void) prom_write(mac_state.mac_dev,
4590Sstevel@tonic-gate 				    mac_state.mac_buf,
4600Sstevel@tonic-gate 				    sizeof (struct arp_packet),
4610Sstevel@tonic-gate 				    0, NETWORK);
4620Sstevel@tonic-gate 				/* don't charge for ARP replies */
4630Sstevel@tonic-gate 				timeout += reltime;
4640Sstevel@tonic-gate 			}
4650Sstevel@tonic-gate 		}
4660Sstevel@tonic-gate 	} while (attempts < ETHER_INPUT_ATTEMPTS &&
4670Sstevel@tonic-gate #ifdef	DEBUG
4680Sstevel@tonic-gate 		(now = prom_gettime()) < timeout);
4690Sstevel@tonic-gate #else
4700Sstevel@tonic-gate 		prom_gettime() < timeout);
4710Sstevel@tonic-gate #endif	/* DEBUG */
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate #ifdef	DEBUG
4740Sstevel@tonic-gate 	printf("ether_input(%d): T/S/N/A/F/P/M: %d/%d/%d/%d/%d/%d/%d "
4750Sstevel@tonic-gate 	    "T/O: %d < %d = %s\n", index, total_attempts, frames, no_data,
4760Sstevel@tonic-gate 	    arps, failures, tot_pr, tot_pc, now, timeout,
4770Sstevel@tonic-gate 	    (now < timeout) ? "TRUE" : "FALSE");
4780Sstevel@tonic-gate #endif	/* DEBUG */
4790Sstevel@tonic-gate 	return (frames);
4800Sstevel@tonic-gate }
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate /*
4830Sstevel@tonic-gate  * Send out an ethernet datagram. We expect a IP frame appropriately fragmented
4840Sstevel@tonic-gate  * at this level.
4850Sstevel@tonic-gate  *
4860Sstevel@tonic-gate  * Errno is set and -1 is returned if an error occurs. Number of bytes sent
4870Sstevel@tonic-gate  * is returned on success.
4880Sstevel@tonic-gate  */
4890Sstevel@tonic-gate /* ARGSUSED */
4900Sstevel@tonic-gate int
ether_output(int index,struct inetgram * ogp)4910Sstevel@tonic-gate ether_output(int index, struct inetgram *ogp)
4920Sstevel@tonic-gate {
4930Sstevel@tonic-gate 	int			header_len, result;
4940Sstevel@tonic-gate 	struct ether_header	eh;
4950Sstevel@tonic-gate 	struct ip		*ip;
4960Sstevel@tonic-gate 	struct in_addr		tmpip, ipdst, netid;
4970Sstevel@tonic-gate 	int			broadcast = FALSE;
4980Sstevel@tonic-gate 	int			size;
4990Sstevel@tonic-gate 	mblk_t			*mp;
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate #ifdef DEBUG
5030Sstevel@tonic-gate 	printf("ether_output (%d): size %d\n", index,
5040Sstevel@tonic-gate 	    ogp->igm_mp->b_wptr - ogp->igm_mp->b_rptr);
5050Sstevel@tonic-gate #endif
5060Sstevel@tonic-gate 	if (!initialized)
5070Sstevel@tonic-gate 		prom_panic("Ethernet device is not initialized.");
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	if (ogp->igm_level != MEDIA_LVL) {
5100Sstevel@tonic-gate 		dprintf("ether_output: frame type wrong: socket: %d\n",
5110Sstevel@tonic-gate 		    index * SOCKETTYPE);
5120Sstevel@tonic-gate 		errno = EINVAL;
5130Sstevel@tonic-gate 		return (-1);
5140Sstevel@tonic-gate 	}
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	header_len = sizeof (struct ether_header);
5170Sstevel@tonic-gate 	mp = ogp->igm_mp;
5180Sstevel@tonic-gate 	size = mp->b_wptr - mp->b_rptr;
5190Sstevel@tonic-gate 	if (size > mac_state.mac_mtu) {
5200Sstevel@tonic-gate 		dprintf("ether_output: frame size too big: %d\n", size);
5210Sstevel@tonic-gate 		errno = E2BIG;
5220Sstevel@tonic-gate 		return (-1);
5230Sstevel@tonic-gate 	}
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	size += header_len;
5260Sstevel@tonic-gate 	ip = (struct ip *)(mp->b_rptr);
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	eh.ether_type = htons(ETHERTYPE_IP);
5290Sstevel@tonic-gate 	bcopy(mac_state.mac_addr_buf, (caddr_t)&eh.ether_shost,
5300Sstevel@tonic-gate 	    mac_state.mac_addr_len);
5310Sstevel@tonic-gate 	bcopy((caddr_t)&ip->ip_dst, (caddr_t)&ipdst, sizeof (ipdst));
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 	if (ipdst.s_addr == htonl(INADDR_BROADCAST))
5340Sstevel@tonic-gate 		broadcast = TRUE; /* limited broadcast */
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 	if (!broadcast) {
5370Sstevel@tonic-gate 		struct in_addr mask;
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 		ipv4_getnetid(&netid);
5400Sstevel@tonic-gate 		ipv4_getnetmask(&mask);
5410Sstevel@tonic-gate 		mask.s_addr = htonl(mask.s_addr);
5420Sstevel@tonic-gate 		netid.s_addr = htonl(netid.s_addr);
543*627Sss146032 
544*627Sss146032 		/*
545*627Sss146032 		 * check for all-hosts directed broadcast for
546*627Sss146032 		 * to its own subnet.
547*627Sss146032 		 */
5480Sstevel@tonic-gate 		if (mask.s_addr != htonl(INADDR_BROADCAST) &&
549*627Sss146032 		    (ipdst.s_addr & ~mask.s_addr) == 0 &&
5500Sstevel@tonic-gate 		    (ipdst.s_addr & mask.s_addr) ==  netid.s_addr) {
5510Sstevel@tonic-gate 			broadcast = TRUE; /* directed broadcast */
5520Sstevel@tonic-gate 		} else {
5530Sstevel@tonic-gate 			if (ogp->igm_router.s_addr != htonl(INADDR_ANY))
5540Sstevel@tonic-gate 				tmpip.s_addr = ogp->igm_router.s_addr;
5550Sstevel@tonic-gate 			else
5560Sstevel@tonic-gate 				tmpip.s_addr = ipdst.s_addr;
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 			result = mac_get_arp(&tmpip, (void *)&eh.ether_dhost,
5590Sstevel@tonic-gate 			    sizeof (ether_addr_t), mac_state.mac_arp_timeout);
5600Sstevel@tonic-gate 			if (!result) {
5610Sstevel@tonic-gate 				errno = ETIMEDOUT;
5620Sstevel@tonic-gate 				dprintf("ether_output: ARP request for %s "
5630Sstevel@tonic-gate 				    "timed out.\n", inet_ntoa(tmpip));
5640Sstevel@tonic-gate 				return (-1);
5650Sstevel@tonic-gate 			}
5660Sstevel@tonic-gate 		}
5670Sstevel@tonic-gate 	}
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 	if (broadcast) {
5700Sstevel@tonic-gate 		bcopy((caddr_t)etherbroadcastaddr,
5710Sstevel@tonic-gate 		    (caddr_t)&eh.ether_dhost, sizeof (ether_addr_t));
5720Sstevel@tonic-gate 	}
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	/* add the ethernet header */
5750Sstevel@tonic-gate 	mp->b_rptr -= sizeof (eh);
5760Sstevel@tonic-gate 	bcopy((caddr_t)&eh, mp->b_rptr, sizeof (eh));
5770Sstevel@tonic-gate #ifdef	DEBUG
5780Sstevel@tonic-gate 	printf("ether_output(%d): level(%d) frame(0x%x) len(%d)\n",
5790Sstevel@tonic-gate 	    index, ogp->igm_level, mp->b_rptr, size);
5800Sstevel@tonic-gate #if DEBUG > 1
5810Sstevel@tonic-gate 	printf("Dump ethernet (%d): \n", size);
5820Sstevel@tonic-gate 	hexdump((char *)mp->b_rptr, size);
5830Sstevel@tonic-gate 	printf("\n");
5840Sstevel@tonic-gate #endif /* DEBUG > 1 */
5850Sstevel@tonic-gate #endif	/* DEBUG */
5860Sstevel@tonic-gate 	return (prom_write(mac_state.mac_dev, (char *)mp->b_rptr, size,
5870Sstevel@tonic-gate 	    0, NETWORK));
5880Sstevel@tonic-gate }
589