13de6a9c0SDavid du Colombier #include "u.h"
23de6a9c0SDavid du Colombier #include "../port/lib.h"
33de6a9c0SDavid du Colombier #include "mem.h"
43de6a9c0SDavid du Colombier #include "dat.h"
53de6a9c0SDavid du Colombier #include "fns.h"
63de6a9c0SDavid du Colombier #include "io.h"
73de6a9c0SDavid du Colombier #include "../port/error.h"
83de6a9c0SDavid du Colombier
93de6a9c0SDavid du Colombier #include "../port/netif.h"
103de6a9c0SDavid du Colombier #include "etherif.h"
113de6a9c0SDavid du Colombier
123de6a9c0SDavid du Colombier static Ether *etherxx[MaxEther];
133de6a9c0SDavid du Colombier
143de6a9c0SDavid du Colombier Chan*
etherattach(char * spec)153de6a9c0SDavid du Colombier etherattach(char* spec)
163de6a9c0SDavid du Colombier {
173de6a9c0SDavid du Colombier int ctlrno;
183de6a9c0SDavid du Colombier char *p;
193de6a9c0SDavid du Colombier Chan *chan;
203de6a9c0SDavid du Colombier
213de6a9c0SDavid du Colombier ctlrno = 0;
223de6a9c0SDavid du Colombier if(spec && *spec){
233de6a9c0SDavid du Colombier ctlrno = strtoul(spec, &p, 0);
243de6a9c0SDavid du Colombier if((ctlrno == 0 && p == spec) || *p != 0)
253de6a9c0SDavid du Colombier error(Ebadarg);
263de6a9c0SDavid du Colombier if(ctlrno < 0 || ctlrno >= MaxEther)
273de6a9c0SDavid du Colombier error(Ebadarg);
283de6a9c0SDavid du Colombier }
293de6a9c0SDavid du Colombier if(etherxx[ctlrno] == 0)
303de6a9c0SDavid du Colombier error(Enodev);
313de6a9c0SDavid du Colombier
323de6a9c0SDavid du Colombier chan = devattach('l', spec);
333de6a9c0SDavid du Colombier if(waserror()){
343de6a9c0SDavid du Colombier chanfree(chan);
353de6a9c0SDavid du Colombier nexterror();
363de6a9c0SDavid du Colombier }
373de6a9c0SDavid du Colombier chan->dev = ctlrno;
383de6a9c0SDavid du Colombier if(etherxx[ctlrno]->attach)
393de6a9c0SDavid du Colombier etherxx[ctlrno]->attach(etherxx[ctlrno]);
403de6a9c0SDavid du Colombier poperror();
413de6a9c0SDavid du Colombier return chan;
423de6a9c0SDavid du Colombier }
433de6a9c0SDavid du Colombier
443de6a9c0SDavid du Colombier static Walkqid*
etherwalk(Chan * chan,Chan * nchan,char ** name,int nname)453de6a9c0SDavid du Colombier etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
463de6a9c0SDavid du Colombier {
473de6a9c0SDavid du Colombier return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
483de6a9c0SDavid du Colombier }
493de6a9c0SDavid du Colombier
503de6a9c0SDavid du Colombier static int
etherstat(Chan * chan,uchar * dp,int n)513de6a9c0SDavid du Colombier etherstat(Chan* chan, uchar* dp, int n)
523de6a9c0SDavid du Colombier {
533de6a9c0SDavid du Colombier return netifstat(etherxx[chan->dev], chan, dp, n);
543de6a9c0SDavid du Colombier }
553de6a9c0SDavid du Colombier
563de6a9c0SDavid du Colombier static Chan*
etheropen(Chan * chan,int omode)573de6a9c0SDavid du Colombier etheropen(Chan* chan, int omode)
583de6a9c0SDavid du Colombier {
593de6a9c0SDavid du Colombier return netifopen(etherxx[chan->dev], chan, omode);
603de6a9c0SDavid du Colombier }
613de6a9c0SDavid du Colombier
623de6a9c0SDavid du Colombier static void
ethercreate(Chan *,char *,int,ulong)633de6a9c0SDavid du Colombier ethercreate(Chan*, char*, int, ulong)
643de6a9c0SDavid du Colombier {
653de6a9c0SDavid du Colombier }
663de6a9c0SDavid du Colombier
673de6a9c0SDavid du Colombier static void
etherclose(Chan * chan)683de6a9c0SDavid du Colombier etherclose(Chan* chan)
693de6a9c0SDavid du Colombier {
703de6a9c0SDavid du Colombier netifclose(etherxx[chan->dev], chan);
713de6a9c0SDavid du Colombier }
723de6a9c0SDavid du Colombier
733de6a9c0SDavid du Colombier static long
etherread(Chan * chan,void * buf,long n,vlong off)743de6a9c0SDavid du Colombier etherread(Chan* chan, void* buf, long n, vlong off)
753de6a9c0SDavid du Colombier {
763de6a9c0SDavid du Colombier Ether *ether;
773de6a9c0SDavid du Colombier ulong offset = off;
783de6a9c0SDavid du Colombier
793de6a9c0SDavid du Colombier ether = etherxx[chan->dev];
803de6a9c0SDavid du Colombier if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
813de6a9c0SDavid du Colombier /*
823de6a9c0SDavid du Colombier * With some controllers it is necessary to reach
833de6a9c0SDavid du Colombier * into the chip to extract statistics.
843de6a9c0SDavid du Colombier */
853de6a9c0SDavid du Colombier if(NETTYPE(chan->qid.path) == Nifstatqid)
863de6a9c0SDavid du Colombier return ether->ifstat(ether, buf, n, offset);
873de6a9c0SDavid du Colombier else if(NETTYPE(chan->qid.path) == Nstatqid)
883de6a9c0SDavid du Colombier ether->ifstat(ether, buf, 0, offset);
893de6a9c0SDavid du Colombier }
903de6a9c0SDavid du Colombier
913de6a9c0SDavid du Colombier return netifread(ether, chan, buf, n, offset);
923de6a9c0SDavid du Colombier }
933de6a9c0SDavid du Colombier
943de6a9c0SDavid du Colombier static Block*
etherbread(Chan * chan,long n,ulong offset)953de6a9c0SDavid du Colombier etherbread(Chan* chan, long n, ulong offset)
963de6a9c0SDavid du Colombier {
973de6a9c0SDavid du Colombier return netifbread(etherxx[chan->dev], chan, n, offset);
983de6a9c0SDavid du Colombier }
993de6a9c0SDavid du Colombier
1003de6a9c0SDavid du Colombier static int
etherwstat(Chan * chan,uchar * dp,int n)1013de6a9c0SDavid du Colombier etherwstat(Chan* chan, uchar* dp, int n)
1023de6a9c0SDavid du Colombier {
1033de6a9c0SDavid du Colombier return netifwstat(etherxx[chan->dev], chan, dp, n);
1043de6a9c0SDavid du Colombier }
1053de6a9c0SDavid du Colombier
1063de6a9c0SDavid du Colombier static void
etherrtrace(Netfile * f,Etherpkt * pkt,int len)1073de6a9c0SDavid du Colombier etherrtrace(Netfile* f, Etherpkt* pkt, int len)
1083de6a9c0SDavid du Colombier {
1093de6a9c0SDavid du Colombier int i, n;
1103de6a9c0SDavid du Colombier Block *bp;
1113de6a9c0SDavid du Colombier
1123de6a9c0SDavid du Colombier if(qwindow(f->in) <= 0)
1133de6a9c0SDavid du Colombier return;
1143de6a9c0SDavid du Colombier if(len > 58)
1153de6a9c0SDavid du Colombier n = 58;
1163de6a9c0SDavid du Colombier else
1173de6a9c0SDavid du Colombier n = len;
1183de6a9c0SDavid du Colombier bp = iallocb(64);
1193de6a9c0SDavid du Colombier if(bp == nil)
1203de6a9c0SDavid du Colombier return;
1213de6a9c0SDavid du Colombier memmove(bp->wp, pkt->d, n);
1223de6a9c0SDavid du Colombier i = TK2MS(MACHP(0)->ticks);
1233de6a9c0SDavid du Colombier bp->wp[58] = len>>8;
1243de6a9c0SDavid du Colombier bp->wp[59] = len;
1253de6a9c0SDavid du Colombier bp->wp[60] = i>>24;
1263de6a9c0SDavid du Colombier bp->wp[61] = i>>16;
1273de6a9c0SDavid du Colombier bp->wp[62] = i>>8;
1283de6a9c0SDavid du Colombier bp->wp[63] = i;
1293de6a9c0SDavid du Colombier bp->wp += 64;
1303de6a9c0SDavid du Colombier qpass(f->in, bp);
1313de6a9c0SDavid du Colombier }
1323de6a9c0SDavid du Colombier
1333de6a9c0SDavid du Colombier Block*
etheriq(Ether * ether,Block * bp,int fromwire)1343de6a9c0SDavid du Colombier etheriq(Ether* ether, Block* bp, int fromwire)
1353de6a9c0SDavid du Colombier {
1363de6a9c0SDavid du Colombier Etherpkt *pkt;
1373de6a9c0SDavid du Colombier ushort type;
1383de6a9c0SDavid du Colombier int len, multi, tome, fromme;
1393de6a9c0SDavid du Colombier Netfile **ep, *f, **fp, *fx;
1403de6a9c0SDavid du Colombier Block *xbp;
1413de6a9c0SDavid du Colombier
1423de6a9c0SDavid du Colombier ether->inpackets++;
1433de6a9c0SDavid du Colombier
1443de6a9c0SDavid du Colombier pkt = (Etherpkt*)bp->rp;
1453de6a9c0SDavid du Colombier len = BLEN(bp);
1463de6a9c0SDavid du Colombier type = (pkt->type[0]<<8)|pkt->type[1];
1473de6a9c0SDavid du Colombier fx = 0;
1483de6a9c0SDavid du Colombier ep = ðer->f[Ntypes];
1493de6a9c0SDavid du Colombier
1503de6a9c0SDavid du Colombier multi = pkt->d[0] & 1;
1513de6a9c0SDavid du Colombier /* check for valid multicast addresses */
1523de6a9c0SDavid du Colombier if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 &&
1533de6a9c0SDavid du Colombier ether->prom == 0){
1543de6a9c0SDavid du Colombier if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
1553de6a9c0SDavid du Colombier if(fromwire){
1563de6a9c0SDavid du Colombier freeb(bp);
1573de6a9c0SDavid du Colombier bp = 0;
1583de6a9c0SDavid du Colombier }
1593de6a9c0SDavid du Colombier return bp;
1603de6a9c0SDavid du Colombier }
1613de6a9c0SDavid du Colombier }
1623de6a9c0SDavid du Colombier /* is it for me? */
1633de6a9c0SDavid du Colombier tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
1643de6a9c0SDavid du Colombier fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
1653de6a9c0SDavid du Colombier
1663de6a9c0SDavid du Colombier /*
1673de6a9c0SDavid du Colombier * Multiplex the packet to all the connections which want it.
1683de6a9c0SDavid du Colombier * If the packet is not to be used subsequently (fromwire != 0),
1693de6a9c0SDavid du Colombier * attempt to simply pass it into one of the connections, thereby
1703de6a9c0SDavid du Colombier * saving a copy of the data (usual case hopefully).
1713de6a9c0SDavid du Colombier */
1723de6a9c0SDavid du Colombier for(fp = ether->f; fp < ep; fp++){
1733de6a9c0SDavid du Colombier if((f = *fp) != nil && (f->type == type || f->type < 0) &&
1743de6a9c0SDavid du Colombier (tome || multi || f->prom)){
1753de6a9c0SDavid du Colombier /* Don't want to hear bridged packets */
1763de6a9c0SDavid du Colombier if(f->bridge && !fromwire && !fromme)
1773de6a9c0SDavid du Colombier continue;
1783de6a9c0SDavid du Colombier if(!f->headersonly){
1793de6a9c0SDavid du Colombier if(fromwire && fx == 0)
1803de6a9c0SDavid du Colombier fx = f;
1813de6a9c0SDavid du Colombier else if(xbp = iallocb(len)){
1823de6a9c0SDavid du Colombier memmove(xbp->wp, pkt, len);
1833de6a9c0SDavid du Colombier xbp->wp += len;
1843de6a9c0SDavid du Colombier if(qpass(f->in, xbp) < 0)
1853de6a9c0SDavid du Colombier ether->soverflows++;
1863de6a9c0SDavid du Colombier }
1873de6a9c0SDavid du Colombier else
1883de6a9c0SDavid du Colombier ether->soverflows++;
1893de6a9c0SDavid du Colombier }
1903de6a9c0SDavid du Colombier else
1913de6a9c0SDavid du Colombier etherrtrace(f, pkt, len);
1923de6a9c0SDavid du Colombier }
1933de6a9c0SDavid du Colombier }
1943de6a9c0SDavid du Colombier
1953de6a9c0SDavid du Colombier if(fx){
1963de6a9c0SDavid du Colombier if(qpass(fx->in, bp) < 0)
1973de6a9c0SDavid du Colombier ether->soverflows++;
1983de6a9c0SDavid du Colombier return 0;
1993de6a9c0SDavid du Colombier }
2003de6a9c0SDavid du Colombier if(fromwire){
2013de6a9c0SDavid du Colombier freeb(bp);
2023de6a9c0SDavid du Colombier return 0;
2033de6a9c0SDavid du Colombier }
2043de6a9c0SDavid du Colombier return bp;
2053de6a9c0SDavid du Colombier }
2063de6a9c0SDavid du Colombier
2073de6a9c0SDavid du Colombier static int
etheroq(Ether * ether,Block * bp)2083de6a9c0SDavid du Colombier etheroq(Ether* ether, Block* bp)
2093de6a9c0SDavid du Colombier {
2103de6a9c0SDavid du Colombier int len, loopback, s;
2113de6a9c0SDavid du Colombier Etherpkt *pkt;
2123de6a9c0SDavid du Colombier
2133de6a9c0SDavid du Colombier ether->outpackets++;
2143de6a9c0SDavid du Colombier
2153de6a9c0SDavid du Colombier /*
2163de6a9c0SDavid du Colombier * Check if the packet has to be placed back onto the input queue,
2173de6a9c0SDavid du Colombier * i.e. if it's a loopback or broadcast packet or the interface is
2183de6a9c0SDavid du Colombier * in promiscuous mode.
2193de6a9c0SDavid du Colombier * If it's a loopback packet indicate to etheriq that the data isn't
2203de6a9c0SDavid du Colombier * needed and return, etheriq will pass-on or free the block.
2213de6a9c0SDavid du Colombier * To enable bridging to work, only packets that were originated
2223de6a9c0SDavid du Colombier * by this interface are fed back.
2233de6a9c0SDavid du Colombier */
2243de6a9c0SDavid du Colombier pkt = (Etherpkt*)bp->rp;
2253de6a9c0SDavid du Colombier len = BLEN(bp);
2263de6a9c0SDavid du Colombier loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
2273de6a9c0SDavid du Colombier if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
2283de6a9c0SDavid du Colombier s = splhi();
2293de6a9c0SDavid du Colombier etheriq(ether, bp, 0);
2303de6a9c0SDavid du Colombier splx(s);
2313de6a9c0SDavid du Colombier }
2323de6a9c0SDavid du Colombier
2333de6a9c0SDavid du Colombier if(!loopback){
2343de6a9c0SDavid du Colombier qbwrite(ether->oq, bp);
2353de6a9c0SDavid du Colombier if(ether->transmit != nil)
2363de6a9c0SDavid du Colombier ether->transmit(ether);
2373de6a9c0SDavid du Colombier } else
2383de6a9c0SDavid du Colombier freeb(bp);
2393de6a9c0SDavid du Colombier
2403de6a9c0SDavid du Colombier return len;
2413de6a9c0SDavid du Colombier }
2423de6a9c0SDavid du Colombier
2433de6a9c0SDavid du Colombier static long
etherwrite(Chan * chan,void * buf,long n,vlong)2443de6a9c0SDavid du Colombier etherwrite(Chan* chan, void* buf, long n, vlong)
2453de6a9c0SDavid du Colombier {
2463de6a9c0SDavid du Colombier Ether *ether;
2473de6a9c0SDavid du Colombier Block *bp;
2483de6a9c0SDavid du Colombier int nn, onoff;
2493de6a9c0SDavid du Colombier Cmdbuf *cb;
2503de6a9c0SDavid du Colombier
2513de6a9c0SDavid du Colombier ether = etherxx[chan->dev];
2523de6a9c0SDavid du Colombier if(NETTYPE(chan->qid.path) != Ndataqid) {
2533de6a9c0SDavid du Colombier nn = netifwrite(ether, chan, buf, n);
2543de6a9c0SDavid du Colombier if(nn >= 0)
2553de6a9c0SDavid du Colombier return nn;
2563de6a9c0SDavid du Colombier cb = parsecmd(buf, n);
2573de6a9c0SDavid du Colombier if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
2583de6a9c0SDavid du Colombier if(cb->nf <= 1)
2593de6a9c0SDavid du Colombier onoff = 1;
2603de6a9c0SDavid du Colombier else
2613de6a9c0SDavid du Colombier onoff = atoi(cb->f[1]);
2623de6a9c0SDavid du Colombier qnoblock(ether->oq, onoff);
2633de6a9c0SDavid du Colombier free(cb);
2643de6a9c0SDavid du Colombier return n;
2653de6a9c0SDavid du Colombier }
2663de6a9c0SDavid du Colombier free(cb);
2673de6a9c0SDavid du Colombier if(ether->ctl!=nil)
2683de6a9c0SDavid du Colombier return ether->ctl(ether,buf,n);
2693de6a9c0SDavid du Colombier
2703de6a9c0SDavid du Colombier error(Ebadctl);
2713de6a9c0SDavid du Colombier }
2723de6a9c0SDavid du Colombier
2733de6a9c0SDavid du Colombier if(n > ether->maxmtu)
2743de6a9c0SDavid du Colombier error(Etoobig);
2753de6a9c0SDavid du Colombier if(n < ether->minmtu)
2763de6a9c0SDavid du Colombier error(Etoosmall);
2773de6a9c0SDavid du Colombier
2783de6a9c0SDavid du Colombier bp = allocb(n);
2793de6a9c0SDavid du Colombier if(waserror()){
2803de6a9c0SDavid du Colombier freeb(bp);
2813de6a9c0SDavid du Colombier nexterror();
2823de6a9c0SDavid du Colombier }
2833de6a9c0SDavid du Colombier memmove(bp->rp, buf, n);
2843de6a9c0SDavid du Colombier memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
2853de6a9c0SDavid du Colombier poperror();
2863de6a9c0SDavid du Colombier bp->wp += n;
2873de6a9c0SDavid du Colombier
2883de6a9c0SDavid du Colombier return etheroq(ether, bp);
2893de6a9c0SDavid du Colombier }
2903de6a9c0SDavid du Colombier
2913de6a9c0SDavid du Colombier static long
etherbwrite(Chan * chan,Block * bp,ulong)2923de6a9c0SDavid du Colombier etherbwrite(Chan* chan, Block* bp, ulong)
2933de6a9c0SDavid du Colombier {
2943de6a9c0SDavid du Colombier Ether *ether;
2953de6a9c0SDavid du Colombier long n;
2963de6a9c0SDavid du Colombier
2973de6a9c0SDavid du Colombier n = BLEN(bp);
2983de6a9c0SDavid du Colombier if(NETTYPE(chan->qid.path) != Ndataqid){
2993de6a9c0SDavid du Colombier if(waserror()) {
3003de6a9c0SDavid du Colombier freeb(bp);
3013de6a9c0SDavid du Colombier nexterror();
3023de6a9c0SDavid du Colombier }
3033de6a9c0SDavid du Colombier n = etherwrite(chan, bp->rp, n, 0);
3043de6a9c0SDavid du Colombier poperror();
3053de6a9c0SDavid du Colombier freeb(bp);
3063de6a9c0SDavid du Colombier return n;
3073de6a9c0SDavid du Colombier }
3083de6a9c0SDavid du Colombier ether = etherxx[chan->dev];
3093de6a9c0SDavid du Colombier
3103de6a9c0SDavid du Colombier if(n > ether->maxmtu){
3113de6a9c0SDavid du Colombier freeb(bp);
3123de6a9c0SDavid du Colombier error(Etoobig);
3133de6a9c0SDavid du Colombier }
3143de6a9c0SDavid du Colombier if(n < ether->minmtu){
3153de6a9c0SDavid du Colombier freeb(bp);
3163de6a9c0SDavid du Colombier error(Etoosmall);
3173de6a9c0SDavid du Colombier }
3183de6a9c0SDavid du Colombier
3193de6a9c0SDavid du Colombier return etheroq(ether, bp);
3203de6a9c0SDavid du Colombier }
3213de6a9c0SDavid du Colombier
3223de6a9c0SDavid du Colombier static struct {
3233de6a9c0SDavid du Colombier char* type;
3243de6a9c0SDavid du Colombier int (*reset)(Ether*);
3253de6a9c0SDavid du Colombier } cards[MaxEther+1];
3263de6a9c0SDavid du Colombier
3273de6a9c0SDavid du Colombier void
addethercard(char * t,int (* r)(Ether *))3283de6a9c0SDavid du Colombier addethercard(char* t, int (*r)(Ether*))
3293de6a9c0SDavid du Colombier {
3303de6a9c0SDavid du Colombier static int ncard;
3313de6a9c0SDavid du Colombier
3323de6a9c0SDavid du Colombier if(ncard == MaxEther)
3333de6a9c0SDavid du Colombier panic("too many ether cards");
3343de6a9c0SDavid du Colombier cards[ncard].type = t;
3353de6a9c0SDavid du Colombier cards[ncard].reset = r;
3363de6a9c0SDavid du Colombier ncard++;
3373de6a9c0SDavid du Colombier }
3383de6a9c0SDavid du Colombier
3393de6a9c0SDavid du Colombier int
parseether(uchar * to,char * from)3403de6a9c0SDavid du Colombier parseether(uchar *to, char *from)
3413de6a9c0SDavid du Colombier {
3423de6a9c0SDavid du Colombier char nip[4];
3433de6a9c0SDavid du Colombier char *p;
3443de6a9c0SDavid du Colombier int i;
3453de6a9c0SDavid du Colombier
3463de6a9c0SDavid du Colombier p = from;
3473de6a9c0SDavid du Colombier for(i = 0; i < Eaddrlen; i++){
3483de6a9c0SDavid du Colombier if(*p == 0)
3493de6a9c0SDavid du Colombier return -1;
3503de6a9c0SDavid du Colombier nip[0] = *p++;
3513de6a9c0SDavid du Colombier if(*p == 0)
3523de6a9c0SDavid du Colombier return -1;
3533de6a9c0SDavid du Colombier nip[1] = *p++;
3543de6a9c0SDavid du Colombier nip[2] = 0;
3553de6a9c0SDavid du Colombier to[i] = strtoul(nip, 0, 16);
3563de6a9c0SDavid du Colombier if(*p == ':')
3573de6a9c0SDavid du Colombier p++;
3583de6a9c0SDavid du Colombier }
3593de6a9c0SDavid du Colombier return 0;
3603de6a9c0SDavid du Colombier }
3613de6a9c0SDavid du Colombier
3623de6a9c0SDavid du Colombier static void
etherreset(void)3633de6a9c0SDavid du Colombier etherreset(void)
3643de6a9c0SDavid du Colombier {
3653de6a9c0SDavid du Colombier Ether *ether;
3663de6a9c0SDavid du Colombier int i, n, ctlrno;
3673de6a9c0SDavid du Colombier char name[KNAMELEN], buf[128];
3683de6a9c0SDavid du Colombier
3693de6a9c0SDavid du Colombier for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
3703de6a9c0SDavid du Colombier if(ether == 0)
3713de6a9c0SDavid du Colombier ether = malloc(sizeof(Ether));
3723de6a9c0SDavid du Colombier memset(ether, 0, sizeof(Ether));
3733de6a9c0SDavid du Colombier ether->ctlrno = ctlrno;
3743de6a9c0SDavid du Colombier ether->mbps = 10;
3753de6a9c0SDavid du Colombier ether->minmtu = ETHERMINTU;
3763de6a9c0SDavid du Colombier ether->maxmtu = ETHERMAXTU;
3773de6a9c0SDavid du Colombier
3783de6a9c0SDavid du Colombier if(archether(ctlrno, ether) <= 0)
3793de6a9c0SDavid du Colombier continue;
3803de6a9c0SDavid du Colombier
3813de6a9c0SDavid du Colombier if(isaconfig("ether", ctlrno, ether) == 0){
382*a1216cc6SDavid du Colombier // free(ether);
3833de6a9c0SDavid du Colombier // return nil;
3843de6a9c0SDavid du Colombier continue;
3853de6a9c0SDavid du Colombier }
3863de6a9c0SDavid du Colombier for(n = 0; cards[n].type; n++){
3873de6a9c0SDavid du Colombier if(cistrcmp(cards[n].type, ether->type))
3883de6a9c0SDavid du Colombier continue;
3893de6a9c0SDavid du Colombier for(i = 0; i < ether->nopt; i++)
3903de6a9c0SDavid du Colombier if(cistrncmp(ether->opt[i], "ea=", 3) == 0){
3913de6a9c0SDavid du Colombier if(parseether(ether->ea,
3923de6a9c0SDavid du Colombier ðer->opt[i][3]) == -1)
3933de6a9c0SDavid du Colombier memset(ether->ea, 0, Eaddrlen);
3943de6a9c0SDavid du Colombier } else if(cistrcmp(ether->opt[i],
3953de6a9c0SDavid du Colombier "100BASE-TXFD") == 0)
3963de6a9c0SDavid du Colombier ether->mbps = 100;
3973de6a9c0SDavid du Colombier if(cards[n].reset(ether))
3983de6a9c0SDavid du Colombier break;
3993de6a9c0SDavid du Colombier snprint(name, sizeof(name), "ether%d", ctlrno);
4003de6a9c0SDavid du Colombier
4013de6a9c0SDavid du Colombier if(ether->interrupt != nil && ether->irq >= 0)
4023de6a9c0SDavid du Colombier intrenable(ether->irq, ether->interrupt,
4033de6a9c0SDavid du Colombier ether, 0, name);
4043de6a9c0SDavid du Colombier
4053de6a9c0SDavid du Colombier i = snprint(buf, sizeof buf,
4063de6a9c0SDavid du Colombier "#l%d: %s: %dMbps port %#lux irq %d",
4073de6a9c0SDavid du Colombier ctlrno, ether->type, ether->mbps, ether->port,
4083de6a9c0SDavid du Colombier ether->irq);
4093de6a9c0SDavid du Colombier if(ether->mem)
4103de6a9c0SDavid du Colombier i += snprint(buf+i, sizeof buf - i,
4113de6a9c0SDavid du Colombier " addr %#lux", PADDR(ether->mem));
4123de6a9c0SDavid du Colombier if(ether->size)
4133de6a9c0SDavid du Colombier i += snprint(buf+i, sizeof buf - i,
4143de6a9c0SDavid du Colombier " size %#luX", ether->size);
4153de6a9c0SDavid du Colombier i += snprint(buf+i, sizeof buf - i,
4163de6a9c0SDavid du Colombier ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
4173de6a9c0SDavid du Colombier ether->ea[0], ether->ea[1], ether->ea[2],
4183de6a9c0SDavid du Colombier ether->ea[3], ether->ea[4], ether->ea[5]);
4193de6a9c0SDavid du Colombier snprint(buf+i, sizeof buf - i, "\n");
4203de6a9c0SDavid du Colombier iprint("%s", buf); /* it may be too early for print */
4213de6a9c0SDavid du Colombier
4223de6a9c0SDavid du Colombier if(ether->mbps >= 1000)
4233de6a9c0SDavid du Colombier netifinit(ether, name, Ntypes, 4*1024*1024);
4243de6a9c0SDavid du Colombier else if(ether->mbps >= 100)
4253de6a9c0SDavid du Colombier netifinit(ether, name, Ntypes, 1024*1024);
4263de6a9c0SDavid du Colombier else
4273de6a9c0SDavid du Colombier netifinit(ether, name, Ntypes, 65*1024);
4283de6a9c0SDavid du Colombier if(ether->oq == 0)
4293de6a9c0SDavid du Colombier ether->oq = qopen(ether->limit, Qmsg, 0, 0);
4303de6a9c0SDavid du Colombier if(ether->oq == 0)
4313de6a9c0SDavid du Colombier panic("etherreset %s", name);
4323de6a9c0SDavid du Colombier ether->alen = Eaddrlen;
4333de6a9c0SDavid du Colombier memmove(ether->addr, ether->ea, Eaddrlen);
4343de6a9c0SDavid du Colombier memset(ether->bcast, 0xFF, Eaddrlen);
4353de6a9c0SDavid du Colombier
4363de6a9c0SDavid du Colombier etherxx[ctlrno] = ether;
4373de6a9c0SDavid du Colombier ether = 0;
4383de6a9c0SDavid du Colombier break;
4393de6a9c0SDavid du Colombier }
4403de6a9c0SDavid du Colombier }
4413de6a9c0SDavid du Colombier if(ether)
4423de6a9c0SDavid du Colombier free(ether);
4433de6a9c0SDavid du Colombier }
4443de6a9c0SDavid du Colombier
4453de6a9c0SDavid du Colombier static void
ethershutdown(void)4463de6a9c0SDavid du Colombier ethershutdown(void)
4473de6a9c0SDavid du Colombier {
4483de6a9c0SDavid du Colombier Ether *ether;
4493de6a9c0SDavid du Colombier int i;
4503de6a9c0SDavid du Colombier
4513de6a9c0SDavid du Colombier for(i = 0; i < MaxEther; i++){
4523de6a9c0SDavid du Colombier ether = etherxx[i];
4533de6a9c0SDavid du Colombier if(ether == nil)
4543de6a9c0SDavid du Colombier continue;
4553de6a9c0SDavid du Colombier if(ether->shutdown == nil) {
4563de6a9c0SDavid du Colombier print("#l%d: no shutdown function\n", i);
4573de6a9c0SDavid du Colombier continue;
4583de6a9c0SDavid du Colombier }
4593de6a9c0SDavid du Colombier (*ether->shutdown)(ether);
4603de6a9c0SDavid du Colombier }
4613de6a9c0SDavid du Colombier }
4623de6a9c0SDavid du Colombier
4633de6a9c0SDavid du Colombier
4643de6a9c0SDavid du Colombier #define POLY 0xedb88320
4653de6a9c0SDavid du Colombier
4663de6a9c0SDavid du Colombier /* really slow 32 bit crc for ethers */
4673de6a9c0SDavid du Colombier ulong
ethercrc(uchar * p,int len)4683de6a9c0SDavid du Colombier ethercrc(uchar *p, int len)
4693de6a9c0SDavid du Colombier {
4703de6a9c0SDavid du Colombier int i, j;
4713de6a9c0SDavid du Colombier ulong crc, b;
4723de6a9c0SDavid du Colombier
4733de6a9c0SDavid du Colombier crc = 0xffffffff;
4743de6a9c0SDavid du Colombier for(i = 0; i < len; i++){
4753de6a9c0SDavid du Colombier b = *p++;
4763de6a9c0SDavid du Colombier for(j = 0; j < 8; j++){
4773de6a9c0SDavid du Colombier crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
4783de6a9c0SDavid du Colombier b >>= 1;
4793de6a9c0SDavid du Colombier }
4803de6a9c0SDavid du Colombier }
4813de6a9c0SDavid du Colombier return crc;
4823de6a9c0SDavid du Colombier }
4833de6a9c0SDavid du Colombier
4843de6a9c0SDavid du Colombier void
dumpoq(Queue * oq)4853de6a9c0SDavid du Colombier dumpoq(Queue *oq)
4863de6a9c0SDavid du Colombier {
4873de6a9c0SDavid du Colombier if (oq == nil)
4883de6a9c0SDavid du Colombier print("no outq! ");
4893de6a9c0SDavid du Colombier else if (qisclosed(oq))
4903de6a9c0SDavid du Colombier print("outq closed ");
4913de6a9c0SDavid du Colombier else if (qfull(oq))
4923de6a9c0SDavid du Colombier print("outq full ");
4933de6a9c0SDavid du Colombier else
4943de6a9c0SDavid du Colombier print("outq %d ", qlen(oq));
4953de6a9c0SDavid du Colombier }
4963de6a9c0SDavid du Colombier
4973de6a9c0SDavid du Colombier void
dumpnetif(Netif * netif)4983de6a9c0SDavid du Colombier dumpnetif(Netif *netif)
4993de6a9c0SDavid du Colombier {
5003de6a9c0SDavid du Colombier print("netif %s ", netif->name);
5013de6a9c0SDavid du Colombier print("limit %d mbps %d link %d ",
5023de6a9c0SDavid du Colombier netif->limit, netif->mbps, netif->link);
5033de6a9c0SDavid du Colombier print("inpkts %lld outpkts %lld errs %d\n",
5043de6a9c0SDavid du Colombier netif->inpackets, netif->outpackets,
5053de6a9c0SDavid du Colombier netif->crcs + netif->oerrs + netif->frames + netif->overflows +
5063de6a9c0SDavid du Colombier netif->buffs + netif->soverflows);
5073de6a9c0SDavid du Colombier }
5083de6a9c0SDavid du Colombier
5093de6a9c0SDavid du Colombier Dev etherdevtab = {
5103de6a9c0SDavid du Colombier 'l',
5113de6a9c0SDavid du Colombier "ether",
5123de6a9c0SDavid du Colombier
5133de6a9c0SDavid du Colombier etherreset,
5143de6a9c0SDavid du Colombier devinit,
5153de6a9c0SDavid du Colombier ethershutdown,
5163de6a9c0SDavid du Colombier etherattach,
5173de6a9c0SDavid du Colombier etherwalk,
5183de6a9c0SDavid du Colombier etherstat,
5193de6a9c0SDavid du Colombier etheropen,
5203de6a9c0SDavid du Colombier ethercreate,
5213de6a9c0SDavid du Colombier etherclose,
5223de6a9c0SDavid du Colombier etherread,
5233de6a9c0SDavid du Colombier etherbread,
5243de6a9c0SDavid du Colombier etherwrite,
5253de6a9c0SDavid du Colombier etherbwrite,
5263de6a9c0SDavid du Colombier devremove,
5273de6a9c0SDavid du Colombier etherwstat,
5283de6a9c0SDavid du Colombier };
529