07b064e02e
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.
452 lines
9.1 KiB
C
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;
|
|
}
|