17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate * with the License.
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate * and limitations under the License.
137c478bd9Sstevel@tonic-gate *
147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate *
207c478bd9Sstevel@tonic-gate * CDDL HEADER END
217c478bd9Sstevel@tonic-gate */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate * Ethernet routines. Includes ARP and Reverse ARP. Used for ethernet-like
317c478bd9Sstevel@tonic-gate * media also - so be sure NOT to use ETHERMTU as a mtu limit. macinit()
327c478bd9Sstevel@tonic-gate * will set this appropriately.
337c478bd9Sstevel@tonic-gate */
347c478bd9Sstevel@tonic-gate
357c478bd9Sstevel@tonic-gate #include <sys/types.h>
367c478bd9Sstevel@tonic-gate #include <socket_impl.h>
377c478bd9Sstevel@tonic-gate #include <socket_inet.h>
387c478bd9Sstevel@tonic-gate #include <sys/time.h>
397c478bd9Sstevel@tonic-gate #include <sys/socket.h>
407c478bd9Sstevel@tonic-gate #include <net/if.h>
417c478bd9Sstevel@tonic-gate #include <net/if_arp.h>
427c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h>
437c478bd9Sstevel@tonic-gate #include <netinet/in.h>
447c478bd9Sstevel@tonic-gate #include <netinet/ip.h>
457c478bd9Sstevel@tonic-gate #include <netinet/if_ether.h>
467c478bd9Sstevel@tonic-gate #include <sys/promif.h>
477c478bd9Sstevel@tonic-gate #include <sys/prom_plat.h>
487c478bd9Sstevel@tonic-gate #include <sys/salib.h>
497c478bd9Sstevel@tonic-gate #include <sys/bootdebug.h>
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate #include "ipv4.h"
527c478bd9Sstevel@tonic-gate #include "ipv4_impl.h"
537c478bd9Sstevel@tonic-gate #include "mac.h"
547c478bd9Sstevel@tonic-gate #include "mac_impl.h"
557c478bd9Sstevel@tonic-gate #include "ethernet_inet.h"
567c478bd9Sstevel@tonic-gate
577c478bd9Sstevel@tonic-gate ether_addr_t etherbroadcastaddr = {
587c478bd9Sstevel@tonic-gate 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
597c478bd9Sstevel@tonic-gate };
607c478bd9Sstevel@tonic-gate
617c478bd9Sstevel@tonic-gate struct arp_packet {
627c478bd9Sstevel@tonic-gate struct ether_header arp_eh;
637c478bd9Sstevel@tonic-gate struct ether_arp arp_ea;
647c478bd9Sstevel@tonic-gate #define USED_SIZE (sizeof (struct ether_header) + sizeof (struct ether_arp))
657c478bd9Sstevel@tonic-gate char filler[ETHERMIN - sizeof (struct ether_arp)];
667c478bd9Sstevel@tonic-gate };
677c478bd9Sstevel@tonic-gate
687c478bd9Sstevel@tonic-gate static char *
ether_print(ether_addr_t ea)697c478bd9Sstevel@tonic-gate ether_print(ether_addr_t ea)
707c478bd9Sstevel@tonic-gate {
717c478bd9Sstevel@tonic-gate static char eprintbuf[20];
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gate (void) sprintf(eprintbuf, "%x:%x:%x:%x:%x:%x", ea[0], ea[1], ea[2],
747c478bd9Sstevel@tonic-gate ea[3], ea[4], ea[5]);
757c478bd9Sstevel@tonic-gate return (eprintbuf);
767c478bd9Sstevel@tonic-gate }
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate * Common ARP code. Broadcast the packet and wait for the right response.
807c478bd9Sstevel@tonic-gate *
817c478bd9Sstevel@tonic-gate * If rarp is called for, caller expects an IPv4 address in the target
827c478bd9Sstevel@tonic-gate * protocol address (tpa) field of the "out" argument.
837c478bd9Sstevel@tonic-gate *
847c478bd9Sstevel@tonic-gate * If arp is called for, caller expects a hardware address in the
857c478bd9Sstevel@tonic-gate * source hardware address (sha) field of the "out" argument.
867c478bd9Sstevel@tonic-gate *
877c478bd9Sstevel@tonic-gate * Returns TRUE if transaction succeeded, FALSE otherwise.
887c478bd9Sstevel@tonic-gate *
897c478bd9Sstevel@tonic-gate * The timeout argument is the number of milliseconds to wait for a
907c478bd9Sstevel@tonic-gate * response. An infinite timeout can be specified as 0xffffffff.
917c478bd9Sstevel@tonic-gate */
927c478bd9Sstevel@tonic-gate static int
ether_comarp(struct arp_packet * out,uint32_t timeout)937c478bd9Sstevel@tonic-gate ether_comarp(struct arp_packet *out, uint32_t timeout)
947c478bd9Sstevel@tonic-gate {
957c478bd9Sstevel@tonic-gate struct arp_packet *in = (struct arp_packet *)mac_state.mac_buf;
967c478bd9Sstevel@tonic-gate int count, time, feedback, len, delay = 2;
977c478bd9Sstevel@tonic-gate char *ind = "-\\|/";
987c478bd9Sstevel@tonic-gate struct in_addr tmp_ia;
997c478bd9Sstevel@tonic-gate uint32_t wait_time;
1007c478bd9Sstevel@tonic-gate
1017c478bd9Sstevel@tonic-gate bcopy((caddr_t)etherbroadcastaddr, (caddr_t)&out->arp_eh.ether_dhost,
1027c478bd9Sstevel@tonic-gate sizeof (ether_addr_t));
1037c478bd9Sstevel@tonic-gate bcopy((caddr_t)mac_state.mac_addr_buf,
1047c478bd9Sstevel@tonic-gate (caddr_t)&out->arp_eh.ether_shost, sizeof (ether_addr_t));
1057c478bd9Sstevel@tonic-gate
1067c478bd9Sstevel@tonic-gate out->arp_ea.arp_hrd = htons(ARPHRD_ETHER);
1077c478bd9Sstevel@tonic-gate out->arp_ea.arp_pro = htons(ETHERTYPE_IP);
1087c478bd9Sstevel@tonic-gate out->arp_ea.arp_hln = sizeof (ether_addr_t);
1097c478bd9Sstevel@tonic-gate out->arp_ea.arp_pln = sizeof (struct in_addr);
1107c478bd9Sstevel@tonic-gate bcopy(mac_state.mac_addr_buf, (caddr_t)&out->arp_ea.arp_sha,
1117c478bd9Sstevel@tonic-gate sizeof (ether_addr_t));
1127c478bd9Sstevel@tonic-gate ipv4_getipaddr(&tmp_ia);
1137c478bd9Sstevel@tonic-gate tmp_ia.s_addr = htonl(tmp_ia.s_addr);
1147c478bd9Sstevel@tonic-gate bcopy((caddr_t)&tmp_ia, (caddr_t)out->arp_ea.arp_spa,
1157c478bd9Sstevel@tonic-gate sizeof (struct in_addr));
1167c478bd9Sstevel@tonic-gate feedback = 0;
1177c478bd9Sstevel@tonic-gate
1187c478bd9Sstevel@tonic-gate wait_time = prom_gettime() + timeout;
1197c478bd9Sstevel@tonic-gate for (count = 0; timeout == ~0U || prom_gettime() < wait_time; count++) {
1207c478bd9Sstevel@tonic-gate if (count == ETHER_WAITCNT) {
1217c478bd9Sstevel@tonic-gate if (out->arp_ea.arp_op == ARPOP_REQUEST) {
1227c478bd9Sstevel@tonic-gate bcopy((caddr_t)out->arp_ea.arp_tpa,
1237c478bd9Sstevel@tonic-gate (caddr_t)&tmp_ia, sizeof (struct in_addr));
1247c478bd9Sstevel@tonic-gate printf(
1257c478bd9Sstevel@tonic-gate "\nRequesting Ethernet address for: %s\n",
1267c478bd9Sstevel@tonic-gate inet_ntoa(tmp_ia));
1277c478bd9Sstevel@tonic-gate } else {
1287c478bd9Sstevel@tonic-gate printf("\nRequesting Internet address for %s\n",
1297c478bd9Sstevel@tonic-gate ether_print(out->arp_ea.arp_tha));
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gate (void) prom_write(mac_state.mac_dev, (caddr_t)out,
1347c478bd9Sstevel@tonic-gate sizeof (*out), 0, NETWORK);
1357c478bd9Sstevel@tonic-gate
1367c478bd9Sstevel@tonic-gate if (count >= ETHER_WAITCNT)
1377c478bd9Sstevel@tonic-gate printf("%c\b", ind[feedback++ % 4]); /* activity */
1387c478bd9Sstevel@tonic-gate
1397c478bd9Sstevel@tonic-gate time = prom_gettime() + (delay * 1000); /* broadcast delay */
1407c478bd9Sstevel@tonic-gate while (prom_gettime() <= time) {
1417c478bd9Sstevel@tonic-gate len = prom_read(mac_state.mac_dev, mac_state.mac_buf,
1427c478bd9Sstevel@tonic-gate mac_state.mac_mtu, 0, NETWORK);
1437c478bd9Sstevel@tonic-gate if (len < USED_SIZE)
1447c478bd9Sstevel@tonic-gate continue;
1457c478bd9Sstevel@tonic-gate if (in->arp_ea.arp_pro != ntohs(ETHERTYPE_IP))
1467c478bd9Sstevel@tonic-gate continue;
1477c478bd9Sstevel@tonic-gate if (out->arp_ea.arp_op == ntohs(ARPOP_REQUEST)) {
1487c478bd9Sstevel@tonic-gate if (in->arp_eh.ether_type !=
1497c478bd9Sstevel@tonic-gate ntohs(ETHERTYPE_ARP))
1507c478bd9Sstevel@tonic-gate continue;
1517c478bd9Sstevel@tonic-gate if (in->arp_ea.arp_op != ntohs(ARPOP_REPLY))
1527c478bd9Sstevel@tonic-gate continue;
1537c478bd9Sstevel@tonic-gate if (bcmp((caddr_t)in->arp_ea.arp_spa,
1547c478bd9Sstevel@tonic-gate (caddr_t)out->arp_ea.arp_tpa,
1557c478bd9Sstevel@tonic-gate sizeof (struct in_addr)) != 0)
1567c478bd9Sstevel@tonic-gate continue;
1577c478bd9Sstevel@tonic-gate if (boothowto & RB_VERBOSE) {
1587c478bd9Sstevel@tonic-gate bcopy((caddr_t)in->arp_ea.arp_spa,
1597c478bd9Sstevel@tonic-gate (caddr_t)&tmp_ia,
1607c478bd9Sstevel@tonic-gate sizeof (struct in_addr));
1617c478bd9Sstevel@tonic-gate printf("Found %s @ %s\n",
1627c478bd9Sstevel@tonic-gate inet_ntoa(tmp_ia),
1637c478bd9Sstevel@tonic-gate ether_print(in->arp_ea.arp_sha));
1647c478bd9Sstevel@tonic-gate }
1657c478bd9Sstevel@tonic-gate /* copy hardware addr into "out" for caller */
1667c478bd9Sstevel@tonic-gate bcopy((caddr_t)&in->arp_ea.arp_sha,
1677c478bd9Sstevel@tonic-gate (caddr_t)&out->arp_ea.arp_sha,
1687c478bd9Sstevel@tonic-gate sizeof (ether_addr_t));
1697c478bd9Sstevel@tonic-gate return (TRUE);
1707c478bd9Sstevel@tonic-gate } else { /* Reverse ARP */
1717c478bd9Sstevel@tonic-gate if (in->arp_eh.ether_type !=
1727c478bd9Sstevel@tonic-gate ntohs(ETHERTYPE_REVARP))
1737c478bd9Sstevel@tonic-gate continue;
1747c478bd9Sstevel@tonic-gate if (in->arp_ea.arp_op != ntohs(REVARP_REPLY))
1757c478bd9Sstevel@tonic-gate continue;
1767c478bd9Sstevel@tonic-gate if (bcmp((caddr_t)in->arp_ea.arp_tha,
1777c478bd9Sstevel@tonic-gate (caddr_t)out->arp_ea.arp_tha,
1787c478bd9Sstevel@tonic-gate sizeof (ether_addr_t)) != 0)
1797c478bd9Sstevel@tonic-gate continue;
1807c478bd9Sstevel@tonic-gate if (boothowto & RB_VERBOSE) {
1817c478bd9Sstevel@tonic-gate bcopy((caddr_t)in->arp_ea.arp_tpa,
1827c478bd9Sstevel@tonic-gate (caddr_t)&tmp_ia,
1837c478bd9Sstevel@tonic-gate sizeof (struct in_addr));
1847c478bd9Sstevel@tonic-gate printf("Internet address is: %s\n",
1857c478bd9Sstevel@tonic-gate inet_ntoa(tmp_ia));
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate /* copy IP address into "out" for caller */
1887c478bd9Sstevel@tonic-gate bcopy((caddr_t)in->arp_ea.arp_tpa,
1897c478bd9Sstevel@tonic-gate (caddr_t)out->arp_ea.arp_tpa,
1907c478bd9Sstevel@tonic-gate sizeof (struct in_addr));
1917c478bd9Sstevel@tonic-gate return (TRUE);
1927c478bd9Sstevel@tonic-gate }
1937c478bd9Sstevel@tonic-gate }
1947c478bd9Sstevel@tonic-gate
1957c478bd9Sstevel@tonic-gate delay = delay * 2; /* Double the request delay */
1967c478bd9Sstevel@tonic-gate if (delay > 64) /* maximum delay is 64 seconds */
1977c478bd9Sstevel@tonic-gate delay = 64;
1987c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate return (FALSE);
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate /*
2037c478bd9Sstevel@tonic-gate * ARP client side
2047c478bd9Sstevel@tonic-gate * Broadcasts to determine MAC address given network order IP address.
2057c478bd9Sstevel@tonic-gate * See RFC 826
2067c478bd9Sstevel@tonic-gate *
2077c478bd9Sstevel@tonic-gate * Returns TRUE if successful, FALSE otherwise.
2087c478bd9Sstevel@tonic-gate */
2097c478bd9Sstevel@tonic-gate int
ether_arp(struct in_addr * ip,void * hap,uint32_t timeout)2107c478bd9Sstevel@tonic-gate ether_arp(struct in_addr *ip, void *hap, uint32_t timeout)
2117c478bd9Sstevel@tonic-gate {
2127c478bd9Sstevel@tonic-gate ether_addr_t *ep = (ether_addr_t *)hap;
2137c478bd9Sstevel@tonic-gate struct arp_packet out;
2147c478bd9Sstevel@tonic-gate int result;
2157c478bd9Sstevel@tonic-gate
2167c478bd9Sstevel@tonic-gate if (!initialized)
2177c478bd9Sstevel@tonic-gate prom_panic("Ethernet device is not initialized.");
2187c478bd9Sstevel@tonic-gate
2197c478bd9Sstevel@tonic-gate bzero((char *)&out, sizeof (struct arp_packet));
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate out.arp_eh.ether_type = htons(ETHERTYPE_ARP);
2227c478bd9Sstevel@tonic-gate out.arp_ea.arp_op = htons(ARPOP_REQUEST);
2237c478bd9Sstevel@tonic-gate bcopy((caddr_t)etherbroadcastaddr, (caddr_t)&out.arp_ea.arp_tha,
2247c478bd9Sstevel@tonic-gate sizeof (ether_addr_t));
2257c478bd9Sstevel@tonic-gate bcopy((caddr_t)ip, (caddr_t)out.arp_ea.arp_tpa,
2267c478bd9Sstevel@tonic-gate sizeof (struct in_addr));
2277c478bd9Sstevel@tonic-gate
2287c478bd9Sstevel@tonic-gate result = ether_comarp(&out, timeout);
2297c478bd9Sstevel@tonic-gate
2307c478bd9Sstevel@tonic-gate if (result && (ep != NULL)) {
2317c478bd9Sstevel@tonic-gate bcopy((caddr_t)&out.arp_ea.arp_sha, (caddr_t)ep,
2327c478bd9Sstevel@tonic-gate sizeof (ether_addr_t));
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate return (result);
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate /*
2387c478bd9Sstevel@tonic-gate * Reverse ARP client side
2397c478bd9Sstevel@tonic-gate * Determine our Internet address given our MAC address
2407c478bd9Sstevel@tonic-gate * See RFC 903
2417c478bd9Sstevel@tonic-gate */
2427c478bd9Sstevel@tonic-gate void
ether_revarp(void)2437c478bd9Sstevel@tonic-gate ether_revarp(void)
2447c478bd9Sstevel@tonic-gate {
2457c478bd9Sstevel@tonic-gate struct in_addr ip;
2467c478bd9Sstevel@tonic-gate struct arp_packet out;
2477c478bd9Sstevel@tonic-gate
2487c478bd9Sstevel@tonic-gate if (!initialized)
2497c478bd9Sstevel@tonic-gate prom_panic("Ethernet device is not initialized.");
2507c478bd9Sstevel@tonic-gate
2517c478bd9Sstevel@tonic-gate bzero((char *)&out, sizeof (struct arp_packet));
2527c478bd9Sstevel@tonic-gate
2537c478bd9Sstevel@tonic-gate out.arp_eh.ether_type = htons(ETHERTYPE_REVARP);
2547c478bd9Sstevel@tonic-gate out.arp_ea.arp_op = htons(REVARP_REQUEST);
2557c478bd9Sstevel@tonic-gate bcopy(mac_state.mac_addr_buf, (caddr_t)&out.arp_ea.arp_tha,
2567c478bd9Sstevel@tonic-gate sizeof (ether_addr_t));
2577c478bd9Sstevel@tonic-gate
2587c478bd9Sstevel@tonic-gate /* Wait forever */
2597c478bd9Sstevel@tonic-gate (void) ether_comarp(&out, 0xffffffff);
2607c478bd9Sstevel@tonic-gate
2617c478bd9Sstevel@tonic-gate bcopy((caddr_t)&out.arp_ea.arp_tpa, (caddr_t)&ip,
2627c478bd9Sstevel@tonic-gate sizeof (struct in_addr));
2637c478bd9Sstevel@tonic-gate
2647c478bd9Sstevel@tonic-gate ip.s_addr = ntohl(ip.s_addr);
2657c478bd9Sstevel@tonic-gate ipv4_setipaddr(&ip);
2667c478bd9Sstevel@tonic-gate }
2677c478bd9Sstevel@tonic-gate
2687c478bd9Sstevel@tonic-gate /* ARGSUSED */
2697c478bd9Sstevel@tonic-gate int
ether_header_len(struct inetgram * igm)2707c478bd9Sstevel@tonic-gate ether_header_len(struct inetgram *igm)
2717c478bd9Sstevel@tonic-gate {
2727c478bd9Sstevel@tonic-gate return (sizeof (struct ether_header));
2737c478bd9Sstevel@tonic-gate }
2747c478bd9Sstevel@tonic-gate
2757c478bd9Sstevel@tonic-gate /*
2767c478bd9Sstevel@tonic-gate * Handle a IP datagram addressed to our ethernet address or to the
2777c478bd9Sstevel@tonic-gate * ethernet broadcast address. Also respond to ARP requests. Generates
2787c478bd9Sstevel@tonic-gate * inetgrams as long as there's data and the mac level IP timeout timer
2797c478bd9Sstevel@tonic-gate * hasn't expired. As soon as there is no data, we try for
2807c478bd9Sstevel@tonic-gate * ETHER_INPUT_ATTEMPTS for more, then exit the loop, even if there is time
2817c478bd9Sstevel@tonic-gate * left, since we expect to have data waiting for us when we're called, we just
2827c478bd9Sstevel@tonic-gate * don't know how much.
2837c478bd9Sstevel@tonic-gate *
2847c478bd9Sstevel@tonic-gate * We workaround slow proms (some proms have hard sleeps for as much as 3msec)
2857c478bd9Sstevel@tonic-gate * even though there are is data waiting.
2867c478bd9Sstevel@tonic-gate *
2877c478bd9Sstevel@tonic-gate * Returns the total number of MEDIA_LVL frames placed on the socket.
2887c478bd9Sstevel@tonic-gate * Caller is expected to free up the inetgram resources.
2897c478bd9Sstevel@tonic-gate */
2907c478bd9Sstevel@tonic-gate int
ether_input(int index)2917c478bd9Sstevel@tonic-gate ether_input(int index)
2927c478bd9Sstevel@tonic-gate {
2937c478bd9Sstevel@tonic-gate struct inetgram *inp;
2947c478bd9Sstevel@tonic-gate struct ether_header *eh;
2957c478bd9Sstevel@tonic-gate int frames = 0; /* successful frames */
2967c478bd9Sstevel@tonic-gate int attempts = 0; /* failed attempts after success */
2977c478bd9Sstevel@tonic-gate int16_t len = 0, data_len;
2987c478bd9Sstevel@tonic-gate uint32_t timeout, reltime;
2997c478bd9Sstevel@tonic-gate uint32_t pre_pr, post_pr; /* prom_read interval */
3007c478bd9Sstevel@tonic-gate
3017c478bd9Sstevel@tonic-gate #ifdef DEBUG
3027c478bd9Sstevel@tonic-gate int failures = 0; /* total failures */
3037c478bd9Sstevel@tonic-gate int total_attempts = 0; /* total prom_read */
3047c478bd9Sstevel@tonic-gate int no_data = 0; /* no data in prom */
3057c478bd9Sstevel@tonic-gate int arps = 0; /* arp requests processed */
3067c478bd9Sstevel@tonic-gate uint32_t tot_pr = 0; /* prom_read time */
3077c478bd9Sstevel@tonic-gate uint32_t tot_pc = 0; /* inetgram creation time */
3087c478bd9Sstevel@tonic-gate uint32_t pre_pc;
3097c478bd9Sstevel@tonic-gate uint32_t now;
3107c478bd9Sstevel@tonic-gate #endif /* DEBUG */
3117c478bd9Sstevel@tonic-gate
3127c478bd9Sstevel@tonic-gate if (!initialized)
3137c478bd9Sstevel@tonic-gate prom_panic("Ethernet device is not initialized.");
3147c478bd9Sstevel@tonic-gate
3157c478bd9Sstevel@tonic-gate if ((reltime = sockets[index].in_timeout) == 0)
3167c478bd9Sstevel@tonic-gate reltime = mac_state.mac_in_timeout;
3177c478bd9Sstevel@tonic-gate timeout = prom_gettime() + reltime;
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate do {
3207c478bd9Sstevel@tonic-gate if (frames > ETHER_MAX_FRAMES) {
3217c478bd9Sstevel@tonic-gate /* someone is trying a denial of service attack */
3227c478bd9Sstevel@tonic-gate break;
3237c478bd9Sstevel@tonic-gate }
3247c478bd9Sstevel@tonic-gate
3257c478bd9Sstevel@tonic-gate /*
3267c478bd9Sstevel@tonic-gate * The following is a workaround for a calvin prom (V2) bug
3277c478bd9Sstevel@tonic-gate * where prom_read() returns a nonzero length, even when it's
3287c478bd9Sstevel@tonic-gate * not read a packet. So we zero out the header to compensate.
3297c478bd9Sstevel@tonic-gate */
3307c478bd9Sstevel@tonic-gate bzero(mac_state.mac_buf, sizeof (struct ether_header));
3317c478bd9Sstevel@tonic-gate
3327c478bd9Sstevel@tonic-gate /*
3337c478bd9Sstevel@tonic-gate * Prom_read() will return 0 or -2 if no data is present. A
3347c478bd9Sstevel@tonic-gate * return value of -1 means an error has occurred. We adjust
3357c478bd9Sstevel@tonic-gate * the timeout by calling the time spent in prom_read() "free".
3367c478bd9Sstevel@tonic-gate * prom_read() returns the number of bytes actually read, but
3377c478bd9Sstevel@tonic-gate * will only copy "len" bytes into our buffer. Adjust in
3387c478bd9Sstevel@tonic-gate * case the MTU is wrong.
3397c478bd9Sstevel@tonic-gate */
3407c478bd9Sstevel@tonic-gate pre_pr = prom_gettime();
3417c478bd9Sstevel@tonic-gate len = prom_read(mac_state.mac_dev, mac_state.mac_buf,
3427c478bd9Sstevel@tonic-gate mac_state.mac_mtu, 0, NETWORK);
3437c478bd9Sstevel@tonic-gate post_pr = prom_gettime();
3447c478bd9Sstevel@tonic-gate timeout += (post_pr - pre_pr);
3457c478bd9Sstevel@tonic-gate #ifdef DEBUG
3467c478bd9Sstevel@tonic-gate tot_pr += (post_pr - pre_pr);
3477c478bd9Sstevel@tonic-gate total_attempts++;
3487c478bd9Sstevel@tonic-gate #endif /* DEBUG */
3497c478bd9Sstevel@tonic-gate
3507c478bd9Sstevel@tonic-gate if (len > mac_state.mac_mtu) {
3517c478bd9Sstevel@tonic-gate dprintf("ether_input: adjusting MTU %d -> %d\n",
3527c478bd9Sstevel@tonic-gate mac_state.mac_mtu, len);
3537c478bd9Sstevel@tonic-gate bkmem_free(mac_state.mac_buf, mac_state.mac_mtu);
3547c478bd9Sstevel@tonic-gate mac_state.mac_mtu = len;
3557c478bd9Sstevel@tonic-gate mac_state.mac_buf = bkmem_alloc(mac_state.mac_mtu);
3567c478bd9Sstevel@tonic-gate if (mac_state.mac_buf == NULL) {
3577c478bd9Sstevel@tonic-gate prom_panic("ether_input: Cannot reallocate "
3587c478bd9Sstevel@tonic-gate "netbuf memory.");
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate len = 0; /* pretend there was no data */
3617c478bd9Sstevel@tonic-gate }
3627c478bd9Sstevel@tonic-gate
3637c478bd9Sstevel@tonic-gate if (len == -1) {
3647c478bd9Sstevel@tonic-gate #ifdef DEBUG
3657c478bd9Sstevel@tonic-gate failures++;
3667c478bd9Sstevel@tonic-gate #endif /* DEBUG */
3677c478bd9Sstevel@tonic-gate break;
3687c478bd9Sstevel@tonic-gate }
3697c478bd9Sstevel@tonic-gate if (len == 0 || len == -2) {
3707c478bd9Sstevel@tonic-gate if (frames != 0)
3717c478bd9Sstevel@tonic-gate attempts++;
3727c478bd9Sstevel@tonic-gate #ifdef DEBUG
3737c478bd9Sstevel@tonic-gate no_data++;
3747c478bd9Sstevel@tonic-gate #endif /* DEBUG */
3757c478bd9Sstevel@tonic-gate continue;
3767c478bd9Sstevel@tonic-gate }
3777c478bd9Sstevel@tonic-gate
3787c478bd9Sstevel@tonic-gate eh = (struct ether_header *)mac_state.mac_buf;
3797c478bd9Sstevel@tonic-gate if (eh->ether_type == ntohs(ETHERTYPE_IP) &&
3807c478bd9Sstevel@tonic-gate len >= (sizeof (struct ether_header) +
3817c478bd9Sstevel@tonic-gate sizeof (struct ip))) {
3827c478bd9Sstevel@tonic-gate
3837c478bd9Sstevel@tonic-gate int offset;
3847c478bd9Sstevel@tonic-gate #ifdef DEBUG
3857c478bd9Sstevel@tonic-gate pre_pc = prom_gettime();
3867c478bd9Sstevel@tonic-gate #endif /* DEBUG */
3877c478bd9Sstevel@tonic-gate
3887c478bd9Sstevel@tonic-gate inp = (struct inetgram *)bkmem_zalloc(
3897c478bd9Sstevel@tonic-gate sizeof (struct inetgram));
3907c478bd9Sstevel@tonic-gate if (inp == NULL) {
3917c478bd9Sstevel@tonic-gate errno = ENOMEM;
3927c478bd9Sstevel@tonic-gate return (frames == 0 ? -1 : frames);
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate offset = sizeof (struct ether_header);
3957c478bd9Sstevel@tonic-gate data_len = len - offset;
3967c478bd9Sstevel@tonic-gate inp->igm_mp = allocb(data_len, 0);
3977c478bd9Sstevel@tonic-gate if (inp->igm_mp == NULL) {
3987c478bd9Sstevel@tonic-gate errno = ENOMEM;
3997c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)inp,
4007c478bd9Sstevel@tonic-gate sizeof (struct inetgram));
4017c478bd9Sstevel@tonic-gate return (frames == 0 ? -1 : frames);
4027c478bd9Sstevel@tonic-gate }
4037c478bd9Sstevel@tonic-gate bcopy((caddr_t)(mac_state.mac_buf + offset),
4047c478bd9Sstevel@tonic-gate inp->igm_mp->b_rptr, data_len);
4057c478bd9Sstevel@tonic-gate inp->igm_mp->b_wptr += data_len;
4067c478bd9Sstevel@tonic-gate inp->igm_level = NETWORK_LVL;
4077c478bd9Sstevel@tonic-gate add_grams(&sockets[index].inq, inp);
4087c478bd9Sstevel@tonic-gate frames++;
4097c478bd9Sstevel@tonic-gate attempts = 0;
4107c478bd9Sstevel@tonic-gate #ifdef DEBUG
4117c478bd9Sstevel@tonic-gate tot_pc += prom_gettime() - pre_pc;
4127c478bd9Sstevel@tonic-gate #endif /* DEBUG */
4137c478bd9Sstevel@tonic-gate continue;
4147c478bd9Sstevel@tonic-gate }
4157c478bd9Sstevel@tonic-gate
4167c478bd9Sstevel@tonic-gate if (eh->ether_type == ntohs(ETHERTYPE_ARP) &&
4177c478bd9Sstevel@tonic-gate len >= (sizeof (struct ether_header) +
4187c478bd9Sstevel@tonic-gate sizeof (struct ether_arp))) {
4197c478bd9Sstevel@tonic-gate
4207c478bd9Sstevel@tonic-gate struct in_addr ip;
4217c478bd9Sstevel@tonic-gate struct ether_arp *ea;
4227c478bd9Sstevel@tonic-gate
4237c478bd9Sstevel@tonic-gate #ifdef DEBUG
4247c478bd9Sstevel@tonic-gate printf("ether_input: ARP message received\n");
4257c478bd9Sstevel@tonic-gate arps++;
4267c478bd9Sstevel@tonic-gate #endif /* DEBUG */
4277c478bd9Sstevel@tonic-gate
4287c478bd9Sstevel@tonic-gate ea = (struct ether_arp *)(mac_state.mac_buf +
4297c478bd9Sstevel@tonic-gate sizeof (struct ether_header));
4307c478bd9Sstevel@tonic-gate if (ea->arp_pro != ntohs(ETHERTYPE_IP))
4317c478bd9Sstevel@tonic-gate continue;
4327c478bd9Sstevel@tonic-gate
4337c478bd9Sstevel@tonic-gate ipv4_getipaddr(&ip);
4347c478bd9Sstevel@tonic-gate ip.s_addr = ntohl(ip.s_addr);
4357c478bd9Sstevel@tonic-gate
4367c478bd9Sstevel@tonic-gate if (ea->arp_op == ntohs(ARPOP_REQUEST) &&
4377c478bd9Sstevel@tonic-gate ip.s_addr != INADDR_ANY &&
4387c478bd9Sstevel@tonic-gate (bcmp((caddr_t)ea->arp_tpa, (caddr_t)&ip,
4397c478bd9Sstevel@tonic-gate sizeof (struct in_addr)) == 0)) {
4407c478bd9Sstevel@tonic-gate ea->arp_op = htons(ARPOP_REPLY);
4417c478bd9Sstevel@tonic-gate bcopy((caddr_t)ea->arp_sha,
4427c478bd9Sstevel@tonic-gate (caddr_t)&eh->ether_dhost,
4437c478bd9Sstevel@tonic-gate sizeof (ether_addr_t));
4447c478bd9Sstevel@tonic-gate bcopy(mac_state.mac_addr_buf,
4457c478bd9Sstevel@tonic-gate (caddr_t)&eh->ether_shost,
4467c478bd9Sstevel@tonic-gate mac_state.mac_addr_len);
4477c478bd9Sstevel@tonic-gate bcopy((caddr_t)ea->arp_sha,
4487c478bd9Sstevel@tonic-gate (caddr_t)ea->arp_tha,
4497c478bd9Sstevel@tonic-gate sizeof (ether_addr_t));
4507c478bd9Sstevel@tonic-gate bcopy((caddr_t)ea->arp_spa,
4517c478bd9Sstevel@tonic-gate (caddr_t)ea->arp_tpa,
4527c478bd9Sstevel@tonic-gate sizeof (struct in_addr));
4537c478bd9Sstevel@tonic-gate bcopy(mac_state.mac_addr_buf,
4547c478bd9Sstevel@tonic-gate (caddr_t)ea->arp_sha,
4557c478bd9Sstevel@tonic-gate mac_state.mac_addr_len);
4567c478bd9Sstevel@tonic-gate bcopy((caddr_t)&ip, (caddr_t)ea->arp_spa,
4577c478bd9Sstevel@tonic-gate sizeof (struct in_addr));
4587c478bd9Sstevel@tonic-gate (void) prom_write(mac_state.mac_dev,
4597c478bd9Sstevel@tonic-gate mac_state.mac_buf,
4607c478bd9Sstevel@tonic-gate sizeof (struct arp_packet),
4617c478bd9Sstevel@tonic-gate 0, NETWORK);
4627c478bd9Sstevel@tonic-gate /* don't charge for ARP replies */
4637c478bd9Sstevel@tonic-gate timeout += reltime;
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate }
4667c478bd9Sstevel@tonic-gate } while (attempts < ETHER_INPUT_ATTEMPTS &&
4677c478bd9Sstevel@tonic-gate #ifdef DEBUG
4687c478bd9Sstevel@tonic-gate (now = prom_gettime()) < timeout);
4697c478bd9Sstevel@tonic-gate #else
4707c478bd9Sstevel@tonic-gate prom_gettime() < timeout);
4717c478bd9Sstevel@tonic-gate #endif /* DEBUG */
4727c478bd9Sstevel@tonic-gate
4737c478bd9Sstevel@tonic-gate #ifdef DEBUG
4747c478bd9Sstevel@tonic-gate printf("ether_input(%d): T/S/N/A/F/P/M: %d/%d/%d/%d/%d/%d/%d "
4757c478bd9Sstevel@tonic-gate "T/O: %d < %d = %s\n", index, total_attempts, frames, no_data,
4767c478bd9Sstevel@tonic-gate arps, failures, tot_pr, tot_pc, now, timeout,
4777c478bd9Sstevel@tonic-gate (now < timeout) ? "TRUE" : "FALSE");
4787c478bd9Sstevel@tonic-gate #endif /* DEBUG */
4797c478bd9Sstevel@tonic-gate return (frames);
4807c478bd9Sstevel@tonic-gate }
4817c478bd9Sstevel@tonic-gate
4827c478bd9Sstevel@tonic-gate /*
4837c478bd9Sstevel@tonic-gate * Send out an ethernet datagram. We expect a IP frame appropriately fragmented
4847c478bd9Sstevel@tonic-gate * at this level.
4857c478bd9Sstevel@tonic-gate *
4867c478bd9Sstevel@tonic-gate * Errno is set and -1 is returned if an error occurs. Number of bytes sent
4877c478bd9Sstevel@tonic-gate * is returned on success.
4887c478bd9Sstevel@tonic-gate */
4897c478bd9Sstevel@tonic-gate /* ARGSUSED */
4907c478bd9Sstevel@tonic-gate int
ether_output(int index,struct inetgram * ogp)4917c478bd9Sstevel@tonic-gate ether_output(int index, struct inetgram *ogp)
4927c478bd9Sstevel@tonic-gate {
4937c478bd9Sstevel@tonic-gate int header_len, result;
4947c478bd9Sstevel@tonic-gate struct ether_header eh;
4957c478bd9Sstevel@tonic-gate struct ip *ip;
4967c478bd9Sstevel@tonic-gate struct in_addr tmpip, ipdst, netid;
4977c478bd9Sstevel@tonic-gate int broadcast = FALSE;
4987c478bd9Sstevel@tonic-gate int size;
4997c478bd9Sstevel@tonic-gate mblk_t *mp;
5007c478bd9Sstevel@tonic-gate
5017c478bd9Sstevel@tonic-gate
5027c478bd9Sstevel@tonic-gate #ifdef DEBUG
5037c478bd9Sstevel@tonic-gate printf("ether_output (%d): size %d\n", index,
5047c478bd9Sstevel@tonic-gate ogp->igm_mp->b_wptr - ogp->igm_mp->b_rptr);
5057c478bd9Sstevel@tonic-gate #endif
5067c478bd9Sstevel@tonic-gate if (!initialized)
5077c478bd9Sstevel@tonic-gate prom_panic("Ethernet device is not initialized.");
5087c478bd9Sstevel@tonic-gate
5097c478bd9Sstevel@tonic-gate if (ogp->igm_level != MEDIA_LVL) {
5107c478bd9Sstevel@tonic-gate dprintf("ether_output: frame type wrong: socket: %d\n",
5117c478bd9Sstevel@tonic-gate index * SOCKETTYPE);
5127c478bd9Sstevel@tonic-gate errno = EINVAL;
5137c478bd9Sstevel@tonic-gate return (-1);
5147c478bd9Sstevel@tonic-gate }
5157c478bd9Sstevel@tonic-gate
5167c478bd9Sstevel@tonic-gate header_len = sizeof (struct ether_header);
5177c478bd9Sstevel@tonic-gate mp = ogp->igm_mp;
5187c478bd9Sstevel@tonic-gate size = mp->b_wptr - mp->b_rptr;
5197c478bd9Sstevel@tonic-gate if (size > mac_state.mac_mtu) {
5207c478bd9Sstevel@tonic-gate dprintf("ether_output: frame size too big: %d\n", size);
5217c478bd9Sstevel@tonic-gate errno = E2BIG;
5227c478bd9Sstevel@tonic-gate return (-1);
5237c478bd9Sstevel@tonic-gate }
5247c478bd9Sstevel@tonic-gate
5257c478bd9Sstevel@tonic-gate size += header_len;
5267c478bd9Sstevel@tonic-gate ip = (struct ip *)(mp->b_rptr);
5277c478bd9Sstevel@tonic-gate
5287c478bd9Sstevel@tonic-gate eh.ether_type = htons(ETHERTYPE_IP);
5297c478bd9Sstevel@tonic-gate bcopy(mac_state.mac_addr_buf, (caddr_t)&eh.ether_shost,
5307c478bd9Sstevel@tonic-gate mac_state.mac_addr_len);
5317c478bd9Sstevel@tonic-gate bcopy((caddr_t)&ip->ip_dst, (caddr_t)&ipdst, sizeof (ipdst));
5327c478bd9Sstevel@tonic-gate
5337c478bd9Sstevel@tonic-gate if (ipdst.s_addr == htonl(INADDR_BROADCAST))
5347c478bd9Sstevel@tonic-gate broadcast = TRUE; /* limited broadcast */
5357c478bd9Sstevel@tonic-gate
5367c478bd9Sstevel@tonic-gate if (!broadcast) {
5377c478bd9Sstevel@tonic-gate struct in_addr mask;
5387c478bd9Sstevel@tonic-gate
5397c478bd9Sstevel@tonic-gate ipv4_getnetid(&netid);
5407c478bd9Sstevel@tonic-gate ipv4_getnetmask(&mask);
5417c478bd9Sstevel@tonic-gate mask.s_addr = htonl(mask.s_addr);
5427c478bd9Sstevel@tonic-gate netid.s_addr = htonl(netid.s_addr);
543*32d0132cSss146032
544*32d0132cSss146032 /*
545*32d0132cSss146032 * check for all-hosts directed broadcast for
546*32d0132cSss146032 * to its own subnet.
547*32d0132cSss146032 */
5487c478bd9Sstevel@tonic-gate if (mask.s_addr != htonl(INADDR_BROADCAST) &&
549*32d0132cSss146032 (ipdst.s_addr & ~mask.s_addr) == 0 &&
5507c478bd9Sstevel@tonic-gate (ipdst.s_addr & mask.s_addr) == netid.s_addr) {
5517c478bd9Sstevel@tonic-gate broadcast = TRUE; /* directed broadcast */
5527c478bd9Sstevel@tonic-gate } else {
5537c478bd9Sstevel@tonic-gate if (ogp->igm_router.s_addr != htonl(INADDR_ANY))
5547c478bd9Sstevel@tonic-gate tmpip.s_addr = ogp->igm_router.s_addr;
5557c478bd9Sstevel@tonic-gate else
5567c478bd9Sstevel@tonic-gate tmpip.s_addr = ipdst.s_addr;
5577c478bd9Sstevel@tonic-gate
5587c478bd9Sstevel@tonic-gate result = mac_get_arp(&tmpip, (void *)&eh.ether_dhost,
5597c478bd9Sstevel@tonic-gate sizeof (ether_addr_t), mac_state.mac_arp_timeout);
5607c478bd9Sstevel@tonic-gate if (!result) {
5617c478bd9Sstevel@tonic-gate errno = ETIMEDOUT;
5627c478bd9Sstevel@tonic-gate dprintf("ether_output: ARP request for %s "
5637c478bd9Sstevel@tonic-gate "timed out.\n", inet_ntoa(tmpip));
5647c478bd9Sstevel@tonic-gate return (-1);
5657c478bd9Sstevel@tonic-gate }
5667c478bd9Sstevel@tonic-gate }
5677c478bd9Sstevel@tonic-gate }
5687c478bd9Sstevel@tonic-gate
5697c478bd9Sstevel@tonic-gate if (broadcast) {
5707c478bd9Sstevel@tonic-gate bcopy((caddr_t)etherbroadcastaddr,
5717c478bd9Sstevel@tonic-gate (caddr_t)&eh.ether_dhost, sizeof (ether_addr_t));
5727c478bd9Sstevel@tonic-gate }
5737c478bd9Sstevel@tonic-gate
5747c478bd9Sstevel@tonic-gate /* add the ethernet header */
5757c478bd9Sstevel@tonic-gate mp->b_rptr -= sizeof (eh);
5767c478bd9Sstevel@tonic-gate bcopy((caddr_t)&eh, mp->b_rptr, sizeof (eh));
5777c478bd9Sstevel@tonic-gate #ifdef DEBUG
5787c478bd9Sstevel@tonic-gate printf("ether_output(%d): level(%d) frame(0x%x) len(%d)\n",
5797c478bd9Sstevel@tonic-gate index, ogp->igm_level, mp->b_rptr, size);
5807c478bd9Sstevel@tonic-gate #if DEBUG > 1
5817c478bd9Sstevel@tonic-gate printf("Dump ethernet (%d): \n", size);
5827c478bd9Sstevel@tonic-gate hexdump((char *)mp->b_rptr, size);
5837c478bd9Sstevel@tonic-gate printf("\n");
5847c478bd9Sstevel@tonic-gate #endif /* DEBUG > 1 */
5857c478bd9Sstevel@tonic-gate #endif /* DEBUG */
5867c478bd9Sstevel@tonic-gate return (prom_write(mac_state.mac_dev, (char *)mp->b_rptr, size,
5877c478bd9Sstevel@tonic-gate 0, NETWORK));
5887c478bd9Sstevel@tonic-gate }
589