## diffname alphapc/devether.c 1999/0415
## diff -e /dev/null /n/emeliedump/1999/0415/sys/src/brazil/alphapc/devether.c
0a
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "ureg.h"
#include "../port/error.h"
#include "../port/netif.h"
#include "etherif.h"
static Ether *etherxx[MaxEther];
Chan*
etherattach(char* spec)
{
ulong ctlrno;
char *p;
Chan *chan;
ctlrno = 0;
if(spec && *spec){
ctlrno = strtoul(spec, &p, 0);
if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther))
error(Ebadarg);
}
if(etherxx[ctlrno] == 0)
error(Enodev);
chan = devattach('l', spec);
chan->dev = ctlrno;
if(etherxx[ctlrno]->attach)
etherxx[ctlrno]->attach(etherxx[ctlrno]);
return chan;
}
static int
etherwalk(Chan* chan, char* name)
{
return netifwalk(etherxx[chan->dev], chan, name);
}
static void
etherstat(Chan* chan, char* dp)
{
netifstat(etherxx[chan->dev], chan, dp);
}
static Chan*
etheropen(Chan* chan, int omode)
{
return netifopen(etherxx[chan->dev], chan, omode);
}
static void
ethercreate(Chan*, char*, int, ulong)
{
}
static void
etherclose(Chan* chan)
{
netifclose(etherxx[chan->dev], chan);
}
static long
etherread(Chan* chan, void* buf, long n, vlong off)
{
Ether *ether;
ulong offset = off;
ether = etherxx[chan->dev];
if((chan->qid.path & CHDIR) == 0 && ether->ifstat){
/*
* With some controllers it is necessary to reach
* into the chip to extract statistics.
*/
if(NETTYPE(chan->qid.path) == Nifstatqid)
return ether->ifstat(ether, buf, n, offset);
else if(NETTYPE(chan->qid.path) == Nstatqid)
ether->ifstat(ether, buf, 0, offset);
}
return netifread(ether, chan, buf, n, offset);
}
static Block*
etherbread(Chan* chan, long n, ulong offset)
{
return netifbread(etherxx[chan->dev], chan, n, offset);
}
static void
etherremove(Chan*)
{
}
static void
etherwstat(Chan* chan, char* dp)
{
netifwstat(etherxx[chan->dev], chan, dp);
}
static void
etherrtrace(Netfile* f, Etherpkt* pkt, int len)
{
int i, n;
Block *bp;
if(qwindow(f->in) <= 0)
return;
if(len > 64)
n = 64;
else
n = len;
bp = iallocb(n);
if(bp == 0)
return;
memmove(bp->wp, pkt->d, n);
i = TK2MS(MACHP(0)->ticks);
bp->wp[58] = len>>8;
bp->wp[59] = len;
bp->wp[60] = i>>24;
bp->wp[61] = i>>16;
bp->wp[62] = i>>8;
bp->wp[63] = i;
bp->wp += 64;
qpass(f->in, bp);
}
Block*
etheriq(Ether* ether, Block* bp, int freebp)
{
Etherpkt *pkt;
ushort type;
int len;
Netfile **ep, *f, **fp, *fx;
Block *xbp;
ether->inpackets++;
pkt = (Etherpkt*)bp->rp;
len = BLEN(bp);
type = (pkt->type[0]<<8)|pkt->type[1];
fx = 0;
ep = ðer->f[Ntypes];
/* check for valid multcast addresses */
if((pkt->d[0] & 1) && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){
if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
if(freebp){
freeb(bp);
bp = 0;
}
return bp;
}
}
/*
* Multiplex the packet to all the connections which want it.
* If the packet is not to be used subsequently (freebp != 0),
* attempt to simply pass it into one of the connections, thereby
* saving a copy of the data (usual case hopefully).
*/
for(fp = ether->f; fp < ep; fp++){
if((f = *fp) && (f->type == type || f->type < 0)){
if(f->type > -2){
if(freebp && fx == 0)
fx = f;
else if(xbp = iallocb(len)){
memmove(xbp->wp, pkt, len);
xbp->wp += len;
qpass(f->in, xbp);
}
else
ether->soverflows++;
}
else
etherrtrace(f, pkt, len);
}
}
if(fx){
qpass(fx->in, bp);
return 0;
}
if(freebp){
freeb(bp);
return 0;
}
return bp;
}
static int
etheroq(Ether* ether, Block* bp)
{
int len, loopback, s;
Etherpkt *pkt;
ether->outpackets++;
/*
* Check if the packet has to be placed back onto the input queue,
* i.e. if it's a loopback or broadcast packet or the interface is
* in promiscuous mode.
* If it's a loopback packet indicate to etheriq that the data isn't
* needed and return, etheriq will pass-on or free the block.
*/
pkt = (Etherpkt*)bp->rp;
len = BLEN(bp);
loopback = (memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0);
if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
s = splhi();
etheriq(ether, bp, loopback);
splx(s);
}
if(!loopback){
qbwrite(ether->oq, bp);
ether->transmit(ether);
}
return len;
}
static long
etherwrite(Chan* chan, void* buf, long n, vlong)
{
Ether *ether;
Block *bp;
ether = etherxx[chan->dev];
if(NETTYPE(chan->qid.path) != Ndataqid)
return netifwrite(ether, chan, buf, n);
if(n > ETHERMAXTU)
error(Etoobig);
if(n < ETHERMINTU)
error(Etoosmall);
bp = allocb(n);
if(waserror()){
freeb(bp);
nexterror();
}
memmove(bp->rp, buf, n);
memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
poperror();
bp->wp += n;
return etheroq(ether, bp);
}
static long
etherbwrite(Chan* chan, Block* bp, ulong)
{
Ether *ether;
long n;
n = BLEN(bp);
ether = etherxx[chan->dev];
if(NETTYPE(chan->qid.path) != Ndataqid){
n = netifwrite(ether, chan, bp->rp, n);
freeb(bp);
return n;
}
if(n > ETHERMAXTU){
freeb(bp);
error(Ebadarg);
}
if(n < ETHERMINTU){
freeb(bp);
error(Etoosmall);
}
return etheroq(ether, bp);
}
static struct {
char* type;
int (*reset)(Ether*);
} cards[MaxEther+1];
void
addethercard(char* t, int (*r)(Ether*))
{
static int ncard;
if(ncard == MaxEther)
panic("too many ether cards");
cards[ncard].type = t;
cards[ncard].reset = r;
ncard++;
}
int
parseether(uchar *to, char *from)
{
char nip[4];
char *p;
int i;
p = from;
for(i = 0; i < 6; i++){
if(*p == 0)
return -1;
nip[0] = *p++;
if(*p == 0)
return -1;
nip[1] = *p++;
nip[2] = 0;
to[i] = strtoul(nip, 0, 16);
if(*p == ':')
p++;
}
return 0;
}
static void
etherreset(void)
{
Ether *ether;
int i, n, ctlrno;
char name[NAMELEN], buf[128];
for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
if(ether == 0)
ether = malloc(sizeof(Ether));
memset(ether, 0, sizeof(Ether));
ether->ctlrno = ctlrno;
ether->tbdf = BUSUNKNOWN;
ether->mbps = 10;
if(isaconfig("ether", ctlrno, ether) == 0)
continue;
for(n = 0; cards[n].type; n++){
if(cistrcmp(cards[n].type, ether->type))
continue;
for(i = 0; i < ether->nopt; i++){
if(strncmp(ether->opt[i], "ea=", 3))
continue;
if(parseether(ether->ea, ðer->opt[i][3]) == -1)
memset(ether->ea, 0, Eaddrlen);
}
if(cards[n].reset(ether))
break;
/*
* IRQ2 doesn't really exist, it's used to gang the interrupt
* controllers together. A device set to IRQ2 will appear on
* the second interrupt controller as IRQ9.
*/
if(ether->irq == 2)
ether->irq = 9;
intrenable(VectorPCI+ether->irq, ether->interrupt, ether, ether->tbdf);
i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
ctlrno, ether->type, ether->mbps, ether->port, ether->irq);
if(ether->mem)
i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem));
if(ether->size)
i += sprint(buf+i, " size 0x%luX", ether->size);
i += sprint(buf+i, ": %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX",
ether->ea[0], ether->ea[1], ether->ea[2],
ether->ea[3], ether->ea[4], ether->ea[5]);
sprint(buf+i, "\n");
print(buf);
snprint(name, sizeof(name), "ether%d", ctlrno);
if(ether->mbps == 100){
netifinit(ether, name, Ntypes, 256*1024);
if(ether->oq == 0)
ether->oq = qopen(256*1024, 1, 0, 0);
}
else{
netifinit(ether, name, Ntypes, 65*1024);
if(ether->oq == 0)
ether->oq = qopen(65*1024, 1, 0, 0);
}
if(ether->oq == 0)
panic("etherreset %s", name);
ether->alen = Eaddrlen;
memmove(ether->addr, ether->ea, Eaddrlen);
memset(ether->bcast, 0xFF, Eaddrlen);
etherxx[ctlrno] = ether;
ether = 0;
break;
}
}
if(ether)
free(ether);
}
#define POLY 0xedb88320
/* really slow 32 bit crc for ethers */
ulong
ethercrc(uchar *p, int len)
{
int i, j;
ulong crc, b;
crc = 0xffffffff;
for(i = 0; i < len; i++){
b = *p++;
for(j = 0; j < 8; j++){
crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
b >>= 1;
}
}
return crc;
}
Dev etherdevtab = {
'l',
"ether",
etherreset,
devinit,
etherattach,
devclone,
etherwalk,
etherstat,
etheropen,
ethercreate,
etherclose,
etherread,
etherbread,
etherwrite,
etherbwrite,
etherremove,
etherwstat,
};
.
## diffname alphapc/devether.c 1999/0515
## diff -e /n/emeliedump/1999/0415/sys/src/brazil/alphapc/devether.c /n/emeliedump/1999/0515/sys/src/brazil/alphapc/devether.c
359c
i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %ld",
.
## diffname alphapc/devether.c 2000/0401
## diff -e /n/emeliedump/1999/0515/sys/src/brazil/alphapc/devether.c /n/emeliedump/2000/0401/sys/src/9/alphapc/devether.c
371d
359c
i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %lud",
.
357c
snprint(name, sizeof(name), "ether%d", ctlrno);
intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name);
.
223c
} else
freeb(bp);
.
216c
etheriq(ether, bp, 0);
.
213c
loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
.
209a
* To enable bridging to work, only packets that were originated
* by this interface are fed back.
.
188c
if(fromwire){
.
185c
if(qpass(fx->in, bp) < 0)
ether->soverflows++;
.
167,169c
if(f = *fp)
if(f->type == type || f->type < 0)
if(tome || multi || f->prom){
/* Don't want to hear bridged packets */
if(f->bridge && !fromwire && !fromme)
continue;
if(!f->headersonly){
if(fromwire && fx == 0)
.
162c
* If the packet is not to be used subsequently (fromwire != 0),
.
159a
/* is it for me? */
tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
.
152c
if(fromwire){
.
150c
if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){
.
148a
multi = pkt->d[0] & 1;
.
137c
int len, multi, tome, fromme;
.
133c
etheriq(Ether* ether, Block* bp, int fromwire)
.
## diffname alphapc/devether.c 2000/0713
## diff -e /n/emeliedump/2000/0401/sys/src/9/alphapc/devether.c /n/emeliedump/2000/0713/sys/src/9/alphapc/devether.c
117,118c
bp = iallocb(64);
if(bp == nil)
.
113,114c
if(len > 58)
n = 58;
.
## diffname alphapc/devether.c 2001/0228
## diff -e /n/emeliedump/2000/0713/sys/src/9/alphapc/devether.c /n/emeliedump/2001/0228/sys/src/9/alphapc/devether.c
369c
if(ether->irq == 2 && BUSTYPE(ether->tbdf) != BusPCI)
.
## diffname alphapc/devether.c 2001/0727
## diff -e /n/emeliedump/2001/0228/sys/src/9/alphapc/devether.c /n/emeliedump/2001/0727/sys/src/9/alphapc/devether.c
438d
349a
ether->minmtu = ETHERMINTU;
ether->maxmtu = ETHERMAXTU;
.
341c
char name[32], buf[128];
.
102c
return netifwstat(etherxx[chan->dev], chan, dp, n);
.
99,100c
static int
etherwstat(Chan* chan, uchar* dp, int n)
.
74c
if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
.
47c
return netifstat(etherxx[chan->dev], chan, dp, n);
.
44,45c
static int
etherstat(Chan* chan, uchar* dp, int n)
.
41c
return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
.
38,39c
static Walkqid*
etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
.
## diffname alphapc/devether.c 2001/1204
## diff -e /n/emeliedump/2001/0727/sys/src/9/alphapc/devether.c /n/emeliedump/2001/1204/sys/src/9/alphapc/devether.c
449c
devremove,
.
94,98d
## diffname alphapc/devether.c 2002/0109
## diff -e /n/emeliedump/2001/1204/sys/src/9/alphapc/devether.c /n/emeliedump/2002/0109/sys/src/9/alphapc/devether.c
433a
devshutdown,
.
## diffname alphapc/devether.c 2002/0711
## diff -e /n/emeliedump/2002/0109/sys/src/9/alphapc/devether.c /n/emeliedump/2002/0711/sys/src/9/alphapc/devether.c
391c
ether->oq = qopen(65*1024, Qmsg, 0, 0);
.
386c
ether->oq = qopen(256*1024, Qmsg, 0, 0);
.
## diffname alphapc/devether.c 2002/0712
## diff -e /n/emeliedump/2002/0711/sys/src/9/alphapc/devether.c /n/emeliedump/2002/0712/sys/src/9/alphapc/devether.c
245a
}
.
244c
if(NETTYPE(chan->qid.path) != Ndataqid){
if(n == sizeof("nonblocking")-1 && strncmp((char*)buf, "nonblocking", n) == 0){
qnoblock(ether->oq, 1);
return n;
}
.
## diffname alphapc/devether.c 2002/1130
## diff -e /n/emeliedump/2002/0712/sys/src/9/alphapc/devether.c /n/emeliedump/2002/1130/sys/src/9/alphapc/devether.c
413a
/* imported from ../pc; not ready for use yet */
static void
ethershutdown(void)
{
Ether *ether;
int i;
for(i = 0; i < MaxEther; i++){
ether = etherxx[i];
if(ether == nil)
continue;
if(ether->shutdown == nil) {
print("#l%d: no shutdown fuction\n", i);
continue;
}
(*ether->shutdown)(ether);
}
}
.
378,379c
i = sprint(buf, "#l%d (%s): %s: %dMbps port 0x%luX irq %lud",
ctlrno, name, ether->type, ether->mbps,
ether->port, ether->irq);
.
376c
/*
* If ether->irq is 0, it is a hack to indicate no
* interrupt used by ethersink.
*/
if(ether->irq > 0)
intrenable(ether->irq, ether->interrupt,
ether, ether->tbdf, name);
.
364c
}
.
362c
if(parseether(ether->ea, ðer->opt[i][3]))
.
343c
char name[32], buf[256];
.
323c
for(i = 0; i < Eaddrlen; i++){
.
290c
if(n < ether->minmtu){
.
288c
error(Etoobig);
.
286c
if(n > ether->maxmtu){
.
284a
ether = etherxx[chan->dev];
.
281c
if(waserror()) {
freeb(bp);
nexterror();
}
n = etherwrite(chan, bp->rp, n, 0);
poperror();
.
279d
256c
if(n < ether->minmtu)
.
254c
if(n > ether->maxmtu)
.
251c
error(Ebadctl);
.
249a
if(ether->ctl!=nil)
return ether->ctl(ether,buf,n);
.
244,245c
if(NETTYPE(chan->qid.path) != Ndataqid) {
nn = netifwrite(ether, chan, buf, n);
if(nn >= 0)
return nn;
.
241a
int nn;
.
179c
if(qpass(f->in, xbp) < 0)
ether->soverflows++;
.
13c
static volatile Ether *etherxx[MaxEther];
.
## diffname alphapc/devether.c 2003/0301
## diff -e /n/emeliedump/2002/1130/sys/src/9/alphapc/devether.c /n/emeliedump/2003/0301/sys/src/9/alphapc/devether.c
1,492c
#include "../pc/devether.c"
.
|