ethernet.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Ethernet routines. Includes ARP and Reverse ARP. Used for ethernet-like
* media also - so be sure NOT to use ETHERMTU as a mtu limit. macinit()
* will set this appropriately.
*/
#include <socket_impl.h>
#include <socket_inet.h>
#include <netinet/in_systm.h>
#include <netinet/if_ether.h>
#include <sys/prom_plat.h>
#include <sys/bootdebug.h>
#include "ipv4.h"
#include "ipv4_impl.h"
#include "mac.h"
#include "mac_impl.h"
#include "ethernet_inet.h"
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
struct arp_packet {
struct ether_header arp_eh;
};
static char *
{
static char eprintbuf[20];
return (eprintbuf);
}
/*
* Common ARP code. Broadcast the packet and wait for the right response.
*
* If rarp is called for, caller expects an IPv4 address in the target
* protocol address (tpa) field of the "out" argument.
*
* If arp is called for, caller expects a hardware address in the
* source hardware address (sha) field of the "out" argument.
*
* Returns TRUE if transaction succeeded, FALSE otherwise.
*
* The timeout argument is the number of milliseconds to wait for a
* response. An infinite timeout can be specified as 0xffffffff.
*/
static int
{
char *ind = "-\\|/";
sizeof (ether_addr_t));
sizeof (ether_addr_t));
sizeof (struct in_addr));
feedback = 0;
if (count == ETHER_WAITCNT) {
"\nRequesting Ethernet address for: %s\n",
} else {
printf("\nRequesting Internet address for %s\n",
}
}
if (count >= ETHER_WAITCNT)
while (prom_gettime() <= time) {
continue;
continue;
continue;
continue;
sizeof (struct in_addr)) != 0)
continue;
if (boothowto & RB_VERBOSE) {
sizeof (struct in_addr));
printf("Found %s @ %s\n",
}
/* copy hardware addr into "out" for caller */
sizeof (ether_addr_t));
return (TRUE);
} else { /* Reverse ARP */
continue;
continue;
sizeof (ether_addr_t)) != 0)
continue;
if (boothowto & RB_VERBOSE) {
sizeof (struct in_addr));
printf("Internet address is: %s\n",
}
/* copy IP address into "out" for caller */
sizeof (struct in_addr));
return (TRUE);
}
}
delay = 64;
}
return (FALSE);
}
/*
* ARP client side
* Broadcasts to determine MAC address given network order IP address.
* See RFC 826
*
* Returns TRUE if successful, FALSE otherwise.
*/
int
{
struct arp_packet out;
int result;
if (!initialized)
prom_panic("Ethernet device is not initialized.");
sizeof (ether_addr_t));
sizeof (struct in_addr));
sizeof (ether_addr_t));
}
return (result);
}
/*
* Reverse ARP client side
* Determine our Internet address given our MAC address
* See RFC 903
*/
void
ether_revarp(void)
{
struct arp_packet out;
if (!initialized)
prom_panic("Ethernet device is not initialized.");
sizeof (ether_addr_t));
/* Wait forever */
sizeof (struct in_addr));
ipv4_setipaddr(&ip);
}
/* ARGSUSED */
int
{
return (sizeof (struct ether_header));
}
/*
* Handle a IP datagram addressed to our ethernet address or to the
* ethernet broadcast address. Also respond to ARP requests. Generates
* inetgrams as long as there's data and the mac level IP timeout timer
* hasn't expired. As soon as there is no data, we try for
* ETHER_INPUT_ATTEMPTS for more, then exit the loop, even if there is time
* left, since we expect to have data waiting for us when we're called, we just
* don't know how much.
*
* We workaround slow proms (some proms have hard sleeps for as much as 3msec)
* even though there are is data waiting.
*
* Returns the total number of MEDIA_LVL frames placed on the socket.
* Caller is expected to free up the inetgram resources.
*/
int
ether_input(int index)
{
struct ether_header *eh;
int frames = 0; /* successful frames */
int attempts = 0; /* failed attempts after success */
#ifdef DEBUG
int failures = 0; /* total failures */
int total_attempts = 0; /* total prom_read */
int no_data = 0; /* no data in prom */
int arps = 0; /* arp requests processed */
#endif /* DEBUG */
if (!initialized)
prom_panic("Ethernet device is not initialized.");
do {
if (frames > ETHER_MAX_FRAMES) {
/* someone is trying a denial of service attack */
break;
}
/*
* The following is a workaround for a calvin prom (V2) bug
* where prom_read() returns a nonzero length, even when it's
* not read a packet. So we zero out the header to compensate.
*/
/*
* Prom_read() will return 0 or -2 if no data is present. A
* return value of -1 means an error has occurred. We adjust
* the timeout by calling the time spent in prom_read() "free".
* prom_read() returns the number of bytes actually read, but
* will only copy "len" bytes into our buffer. Adjust in
* case the MTU is wrong.
*/
pre_pr = prom_gettime();
post_pr = prom_gettime();
#ifdef DEBUG
#endif /* DEBUG */
dprintf("ether_input: adjusting MTU %d -> %d\n",
prom_panic("ether_input: Cannot reallocate "
"netbuf memory.");
}
len = 0; /* pretend there was no data */
}
if (len == -1) {
#ifdef DEBUG
failures++;
#endif /* DEBUG */
break;
}
if (frames != 0)
attempts++;
#ifdef DEBUG
no_data++;
#endif /* DEBUG */
continue;
}
len >= (sizeof (struct ether_header) +
sizeof (struct ip))) {
int offset;
#ifdef DEBUG
pre_pc = prom_gettime();
#endif /* DEBUG */
sizeof (struct inetgram));
}
offset = sizeof (struct ether_header);
sizeof (struct inetgram));
}
frames++;
attempts = 0;
#ifdef DEBUG
#endif /* DEBUG */
continue;
}
len >= (sizeof (struct ether_header) +
sizeof (struct ether_arp))) {
#ifdef DEBUG
printf("ether_input: ARP message received\n");
arps++;
#endif /* DEBUG */
sizeof (struct ether_header));
continue;
ipv4_getipaddr(&ip);
sizeof (struct in_addr)) == 0)) {
sizeof (ether_addr_t));
sizeof (ether_addr_t));
sizeof (struct in_addr));
sizeof (struct in_addr));
sizeof (struct arp_packet),
0, NETWORK);
/* don't charge for ARP replies */
}
}
} while (attempts < ETHER_INPUT_ATTEMPTS &&
#ifdef DEBUG
#else
prom_gettime() < timeout);
#endif /* DEBUG */
#ifdef DEBUG
printf("ether_input(%d): T/S/N/A/F/P/M: %d/%d/%d/%d/%d/%d/%d "
#endif /* DEBUG */
return (frames);
}
/*
* Send out an ethernet datagram. We expect a IP frame appropriately fragmented
* at this level.
*
* Errno is set and -1 is returned if an error occurs. Number of bytes sent
* is returned on success.
*/
/* ARGSUSED */
int
{
int header_len, result;
struct ether_header eh;
int size;
#ifdef DEBUG
#endif
if (!initialized)
prom_panic("Ethernet device is not initialized.");
dprintf("ether_output: frame type wrong: socket: %d\n",
index * SOCKETTYPE);
return (-1);
}
header_len = sizeof (struct ether_header);
return (-1);
}
size += header_len;
if (!broadcast) {
} else {
else
if (!result) {
dprintf("ether_output: ARP request for %s "
return (-1);
}
}
}
if (broadcast) {
}
/* add the ethernet header */
#ifdef DEBUG
printf("ether_output(%d): level(%d) frame(0x%x) len(%d)\n",
#if DEBUG > 1
printf("\n");
#endif /* DEBUG > 1 */
#endif /* DEBUG */
0, NETWORK));
}