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