NetBSD/sys/arch/sun3/stand/libsa/netif_sun.c
is 07b064e02e New ARP system, supports IPv4 over any hardware link.
Some of the stuff (e.g., rarpd, bootpd, dhcpd etc., libsa) still will
only support Ethernet. Tcpdump itself should be ok, but libpcap needs
lot of work.

For the detailed change history, look at the commit log entries for
the is-newarp branch.
1997-03-15 18:09:08 +00:00

452 lines
9.1 KiB
C

/* $NetBSD: netif_sun.c,v 1.6 1997/03/15 18:10:56 is Exp $ */
/*
* Copyright (c) 1995 Gordon W. Ross
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
* 4. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Gordon W. Ross
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* The Sun PROM has a fairly general set of network drivers,
* so it is easiest to just replace the netif module with
* this adaptation to the PROM network interface.
*/
#include <sys/param.h>
#include <sys/socket.h>
#include <string.h>
#include <time.h>
#include <net/if.h>
#include <netinet/in.h>
#include "if_ether.h"
#include <netinet/in_systm.h>
#include <machine/control.h>
#include <machine/idprom.h>
#include <machine/mon.h>
#include <machine/saio.h>
#include "stand.h"
#include "net.h"
#include "netif.h"
#include "clock.h"
#include "dvma.h"
#include "promdev.h"
#define PKT_BUF_SIZE 2048
int debug;
int errno;
static void sun3_getether __P((u_char *));
struct iodesc sockets[SOPEN_MAX];
static struct netif prom_nif;
static struct devdata {
struct saioreq dd_si;
int rbuf_len;
char *rbuf;
int tbuf_len;
char *tbuf;
u_short dd_opens;
char dd_myea[6];
} prom_dd;
static struct idprom sun3_idprom;
void
sun3_getether(ea)
u_char *ea;
{
u_char *src, *dst;
int len, x;
if (sun3_idprom.idp_format == 0) {
dst = (char*)&sun3_idprom;
src = (char*)IDPROM_BASE;
len = IDPROM_SIZE;
do {
x = get_control_byte(src++);
*dst++ = x;
} while (--len > 0);
}
MACPY(sun3_idprom.idp_etheraddr, ea);
}
/*
* Open the PROM device.
* Return netif ptr on success.
*/
struct devdata *
netif_init(aux)
void *aux;
{
struct devdata *dd = &prom_dd;
struct saioreq *si;
struct bootparam *bp;
int error;
/*
* Setup our part of the saioreq.
* (determines what gets opened)
*/
si = &dd->dd_si;
bzero((caddr_t)si, sizeof(*si));
bp = *romVectorPtr->bootParam;
si->si_boottab = bp->bootDevice;
si->si_ctlr = bp->ctlrNum;
si->si_unit = bp->unitNum;
si->si_boff = bp->partNum;
#ifdef NETIF_DEBUG
if (debug)
printf("netif_init: calling prom_iopen\n");
#endif
/*
* Note: Sun PROMs will do RARP on open, but does not tell
* you the IP address it gets, so it is just noise to us...
*/
if ((error = prom_iopen(si)) != 0) {
printf("netif_init: prom_iopen, error=%d\n", error);
return (NULL);
}
if (si->si_sif == NULL) {
printf("netif_init: not a network device\n");
prom_iclose(si);
return (NULL);
}
#ifdef NETIF_DEBUG
if (debug)
printf("netif_init: allocating buffers\n");
#endif
/* Allocate the transmit/receive buffers. */
if (dd->rbuf == NULL) {
dd->rbuf_len = PKT_BUF_SIZE;
dd->rbuf = dvma_alloc(dd->rbuf_len);
}
if (dd->tbuf == NULL) {
dd->tbuf_len = PKT_BUF_SIZE;
dd->tbuf = dvma_alloc(dd->tbuf_len);
}
if ((dd->rbuf == NULL) ||
(dd->tbuf == NULL))
panic("netif_init: malloc failed\n");
#ifdef NETIF_DEBUG
if (debug)
printf("netif_init: rbuf=0x%x, tbuf=0x%x\n",
dd->rbuf, dd->tbuf);
#endif
/* Record our ethernet address. */
sun3_getether(dd->dd_myea);
dd->dd_opens = 0;
return(dd);
}
void
netif_fini(dd)
struct devdata *dd;
{
struct saioreq *si;
si = &dd->dd_si;
#ifdef NETIF_DEBUG
if (debug)
printf("netif_fini: calling prom_iclose\n");
#endif
prom_iclose(si);
/* Dellocate the transmit/receive buffers. */
if (dd->rbuf) {
dvma_free(dd->rbuf, dd->rbuf_len);
dd->rbuf = NULL;
}
if (dd->tbuf) {
dvma_free(dd->tbuf, dd->tbuf_len);
dd->tbuf = NULL;
}
}
int
netif_attach(nif, s, aux)
struct netif *nif;
struct iodesc *s;
void *aux;
{
struct devdata *dd;
dd = nif->nif_devdata;
if (dd == NULL) {
dd = netif_init(aux);
if (dd == NULL)
return (ENXIO);
nif->nif_devdata = dd;
}
dd->dd_opens++;
MACPY(dd->dd_myea, s->myea);
s->io_netif = nif;
return(0);
}
void
netif_detach(nif)
struct netif *nif;
{
struct devdata *dd;
dd = nif->nif_devdata;
if (dd == NULL)
return;
dd->dd_opens--;
if (dd->dd_opens > 0)
return;
netif_fini(dd);
nif->nif_devdata = NULL;
}
int
netif_open(aux)
void *aux;
{
struct netif *nif;
struct iodesc *s;
int fd, error;
/* find a free socket */
for (fd = 0, s = sockets; fd < SOPEN_MAX; fd++, s++)
if (s->io_netif == NULL)
goto found;
errno = EMFILE;
return (-1);
found:
bzero(s, sizeof(*s));
nif = &prom_nif;
error = netif_attach(nif, s);
if (error != 0) {
errno = error;
return (-1);
}
return (fd);
}
int
netif_close(fd)
int fd;
{
struct iodesc *s;
struct netif *nif;
if (fd < 0 || fd >= SOPEN_MAX) {
errno = EBADF;
return(-1);
}
s = &sockets[fd];
nif = s->io_netif;
/* Already closed? */
if (nif == NULL)
return(0);
netif_detach(nif);
s->io_netif = NULL;
return(0);
}
struct iodesc *
socktodesc(fd)
int fd;
{
if (fd < 0 || fd >= SOPEN_MAX) {
errno = EBADF;
return (NULL);
}
return (&sockets[fd]);
}
/*
* Send a packet. The ether header is already there.
* Return the length sent (or -1 on error).
*/
int
netif_put(desc, pkt, len)
struct iodesc *desc;
void *pkt;
size_t len;
{
struct netif *nif;
struct devdata *dd;
struct saioreq *si;
struct saif *sif;
char *dmabuf;
int rv, slen;
#ifdef NETIF_DEBUG
if (debug > 1) {
struct ether_header *eh;
printf("netif_put: desc=0x%x pkt=0x%x len=%d\n",
desc, pkt, len);
eh = pkt;
printf("dst: %s ", ether_sprintf(eh->ether_dhost));
printf("src: %s ", ether_sprintf(eh->ether_shost));
printf("type: 0x%x\n", eh->ether_type & 0xFFFF);
}
#endif
nif = desc->io_netif;
dd = nif->nif_devdata;
si = &dd->dd_si;
sif = si->si_sif;
slen = len;
#ifdef PARANOID
if (sif == NULL)
panic("netif_put: no saif ptr\n");
#endif
/*
* Copy into our transmit buffer because the PROM
* network driver might continue using the packet
* after the sif_xmit call returns. We never send
* very much data anyway, so the copy is fine.
*/
if (slen > dd->tbuf_len)
panic("netif_put: slen=%d\n", slen);
bcopy(pkt, dd->tbuf, slen);
if (slen < 60) {
slen = 60;
}
rv = (*sif->sif_xmit)(si->si_devdata, dd->tbuf, slen);
#ifdef NETIF_DEBUG
if (debug > 1)
printf("netif_put: xmit returned %d\n", rv);
#endif
/*
* Just ignore the return value. If the PROM transmit
* function fails, it will make some noise, such as:
* le: No Carrier
*/
return len;
}
/*
* Receive a packet, including the ether header.
* Return the total length received (or -1 on error).
*/
int
netif_get(desc, pkt, maxlen, timo)
struct iodesc *desc;
void *pkt;
size_t maxlen;
time_t timo; /* seconds */
{
struct netif *nif;
struct devdata *dd;
struct saioreq *si;
struct saif *sif;
int tick0, tmo_ticks;
int rlen = 0;
#ifdef NETIF_DEBUG
if (debug > 1)
printf("netif_get: pkt=0x%x, maxlen=%d, tmo=%d\n",
pkt, maxlen, timo);
#endif
nif = desc->io_netif;
dd = nif->nif_devdata;
si = &dd->dd_si;
sif = si->si_sif;
tmo_ticks = timo * hz;
/* Have to receive into our own buffer and copy. */
do {
tick0 = getticks();
do {
rlen = (*sif->sif_poll)(si->si_devdata, dd->rbuf);
if (rlen != 0)
goto break2;
} while (getticks() == tick0);
} while (--tmo_ticks > 0);
/* No packet arrived. Better reset the interface. */
printf("netif_get: timeout; resetting\n");
(*sif->sif_reset)(si->si_devdata, si);
break2:
#ifdef NETIF_DEBUG
if (debug > 1)
printf("netif_get: received rlen=%d\n", rlen);
#endif
/* Need at least a valid Ethernet header. */
if (rlen < 12)
return -1;
/* If we went beyond our buffer, were dead! */
if (rlen > dd->rbuf_len)
panic("netif_get: rlen=%d\n", rlen);
/* The caller's buffer may be smaller... */
if (rlen > maxlen)
rlen = maxlen;
bcopy(dd->rbuf, pkt, rlen);
#ifdef NETIF_DEBUG
if (debug > 1) {
struct ether_header *eh = pkt;
printf("dst: %s ", ether_sprintf(eh->ether_dhost));
printf("src: %s ", ether_sprintf(eh->ether_shost));
printf("type: 0x%x\n", eh->ether_type & 0xFFFF);
}
#endif
return rlen;
}