/* Stuff generic to all Ethernet controllers
 * Copyright 1991 Phil Karn, KA9Q
 */
#include "global.h"
#ifdef ETHER
#include "mbuf.h"
#include "iface.h"
#include "arp.h"
#include "enet.h"

#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: enet.c,v 1.12 2001/05/06 16:32:56 brian Exp $";
#endif

unsigned char Ether_bdcst[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

static struct mbuf *htonether(struct ether *ether,struct mbuf *data);



/* Convert Ethernet header in host form to network mbuf */
static struct mbuf *
htonether(
struct ether *ether,
struct mbuf *data
){
char *cp;
struct mbuf *bp;

	if(data == NULL || (bp = pushdown (data, ETHERLEN)) == NULLBUF)
		return NULLBUF;

	cp = (char *) bp->data;

	memcpy (cp, ether->dest, EADDR_LEN);
	cp += EADDR_LEN;
	memcpy (cp, ether->source, EADDR_LEN);
	cp += EADDR_LEN;
	(void) put16 ((unsigned char *) cp, (int16) ether->type);

	return bp;
}



/* Extract Ethernet header */
int
ntohether(
struct ether *ether,
struct mbuf **bpp
){
	(void) pullup (bpp, ether->dest, EADDR_LEN);
	(void) pullup (bpp, ether->source, EADDR_LEN);
	ether->type = pull16 (bpp);
	return ETHERLEN;
}



/* Format an Ethernet address into a printable ascii string */
char *
pether(
char *out,
char *addr
){
	sprintf(out,"%02x:%02x:%02x:%02x:%02x:%02x",
	 uchar(addr[0]),uchar(addr[1]),
	 uchar(addr[2]),uchar(addr[3]),
	 uchar(addr[4]),uchar(addr[5]));
	return out;
}



/* Convert an Ethernet address from Hex/ASCII to binary */
int
gether(
register char *outorig,
register const char *cp
){
register int i;
unsigned char *out = (unsigned char *) outorig;

	for (i = 6; i != 0; i--)	{
		*out++ = uchar(htoi (cp));
		if ((cp = strchr (cp, ':')) == NULL)	/* Find delimiter */
			break;
		cp++;			/* and skip over it */
	}
	return i;
}



/* Send an IP datagram on Ethernet */
int
enet_send(
struct mbuf *bp,	/* Buffer to send */
struct iface *iface,	/* Pointer to interface control block */
uint32 gateway,		/* IP address of next hop */
int prec OPTIONAL,
int del OPTIONAL,
int tput OPTIONAL,
int rel OPTIONAL
){
char *egate;

	if (gateway == iface->broadcast) /* This is a broadcast IP datagram */
		return (*iface->output) (iface, (char *) Ether_bdcst, iface->hwaddr, IP_TYPE, bp);

	egate = res_arp (iface, ARP_ETHER, gateway, bp);
	if(egate != NULLCHAR)
		return (*iface->output) (iface, egate, iface->hwaddr, IP_TYPE, bp);
	return 0;
}



/* Send a packet with Ethernet header */
int
enet_output(
struct iface *iface,	/* Pointer to interface control block */
const char *dest,	/* Destination Ethernet address */
char *source,		/* Source Ethernet address */
int16 type,		/* Type field */
struct mbuf *data	/* Data field */
){
struct ether ep;
struct mbuf *bp;

	memcpy (ep.dest, dest, EADDR_LEN);
	memcpy (ep.source, source, EADDR_LEN);
	ep.type = type;
	if ((bp = htonether(&ep,data)) == NULLBUF)	{
		free_p (data);
		return -1;
	}
	return (*iface->raw)(iface,bp);
}



/* Process incoming Ethernet packets. Shared by all ethernet drivers. */
void
eproc(
struct iface *iface,
struct mbuf *bp
){
struct ether hdr;

	/* Remove Ethernet header and kick packet upstairs */
	(void) ntohether(&hdr,&bp);

	if(memcmp (hdr.dest, iface->hwaddr, EADDR_LEN) && memcmp (hdr.dest, Ether_bdcst, EADDR_LEN))	{
		free_p(bp);
		return;
	}

	switch(hdr.type)	{
		case REVARP_TYPE:
		case ARP_TYPE:
			arp_input (iface, bp);
			break;
		case IP_TYPE:
			(void) ip_route (iface, bp, hdr.dest[0] & 1);
			break;
		default:
			free_p (bp);
			break;
	}
}

#endif		/* ETHER */
