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