19a747e4fSDavid du Colombier #include "u.h"
29a747e4fSDavid du Colombier #include "../port/lib.h"
39a747e4fSDavid du Colombier #include "mem.h"
49a747e4fSDavid du Colombier #include "dat.h"
59a747e4fSDavid du Colombier #include "fns.h"
69a747e4fSDavid du Colombier #include "io.h"
79a747e4fSDavid du Colombier #include "ureg.h"
89a747e4fSDavid du Colombier #include "../port/error.h"
99a747e4fSDavid du Colombier #include "../port/netif.h"
109a747e4fSDavid du Colombier
119a747e4fSDavid du Colombier #include "etherif.h"
129a747e4fSDavid du Colombier
139a747e4fSDavid du Colombier static Ether *etherxx[MaxEther];
149a747e4fSDavid du Colombier
159a747e4fSDavid du Colombier Chan*
etherattach(char * spec)169a747e4fSDavid du Colombier etherattach(char* spec)
179a747e4fSDavid du Colombier {
189a747e4fSDavid du Colombier ulong ctlrno;
199a747e4fSDavid du Colombier char *p;
209a747e4fSDavid du Colombier Chan *chan;
219a747e4fSDavid du Colombier
229a747e4fSDavid du Colombier ctlrno = 0;
239a747e4fSDavid du Colombier if(spec && *spec){
249a747e4fSDavid du Colombier ctlrno = strtoul(spec, &p, 0);
259a747e4fSDavid du Colombier if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther))
269a747e4fSDavid du Colombier error(Ebadarg);
279a747e4fSDavid du Colombier }
289a747e4fSDavid du Colombier if(etherxx[ctlrno] == 0)
299a747e4fSDavid du Colombier error(Enodev);
309a747e4fSDavid du Colombier
319a747e4fSDavid du Colombier chan = devattach('l', spec);
329a747e4fSDavid du Colombier chan->dev = ctlrno;
339a747e4fSDavid du Colombier if(etherxx[ctlrno]->attach)
349a747e4fSDavid du Colombier etherxx[ctlrno]->attach(etherxx[ctlrno]);
359a747e4fSDavid du Colombier return chan;
369a747e4fSDavid du Colombier }
379a747e4fSDavid du Colombier
389a747e4fSDavid du Colombier static Walkqid*
etherwalk(Chan * chan,Chan * nchan,char ** name,int nname)399a747e4fSDavid du Colombier etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
409a747e4fSDavid du Colombier {
419a747e4fSDavid du Colombier return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
429a747e4fSDavid du Colombier }
439a747e4fSDavid du Colombier
449a747e4fSDavid du Colombier static int
etherstat(Chan * chan,uchar * dp,int n)459a747e4fSDavid du Colombier etherstat(Chan* chan, uchar* dp, int n)
469a747e4fSDavid du Colombier {
479a747e4fSDavid du Colombier return netifstat(etherxx[chan->dev], chan, dp, n);
489a747e4fSDavid du Colombier }
499a747e4fSDavid du Colombier
509a747e4fSDavid du Colombier static Chan*
etheropen(Chan * chan,int omode)519a747e4fSDavid du Colombier etheropen(Chan* chan, int omode)
529a747e4fSDavid du Colombier {
539a747e4fSDavid du Colombier return netifopen(etherxx[chan->dev], chan, omode);
549a747e4fSDavid du Colombier }
559a747e4fSDavid du Colombier
569a747e4fSDavid du Colombier static void
ethercreate(Chan *,char *,int,ulong)579a747e4fSDavid du Colombier ethercreate(Chan*, char*, int, ulong)
589a747e4fSDavid du Colombier {
599a747e4fSDavid du Colombier }
609a747e4fSDavid du Colombier
619a747e4fSDavid du Colombier static void
etherclose(Chan * chan)629a747e4fSDavid du Colombier etherclose(Chan* chan)
639a747e4fSDavid du Colombier {
649a747e4fSDavid du Colombier netifclose(etherxx[chan->dev], chan);
659a747e4fSDavid du Colombier }
669a747e4fSDavid du Colombier
679a747e4fSDavid du Colombier static long
etherread(Chan * chan,void * buf,long n,vlong off)689a747e4fSDavid du Colombier etherread(Chan* chan, void* buf, long n, vlong off)
699a747e4fSDavid du Colombier {
709a747e4fSDavid du Colombier Ether *ether;
719a747e4fSDavid du Colombier ulong offset = off;
729a747e4fSDavid du Colombier
739a747e4fSDavid du Colombier ether = etherxx[chan->dev];
749a747e4fSDavid du Colombier if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
759a747e4fSDavid du Colombier /*
769a747e4fSDavid du Colombier * With some controllers it is necessary to reach
779a747e4fSDavid du Colombier * into the chip to extract statistics.
789a747e4fSDavid du Colombier */
799a747e4fSDavid du Colombier if(NETTYPE(chan->qid.path) == Nifstatqid)
809a747e4fSDavid du Colombier return ether->ifstat(ether, buf, n, offset);
819a747e4fSDavid du Colombier else if(NETTYPE(chan->qid.path) == Nstatqid)
829a747e4fSDavid du Colombier ether->ifstat(ether, buf, 0, offset);
839a747e4fSDavid du Colombier }
849a747e4fSDavid du Colombier
859a747e4fSDavid du Colombier return netifread(ether, chan, buf, n, offset);
869a747e4fSDavid du Colombier }
879a747e4fSDavid du Colombier
889a747e4fSDavid du Colombier static Block*
etherbread(Chan * chan,long n,ulong offset)899a747e4fSDavid du Colombier etherbread(Chan* chan, long n, ulong offset)
909a747e4fSDavid du Colombier {
919a747e4fSDavid du Colombier return netifbread(etherxx[chan->dev], chan, n, offset);
929a747e4fSDavid du Colombier }
939a747e4fSDavid du Colombier
949a747e4fSDavid du Colombier static int
etherwstat(Chan * chan,uchar * dp,int n)959a747e4fSDavid du Colombier etherwstat(Chan* chan, uchar* dp, int n)
969a747e4fSDavid du Colombier {
979a747e4fSDavid du Colombier return netifwstat(etherxx[chan->dev], chan, dp, n);
989a747e4fSDavid du Colombier }
999a747e4fSDavid du Colombier
1009a747e4fSDavid du Colombier static void
etherrtrace(Netfile * f,Etherpkt * pkt,int len)1019a747e4fSDavid du Colombier etherrtrace(Netfile* f, Etherpkt* pkt, int len)
1029a747e4fSDavid du Colombier {
1039a747e4fSDavid du Colombier int i, n;
1049a747e4fSDavid du Colombier Block *bp;
1059a747e4fSDavid du Colombier
1069a747e4fSDavid du Colombier if(qwindow(f->in) <= 0)
1079a747e4fSDavid du Colombier return;
1089a747e4fSDavid du Colombier if(len > 58)
1099a747e4fSDavid du Colombier n = 58;
1109a747e4fSDavid du Colombier else
1119a747e4fSDavid du Colombier n = len;
1129a747e4fSDavid du Colombier bp = iallocb(64);
1139a747e4fSDavid du Colombier if(bp == nil)
1149a747e4fSDavid du Colombier return;
1159a747e4fSDavid du Colombier memmove(bp->wp, pkt->d, n);
1169a747e4fSDavid du Colombier i = TK2MS(MACHP(0)->ticks);
1179a747e4fSDavid du Colombier bp->wp[58] = len>>8;
1189a747e4fSDavid du Colombier bp->wp[59] = len;
1199a747e4fSDavid du Colombier bp->wp[60] = i>>24;
1209a747e4fSDavid du Colombier bp->wp[61] = i>>16;
1219a747e4fSDavid du Colombier bp->wp[62] = i>>8;
1229a747e4fSDavid du Colombier bp->wp[63] = i;
1239a747e4fSDavid du Colombier bp->wp += 64;
1249a747e4fSDavid du Colombier qpass(f->in, bp);
1259a747e4fSDavid du Colombier }
1269a747e4fSDavid du Colombier
1279a747e4fSDavid du Colombier Block*
etheriq(Ether * ether,Block * bp,int fromwire)1289a747e4fSDavid du Colombier etheriq(Ether* ether, Block* bp, int fromwire)
1299a747e4fSDavid du Colombier {
1309a747e4fSDavid du Colombier Etherpkt *pkt;
1319a747e4fSDavid du Colombier ushort type;
1329a747e4fSDavid du Colombier int len, multi, tome, fromme;
1339a747e4fSDavid du Colombier Netfile **ep, *f, **fp, *fx;
1349a747e4fSDavid du Colombier Block *xbp;
1359a747e4fSDavid du Colombier
1369a747e4fSDavid du Colombier ether->inpackets++;
1379a747e4fSDavid du Colombier
1389a747e4fSDavid du Colombier pkt = (Etherpkt*)bp->rp;
1399a747e4fSDavid du Colombier len = BLEN(bp);
1409a747e4fSDavid du Colombier type = (pkt->type[0]<<8)|pkt->type[1];
1419a747e4fSDavid du Colombier fx = 0;
1429a747e4fSDavid du Colombier ep = ðer->f[Ntypes];
1439a747e4fSDavid du Colombier
1449a747e4fSDavid du Colombier multi = pkt->d[0] & 1;
145*d95be1c0SDavid du Colombier /* check for valid multicast addresses */
1469a747e4fSDavid du Colombier if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){
1479a747e4fSDavid du Colombier if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
1489a747e4fSDavid du Colombier if(fromwire){
1499a747e4fSDavid du Colombier freeb(bp);
1509a747e4fSDavid du Colombier bp = 0;
1519a747e4fSDavid du Colombier }
1529a747e4fSDavid du Colombier return bp;
1539a747e4fSDavid du Colombier }
1549a747e4fSDavid du Colombier }
1559a747e4fSDavid du Colombier
1569a747e4fSDavid du Colombier /* is it for me? */
1579a747e4fSDavid du Colombier tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
1589a747e4fSDavid du Colombier fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
1599a747e4fSDavid du Colombier
1609a747e4fSDavid du Colombier /*
1619a747e4fSDavid du Colombier * Multiplex the packet to all the connections which want it.
1629a747e4fSDavid du Colombier * If the packet is not to be used subsequently (fromwire != 0),
1639a747e4fSDavid du Colombier * attempt to simply pass it into one of the connections, thereby
1649a747e4fSDavid du Colombier * saving a copy of the data (usual case hopefully).
1659a747e4fSDavid du Colombier */
1669a747e4fSDavid du Colombier for(fp = ether->f; fp < ep; fp++){
1679a747e4fSDavid du Colombier if(f = *fp)
1689a747e4fSDavid du Colombier if(f->type == type || f->type < 0)
1699a747e4fSDavid du Colombier if(tome || multi || f->prom){
1709a747e4fSDavid du Colombier /* Don't want to hear bridged packets */
1719a747e4fSDavid du Colombier if(f->bridge && !fromwire && !fromme)
1729a747e4fSDavid du Colombier continue;
1739a747e4fSDavid du Colombier if(!f->headersonly){
1749a747e4fSDavid du Colombier if(fromwire && fx == 0)
1759a747e4fSDavid du Colombier fx = f;
1769a747e4fSDavid du Colombier else if(xbp = iallocb(len)){
1779a747e4fSDavid du Colombier memmove(xbp->wp, pkt, len);
1789a747e4fSDavid du Colombier xbp->wp += len;
1799a747e4fSDavid du Colombier qpass(f->in, xbp);
1809a747e4fSDavid du Colombier }
1819a747e4fSDavid du Colombier else
1829a747e4fSDavid du Colombier ether->soverflows++;
1839a747e4fSDavid du Colombier }
1849a747e4fSDavid du Colombier else
1859a747e4fSDavid du Colombier etherrtrace(f, pkt, len);
1869a747e4fSDavid du Colombier }
1879a747e4fSDavid du Colombier }
1889a747e4fSDavid du Colombier
1899a747e4fSDavid du Colombier if(fx){
1909a747e4fSDavid du Colombier if(qpass(fx->in, bp) < 0)
1919a747e4fSDavid du Colombier ether->soverflows++;
1929a747e4fSDavid du Colombier return 0;
1939a747e4fSDavid du Colombier }
1949a747e4fSDavid du Colombier if(fromwire){
1959a747e4fSDavid du Colombier freeb(bp);
1969a747e4fSDavid du Colombier return 0;
1979a747e4fSDavid du Colombier }
1989a747e4fSDavid du Colombier
1999a747e4fSDavid du Colombier return bp;
2009a747e4fSDavid du Colombier }
2019a747e4fSDavid du Colombier
2029a747e4fSDavid du Colombier static int
etheroq(Ether * ether,Block * bp)2039a747e4fSDavid du Colombier etheroq(Ether* ether, Block* bp)
2049a747e4fSDavid du Colombier {
2059a747e4fSDavid du Colombier int len, loopback, s;
2069a747e4fSDavid du Colombier Etherpkt *pkt;
2079a747e4fSDavid du Colombier
2089a747e4fSDavid du Colombier ether->outpackets++;
2099a747e4fSDavid du Colombier
2109a747e4fSDavid du Colombier /*
2119a747e4fSDavid du Colombier * Check if the packet has to be placed back onto the input queue,
2129a747e4fSDavid du Colombier * i.e. if it's a loopback or broadcast packet or the interface is
2139a747e4fSDavid du Colombier * in promiscuous mode.
2149a747e4fSDavid du Colombier * If it's a loopback packet indicate to etheriq that the data isn't
2159a747e4fSDavid du Colombier * needed and return, etheriq will pass-on or free the block.
2169a747e4fSDavid du Colombier * To enable bridging to work, only packets that were originated
2179a747e4fSDavid du Colombier * by this interface are fed back.
2189a747e4fSDavid du Colombier */
2199a747e4fSDavid du Colombier pkt = (Etherpkt*)bp->rp;
2209a747e4fSDavid du Colombier len = BLEN(bp);
2219a747e4fSDavid du Colombier loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
2229a747e4fSDavid du Colombier if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
2239a747e4fSDavid du Colombier s = splhi();
2249a747e4fSDavid du Colombier etheriq(ether, bp, 0);
2259a747e4fSDavid du Colombier splx(s);
2269a747e4fSDavid du Colombier }
2279a747e4fSDavid du Colombier
2289a747e4fSDavid du Colombier if(!loopback){
2299a747e4fSDavid du Colombier qbwrite(ether->oq, bp);
2309a747e4fSDavid du Colombier ether->transmit(ether);
2319a747e4fSDavid du Colombier } else
2329a747e4fSDavid du Colombier freeb(bp);
2339a747e4fSDavid du Colombier
2349a747e4fSDavid du Colombier return len;
2359a747e4fSDavid du Colombier }
2369a747e4fSDavid du Colombier
2379a747e4fSDavid du Colombier static long
etherwrite(Chan * chan,void * buf,long n,vlong)2389a747e4fSDavid du Colombier etherwrite(Chan* chan, void* buf, long n, vlong)
2399a747e4fSDavid du Colombier {
2409a747e4fSDavid du Colombier Ether *ether;
2419a747e4fSDavid du Colombier Block *bp;
2429a747e4fSDavid du Colombier int nn;
2439a747e4fSDavid du Colombier
2449a747e4fSDavid du Colombier ether = etherxx[chan->dev];
2459a747e4fSDavid du Colombier if(NETTYPE(chan->qid.path) != Ndataqid) {
2469a747e4fSDavid du Colombier nn = netifwrite(ether, chan, buf, n);
2479a747e4fSDavid du Colombier if(nn >= 0)
2489a747e4fSDavid du Colombier return nn;
2499a747e4fSDavid du Colombier
2503ff48bf5SDavid du Colombier if(n == sizeof("nonblocking")-1 && strncmp((char*)buf, "nonblocking", n) == 0){
2513ff48bf5SDavid du Colombier qnoblock(ether->oq, 1);
25259c21d95SDavid du Colombier return n;
2533ff48bf5SDavid du Colombier }
2543ff48bf5SDavid du Colombier
2559a747e4fSDavid du Colombier if(ether->ctl!=nil)
2569a747e4fSDavid du Colombier return ether->ctl(ether,buf,n);
2579a747e4fSDavid du Colombier
2589a747e4fSDavid du Colombier error(Ebadctl);
2599a747e4fSDavid du Colombier }
2609a747e4fSDavid du Colombier
2619a747e4fSDavid du Colombier if(n > ether->maxmtu)
2629a747e4fSDavid du Colombier error(Etoobig);
2639a747e4fSDavid du Colombier if(n < ether->minmtu)
2649a747e4fSDavid du Colombier error(Etoosmall);
2659a747e4fSDavid du Colombier
2669a747e4fSDavid du Colombier bp = allocb(n);
2679a747e4fSDavid du Colombier if(waserror()){
2689a747e4fSDavid du Colombier freeb(bp);
2699a747e4fSDavid du Colombier nexterror();
2709a747e4fSDavid du Colombier }
2719a747e4fSDavid du Colombier memmove(bp->rp, buf, n);
2729a747e4fSDavid du Colombier memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
2739a747e4fSDavid du Colombier poperror();
2749a747e4fSDavid du Colombier bp->wp += n;
2759a747e4fSDavid du Colombier
2769a747e4fSDavid du Colombier return etheroq(ether, bp);
2779a747e4fSDavid du Colombier }
2789a747e4fSDavid du Colombier
2799a747e4fSDavid du Colombier static long
etherbwrite(Chan * chan,Block * bp,ulong)2809a747e4fSDavid du Colombier etherbwrite(Chan* chan, Block* bp, ulong)
2819a747e4fSDavid du Colombier {
2829a747e4fSDavid du Colombier Ether *ether;
2839a747e4fSDavid du Colombier long n;
2849a747e4fSDavid du Colombier
2859a747e4fSDavid du Colombier n = BLEN(bp);
2869a747e4fSDavid du Colombier if(NETTYPE(chan->qid.path) != Ndataqid){
2879a747e4fSDavid du Colombier if(waserror()) {
2889a747e4fSDavid du Colombier freeb(bp);
2899a747e4fSDavid du Colombier nexterror();
2909a747e4fSDavid du Colombier }
2919a747e4fSDavid du Colombier n = etherwrite(chan, bp->rp, n, 0);
2929a747e4fSDavid du Colombier poperror();
2939a747e4fSDavid du Colombier freeb(bp);
2949a747e4fSDavid du Colombier return n;
2959a747e4fSDavid du Colombier }
2969a747e4fSDavid du Colombier ether = etherxx[chan->dev];
2979a747e4fSDavid du Colombier
2989a747e4fSDavid du Colombier if(n > ether->maxmtu){
2999a747e4fSDavid du Colombier freeb(bp);
3009a747e4fSDavid du Colombier error(Etoobig);
3019a747e4fSDavid du Colombier }
3029a747e4fSDavid du Colombier if(n < ether->minmtu){
3039a747e4fSDavid du Colombier freeb(bp);
3049a747e4fSDavid du Colombier error(Etoosmall);
3059a747e4fSDavid du Colombier }
3069a747e4fSDavid du Colombier
3079a747e4fSDavid du Colombier return etheroq(ether, bp);
3089a747e4fSDavid du Colombier }
3099a747e4fSDavid du Colombier
3109a747e4fSDavid du Colombier static struct {
3119a747e4fSDavid du Colombier char* type;
3129a747e4fSDavid du Colombier int (*reset)(Ether*);
3139a747e4fSDavid du Colombier } cards[MaxEther+1];
3149a747e4fSDavid du Colombier
3159a747e4fSDavid du Colombier void
addethercard(char * t,int (* r)(Ether *))3169a747e4fSDavid du Colombier addethercard(char* t, int (*r)(Ether*))
3179a747e4fSDavid du Colombier {
3189a747e4fSDavid du Colombier static int ncard;
3199a747e4fSDavid du Colombier
3209a747e4fSDavid du Colombier if(ncard == MaxEther)
3219a747e4fSDavid du Colombier panic("too many ether cards");
3229a747e4fSDavid du Colombier cards[ncard].type = t;
3239a747e4fSDavid du Colombier cards[ncard].reset = r;
3249a747e4fSDavid du Colombier ncard++;
3259a747e4fSDavid du Colombier }
3269a747e4fSDavid du Colombier
3279a747e4fSDavid du Colombier int
parseether(uchar * to,char * from)3289a747e4fSDavid du Colombier parseether(uchar *to, char *from)
3299a747e4fSDavid du Colombier {
3309a747e4fSDavid du Colombier char nip[4];
3319a747e4fSDavid du Colombier char *p;
3329a747e4fSDavid du Colombier int i;
3339a747e4fSDavid du Colombier
3349a747e4fSDavid du Colombier p = from;
3359a747e4fSDavid du Colombier for(i = 0; i < 6; i++){
3369a747e4fSDavid du Colombier if(*p == 0)
3379a747e4fSDavid du Colombier return -1;
3389a747e4fSDavid du Colombier nip[0] = *p++;
3399a747e4fSDavid du Colombier if(*p == 0)
3409a747e4fSDavid du Colombier return -1;
3419a747e4fSDavid du Colombier nip[1] = *p++;
3429a747e4fSDavid du Colombier nip[2] = 0;
3439a747e4fSDavid du Colombier to[i] = strtoul(nip, 0, 16);
3449a747e4fSDavid du Colombier if(*p == ':')
3459a747e4fSDavid du Colombier p++;
3469a747e4fSDavid du Colombier }
3479a747e4fSDavid du Colombier return 0;
3489a747e4fSDavid du Colombier }
3499a747e4fSDavid du Colombier
3509a747e4fSDavid du Colombier static void
etherreset(void)3519a747e4fSDavid du Colombier etherreset(void)
3529a747e4fSDavid du Colombier {
3539a747e4fSDavid du Colombier Ether *ether;
3549a747e4fSDavid du Colombier int i, n, ctlrno;
3559a747e4fSDavid du Colombier char name[32], buf[128];
3569a747e4fSDavid du Colombier
3579a747e4fSDavid du Colombier for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
3589a747e4fSDavid du Colombier if(ether == 0)
3599a747e4fSDavid du Colombier ether = malloc(sizeof(Ether));
3609a747e4fSDavid du Colombier memset(ether, 0, sizeof(Ether));
3619a747e4fSDavid du Colombier ether->ctlrno = ctlrno;
3629a747e4fSDavid du Colombier ether->tbdf = BUSUNKNOWN;
3639a747e4fSDavid du Colombier ether->mbps = 10;
3649a747e4fSDavid du Colombier ether->minmtu = ETHERMINTU;
3659a747e4fSDavid du Colombier ether->maxmtu = ETHERMAXTU;
3669a747e4fSDavid du Colombier if(isaconfig("ether", ctlrno, ether) == 0)
3679a747e4fSDavid du Colombier continue;
3689a747e4fSDavid du Colombier for(n = 0; cards[n].type; n++){
3699a747e4fSDavid du Colombier if(cistrcmp(cards[n].type, ether->type))
3709a747e4fSDavid du Colombier continue;
3719a747e4fSDavid du Colombier for(i = 0; i < ether->nopt; i++){
3729a747e4fSDavid du Colombier if(strncmp(ether->opt[i], "ea=", 3))
3739a747e4fSDavid du Colombier continue;
3749a747e4fSDavid du Colombier if(parseether(ether->ea, ðer->opt[i][3]) == -1)
3759a747e4fSDavid du Colombier memset(ether->ea, 0, Eaddrlen);
3769a747e4fSDavid du Colombier }
3779a747e4fSDavid du Colombier if(cards[n].reset(ether))
3789a747e4fSDavid du Colombier break;
3799a747e4fSDavid du Colombier
3809a747e4fSDavid du Colombier /*
3819a747e4fSDavid du Colombier * IRQ2 doesn't really exist, it's used to gang the interrupt
3829a747e4fSDavid du Colombier * controllers together. A device set to IRQ2 will appear on
3839a747e4fSDavid du Colombier * the second interrupt controller as IRQ9.
3849a747e4fSDavid du Colombier */
3859a747e4fSDavid du Colombier if(ether->irq == 2 && BUSTYPE(ether->tbdf) != BusPCI)
3869a747e4fSDavid du Colombier ether->irq = 9;
3879a747e4fSDavid du Colombier snprint(name, sizeof(name), "ether%d", ctlrno);
3889a747e4fSDavid du Colombier
3899a747e4fSDavid du Colombier /*
390fb7f0c93SDavid du Colombier * If ether->irq is <0, it is a hack to indicate no interrupt
3919a747e4fSDavid du Colombier * used by ethersink.
3929a747e4fSDavid du Colombier */
393fb7f0c93SDavid du Colombier if(ether->irq >= 0)
3949a747e4fSDavid du Colombier intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name);
3959a747e4fSDavid du Colombier
396fb7f0c93SDavid du Colombier i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
3979a747e4fSDavid du Colombier ctlrno, ether->type, ether->mbps, ether->port, ether->irq);
3989a747e4fSDavid du Colombier if(ether->mem)
3999a747e4fSDavid du Colombier i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem));
4009a747e4fSDavid du Colombier if(ether->size)
4019a747e4fSDavid du Colombier i += sprint(buf+i, " size 0x%luX", ether->size);
4026063170eSDavid du Colombier i += sprint(buf+i, ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
4039a747e4fSDavid du Colombier ether->ea[0], ether->ea[1], ether->ea[2],
4049a747e4fSDavid du Colombier ether->ea[3], ether->ea[4], ether->ea[5]);
4059a747e4fSDavid du Colombier sprint(buf+i, "\n");
4069a747e4fSDavid du Colombier print(buf);
4079a747e4fSDavid du Colombier
4089a747e4fSDavid du Colombier if(ether->mbps >= 100){
4099a747e4fSDavid du Colombier netifinit(ether, name, Ntypes, 256*1024);
4109a747e4fSDavid du Colombier if(ether->oq == 0)
4113ff48bf5SDavid du Colombier ether->oq = qopen(256*1024, Qmsg, 0, 0);
4129a747e4fSDavid du Colombier }
4139a747e4fSDavid du Colombier else{
4149a747e4fSDavid du Colombier netifinit(ether, name, Ntypes, 65*1024);
4159a747e4fSDavid du Colombier if(ether->oq == 0)
4163ff48bf5SDavid du Colombier ether->oq = qopen(65*1024, Qmsg, 0, 0);
4179a747e4fSDavid du Colombier }
4189a747e4fSDavid du Colombier if(ether->oq == 0)
4199a747e4fSDavid du Colombier panic("etherreset %s", name);
4209a747e4fSDavid du Colombier ether->alen = Eaddrlen;
4219a747e4fSDavid du Colombier memmove(ether->addr, ether->ea, Eaddrlen);
4229a747e4fSDavid du Colombier memset(ether->bcast, 0xFF, Eaddrlen);
4239a747e4fSDavid du Colombier
4249a747e4fSDavid du Colombier etherxx[ctlrno] = ether;
4259a747e4fSDavid du Colombier ether = 0;
4269a747e4fSDavid du Colombier break;
4279a747e4fSDavid du Colombier }
4289a747e4fSDavid du Colombier }
4299a747e4fSDavid du Colombier if(ether)
4309a747e4fSDavid du Colombier free(ether);
4319a747e4fSDavid du Colombier }
4329a747e4fSDavid du Colombier
4339a747e4fSDavid du Colombier #define POLY 0xedb88320
4349a747e4fSDavid du Colombier
4359a747e4fSDavid du Colombier /* really slow 32 bit crc for ethers */
4369a747e4fSDavid du Colombier ulong
ethercrc(uchar * p,int len)4379a747e4fSDavid du Colombier ethercrc(uchar *p, int len)
4389a747e4fSDavid du Colombier {
4399a747e4fSDavid du Colombier int i, j;
4409a747e4fSDavid du Colombier ulong crc, b;
4419a747e4fSDavid du Colombier
4429a747e4fSDavid du Colombier crc = 0xffffffff;
4439a747e4fSDavid du Colombier for(i = 0; i < len; i++){
4449a747e4fSDavid du Colombier b = *p++;
4459a747e4fSDavid du Colombier for(j = 0; j < 8; j++){
4469a747e4fSDavid du Colombier crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
4479a747e4fSDavid du Colombier b >>= 1;
4489a747e4fSDavid du Colombier }
4499a747e4fSDavid du Colombier }
4509a747e4fSDavid du Colombier return crc;
4519a747e4fSDavid du Colombier }
4529a747e4fSDavid du Colombier
4539a747e4fSDavid du Colombier Dev etherdevtab = {
4549a747e4fSDavid du Colombier 'l',
4559a747e4fSDavid du Colombier "ether",
4569a747e4fSDavid du Colombier
4579a747e4fSDavid du Colombier etherreset,
4589a747e4fSDavid du Colombier devinit,
4599a747e4fSDavid du Colombier devshutdown,
4609a747e4fSDavid du Colombier etherattach,
4619a747e4fSDavid du Colombier etherwalk,
4629a747e4fSDavid du Colombier etherstat,
4639a747e4fSDavid du Colombier etheropen,
4649a747e4fSDavid du Colombier ethercreate,
4659a747e4fSDavid du Colombier etherclose,
4669a747e4fSDavid du Colombier etherread,
4679a747e4fSDavid du Colombier etherbread,
4689a747e4fSDavid du Colombier etherwrite,
4699a747e4fSDavid du Colombier etherbwrite,
4709a747e4fSDavid du Colombier devremove,
4719a747e4fSDavid du Colombier etherwstat,
4729a747e4fSDavid du Colombier };
473