18e32b400SDavid du Colombier #include "u.h"
28e32b400SDavid du Colombier #include "../port/lib.h"
38e32b400SDavid du Colombier #include "mem.h"
48e32b400SDavid du Colombier #include "dat.h"
58e32b400SDavid du Colombier #include "fns.h"
68e32b400SDavid du Colombier #include "io.h"
78e32b400SDavid du Colombier #include "../port/error.h"
88e32b400SDavid du Colombier
98e32b400SDavid du Colombier #include "../port/netif.h"
108e32b400SDavid du Colombier #include "etherif.h"
118e32b400SDavid du Colombier
128e32b400SDavid du Colombier extern int archether(unsigned ctlno, Ether *ether);
138e32b400SDavid du Colombier
148e32b400SDavid du Colombier static Ether *etherxx[MaxEther];
158e32b400SDavid du Colombier
168e32b400SDavid du Colombier Chan*
etherattach(char * spec)178e32b400SDavid du Colombier etherattach(char* spec)
188e32b400SDavid du Colombier {
198e32b400SDavid du Colombier int ctlrno;
208e32b400SDavid du Colombier char *p;
218e32b400SDavid du Colombier Chan *chan;
228e32b400SDavid du Colombier
238e32b400SDavid du Colombier ctlrno = 0;
248e32b400SDavid du Colombier if(spec && *spec){
258e32b400SDavid du Colombier ctlrno = strtoul(spec, &p, 0);
268e32b400SDavid du Colombier if((ctlrno == 0 && p == spec) || *p != 0)
278e32b400SDavid du Colombier error(Ebadarg);
288e32b400SDavid du Colombier if(ctlrno < 0 || ctlrno >= MaxEther)
298e32b400SDavid du Colombier error(Ebadarg);
308e32b400SDavid du Colombier }
318e32b400SDavid du Colombier if(etherxx[ctlrno] == 0)
328e32b400SDavid du Colombier error(Enodev);
338e32b400SDavid du Colombier
348e32b400SDavid du Colombier chan = devattach('l', spec);
358e32b400SDavid du Colombier if(waserror()){
368e32b400SDavid du Colombier chanfree(chan);
378e32b400SDavid du Colombier nexterror();
388e32b400SDavid du Colombier }
398e32b400SDavid du Colombier chan->dev = ctlrno;
408e32b400SDavid du Colombier if(etherxx[ctlrno]->attach)
418e32b400SDavid du Colombier etherxx[ctlrno]->attach(etherxx[ctlrno]);
428e32b400SDavid du Colombier poperror();
438e32b400SDavid du Colombier return chan;
448e32b400SDavid du Colombier }
458e32b400SDavid du Colombier
468e32b400SDavid du Colombier static Walkqid*
etherwalk(Chan * chan,Chan * nchan,char ** name,int nname)478e32b400SDavid du Colombier etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
488e32b400SDavid du Colombier {
498e32b400SDavid du Colombier return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
508e32b400SDavid du Colombier }
518e32b400SDavid du Colombier
528e32b400SDavid du Colombier static int
etherstat(Chan * chan,uchar * dp,int n)538e32b400SDavid du Colombier etherstat(Chan* chan, uchar* dp, int n)
548e32b400SDavid du Colombier {
558e32b400SDavid du Colombier return netifstat(etherxx[chan->dev], chan, dp, n);
568e32b400SDavid du Colombier }
578e32b400SDavid du Colombier
588e32b400SDavid du Colombier static Chan*
etheropen(Chan * chan,int omode)598e32b400SDavid du Colombier etheropen(Chan* chan, int omode)
608e32b400SDavid du Colombier {
618e32b400SDavid du Colombier return netifopen(etherxx[chan->dev], chan, omode);
628e32b400SDavid du Colombier }
638e32b400SDavid du Colombier
648e32b400SDavid du Colombier static void
ethercreate(Chan *,char *,int,ulong)658e32b400SDavid du Colombier ethercreate(Chan*, char*, int, ulong)
668e32b400SDavid du Colombier {
678e32b400SDavid du Colombier }
688e32b400SDavid du Colombier
698e32b400SDavid du Colombier static void
etherclose(Chan * chan)708e32b400SDavid du Colombier etherclose(Chan* chan)
718e32b400SDavid du Colombier {
728e32b400SDavid du Colombier netifclose(etherxx[chan->dev], chan);
738e32b400SDavid du Colombier }
748e32b400SDavid du Colombier
758e32b400SDavid du Colombier static long
etherread(Chan * chan,void * buf,long n,vlong off)768e32b400SDavid du Colombier etherread(Chan* chan, void* buf, long n, vlong off)
778e32b400SDavid du Colombier {
788e32b400SDavid du Colombier Ether *ether;
798e32b400SDavid du Colombier ulong offset = off;
808e32b400SDavid du Colombier
818e32b400SDavid du Colombier ether = etherxx[chan->dev];
828e32b400SDavid du Colombier if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
838e32b400SDavid du Colombier /*
848e32b400SDavid du Colombier * With some controllers it is necessary to reach
858e32b400SDavid du Colombier * into the chip to extract statistics.
868e32b400SDavid du Colombier */
878e32b400SDavid du Colombier if(NETTYPE(chan->qid.path) == Nifstatqid)
888e32b400SDavid du Colombier return ether->ifstat(ether, buf, n, offset);
898e32b400SDavid du Colombier else if(NETTYPE(chan->qid.path) == Nstatqid)
908e32b400SDavid du Colombier ether->ifstat(ether, buf, 0, offset);
918e32b400SDavid du Colombier }
928e32b400SDavid du Colombier
938e32b400SDavid du Colombier return netifread(ether, chan, buf, n, offset);
948e32b400SDavid du Colombier }
958e32b400SDavid du Colombier
968e32b400SDavid du Colombier static Block*
etherbread(Chan * chan,long n,ulong offset)978e32b400SDavid du Colombier etherbread(Chan* chan, long n, ulong offset)
988e32b400SDavid du Colombier {
998e32b400SDavid du Colombier return netifbread(etherxx[chan->dev], chan, n, offset);
1008e32b400SDavid du Colombier }
1018e32b400SDavid du Colombier
1028e32b400SDavid du Colombier static int
etherwstat(Chan * chan,uchar * dp,int n)1038e32b400SDavid du Colombier etherwstat(Chan* chan, uchar* dp, int n)
1048e32b400SDavid du Colombier {
1058e32b400SDavid du Colombier return netifwstat(etherxx[chan->dev], chan, dp, n);
1068e32b400SDavid du Colombier }
1078e32b400SDavid du Colombier
1088e32b400SDavid du Colombier static void
etherrtrace(Netfile * f,Etherpkt * pkt,int len)1098e32b400SDavid du Colombier etherrtrace(Netfile* f, Etherpkt* pkt, int len)
1108e32b400SDavid du Colombier {
1118e32b400SDavid du Colombier int i, n;
1128e32b400SDavid du Colombier Block *bp;
1138e32b400SDavid du Colombier
1148e32b400SDavid du Colombier if(qwindow(f->in) <= 0)
1158e32b400SDavid du Colombier return;
1168e32b400SDavid du Colombier if(len > 58)
1178e32b400SDavid du Colombier n = 58;
1188e32b400SDavid du Colombier else
1198e32b400SDavid du Colombier n = len;
1208e32b400SDavid du Colombier bp = iallocb(64);
1218e32b400SDavid du Colombier if(bp == nil)
1228e32b400SDavid du Colombier return;
1238e32b400SDavid du Colombier memmove(bp->wp, pkt->d, n);
1248e32b400SDavid du Colombier i = TK2MS(MACHP(0)->ticks);
1258e32b400SDavid du Colombier bp->wp[58] = len>>8;
1268e32b400SDavid du Colombier bp->wp[59] = len;
1278e32b400SDavid du Colombier bp->wp[60] = i>>24;
1288e32b400SDavid du Colombier bp->wp[61] = i>>16;
1298e32b400SDavid du Colombier bp->wp[62] = i>>8;
1308e32b400SDavid du Colombier bp->wp[63] = i;
1318e32b400SDavid du Colombier bp->wp += 64;
1328e32b400SDavid du Colombier qpass(f->in, bp);
1338e32b400SDavid du Colombier }
1348e32b400SDavid du Colombier
1358e32b400SDavid du Colombier Block*
etheriq(Ether * ether,Block * bp,int fromwire)1368e32b400SDavid du Colombier etheriq(Ether* ether, Block* bp, int fromwire)
1378e32b400SDavid du Colombier {
1388e32b400SDavid du Colombier Etherpkt *pkt;
1398e32b400SDavid du Colombier ushort type;
1408e32b400SDavid du Colombier int len, multi, tome, fromme;
1418e32b400SDavid du Colombier Netfile **ep, *f, **fp, *fx;
1428e32b400SDavid du Colombier Block *xbp;
1438e32b400SDavid du Colombier
1448e32b400SDavid du Colombier ether->inpackets++;
1458e32b400SDavid du Colombier
1468e32b400SDavid du Colombier pkt = (Etherpkt*)bp->rp;
1478e32b400SDavid du Colombier len = BLEN(bp);
1488e32b400SDavid du Colombier type = (pkt->type[0]<<8)|pkt->type[1];
1498e32b400SDavid du Colombier fx = 0;
1508e32b400SDavid du Colombier ep = ðer->f[Ntypes];
1518e32b400SDavid du Colombier
1528e32b400SDavid du Colombier multi = pkt->d[0] & 1;
1538e32b400SDavid du Colombier /* check for valid multicast addresses */
1548e32b400SDavid du Colombier if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 &&
1558e32b400SDavid du Colombier ether->prom == 0){
1568e32b400SDavid du Colombier if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
1578e32b400SDavid du Colombier if(fromwire){
1588e32b400SDavid du Colombier freeb(bp);
1598e32b400SDavid du Colombier bp = 0;
1608e32b400SDavid du Colombier }
1618e32b400SDavid du Colombier return bp;
1628e32b400SDavid du Colombier }
1638e32b400SDavid du Colombier }
1648e32b400SDavid du Colombier /* is it for me? */
1658e32b400SDavid du Colombier tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
1668e32b400SDavid du Colombier fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
1678e32b400SDavid du Colombier
1688e32b400SDavid du Colombier /*
1698e32b400SDavid du Colombier * Multiplex the packet to all the connections which want it.
1708e32b400SDavid du Colombier * If the packet is not to be used subsequently (fromwire != 0),
1718e32b400SDavid du Colombier * attempt to simply pass it into one of the connections, thereby
1728e32b400SDavid du Colombier * saving a copy of the data (usual case hopefully).
1738e32b400SDavid du Colombier */
1748e32b400SDavid du Colombier for(fp = ether->f; fp < ep; fp++){
1758e32b400SDavid du Colombier if((f = *fp) != nil && (f->type == type || f->type < 0) &&
1768e32b400SDavid du Colombier (tome || multi || f->prom)){
1778e32b400SDavid du Colombier /* Don't want to hear bridged packets */
1788e32b400SDavid du Colombier if(f->bridge && !fromwire && !fromme)
1798e32b400SDavid du Colombier continue;
1808e32b400SDavid du Colombier if(!f->headersonly){
1818e32b400SDavid du Colombier if(fromwire && fx == 0)
1828e32b400SDavid du Colombier fx = f;
1838e32b400SDavid du Colombier else if(xbp = iallocb(len)){
1848e32b400SDavid du Colombier memmove(xbp->wp, pkt, len);
1858e32b400SDavid du Colombier xbp->wp += len;
1868e32b400SDavid du Colombier if(qpass(f->in, xbp) < 0)
1878e32b400SDavid du Colombier ether->soverflows++;
1888e32b400SDavid du Colombier }
1898e32b400SDavid du Colombier else
1908e32b400SDavid du Colombier ether->soverflows++;
1918e32b400SDavid du Colombier }
1928e32b400SDavid du Colombier else
1938e32b400SDavid du Colombier etherrtrace(f, pkt, len);
1948e32b400SDavid du Colombier }
1958e32b400SDavid du Colombier }
1968e32b400SDavid du Colombier
1978e32b400SDavid du Colombier if(fx){
1988e32b400SDavid du Colombier if(qpass(fx->in, bp) < 0)
1998e32b400SDavid du Colombier ether->soverflows++;
2008e32b400SDavid du Colombier return 0;
2018e32b400SDavid du Colombier }
2028e32b400SDavid du Colombier if(fromwire){
2038e32b400SDavid du Colombier freeb(bp);
2048e32b400SDavid du Colombier return 0;
2058e32b400SDavid du Colombier }
2068e32b400SDavid du Colombier return bp;
2078e32b400SDavid du Colombier }
2088e32b400SDavid du Colombier
2098e32b400SDavid du Colombier static int
etheroq(Ether * ether,Block * bp)2108e32b400SDavid du Colombier etheroq(Ether* ether, Block* bp)
2118e32b400SDavid du Colombier {
2128e32b400SDavid du Colombier int len, loopback, s;
2138e32b400SDavid du Colombier Etherpkt *pkt;
2148e32b400SDavid du Colombier
2158e32b400SDavid du Colombier ether->outpackets++;
2168e32b400SDavid du Colombier
2178e32b400SDavid du Colombier /*
2188e32b400SDavid du Colombier * Check if the packet has to be placed back onto the input queue,
2198e32b400SDavid du Colombier * i.e. if it's a loopback or broadcast packet or the interface is
2208e32b400SDavid du Colombier * in promiscuous mode.
2218e32b400SDavid du Colombier * If it's a loopback packet indicate to etheriq that the data isn't
2228e32b400SDavid du Colombier * needed and return, etheriq will pass-on or free the block.
2238e32b400SDavid du Colombier * To enable bridging to work, only packets that were originated
2248e32b400SDavid du Colombier * by this interface are fed back.
2258e32b400SDavid du Colombier */
2268e32b400SDavid du Colombier pkt = (Etherpkt*)bp->rp;
2278e32b400SDavid du Colombier len = BLEN(bp);
2288e32b400SDavid du Colombier loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
2298e32b400SDavid du Colombier if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
2308e32b400SDavid du Colombier s = splhi();
2318e32b400SDavid du Colombier etheriq(ether, bp, 0);
2328e32b400SDavid du Colombier splx(s);
2338e32b400SDavid du Colombier }
2348e32b400SDavid du Colombier
2358e32b400SDavid du Colombier if(!loopback){
2368e32b400SDavid du Colombier qbwrite(ether->oq, bp);
2378e32b400SDavid du Colombier if(ether->transmit != nil)
2388e32b400SDavid du Colombier ether->transmit(ether);
2398e32b400SDavid du Colombier } else
2408e32b400SDavid du Colombier freeb(bp);
2418e32b400SDavid du Colombier
2428e32b400SDavid du Colombier return len;
2438e32b400SDavid du Colombier }
2448e32b400SDavid du Colombier
2458e32b400SDavid du Colombier static long
etherwrite(Chan * chan,void * buf,long n,vlong)2468e32b400SDavid du Colombier etherwrite(Chan* chan, void* buf, long n, vlong)
2478e32b400SDavid du Colombier {
2488e32b400SDavid du Colombier Ether *ether;
2498e32b400SDavid du Colombier Block *bp;
2508e32b400SDavid du Colombier int nn, onoff;
2518e32b400SDavid du Colombier Cmdbuf *cb;
2528e32b400SDavid du Colombier
2538e32b400SDavid du Colombier ether = etherxx[chan->dev];
2548e32b400SDavid du Colombier if(NETTYPE(chan->qid.path) != Ndataqid) {
2558e32b400SDavid du Colombier nn = netifwrite(ether, chan, buf, n);
2568e32b400SDavid du Colombier if(nn >= 0)
2578e32b400SDavid du Colombier return nn;
2588e32b400SDavid du Colombier cb = parsecmd(buf, n);
2598e32b400SDavid du Colombier if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
2608e32b400SDavid du Colombier if(cb->nf <= 1)
2618e32b400SDavid du Colombier onoff = 1;
2628e32b400SDavid du Colombier else
2638e32b400SDavid du Colombier onoff = atoi(cb->f[1]);
2648e32b400SDavid du Colombier qnoblock(ether->oq, onoff);
2658e32b400SDavid du Colombier free(cb);
2668e32b400SDavid du Colombier return n;
2678e32b400SDavid du Colombier }
2688e32b400SDavid du Colombier free(cb);
2698e32b400SDavid du Colombier if(ether->ctl!=nil)
2708e32b400SDavid du Colombier return ether->ctl(ether,buf,n);
2718e32b400SDavid du Colombier
2728e32b400SDavid du Colombier error(Ebadctl);
2738e32b400SDavid du Colombier }
2748e32b400SDavid du Colombier
2758e32b400SDavid du Colombier if(n > ether->maxmtu)
2768e32b400SDavid du Colombier error(Etoobig);
2778e32b400SDavid du Colombier if(n < ether->minmtu)
2788e32b400SDavid du Colombier error(Etoosmall);
2798e32b400SDavid du Colombier
2808e32b400SDavid du Colombier bp = allocb(n);
2818e32b400SDavid du Colombier if(waserror()){
2828e32b400SDavid du Colombier freeb(bp);
2838e32b400SDavid du Colombier nexterror();
2848e32b400SDavid du Colombier }
2858e32b400SDavid du Colombier memmove(bp->rp, buf, n);
2868e32b400SDavid du Colombier memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
2878e32b400SDavid du Colombier poperror();
2888e32b400SDavid du Colombier bp->wp += n;
2898e32b400SDavid du Colombier
2908e32b400SDavid du Colombier return etheroq(ether, bp);
2918e32b400SDavid du Colombier }
2928e32b400SDavid du Colombier
2938e32b400SDavid du Colombier static long
etherbwrite(Chan * chan,Block * bp,ulong)2948e32b400SDavid du Colombier etherbwrite(Chan* chan, Block* bp, ulong)
2958e32b400SDavid du Colombier {
2968e32b400SDavid du Colombier Ether *ether;
2978e32b400SDavid du Colombier long n;
2988e32b400SDavid du Colombier
2998e32b400SDavid du Colombier n = BLEN(bp);
3008e32b400SDavid du Colombier if(NETTYPE(chan->qid.path) != Ndataqid){
3018e32b400SDavid du Colombier if(waserror()) {
3028e32b400SDavid du Colombier freeb(bp);
3038e32b400SDavid du Colombier nexterror();
3048e32b400SDavid du Colombier }
3058e32b400SDavid du Colombier n = etherwrite(chan, bp->rp, n, 0);
3068e32b400SDavid du Colombier poperror();
3078e32b400SDavid du Colombier freeb(bp);
3088e32b400SDavid du Colombier return n;
3098e32b400SDavid du Colombier }
3108e32b400SDavid du Colombier ether = etherxx[chan->dev];
3118e32b400SDavid du Colombier
3128e32b400SDavid du Colombier if(n > ether->maxmtu){
3138e32b400SDavid du Colombier freeb(bp);
3148e32b400SDavid du Colombier error(Etoobig);
3158e32b400SDavid du Colombier }
3168e32b400SDavid du Colombier if(n < ether->minmtu){
3178e32b400SDavid du Colombier freeb(bp);
3188e32b400SDavid du Colombier error(Etoosmall);
3198e32b400SDavid du Colombier }
3208e32b400SDavid du Colombier
3218e32b400SDavid du Colombier return etheroq(ether, bp);
3228e32b400SDavid du Colombier }
3238e32b400SDavid du Colombier
3248e32b400SDavid du Colombier static struct {
3258e32b400SDavid du Colombier char* type;
3268e32b400SDavid du Colombier int (*reset)(Ether*);
3278e32b400SDavid du Colombier } cards[MaxEther+1];
3288e32b400SDavid du Colombier
3298e32b400SDavid du Colombier void
addethercard(char * t,int (* r)(Ether *))3308e32b400SDavid du Colombier addethercard(char* t, int (*r)(Ether*))
3318e32b400SDavid du Colombier {
3328e32b400SDavid du Colombier static int ncard;
3338e32b400SDavid du Colombier
3348e32b400SDavid du Colombier if(ncard == MaxEther)
3358e32b400SDavid du Colombier panic("too many ether cards");
3368e32b400SDavid du Colombier cards[ncard].type = t;
3378e32b400SDavid du Colombier cards[ncard].reset = r;
3388e32b400SDavid du Colombier ncard++;
3398e32b400SDavid du Colombier }
3408e32b400SDavid du Colombier
3418e32b400SDavid du Colombier int
parseether(uchar * to,char * from)3428e32b400SDavid du Colombier parseether(uchar *to, char *from)
3438e32b400SDavid du Colombier {
3448e32b400SDavid du Colombier char nip[4];
3458e32b400SDavid du Colombier char *p;
3468e32b400SDavid du Colombier int i;
3478e32b400SDavid du Colombier
3488e32b400SDavid du Colombier p = from;
3498e32b400SDavid du Colombier for(i = 0; i < Eaddrlen; i++){
3508e32b400SDavid du Colombier if(*p == 0)
3518e32b400SDavid du Colombier return -1;
3528e32b400SDavid du Colombier nip[0] = *p++;
3538e32b400SDavid du Colombier if(*p == 0)
3548e32b400SDavid du Colombier return -1;
3558e32b400SDavid du Colombier nip[1] = *p++;
3568e32b400SDavid du Colombier nip[2] = 0;
3578e32b400SDavid du Colombier to[i] = strtoul(nip, 0, 16);
3588e32b400SDavid du Colombier if(*p == ':')
3598e32b400SDavid du Colombier p++;
3608e32b400SDavid du Colombier }
3618e32b400SDavid du Colombier return 0;
3628e32b400SDavid du Colombier }
3638e32b400SDavid du Colombier
3648e32b400SDavid du Colombier static void
etherreset(void)3658e32b400SDavid du Colombier etherreset(void)
3668e32b400SDavid du Colombier {
3678e32b400SDavid du Colombier Ether *ether;
3688e32b400SDavid du Colombier int i, n, ctlrno;
3698e32b400SDavid du Colombier char name[KNAMELEN], buf[128];
3708e32b400SDavid du Colombier
3718e32b400SDavid du Colombier for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
3728e32b400SDavid du Colombier if(ether == 0)
3738e32b400SDavid du Colombier ether = malloc(sizeof(Ether));
3748e32b400SDavid du Colombier memset(ether, 0, sizeof(Ether));
3758e32b400SDavid du Colombier ether->ctlrno = ctlrno;
3768e32b400SDavid du Colombier ether->mbps = 10;
3778e32b400SDavid du Colombier ether->minmtu = ETHERMINTU;
3788e32b400SDavid du Colombier ether->maxmtu = ETHERMAXTU;
3798e32b400SDavid du Colombier
3808e32b400SDavid du Colombier if(archether(ctlrno, ether) <= 0)
3818e32b400SDavid du Colombier continue;
3828e32b400SDavid du Colombier
3838e32b400SDavid du Colombier if(isaconfig("ether", ctlrno, ether) == 0){
384*a1216cc6SDavid du Colombier // free(ether);
3858e32b400SDavid du Colombier // return nil;
3868e32b400SDavid du Colombier continue;
3878e32b400SDavid du Colombier }
3888e32b400SDavid du Colombier for(n = 0; cards[n].type; n++){
3898e32b400SDavid du Colombier if(cistrcmp(cards[n].type, ether->type))
3908e32b400SDavid du Colombier continue;
3918e32b400SDavid du Colombier for(i = 0; i < ether->nopt; i++)
3928e32b400SDavid du Colombier if(cistrncmp(ether->opt[i], "ea=", 3) == 0){
3938e32b400SDavid du Colombier if(parseether(ether->ea,
3948e32b400SDavid du Colombier ðer->opt[i][3]) == -1)
3958e32b400SDavid du Colombier memset(ether->ea, 0, Eaddrlen);
3968e32b400SDavid du Colombier } else if(cistrcmp(ether->opt[i],
3978e32b400SDavid du Colombier "100BASE-TXFD") == 0)
3988e32b400SDavid du Colombier ether->mbps = 100;
3998e32b400SDavid du Colombier if(cards[n].reset(ether))
4008e32b400SDavid du Colombier break;
4018e32b400SDavid du Colombier snprint(name, sizeof(name), "ether%d", ctlrno);
4028e32b400SDavid du Colombier
4038e32b400SDavid du Colombier if(ether->interrupt != nil && ether->irq >= 0)
4048e32b400SDavid du Colombier intrenable(ether->irq, ether->interrupt,
4058e32b400SDavid du Colombier ether, 0, name);
4068e32b400SDavid du Colombier
4078e32b400SDavid du Colombier i = snprint(buf, sizeof buf,
4088e32b400SDavid du Colombier "#l%d: %s: %dMbps port %#lux irq %d",
4098e32b400SDavid du Colombier ctlrno, ether->type, ether->mbps, ether->port,
4108e32b400SDavid du Colombier ether->irq);
4118e32b400SDavid du Colombier if(ether->mem)
4128e32b400SDavid du Colombier i += snprint(buf+i, sizeof buf - i,
4138e32b400SDavid du Colombier " addr %#lux", PADDR(ether->mem));
4148e32b400SDavid du Colombier if(ether->size)
4158e32b400SDavid du Colombier i += snprint(buf+i, sizeof buf - i,
416fe25a076SDavid du Colombier " size %#luX", ether->size);
4178e32b400SDavid du Colombier i += snprint(buf+i, sizeof buf - i,
4188e32b400SDavid du Colombier ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
4198e32b400SDavid du Colombier ether->ea[0], ether->ea[1], ether->ea[2],
4208e32b400SDavid du Colombier ether->ea[3], ether->ea[4], ether->ea[5]);
4218e32b400SDavid du Colombier snprint(buf+i, sizeof buf - i, "\n");
4228e32b400SDavid du Colombier iprint("%s", buf); /* it may be too early for print */
4238e32b400SDavid du Colombier
4248e32b400SDavid du Colombier if(ether->mbps >= 1000)
4258e32b400SDavid du Colombier netifinit(ether, name, Ntypes, 4*1024*1024);
4268e32b400SDavid du Colombier else if(ether->mbps >= 100)
4278e32b400SDavid du Colombier netifinit(ether, name, Ntypes, 1024*1024);
4288e32b400SDavid du Colombier else
4298e32b400SDavid du Colombier netifinit(ether, name, Ntypes, 65*1024);
4308e32b400SDavid du Colombier if(ether->oq == 0)
4318e32b400SDavid du Colombier ether->oq = qopen(ether->limit, Qmsg, 0, 0);
4328e32b400SDavid du Colombier if(ether->oq == 0)
4338e32b400SDavid du Colombier panic("etherreset %s", name);
4348e32b400SDavid du Colombier ether->alen = Eaddrlen;
4358e32b400SDavid du Colombier memmove(ether->addr, ether->ea, Eaddrlen);
4368e32b400SDavid du Colombier memset(ether->bcast, 0xFF, Eaddrlen);
4378e32b400SDavid du Colombier
4388e32b400SDavid du Colombier etherxx[ctlrno] = ether;
4398e32b400SDavid du Colombier ether = 0;
4408e32b400SDavid du Colombier break;
4418e32b400SDavid du Colombier }
4428e32b400SDavid du Colombier }
4438e32b400SDavid du Colombier if(ether)
4448e32b400SDavid du Colombier free(ether);
4458e32b400SDavid du Colombier }
4468e32b400SDavid du Colombier
4478e32b400SDavid du Colombier static void
ethershutdown(void)4488e32b400SDavid du Colombier ethershutdown(void)
4498e32b400SDavid du Colombier {
4508e32b400SDavid du Colombier Ether *ether;
4518e32b400SDavid du Colombier int i;
4528e32b400SDavid du Colombier
4538e32b400SDavid du Colombier for(i = 0; i < MaxEther; i++){
4548e32b400SDavid du Colombier ether = etherxx[i];
4558e32b400SDavid du Colombier if(ether == nil)
4568e32b400SDavid du Colombier continue;
4578e32b400SDavid du Colombier if(ether->shutdown == nil) {
4588e32b400SDavid du Colombier print("#l%d: no shutdown function\n", i);
4598e32b400SDavid du Colombier continue;
4608e32b400SDavid du Colombier }
4618e32b400SDavid du Colombier (*ether->shutdown)(ether);
4628e32b400SDavid du Colombier }
4638e32b400SDavid du Colombier }
4648e32b400SDavid du Colombier
4658e32b400SDavid du Colombier
4668e32b400SDavid du Colombier #define POLY 0xedb88320
4678e32b400SDavid du Colombier
4688e32b400SDavid du Colombier /* really slow 32 bit crc for ethers */
4698e32b400SDavid du Colombier ulong
ethercrc(uchar * p,int len)4708e32b400SDavid du Colombier ethercrc(uchar *p, int len)
4718e32b400SDavid du Colombier {
4728e32b400SDavid du Colombier int i, j;
4738e32b400SDavid du Colombier ulong crc, b;
4748e32b400SDavid du Colombier
4758e32b400SDavid du Colombier crc = 0xffffffff;
4768e32b400SDavid du Colombier for(i = 0; i < len; i++){
4778e32b400SDavid du Colombier b = *p++;
4788e32b400SDavid du Colombier for(j = 0; j < 8; j++){
4798e32b400SDavid du Colombier crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
4808e32b400SDavid du Colombier b >>= 1;
4818e32b400SDavid du Colombier }
4828e32b400SDavid du Colombier }
4838e32b400SDavid du Colombier return crc;
4848e32b400SDavid du Colombier }
4858e32b400SDavid du Colombier
4868e32b400SDavid du Colombier void
dumpoq(Queue * oq)4878e32b400SDavid du Colombier dumpoq(Queue *oq)
4888e32b400SDavid du Colombier {
4898e32b400SDavid du Colombier if (oq == nil)
4908e32b400SDavid du Colombier print("no outq! ");
4918e32b400SDavid du Colombier else if (qisclosed(oq))
4928e32b400SDavid du Colombier print("outq closed ");
4938e32b400SDavid du Colombier else if (qfull(oq))
4948e32b400SDavid du Colombier print("outq full ");
4958e32b400SDavid du Colombier else
4968e32b400SDavid du Colombier print("outq %d ", qlen(oq));
4978e32b400SDavid du Colombier }
4988e32b400SDavid du Colombier
4998e32b400SDavid du Colombier void
dumpnetif(Netif * netif)5008e32b400SDavid du Colombier dumpnetif(Netif *netif)
5018e32b400SDavid du Colombier {
5028e32b400SDavid du Colombier print("netif %s ", netif->name);
5038e32b400SDavid du Colombier print("limit %d mbps %d link %d ",
5048e32b400SDavid du Colombier netif->limit, netif->mbps, netif->link);
5058e32b400SDavid du Colombier print("inpkts %lld outpkts %lld errs %d\n",
5068e32b400SDavid du Colombier netif->inpackets, netif->outpackets,
5078e32b400SDavid du Colombier netif->crcs + netif->oerrs + netif->frames + netif->overflows +
5088e32b400SDavid du Colombier netif->buffs + netif->soverflows);
5098e32b400SDavid du Colombier }
5108e32b400SDavid du Colombier
5118e32b400SDavid du Colombier Dev etherdevtab = {
5128e32b400SDavid du Colombier 'l',
5138e32b400SDavid du Colombier "ether",
5148e32b400SDavid du Colombier
5158e32b400SDavid du Colombier etherreset,
5168e32b400SDavid du Colombier devinit,
5178e32b400SDavid du Colombier ethershutdown,
5188e32b400SDavid du Colombier etherattach,
5198e32b400SDavid du Colombier etherwalk,
5208e32b400SDavid du Colombier etherstat,
5218e32b400SDavid du Colombier etheropen,
5228e32b400SDavid du Colombier ethercreate,
5238e32b400SDavid du Colombier etherclose,
5248e32b400SDavid du Colombier etherread,
5258e32b400SDavid du Colombier etherbread,
5268e32b400SDavid du Colombier etherwrite,
5278e32b400SDavid du Colombier etherbwrite,
5288e32b400SDavid du Colombier devremove,
5298e32b400SDavid du Colombier etherwstat,
5308e32b400SDavid du Colombier };
531