13e12c5d1SDavid du Colombier #include "u.h"
23e12c5d1SDavid du Colombier #include "../port/lib.h"
33e12c5d1SDavid du Colombier #include "mem.h"
43e12c5d1SDavid du Colombier #include "dat.h"
53e12c5d1SDavid du Colombier #include "fns.h"
63e12c5d1SDavid du Colombier #include "io.h"
787dfdc75SDavid du Colombier #include "pool.h"
87dd7cddfSDavid du Colombier #include "ureg.h"
97dd7cddfSDavid du Colombier #include "../port/error.h"
107dd7cddfSDavid du Colombier #include "../port/netif.h"
113e12c5d1SDavid du Colombier
127dd7cddfSDavid du Colombier #include "etherif.h"
133e12c5d1SDavid du Colombier
147dd7cddfSDavid du Colombier static Ether *etherxx[MaxEther];
153e12c5d1SDavid du Colombier
163e12c5d1SDavid du Colombier Chan*
etherattach(char * spec)177dd7cddfSDavid du Colombier etherattach(char* spec)
183e12c5d1SDavid du Colombier {
197dd7cddfSDavid du Colombier ulong ctlrno;
207dd7cddfSDavid du Colombier char *p;
217dd7cddfSDavid du Colombier Chan *chan;
223e12c5d1SDavid du Colombier
237dd7cddfSDavid du Colombier ctlrno = 0;
247dd7cddfSDavid du Colombier if(spec && *spec){
257dd7cddfSDavid du Colombier ctlrno = strtoul(spec, &p, 0);
267dd7cddfSDavid du Colombier if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther))
277dd7cddfSDavid du Colombier error(Ebadarg);
283e12c5d1SDavid du Colombier }
297dd7cddfSDavid du Colombier if(etherxx[ctlrno] == 0)
307dd7cddfSDavid du Colombier error(Enodev);
313e12c5d1SDavid du Colombier
327dd7cddfSDavid du Colombier chan = devattach('l', spec);
33830cad64SDavid du Colombier if(waserror()){
34830cad64SDavid du Colombier chanfree(chan);
35830cad64SDavid du Colombier nexterror();
36830cad64SDavid du Colombier }
377dd7cddfSDavid du Colombier chan->dev = ctlrno;
387dd7cddfSDavid du Colombier if(etherxx[ctlrno]->attach)
397dd7cddfSDavid du Colombier etherxx[ctlrno]->attach(etherxx[ctlrno]);
40830cad64SDavid du Colombier poperror();
417dd7cddfSDavid du Colombier return chan;
423e12c5d1SDavid du Colombier }
433e12c5d1SDavid du Colombier
449a747e4fSDavid du Colombier static Walkqid*
etherwalk(Chan * chan,Chan * nchan,char ** name,int nname)459a747e4fSDavid du Colombier etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
463e12c5d1SDavid du Colombier {
479a747e4fSDavid du Colombier return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
483e12c5d1SDavid du Colombier }
493e12c5d1SDavid du Colombier
509a747e4fSDavid du Colombier static int
etherstat(Chan * chan,uchar * dp,int n)519a747e4fSDavid du Colombier etherstat(Chan* chan, uchar* dp, int n)
523e12c5d1SDavid du Colombier {
539a747e4fSDavid du Colombier return netifstat(etherxx[chan->dev], chan, dp, n);
547dd7cddfSDavid du Colombier }
557dd7cddfSDavid du Colombier
567dd7cddfSDavid du Colombier static Chan*
etheropen(Chan * chan,int omode)577dd7cddfSDavid du Colombier etheropen(Chan* chan, int omode)
587dd7cddfSDavid du Colombier {
597dd7cddfSDavid du Colombier return netifopen(etherxx[chan->dev], chan, omode);
607dd7cddfSDavid du Colombier }
617dd7cddfSDavid du Colombier
627dd7cddfSDavid du Colombier static void
ethercreate(Chan *,char *,int,ulong)637dd7cddfSDavid du Colombier ethercreate(Chan*, char*, int, ulong)
647dd7cddfSDavid du Colombier {
657dd7cddfSDavid du Colombier }
667dd7cddfSDavid du Colombier
677dd7cddfSDavid du Colombier static void
etherclose(Chan * chan)687dd7cddfSDavid du Colombier etherclose(Chan* chan)
697dd7cddfSDavid du Colombier {
707dd7cddfSDavid du Colombier netifclose(etherxx[chan->dev], chan);
717dd7cddfSDavid du Colombier }
727dd7cddfSDavid du Colombier
737dd7cddfSDavid du Colombier static long
etherread(Chan * chan,void * buf,long n,vlong off)747dd7cddfSDavid du Colombier etherread(Chan* chan, void* buf, long n, vlong off)
757dd7cddfSDavid du Colombier {
767dd7cddfSDavid du Colombier Ether *ether;
777dd7cddfSDavid du Colombier ulong offset = off;
787dd7cddfSDavid du Colombier
797dd7cddfSDavid du Colombier ether = etherxx[chan->dev];
809a747e4fSDavid du Colombier if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
817dd7cddfSDavid du Colombier /*
827dd7cddfSDavid du Colombier * With some controllers it is necessary to reach
837dd7cddfSDavid du Colombier * into the chip to extract statistics.
847dd7cddfSDavid du Colombier */
857dd7cddfSDavid du Colombier if(NETTYPE(chan->qid.path) == Nifstatqid)
867dd7cddfSDavid du Colombier return ether->ifstat(ether, buf, n, offset);
877dd7cddfSDavid du Colombier else if(NETTYPE(chan->qid.path) == Nstatqid)
887dd7cddfSDavid du Colombier ether->ifstat(ether, buf, 0, offset);
897dd7cddfSDavid du Colombier }
907dd7cddfSDavid du Colombier
917dd7cddfSDavid du Colombier return netifread(ether, chan, buf, n, offset);
927dd7cddfSDavid du Colombier }
937dd7cddfSDavid du Colombier
947dd7cddfSDavid du Colombier static Block*
etherbread(Chan * chan,long n,ulong offset)957dd7cddfSDavid du Colombier etherbread(Chan* chan, long n, ulong offset)
967dd7cddfSDavid du Colombier {
977dd7cddfSDavid du Colombier return netifbread(etherxx[chan->dev], chan, n, offset);
987dd7cddfSDavid du Colombier }
997dd7cddfSDavid du Colombier
1009a747e4fSDavid du Colombier static int
etherwstat(Chan * chan,uchar * dp,int n)1019a747e4fSDavid du Colombier etherwstat(Chan* chan, uchar* dp, int n)
1027dd7cddfSDavid du Colombier {
1039a747e4fSDavid du Colombier return netifwstat(etherxx[chan->dev], chan, dp, n);
1047dd7cddfSDavid du Colombier }
1057dd7cddfSDavid du Colombier
1067dd7cddfSDavid du Colombier static void
etherrtrace(Netfile * f,Etherpkt * pkt,int len)1077dd7cddfSDavid du Colombier etherrtrace(Netfile* f, Etherpkt* pkt, int len)
1087dd7cddfSDavid du Colombier {
1099a747e4fSDavid du Colombier int i, n;
1107dd7cddfSDavid du Colombier Block *bp;
1117dd7cddfSDavid du Colombier
1127dd7cddfSDavid du Colombier if(qwindow(f->in) <= 0)
1137dd7cddfSDavid du Colombier return;
11459cc4ca5SDavid du Colombier if(len > 58)
11559cc4ca5SDavid du Colombier n = 58;
1167dd7cddfSDavid du Colombier else
1177dd7cddfSDavid du Colombier n = len;
1189a747e4fSDavid du Colombier bp = iallocb(64);
11959cc4ca5SDavid du Colombier if(bp == nil)
1207dd7cddfSDavid du Colombier return;
1217dd7cddfSDavid du Colombier memmove(bp->wp, pkt->d, n);
1229a747e4fSDavid du Colombier i = TK2MS(MACHP(0)->ticks);
1237dd7cddfSDavid du Colombier bp->wp[58] = len>>8;
1247dd7cddfSDavid du Colombier bp->wp[59] = len;
1259a747e4fSDavid du Colombier bp->wp[60] = i>>24;
1269a747e4fSDavid du Colombier bp->wp[61] = i>>16;
1279a747e4fSDavid du Colombier bp->wp[62] = i>>8;
1289a747e4fSDavid du Colombier bp->wp[63] = i;
1299a747e4fSDavid du Colombier bp->wp += 64;
1307dd7cddfSDavid du Colombier qpass(f->in, bp);
1317dd7cddfSDavid du Colombier }
1327dd7cddfSDavid du Colombier
1337dd7cddfSDavid du Colombier Block*
etheriq(Ether * ether,Block * bp,int fromwire)1347dd7cddfSDavid du Colombier etheriq(Ether* ether, Block* bp, int fromwire)
1357dd7cddfSDavid du Colombier {
136bd389b36SDavid du Colombier Etherpkt *pkt;
1377dd7cddfSDavid du Colombier ushort type;
1387dd7cddfSDavid du Colombier int len, multi, tome, fromme;
1397dd7cddfSDavid du Colombier Netfile **ep, *f, **fp, *fx;
1407dd7cddfSDavid du Colombier Block *xbp;
1413e12c5d1SDavid du Colombier
1427dd7cddfSDavid du Colombier ether->inpackets++;
1437dd7cddfSDavid du Colombier
1447dd7cddfSDavid du Colombier pkt = (Etherpkt*)bp->rp;
1457dd7cddfSDavid du Colombier len = BLEN(bp);
1467dd7cddfSDavid du Colombier type = (pkt->type[0]<<8)|pkt->type[1];
1477dd7cddfSDavid du Colombier fx = 0;
1487dd7cddfSDavid du Colombier ep = ðer->f[Ntypes];
1497dd7cddfSDavid du Colombier
1507dd7cddfSDavid du Colombier multi = pkt->d[0] & 1;
151d95be1c0SDavid du Colombier /* check for valid multicast addresses */
15208fd2d13SDavid du Colombier if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 && ether->prom == 0){
1537dd7cddfSDavid du Colombier if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
1547dd7cddfSDavid du Colombier if(fromwire){
1553e12c5d1SDavid du Colombier freeb(bp);
1567dd7cddfSDavid du Colombier bp = 0;
1573e12c5d1SDavid du Colombier }
1587dd7cddfSDavid du Colombier return bp;
1593e12c5d1SDavid du Colombier }
1603e12c5d1SDavid du Colombier }
1613e12c5d1SDavid du Colombier
1627dd7cddfSDavid du Colombier /* is it for me? */
1637dd7cddfSDavid du Colombier tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
1647dd7cddfSDavid du Colombier fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
1657dd7cddfSDavid du Colombier
1663e12c5d1SDavid du Colombier /*
1677dd7cddfSDavid du Colombier * Multiplex the packet to all the connections which want it.
1687dd7cddfSDavid du Colombier * If the packet is not to be used subsequently (fromwire != 0),
1697dd7cddfSDavid du Colombier * attempt to simply pass it into one of the connections, thereby
1707dd7cddfSDavid du Colombier * saving a copy of the data (usual case hopefully).
1713e12c5d1SDavid du Colombier */
1727dd7cddfSDavid du Colombier for(fp = ether->f; fp < ep; fp++){
1737dd7cddfSDavid du Colombier if(f = *fp)
1747dd7cddfSDavid du Colombier if(f->type == type || f->type < 0)
1757dd7cddfSDavid du Colombier if(tome || multi || f->prom){
1767dd7cddfSDavid du Colombier /* Don't want to hear bridged packets */
1777dd7cddfSDavid du Colombier if(f->bridge && !fromwire && !fromme)
1787dd7cddfSDavid du Colombier continue;
1797dd7cddfSDavid du Colombier if(!f->headersonly){
1807dd7cddfSDavid du Colombier if(fromwire && fx == 0)
1817dd7cddfSDavid du Colombier fx = f;
1827dd7cddfSDavid du Colombier else if(xbp = iallocb(len)){
1837dd7cddfSDavid du Colombier memmove(xbp->wp, pkt, len);
1847dd7cddfSDavid du Colombier xbp->wp += len;
185aa26ca9fSDavid du Colombier if(qpass(f->in, xbp) < 0){
18608cb2eb6SDavid du Colombier // print("soverflow for f->in\n");
1879a747e4fSDavid du Colombier ether->soverflows++;
1887dd7cddfSDavid du Colombier }
189aa26ca9fSDavid du Colombier }
190aa26ca9fSDavid du Colombier else{
19108cb2eb6SDavid du Colombier // print("soverflow iallocb\n");
1927dd7cddfSDavid du Colombier ether->soverflows++;
1937dd7cddfSDavid du Colombier }
194aa26ca9fSDavid du Colombier }
1957dd7cddfSDavid du Colombier else
1967dd7cddfSDavid du Colombier etherrtrace(f, pkt, len);
1977dd7cddfSDavid du Colombier }
1987dd7cddfSDavid du Colombier }
1997dd7cddfSDavid du Colombier
2007dd7cddfSDavid du Colombier if(fx){
201aa26ca9fSDavid du Colombier if(qpass(fx->in, bp) < 0){
20208cb2eb6SDavid du Colombier // print("soverflow for fx->in\n");
2037dd7cddfSDavid du Colombier ether->soverflows++;
204aa26ca9fSDavid du Colombier }
2057dd7cddfSDavid du Colombier return 0;
2067dd7cddfSDavid du Colombier }
2077dd7cddfSDavid du Colombier if(fromwire){
208219b2ee8SDavid du Colombier freeb(bp);
2097dd7cddfSDavid du Colombier return 0;
2103e12c5d1SDavid du Colombier }
2113e12c5d1SDavid du Colombier
2127dd7cddfSDavid du Colombier return bp;
2137dd7cddfSDavid du Colombier }
2147dd7cddfSDavid du Colombier
2157dd7cddfSDavid du Colombier static int
etheroq(Ether * ether,Block * bp)2167dd7cddfSDavid du Colombier etheroq(Ether* ether, Block* bp)
2177dd7cddfSDavid du Colombier {
2187dd7cddfSDavid du Colombier int len, loopback, s;
2197dd7cddfSDavid du Colombier Etherpkt *pkt;
2207dd7cddfSDavid du Colombier
2217dd7cddfSDavid du Colombier ether->outpackets++;
2227dd7cddfSDavid du Colombier
2233e12c5d1SDavid du Colombier /*
2247dd7cddfSDavid du Colombier * Check if the packet has to be placed back onto the input queue,
2257dd7cddfSDavid du Colombier * i.e. if it's a loopback or broadcast packet or the interface is
2267dd7cddfSDavid du Colombier * in promiscuous mode.
2277dd7cddfSDavid du Colombier * If it's a loopback packet indicate to etheriq that the data isn't
2287dd7cddfSDavid du Colombier * needed and return, etheriq will pass-on or free the block.
2297dd7cddfSDavid du Colombier * To enable bridging to work, only packets that were originated
2307dd7cddfSDavid du Colombier * by this interface are fed back.
2313e12c5d1SDavid du Colombier */
2327dd7cddfSDavid du Colombier pkt = (Etherpkt*)bp->rp;
2337dd7cddfSDavid du Colombier len = BLEN(bp);
2347dd7cddfSDavid du Colombier loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
2357dd7cddfSDavid du Colombier if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
236219b2ee8SDavid du Colombier s = splhi();
2377dd7cddfSDavid du Colombier etheriq(ether, bp, 0);
238219b2ee8SDavid du Colombier splx(s);
2397dd7cddfSDavid du Colombier }
2403e12c5d1SDavid du Colombier
2417dd7cddfSDavid du Colombier if(!loopback){
242aa26ca9fSDavid du Colombier if(qfull(ether->oq))
243aa26ca9fSDavid du Colombier print("etheroq: WARNING: ether->oq full!\n");
2447dd7cddfSDavid du Colombier qbwrite(ether->oq, bp);
2455e96a66cSDavid du Colombier if(ether->transmit != nil)
2467dd7cddfSDavid du Colombier ether->transmit(ether);
2477dd7cddfSDavid du Colombier } else
248219b2ee8SDavid du Colombier freeb(bp);
2497dd7cddfSDavid du Colombier
2507dd7cddfSDavid du Colombier return len;
2513e12c5d1SDavid du Colombier }
2523e12c5d1SDavid du Colombier
2537dd7cddfSDavid du Colombier static long
etherwrite(Chan * chan,void * buf,long n,vlong)2547dd7cddfSDavid du Colombier etherwrite(Chan* chan, void* buf, long n, vlong)
2553e12c5d1SDavid du Colombier {
2567dd7cddfSDavid du Colombier Ether *ether;
2573e12c5d1SDavid du Colombier Block *bp;
258fb7f0c93SDavid du Colombier int nn, onoff;
259fb7f0c93SDavid du Colombier Cmdbuf *cb;
2603e12c5d1SDavid du Colombier
2617dd7cddfSDavid du Colombier ether = etherxx[chan->dev];
26259cc4ca5SDavid du Colombier if(NETTYPE(chan->qid.path) != Ndataqid) {
26359cc4ca5SDavid du Colombier nn = netifwrite(ether, chan, buf, n);
26459cc4ca5SDavid du Colombier if(nn >= 0)
26559cc4ca5SDavid du Colombier return nn;
266fb7f0c93SDavid du Colombier cb = parsecmd(buf, n);
267830cad64SDavid du Colombier if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
268fb7f0c93SDavid du Colombier if(cb->nf <= 1)
269fb7f0c93SDavid du Colombier onoff = 1;
270fb7f0c93SDavid du Colombier else
271fb7f0c93SDavid du Colombier onoff = atoi(cb->f[1]);
272fb7f0c93SDavid du Colombier qnoblock(ether->oq, onoff);
273fb7f0c93SDavid du Colombier free(cb);
2743ff48bf5SDavid du Colombier return n;
2753ff48bf5SDavid du Colombier }
276fb7f0c93SDavid du Colombier free(cb);
27759cc4ca5SDavid du Colombier if(ether->ctl != nil)
27859cc4ca5SDavid du Colombier return ether->ctl(ether, buf, n);
27959cc4ca5SDavid du Colombier
28059cc4ca5SDavid du Colombier error(Ebadctl);
28159cc4ca5SDavid du Colombier }
28259cc4ca5SDavid du Colombier
28323173ec1SDavid du Colombier if(n > ether->mtu)
2847dd7cddfSDavid du Colombier error(Etoobig);
28559cc4ca5SDavid du Colombier if(n < ether->minmtu)
2867dd7cddfSDavid du Colombier error(Etoosmall);
2873e12c5d1SDavid du Colombier
2887dd7cddfSDavid du Colombier bp = allocb(n);
2899a747e4fSDavid du Colombier if(waserror()){
2909a747e4fSDavid du Colombier freeb(bp);
2919a747e4fSDavid du Colombier nexterror();
2929a747e4fSDavid du Colombier }
2937dd7cddfSDavid du Colombier memmove(bp->rp, buf, n);
2947dd7cddfSDavid du Colombier memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
2959a747e4fSDavid du Colombier poperror();
2967dd7cddfSDavid du Colombier bp->wp += n;
297bd389b36SDavid du Colombier
2987dd7cddfSDavid du Colombier return etheroq(ether, bp);
2997dd7cddfSDavid du Colombier }
3003e12c5d1SDavid du Colombier
3017dd7cddfSDavid du Colombier static long
etherbwrite(Chan * chan,Block * bp,ulong)3027dd7cddfSDavid du Colombier etherbwrite(Chan* chan, Block* bp, ulong)
3037dd7cddfSDavid du Colombier {
3047dd7cddfSDavid du Colombier Ether *ether;
3057dd7cddfSDavid du Colombier long n;
3067dd7cddfSDavid du Colombier
3077dd7cddfSDavid du Colombier n = BLEN(bp);
3087dd7cddfSDavid du Colombier if(NETTYPE(chan->qid.path) != Ndataqid){
30959cc4ca5SDavid du Colombier if(waserror()) {
31059cc4ca5SDavid du Colombier freeb(bp);
31159cc4ca5SDavid du Colombier nexterror();
31259cc4ca5SDavid du Colombier }
31359cc4ca5SDavid du Colombier n = etherwrite(chan, bp->rp, n, 0);
31459cc4ca5SDavid du Colombier poperror();
3153e12c5d1SDavid du Colombier freeb(bp);
3167dd7cddfSDavid du Colombier return n;
3173e12c5d1SDavid du Colombier }
31859cc4ca5SDavid du Colombier ether = etherxx[chan->dev];
3193e12c5d1SDavid du Colombier
32023173ec1SDavid du Colombier if(n > ether->mtu){
3217dd7cddfSDavid du Colombier freeb(bp);
32259cc4ca5SDavid du Colombier error(Etoobig);
3237dd7cddfSDavid du Colombier }
32459cc4ca5SDavid du Colombier if(n < ether->minmtu){
3257dd7cddfSDavid du Colombier freeb(bp);
3267dd7cddfSDavid du Colombier error(Etoosmall);
327bd389b36SDavid du Colombier }
328bd389b36SDavid du Colombier
3297dd7cddfSDavid du Colombier return etheroq(ether, bp);
3303e12c5d1SDavid du Colombier }
3313e12c5d1SDavid du Colombier
3327dd7cddfSDavid du Colombier static struct {
333219b2ee8SDavid du Colombier char* type;
3347dd7cddfSDavid du Colombier int (*reset)(Ether*);
3357dd7cddfSDavid du Colombier } cards[MaxEther+1];
336219b2ee8SDavid du Colombier
337219b2ee8SDavid du Colombier void
addethercard(char * t,int (* r)(Ether *))3387dd7cddfSDavid du Colombier addethercard(char* t, int (*r)(Ether*))
339219b2ee8SDavid du Colombier {
340219b2ee8SDavid du Colombier static int ncard;
341219b2ee8SDavid du Colombier
3427dd7cddfSDavid du Colombier if(ncard == MaxEther)
343219b2ee8SDavid du Colombier panic("too many ether cards");
344219b2ee8SDavid du Colombier cards[ncard].type = t;
345219b2ee8SDavid du Colombier cards[ncard].reset = r;
346219b2ee8SDavid du Colombier ncard++;
347219b2ee8SDavid du Colombier }
348219b2ee8SDavid du Colombier
3497dd7cddfSDavid du Colombier int
parseether(uchar * to,char * from)3507dd7cddfSDavid du Colombier parseether(uchar *to, char *from)
3517dd7cddfSDavid du Colombier {
3527dd7cddfSDavid du Colombier char nip[4];
3537dd7cddfSDavid du Colombier char *p;
3547dd7cddfSDavid du Colombier int i;
3557dd7cddfSDavid du Colombier
3567dd7cddfSDavid du Colombier p = from;
3573ff48bf5SDavid du Colombier for(i = 0; i < Eaddrlen; i++){
3587dd7cddfSDavid du Colombier if(*p == 0)
3597dd7cddfSDavid du Colombier return -1;
3607dd7cddfSDavid du Colombier nip[0] = *p++;
3617dd7cddfSDavid du Colombier if(*p == 0)
3627dd7cddfSDavid du Colombier return -1;
3637dd7cddfSDavid du Colombier nip[1] = *p++;
3647dd7cddfSDavid du Colombier nip[2] = 0;
3657dd7cddfSDavid du Colombier to[i] = strtoul(nip, 0, 16);
3667dd7cddfSDavid du Colombier if(*p == ':')
3677dd7cddfSDavid du Colombier p++;
3687dd7cddfSDavid du Colombier }
3697dd7cddfSDavid du Colombier return 0;
3707dd7cddfSDavid du Colombier }
3717dd7cddfSDavid du Colombier
3729a747e4fSDavid du Colombier static Ether*
etherprobe(int cardno,int ctlrno)3739a747e4fSDavid du Colombier etherprobe(int cardno, int ctlrno)
374219b2ee8SDavid du Colombier {
37587dfdc75SDavid du Colombier int i, lg;
37687dfdc75SDavid du Colombier ulong mb, bsz;
3777dd7cddfSDavid du Colombier Ether *ether;
3789a747e4fSDavid du Colombier char buf[128], name[32];
379219b2ee8SDavid du Colombier
3807dd7cddfSDavid du Colombier ether = malloc(sizeof(Ether));
381aa72973aSDavid du Colombier if(ether == nil)
382aa72973aSDavid du Colombier error(Enomem);
3837dd7cddfSDavid du Colombier memset(ether, 0, sizeof(Ether));
3847dd7cddfSDavid du Colombier ether->ctlrno = ctlrno;
3857dd7cddfSDavid du Colombier ether->tbdf = BUSUNKNOWN;
3867dd7cddfSDavid du Colombier ether->mbps = 10;
38759cc4ca5SDavid du Colombier ether->minmtu = ETHERMINTU;
38859cc4ca5SDavid du Colombier ether->maxmtu = ETHERMAXTU;
38923173ec1SDavid du Colombier ether->mtu = ETHERMAXTU;
3909a747e4fSDavid du Colombier
3919a747e4fSDavid du Colombier if(cardno < 0){
3929a747e4fSDavid du Colombier if(isaconfig("ether", ctlrno, ether) == 0){
3939a747e4fSDavid du Colombier free(ether);
3949a747e4fSDavid du Colombier return nil;
3959a747e4fSDavid du Colombier }
3969a747e4fSDavid du Colombier for(cardno = 0; cards[cardno].type; cardno++){
3979a747e4fSDavid du Colombier if(cistrcmp(cards[cardno].type, ether->type))
3987dd7cddfSDavid du Colombier continue;
3997dd7cddfSDavid du Colombier for(i = 0; i < ether->nopt; i++){
4007dd7cddfSDavid du Colombier if(strncmp(ether->opt[i], "ea=", 3))
4017dd7cddfSDavid du Colombier continue;
4029a747e4fSDavid du Colombier if(parseether(ether->ea, ðer->opt[i][3]))
4037dd7cddfSDavid du Colombier memset(ether->ea, 0, Eaddrlen);
4047dd7cddfSDavid du Colombier }
405219b2ee8SDavid du Colombier break;
4069a747e4fSDavid du Colombier }
4079a747e4fSDavid du Colombier }
4089a747e4fSDavid du Colombier
4099a747e4fSDavid du Colombier if(cardno >= MaxEther || cards[cardno].type == nil){
4109a747e4fSDavid du Colombier free(ether);
4119a747e4fSDavid du Colombier return nil;
4129a747e4fSDavid du Colombier }
4139a747e4fSDavid du Colombier if(cards[cardno].reset(ether) < 0){
4149a747e4fSDavid du Colombier free(ether);
4159a747e4fSDavid du Colombier return nil;
4169a747e4fSDavid du Colombier }
417219b2ee8SDavid du Colombier
418219b2ee8SDavid du Colombier /*
419219b2ee8SDavid du Colombier * IRQ2 doesn't really exist, it's used to gang the interrupt
420219b2ee8SDavid du Colombier * controllers together. A device set to IRQ2 will appear on
421219b2ee8SDavid du Colombier * the second interrupt controller as IRQ9.
422219b2ee8SDavid du Colombier */
4237dd7cddfSDavid du Colombier if(ether->irq == 2)
4247dd7cddfSDavid du Colombier ether->irq = 9;
4257dd7cddfSDavid du Colombier snprint(name, sizeof(name), "ether%d", ctlrno);
42659cc4ca5SDavid du Colombier
4279a747e4fSDavid du Colombier /*
428fb7f0c93SDavid du Colombier * If ether->irq is <0, it is a hack to indicate no interrupt
4299a747e4fSDavid du Colombier * used by ethersink.
43059cc4ca5SDavid du Colombier */
431fb7f0c93SDavid du Colombier if(ether->irq >= 0)
4327dd7cddfSDavid du Colombier intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name);
433219b2ee8SDavid du Colombier
4341bdadbfaSDavid du Colombier i = sprint(buf, "#l%d: %s: ", ctlrno, cards[cardno].type);
4351bdadbfaSDavid du Colombier if(ether->mbps >= 1000)
4361bdadbfaSDavid du Colombier i += sprint(buf+i, "%dGbps", ether->mbps/1000);
4371bdadbfaSDavid du Colombier else
4381bdadbfaSDavid du Colombier i += sprint(buf+i, "%dMbps", ether->mbps);
4391bdadbfaSDavid du Colombier i += sprint(buf+i, " port 0x%luX irq %d", ether->port, ether->irq);
4407dd7cddfSDavid du Colombier if(ether->mem)
4414de34a7eSDavid du Colombier i += sprint(buf+i, " addr 0x%luX", ether->mem);
4427dd7cddfSDavid du Colombier if(ether->size)
4437dd7cddfSDavid du Colombier i += sprint(buf+i, " size 0x%luX", ether->size);
4446063170eSDavid du Colombier i += sprint(buf+i, ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
4457dd7cddfSDavid du Colombier ether->ea[0], ether->ea[1], ether->ea[2],
4467dd7cddfSDavid du Colombier ether->ea[3], ether->ea[4], ether->ea[5]);
4477dd7cddfSDavid du Colombier sprint(buf+i, "\n");
4487dd7cddfSDavid du Colombier print(buf);
449219b2ee8SDavid du Colombier
450*6520663fSDavid du Colombier /*
451*6520663fSDavid du Colombier * input queues are allocated by ../port/netif.c:/^openfile.
452*6520663fSDavid du Colombier * the size will be the last argument to netifinit() below.
453*6520663fSDavid du Colombier *
454*6520663fSDavid du Colombier * output queues should be small, to minimise `bufferbloat',
455*6520663fSDavid du Colombier * which confuses tcp's feedback loop. at 1Gb/s, it only takes
456*6520663fSDavid du Colombier * ~15µs to transmit a full-sized non-jumbo packet.
457*6520663fSDavid du Colombier */
458*6520663fSDavid du Colombier
45987dfdc75SDavid du Colombier /* compute log10(ether->mbps) into lg */
46087dfdc75SDavid du Colombier for(lg = 0, mb = ether->mbps; mb >= 10; lg++)
46187dfdc75SDavid du Colombier mb /= 10;
462*6520663fSDavid du Colombier if (lg > 14) /* sanity cap; 2**(14+15) = 2²⁹ */
46387dfdc75SDavid du Colombier lg = 14;
46487dfdc75SDavid du Colombier
465*6520663fSDavid du Colombier /* allocate larger input queues for higher-speed interfaces */
466*6520663fSDavid du Colombier bsz = 1UL << (lg + 15); /* 2ⁱ⁵ = 32K, bsz = 2ⁿ × 32K */
467*6520663fSDavid du Colombier while (bsz > mainmem->maxsize / 8 && bsz > 128*1024) /* sanity */
468*6520663fSDavid du Colombier bsz /= 2;
46987dfdc75SDavid du Colombier netifinit(ether, name, Ntypes, bsz);
470*6520663fSDavid du Colombier
47187dfdc75SDavid du Colombier if(ether->oq == nil)
472*6520663fSDavid du Colombier ether->oq = qopen(1 << (lg + 13), Qmsg, 0, 0);
473*6520663fSDavid du Colombier if(ether->oq == nil)
474*6520663fSDavid du Colombier panic("etherreset %s: can't allocate output queue", name);
475*6520663fSDavid du Colombier
4767dd7cddfSDavid du Colombier ether->alen = Eaddrlen;
4777dd7cddfSDavid du Colombier memmove(ether->addr, ether->ea, Eaddrlen);
4787dd7cddfSDavid du Colombier memset(ether->bcast, 0xFF, Eaddrlen);
4797dd7cddfSDavid du Colombier
4809a747e4fSDavid du Colombier return ether;
4819a747e4fSDavid du Colombier }
4829a747e4fSDavid du Colombier
4839a747e4fSDavid du Colombier static void
etherreset(void)4849a747e4fSDavid du Colombier etherreset(void)
4859a747e4fSDavid du Colombier {
4869a747e4fSDavid du Colombier Ether *ether;
4879a747e4fSDavid du Colombier int cardno, ctlrno;
4889a747e4fSDavid du Colombier
4899a747e4fSDavid du Colombier for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){
4909a747e4fSDavid du Colombier if((ether = etherprobe(-1, ctlrno)) == nil)
4919a747e4fSDavid du Colombier continue;
4927dd7cddfSDavid du Colombier etherxx[ctlrno] = ether;
4939a747e4fSDavid du Colombier }
4949a747e4fSDavid du Colombier
495b7b24591SDavid du Colombier if(getconf("*noetherprobe"))
496b7b24591SDavid du Colombier return;
497b7b24591SDavid du Colombier
4989a747e4fSDavid du Colombier cardno = ctlrno = 0;
4999a747e4fSDavid du Colombier while(cards[cardno].type != nil && ctlrno < MaxEther){
5009a747e4fSDavid du Colombier if(etherxx[ctlrno] != nil){
5019a747e4fSDavid du Colombier ctlrno++;
5029a747e4fSDavid du Colombier continue;
5039a747e4fSDavid du Colombier }
5049a747e4fSDavid du Colombier if((ether = etherprobe(cardno, ctlrno)) == nil){
5059a747e4fSDavid du Colombier cardno++;
5069a747e4fSDavid du Colombier continue;
5079a747e4fSDavid du Colombier }
5089a747e4fSDavid du Colombier etherxx[ctlrno] = ether;
5099a747e4fSDavid du Colombier ctlrno++;
510219b2ee8SDavid du Colombier }
511219b2ee8SDavid du Colombier }
5129a747e4fSDavid du Colombier
5139a747e4fSDavid du Colombier static void
ethershutdown(void)5149a747e4fSDavid du Colombier ethershutdown(void)
5159a747e4fSDavid du Colombier {
5169a747e4fSDavid du Colombier Ether *ether;
5179a747e4fSDavid du Colombier int i;
5189a747e4fSDavid du Colombier
5199a747e4fSDavid du Colombier for(i = 0; i < MaxEther; i++){
5209a747e4fSDavid du Colombier ether = etherxx[i];
5219a747e4fSDavid du Colombier if(ether == nil)
5229a747e4fSDavid du Colombier continue;
5239a747e4fSDavid du Colombier if(ether->shutdown == nil) {
52498bee55eSDavid du Colombier print("#l%d: no shutdown function\n", i);
5259a747e4fSDavid du Colombier continue;
5267dd7cddfSDavid du Colombier }
5279a747e4fSDavid du Colombier (*ether->shutdown)(ether);
5289a747e4fSDavid du Colombier }
5299a747e4fSDavid du Colombier }
5309a747e4fSDavid du Colombier
531219b2ee8SDavid du Colombier
5327dd7cddfSDavid du Colombier #define POLY 0xedb88320
5337dd7cddfSDavid du Colombier
5347dd7cddfSDavid du Colombier /* really slow 32 bit crc for ethers */
5357dd7cddfSDavid du Colombier ulong
ethercrc(uchar * p,int len)5367dd7cddfSDavid du Colombier ethercrc(uchar *p, int len)
5373e12c5d1SDavid du Colombier {
5387dd7cddfSDavid du Colombier int i, j;
5397dd7cddfSDavid du Colombier ulong crc, b;
5403e12c5d1SDavid du Colombier
5417dd7cddfSDavid du Colombier crc = 0xffffffff;
5427dd7cddfSDavid du Colombier for(i = 0; i < len; i++){
5437dd7cddfSDavid du Colombier b = *p++;
5447dd7cddfSDavid du Colombier for(j = 0; j < 8; j++){
5457dd7cddfSDavid du Colombier crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
5467dd7cddfSDavid du Colombier b >>= 1;
5477dd7cddfSDavid du Colombier }
5487dd7cddfSDavid du Colombier }
5497dd7cddfSDavid du Colombier return crc;
550bd389b36SDavid du Colombier }
551bd389b36SDavid du Colombier
5527dd7cddfSDavid du Colombier Dev etherdevtab = {
5537dd7cddfSDavid du Colombier 'l',
5547dd7cddfSDavid du Colombier "ether",
555bd389b36SDavid du Colombier
5567dd7cddfSDavid du Colombier etherreset,
5577dd7cddfSDavid du Colombier devinit,
5589a747e4fSDavid du Colombier ethershutdown,
5597dd7cddfSDavid du Colombier etherattach,
5607dd7cddfSDavid du Colombier etherwalk,
5617dd7cddfSDavid du Colombier etherstat,
5627dd7cddfSDavid du Colombier etheropen,
5637dd7cddfSDavid du Colombier ethercreate,
5647dd7cddfSDavid du Colombier etherclose,
5657dd7cddfSDavid du Colombier etherread,
5667dd7cddfSDavid du Colombier etherbread,
5677dd7cddfSDavid du Colombier etherwrite,
5687dd7cddfSDavid du Colombier etherbwrite,
5699a747e4fSDavid du Colombier devremove,
5707dd7cddfSDavid du Colombier etherwstat,
5717dd7cddfSDavid du Colombier };
572