ref: d6e0e9c402e215dc5659ad525e3e652501f76810
parent: debb786fea3d6ea8018c3d83cdedfdbff0703441
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Feb 11 13:08:03 EST 2018
kernel: move devether and wifi to port/ the only architecture dependence of devether was enabling interrupts, which is now done at the end of the driver's reset() function now. the wifi stack and dummy ethersink also go to port/. do the IRQ2->IRQ9 hack for pc kernels in intrenabale(), so not every caller of intrenable() has to be aware of it.
--- a/sys/src/9/kw/archkw.c
+++ b/sys/src/9/kw/archkw.c
@@ -11,7 +11,7 @@
#include "io.h"
#include "../port/netif.h"
-#include "etherif.h"
+#include "../port/etherif.h"
#include "../port/flashif.h"
#include "arm.h"
@@ -393,17 +393,6 @@
void
archkwlink(void)
{
-}
-
-int
-archether(unsigned ctlno, Ether *ether)
-{
- if(ctlno >= 2)
- return -1;
- ether->type = "88e1116";
- ether->port = ctlno;
-// ether->mbps = 1000;
- return 1;
}
/* LED/USB gpios */
--- a/sys/src/9/kw/devether.c
+++ /dev/null
@@ -1,502 +1,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "../port/error.h"
-
-#include "../port/netif.h"
-#include "etherif.h"
-
-extern int archether(unsigned ctlno, Ether *ether);
-
-static Ether *etherxx[MaxEther];
-
-Chan*
-etherattach(char* spec)
-{
- int ctlrno;
- char *p;
- Chan *chan;
-
- ctlrno = 0;
- if(spec && *spec){
- ctlrno = strtoul(spec, &p, 0);
- if((ctlrno == 0 && p == spec) || *p != 0)
- error(Ebadarg);
- if(ctlrno < 0 || ctlrno >= MaxEther)
- error(Ebadarg);
- }
- if(etherxx[ctlrno] == 0)
- error(Enodev);
-
- chan = devattach('l', spec);
- if(waserror()){
- chanfree(chan);
- nexterror();
- }
- chan->dev = ctlrno;
- if(etherxx[ctlrno]->attach)
- etherxx[ctlrno]->attach(etherxx[ctlrno]);
- poperror();
- return chan;
-}
-
-static Walkqid*
-etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
-{
- return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
-}
-
-static int
-etherstat(Chan* chan, uchar* dp, int n)
-{
- return netifstat(etherxx[chan->dev], chan, dp, n);
-}
-
-static Chan*
-etheropen(Chan* chan, int omode)
-{
- return netifopen(etherxx[chan->dev], chan, omode);
-}
-
-static Chan*
-ethercreate(Chan*, char*, int, ulong)
-{
- error(Eperm);
- return 0;
-}
-
-static void
-etherclose(Chan* chan)
-{
- netifclose(etherxx[chan->dev], chan);
-}
-
-static long
-etherread(Chan* chan, void* buf, long n, vlong off)
-{
- Ether *ether;
- ulong offset = off;
-
- ether = etherxx[chan->dev];
- if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
- /*
- * With some controllers it is necessary to reach
- * into the chip to extract statistics.
- */
- if(NETTYPE(chan->qid.path) == Nifstatqid)
- return ether->ifstat(ether, buf, n, offset);
- else if(NETTYPE(chan->qid.path) == Nstatqid)
- ether->ifstat(ether, buf, 0, offset);
- }
-
- return netifread(ether, chan, buf, n, offset);
-}
-
-static Block*
-etherbread(Chan* chan, long n, ulong offset)
-{
- return netifbread(etherxx[chan->dev], chan, n, offset);
-}
-
-static int
-etherwstat(Chan* chan, uchar* dp, int n)
-{
- return netifwstat(etherxx[chan->dev], chan, dp, n);
-}
-
-static void
-etherrtrace(Netfile* f, Etherpkt* pkt, int len)
-{
- int i, n;
- Block *bp;
-
- if(qwindow(f->in) <= 0)
- return;
- if(len > 58)
- n = 58;
- else
- n = len;
- bp = iallocb(64);
- if(bp == nil)
- return;
- memmove(bp->wp, pkt->d, n);
- i = TK2MS(MACHP(0)->ticks);
- bp->wp[58] = len>>8;
- bp->wp[59] = len;
- bp->wp[60] = i>>24;
- bp->wp[61] = i>>16;
- bp->wp[62] = i>>8;
- bp->wp[63] = i;
- bp->wp += 64;
- qpass(f->in, bp);
-}
-
-Block*
-etheriq(Ether* ether, Block* bp, int fromwire)
-{
- Etherpkt *pkt;
- ushort type;
- int len, multi, tome, fromme;
- Netfile **ep, *f, **fp, *fx;
- Block *xbp;
-
- ether->inpackets++;
-
- pkt = (Etherpkt*)bp->rp;
- len = BLEN(bp);
- type = (pkt->type[0]<<8)|pkt->type[1];
- fx = 0;
- ep = ðer->f[Ntypes];
-
- multi = pkt->d[0] & 1;
- /* check for valid multicast addresses */
- if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 && ether->prom == 0){
- if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
- if(fromwire){
- freeb(bp);
- bp = 0;
- }
- return bp;
- }
- }
-
- /* is it for me? */
- tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
- fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
-
- /*
- * Multiplex the packet to all the connections which want it.
- * If the packet is not to be used subsequently (fromwire != 0),
- * attempt to simply pass it into one of the connections, thereby
- * saving a copy of the data (usual case hopefully).
- */
- for(fp = ether->f; fp < ep; fp++){
- if(f = *fp)
- if(f->type == type || f->type < 0)
- if(tome || multi || f->prom){
- /* Don't want to hear loopback or bridged packets */
- if(f->bridge && (tome || !fromwire && !fromme))
- continue;
- if(!f->headersonly){
- if(fromwire && fx == 0)
- fx = f;
- else if(xbp = iallocb(len)){
- memmove(xbp->wp, pkt, len);
- xbp->wp += len;
- if(qpass(f->in, xbp) < 0)
- ether->soverflows++;
- }
- else
- ether->soverflows++;
- }
- else
- etherrtrace(f, pkt, len);
- }
- }
-
- if(fx){
- if(qpass(fx->in, bp) < 0)
- ether->soverflows++;
- return 0;
- }
- if(fromwire){
- freeb(bp);
- return 0;
- }
-
- return bp;
-}
-
-static int
-etheroq(Ether* ether, Block* bp)
-{
- int len, loopback;
- Etherpkt *pkt;
-
- ether->outpackets++;
-
- /*
- * Check if the packet has to be placed back onto the input queue,
- * i.e. if it's a loopback or broadcast packet or the interface is
- * in promiscuous mode.
- * If it's a loopback packet indicate to etheriq that the data isn't
- * needed and return, etheriq will pass-on or free the block.
- * To enable bridging to work, only packets that were originated
- * by this interface are fed back.
- */
- pkt = (Etherpkt*)bp->rp;
- len = BLEN(bp);
- loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
- if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom)
- if(etheriq(ether, bp, loopback) == 0)
- return len;
-
- qbwrite(ether->oq, bp);
- if(ether->transmit != nil)
- ether->transmit(ether);
- return len;
-}
-
-static long
-etherwrite(Chan* chan, void* buf, long n, vlong)
-{
- Ether *ether;
- Block *bp;
- int nn, onoff;
- Cmdbuf *cb;
-
- ether = etherxx[chan->dev];
- if(NETTYPE(chan->qid.path) != Ndataqid) {
- nn = netifwrite(ether, chan, buf, n);
- if(nn >= 0)
- return nn;
- cb = parsecmd(buf, n);
- if(strcmp(cb->f[0], "nonblocking") == 0){
- if(cb->nf <= 1)
- onoff = 1;
- else
- onoff = atoi(cb->f[1]);
- qnoblock(ether->oq, onoff);
- free(cb);
- return n;
- }
- free(cb);
- if(ether->ctl!=nil)
- return ether->ctl(ether,buf,n);
-
- error(Ebadctl);
- }
-
- if(n > ether->maxmtu)
- error(Etoobig);
- if(n < ether->minmtu)
- error(Etoosmall);
-
- bp = allocb(n);
- if(waserror()){
- freeb(bp);
- nexterror();
- }
- memmove(bp->rp, buf, n);
- if(!ether->f[NETID(chan->qid.path)]->bridge)
- memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
- poperror();
- bp->wp += n;
-
- return etheroq(ether, bp);
-}
-
-static long
-etherbwrite(Chan* chan, Block* bp, ulong)
-{
- Ether *ether;
- long n;
-
- n = BLEN(bp);
- if(NETTYPE(chan->qid.path) != Ndataqid){
- if(waserror()) {
- freeb(bp);
- nexterror();
- }
- n = etherwrite(chan, bp->rp, n, 0);
- poperror();
- freeb(bp);
- return n;
- }
- ether = etherxx[chan->dev];
-
- if(n > ether->maxmtu){
- freeb(bp);
- error(Etoobig);
- }
- if(n < ether->minmtu){
- freeb(bp);
- error(Etoosmall);
- }
-
- return etheroq(ether, bp);
-}
-
-static struct {
- char* type;
- int (*reset)(Ether*);
-} cards[MaxEther+1];
-
-void
-addethercard(char* t, int (*r)(Ether*))
-{
- static int ncard;
-
- if(ncard == MaxEther)
- panic("too many ether cards");
- cards[ncard].type = t;
- cards[ncard].reset = r;
- ncard++;
-}
-
-static void
-etherreset(void)
-{
- Ether *ether;
- int i, n, ctlrno;
- char name[KNAMELEN], buf[128];
-
- for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
- if(ether == 0)
- ether = malloc(sizeof(Ether));
- memset(ether, 0, sizeof(Ether));
- ether->ctlrno = ctlrno;
- ether->mbps = 10;
- ether->minmtu = ETHERMINTU;
- ether->maxmtu = ETHERMAXTU;
-
- if(archether(ctlrno, ether) <= 0)
- continue;
-
- for(n = 0; cards[n].type; n++){
- if(cistrcmp(cards[n].type, ether->type))
- continue;
- for(i = 0; i < ether->nopt; i++){
- if(cistrncmp(ether->opt[i], "ea=", 3) == 0){
- if(parseether(ether->ea, ðer->opt[i][3]) == -1)
- memset(ether->ea, 0, Eaddrlen);
- }else if(cistrcmp(ether->opt[i], "fullduplex") == 0 ||
- cistrcmp(ether->opt[i], "10BASE-TFD") == 0)
- ether->fullduplex = 1;
- else if(cistrcmp(ether->opt[i], "100BASE-TXFD") == 0)
- ether->mbps = 100;
- }
- if(cards[n].reset(ether))
- break;
- snprint(name, sizeof(name), "ether%d", ctlrno);
-
- if(ether->interrupt != nil)
- intrenable(Irqlo, ether->irq, ether->interrupt,
- ether, name);
-
- i = snprint(buf, sizeof buf,
- "#l%d: %s: %dMbps port %#lux irq %d",
- ctlrno, ether->type, ether->mbps, ether->port,
- ether->irq);
- if(ether->mem)
- i += snprint(buf+i, sizeof buf - i,
- " addr %#lux", PADDR(ether->mem));
- if(ether->size)
- i += snprint(buf+i, sizeof buf - i,
- " size %#luX", ether->size);
- i += snprint(buf+i, sizeof buf - i,
- ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
- ether->ea[0], ether->ea[1], ether->ea[2],
- ether->ea[3], ether->ea[4], ether->ea[5]);
- snprint(buf+i, sizeof buf - i, "\n");
- print("%s", buf);
-
- if(ether->mbps >= 1000)
- netifinit(ether, name, Ntypes, 4*1024*1024);
- else if(ether->mbps >= 100)
- netifinit(ether, name, Ntypes, 1024*1024);
- else
- netifinit(ether, name, Ntypes, 65*1024);
- if(ether->oq == 0)
- ether->oq = qopen(ether->limit, Qmsg, 0, 0);
- if(ether->oq == 0)
- panic("etherreset %s", name);
- ether->alen = Eaddrlen;
- memmove(ether->addr, ether->ea, Eaddrlen);
- memset(ether->bcast, 0xFF, Eaddrlen);
-
- etherxx[ctlrno] = ether;
- ether = 0;
- break;
- }
- }
- if(ether)
- free(ether);
-}
-
-static void
-ethershutdown(void)
-{
- Ether *ether;
- int i;
-
- for(i = 0; i < MaxEther; i++){
- ether = etherxx[i];
- if(ether == nil)
- continue;
- if(ether->shutdown == nil) {
- print("#l%d: no shutdown function\n", i);
- continue;
- }
- (*ether->shutdown)(ether);
- }
-}
-
-#define POLY 0xedb88320
-
-/* really slow 32 bit crc for ethers */
-ulong
-ethercrc(uchar *p, int len)
-{
- int i, j;
- ulong crc, b;
-
- crc = 0xffffffff;
- for(i = 0; i < len; i++){
- b = *p++;
- for(j = 0; j < 8; j++){
- crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
- b >>= 1;
- }
- }
- return crc;
-}
-
-void
-dumpoq(Queue *oq)
-{
- if (oq == nil)
- print("no outq! ");
- else if (qisclosed(oq))
- print("outq closed ");
- else if (qfull(oq))
- print("outq full ");
- else
- print("outq %d ", qlen(oq));
-}
-
-void
-dumpnetif(Netif *netif)
-{
- print("netif %s ", netif->name);
- print("limit %d mbps %d link %d ",
- netif->limit, netif->mbps, netif->link);
- print("inpkts %lld outpkts %lld errs %d\n",
- netif->inpackets, netif->outpackets,
- netif->crcs + netif->oerrs + netif->frames + netif->overflows +
- netif->buffs + netif->soverflows);
-}
-
-Dev etherdevtab = {
- 'l',
- "ether",
-
- etherreset,
- devinit,
- ethershutdown,
- etherattach,
- etherwalk,
- etherstat,
- etheropen,
- ethercreate,
- etherclose,
- etherread,
- etherbread,
- etherwrite,
- etherbwrite,
- devremove,
- etherwstat,
-};
--- a/sys/src/9/kw/ether1116.c
+++ b/sys/src/9/kw/ether1116.c
@@ -16,8 +16,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
#include "ethermii.h"
#include "../ip/ip.h"
@@ -144,6 +144,9 @@
Mii *mii;
int port;
+ int linkchg; /* link status changed? */
+ uvlong starttime; /* last activity time */
+
/* stats */
ulong intrs;
ulong newintrs;
@@ -579,14 +582,16 @@
static void
etheractive(Ether *ether)
{
- ether->starttime = TK2MS(MACHP(0)->ticks)/1000;
+ Ctlr *ctlr = ether->ctlr;
+ ctlr->starttime = TK2MS(MACHP(0)->ticks)/1000;
}
static void
ethercheck(Ether *ether)
{
- if (ether->starttime != 0 &&
- TK2MS(MACHP(0)->ticks)/1000 - ether->starttime > Etherstuck) {
+ Ctlr *ctlr = ether->ctlr;
+ if (ctlr->starttime != 0 &&
+ TK2MS(MACHP(0)->ticks)/1000 - ctlr->starttime > Etherstuck) {
etheractive(ether);
if (ether->ctlrno == 0) /* only complain about main ether */
iprint("#l%d: ethernet stuck\n", ether->ctlrno);
@@ -833,7 +838,7 @@
*/
if(irqe & IEphystschg) {
ether->link = (reg->ps0 & PS0linkup) != 0;
- ether->linkchg = 1;
+ ctlr->linkchg = 1;
}
if(irqe & IEtxerrq(Qno))
ether->oerrs++;
@@ -858,10 +863,10 @@
irq &= ~(Irxerr | Irxerrq(Qno));
}
- if(ether->linkchg && (reg->ps1 & PS1an_done)) {
+ if(ctlr->linkchg && (reg->ps1 & PS1an_done)) {
handled++;
ether->link = (reg->ps0 & PS0linkup) != 0;
- ether->linkchg = 0;
+ ctlr->linkchg = 0;
}
ctlr->newintrs++;
@@ -1652,7 +1657,6 @@
p = seprint(p, e, "transmitted broadcast frames: %lud\n", ctlr->txbcastpkt);
p = seprint(p, e, "transmitted multicast frames: %lud\n", ctlr->txmcastpkt);
p = seprint(p, e, "transmit frames dropped by collision: %lud\n", ctlr->txcollpktdrop);
- p = seprint(p, e, "misaligned buffers: %lud\n", ether->pktsmisaligned);
p = seprint(p, e, "bad mac control frames: %lud\n", ctlr->badmacctlpkts);
p = seprint(p, e, "transmitted flow control messages: %lud\n", ctlr->txflctl);
@@ -1689,7 +1693,7 @@
ether->irq = IRQ0gbe1sum;
break;
default:
- panic("ether1116: bad ether ctlr #%d", ether->ctlrno);
+ return -1;
}
ctlr->reg = (Gbereg*)soc.ether[ether->ctlrno];
@@ -1728,7 +1732,6 @@
ether->attach = attach;
ether->transmit = transmit;
- ether->interrupt = interrupt;
ether->ifstat = ifstat;
ether->shutdown = shutdown;
ether->ctl = ctl;
@@ -1736,6 +1739,9 @@
ether->arg = ether;
ether->promiscuous = promiscuous;
ether->multicast = multicast;
+
+ intrenable(Irqlo, ether->irq, interrupt, ether, ether->name);
+
return 0;
}
--- a/sys/src/9/kw/etherif.h
+++ /dev/null
@@ -1,55 +1,0 @@
-enum
-{
- MaxEther = 2,
- Ntypes = 8,
-};
-
-typedef struct Ether Ether;
-struct Ether {
- RWlock; /* TO DO */
- ISAConf; /* hardware info */
- int ctlrno;
- int minmtu;
- int maxmtu;
- uchar ea[Eaddrlen];
- void *address;
- int tbusy;
-
- void (*attach)(Ether*); /* filled in by reset routine */
- void (*closed)(Ether*);
- void (*detach)(Ether*);
- void (*transmit)(Ether*);
- void (*interrupt)(Ureg*, void*);
- long (*ifstat)(Ether*, void*, long, ulong);
- long (*ctl)(Ether*, void*, long); /* custom ctl messages */
- void (*power)(Ether*, int); /* power on/off */
- void (*shutdown)(Ether*); /* shutdown hardware before reboot */
- void *ctlr;
- int pcmslot; /* PCMCIA */
- int fullduplex; /* non-zero if full duplex */
- int linkchg; /* link status changed? */
- uvlong starttime; /* last activity time */
-
- Queue* oq;
-
- /* statistics */
- ulong interrupts;
- ulong dmarxintr;
- ulong dmatxintr;
- ulong promisc;
- ulong pktsdropped;
- ulong pktsmisaligned;
- ulong resets; /* after initialisation */
- ulong bcasts; /* broadcast pkts rcv'd */
- ulong mcasts; /* multicast pkts rcv'd */
-
- Netif;
-};
-
-extern Block* etheriq(Ether*, Block*, int);
-extern void addethercard(char*, int(*)(Ether*));
-extern ulong ethercrc(uchar*, int);
-extern int parseether(uchar*, char*);
-
-#define NEXT(x, l) (((x)+1)%(l))
-#define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1)
--- a/sys/src/9/kw/ethermii.c
+++ b/sys/src/9/kw/ethermii.c
@@ -6,8 +6,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
#include "ethermii.h"
int
--- a/sys/src/9/kw/mem.h
+++ b/sys/src/9/kw/mem.h
@@ -5,9 +5,6 @@
#define MiB 1048576u /* Mebi 0x0000000000100000 */
#define GiB 1073741824u /* Gibi 000000000040000000 */
-#define HOWMANY(x, y) (((x)+((y)-1))/(y))
-#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y)) /* ceiling */
-#define ROUNDDN(x, y) (((x)/(y))*(y)) /* floor */
#define MIN(a, b) ((a) < (b)? (a): (b))
#define MAX(a, b) ((a) > (b)? (a): (b))
@@ -36,7 +33,7 @@
*/
#define BY2PG (4*KiB) /* bytes per page */
#define PGSHIFT 12 /* log(BY2PG) */
-#define PGROUND(s) ROUNDUP(s, BY2PG)
+#define PGROUND(s) ROUND(s, BY2PG)
#define ROUND(s, sz) (((s)+(sz-1))&~(sz-1))
#define MAXMACH 1 /* max # cpus system can run */
--- a/sys/src/9/kw/mkfile
+++ b/sys/src/9/kw/mkfile
@@ -124,7 +124,7 @@
trap.$O: /$objtype/include/ureg.h
archkw.$O devether.$O ether1116.$O ethermii.$O: \
- etherif.h ethermii.h ../port/netif.h
+ ethermii.h ../port/etherif.h ../port/netif.h
archkw.$O devflash.$O flashkw.$O: ../port/flashif.h
fpi.$O fpiarm.$O fpimem.$O: fpi.h
l.$O lexception.$O lproc.$O mmu.$O: arm.s arm.h mem.h
--- a/sys/src/9/kw/mmu.c
+++ b/sys/src/9/kw/mmu.c
@@ -465,7 +465,7 @@
o = pa & (BY2PG-1);
pa -= o;
size += o;
- size = ROUNDUP(size, BY2PG);
+ size = PGROUND(size);
va = kseg0|pa;
pae = mmukmap(va, pa, size);
--- a/sys/src/9/mtx/devether.c
+++ /dev/null
@@ -1,447 +1,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "ureg.h"
-#include "../port/error.h"
-#include "../port/netif.h"
-
-#include "etherif.h"
-
-static Ether *etherxx[MaxEther];
-
-Chan*
-etherattach(char* spec)
-{
- ulong ctlrno;
- char *p;
- Chan *chan;
-
- ctlrno = 0;
- if(spec && *spec){
- ctlrno = strtoul(spec, &p, 0);
- if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther))
- error(Ebadarg);
- }
- if(etherxx[ctlrno] == 0)
- error(Enodev);
-
- chan = devattach('l', spec);
- chan->dev = ctlrno;
- if(etherxx[ctlrno]->attach)
- etherxx[ctlrno]->attach(etherxx[ctlrno]);
- return chan;
-}
-
-static Walkqid*
-etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
-{
- return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
-}
-
-static int
-etherstat(Chan* chan, uchar* dp, int n)
-{
- return netifstat(etherxx[chan->dev], chan, dp, n);
-}
-
-static Chan*
-etheropen(Chan* chan, int omode)
-{
- return netifopen(etherxx[chan->dev], chan, omode);
-}
-
-static Chan*
-ethercreate(Chan*, char*, int, ulong)
-{
- error(Eperm);
- return 0;
-}
-
-static void
-etherclose(Chan* chan)
-{
- netifclose(etherxx[chan->dev], chan);
-}
-
-static long
-etherread(Chan* chan, void* buf, long n, vlong off)
-{
- Ether *ether;
- ulong offset = off;
-
- ether = etherxx[chan->dev];
- if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
- /*
- * With some controllers it is necessary to reach
- * into the chip to extract statistics.
- */
- if(NETTYPE(chan->qid.path) == Nifstatqid)
- return ether->ifstat(ether, buf, n, offset);
- else if(NETTYPE(chan->qid.path) == Nstatqid)
- ether->ifstat(ether, buf, 0, offset);
- }
-
- return netifread(ether, chan, buf, n, offset);
-}
-
-static Block*
-etherbread(Chan* chan, long n, ulong offset)
-{
- return netifbread(etherxx[chan->dev], chan, n, offset);
-}
-
-static int
-etherwstat(Chan* chan, uchar* dp, int n)
-{
- return netifwstat(etherxx[chan->dev], chan, dp, n);
-}
-
-static void
-etherrtrace(Netfile* f, Etherpkt* pkt, int len)
-{
- int i, n;
- Block *bp;
-
- if(qwindow(f->in) <= 0)
- return;
- if(len > 58)
- n = 58;
- else
- n = len;
- bp = iallocb(64);
- if(bp == nil)
- return;
- memmove(bp->wp, pkt->d, n);
- i = TK2MS(MACHP(0)->ticks);
- bp->wp[58] = len>>8;
- bp->wp[59] = len;
- bp->wp[60] = i>>24;
- bp->wp[61] = i>>16;
- bp->wp[62] = i>>8;
- bp->wp[63] = i;
- bp->wp += 64;
- qpass(f->in, bp);
-}
-
-Block*
-etheriq(Ether* ether, Block* bp, int fromwire)
-{
- Etherpkt *pkt;
- ushort type;
- int len, multi, tome, fromme;
- Netfile **ep, *f, **fp, *fx;
- Block *xbp;
-
- ether->inpackets++;
-
- pkt = (Etherpkt*)bp->rp;
- len = BLEN(bp);
- type = (pkt->type[0]<<8)|pkt->type[1];
- fx = 0;
- ep = ðer->f[Ntypes];
-
- multi = pkt->d[0] & 1;
- /* check for valid multicast addresses */
- if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){
- if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
- if(fromwire){
- freeb(bp);
- bp = 0;
- }
- return bp;
- }
- }
-
- /* is it for me? */
- tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
- fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
-
- /*
- * Multiplex the packet to all the connections which want it.
- * If the packet is not to be used subsequently (fromwire != 0),
- * attempt to simply pass it into one of the connections, thereby
- * saving a copy of the data (usual case hopefully).
- */
- for(fp = ether->f; fp < ep; fp++){
- if(f = *fp)
- if(f->type == type || f->type < 0)
- if(tome || multi || f->prom){
- /* Don't want to hear loopback or bridged packets */
- if(f->bridge && (tome || !fromwire && !fromme))
- continue;
- if(!f->headersonly){
- if(fromwire && fx == 0)
- fx = f;
- else if(xbp = iallocb(len)){
- memmove(xbp->wp, pkt, len);
- xbp->wp += len;
- qpass(f->in, xbp);
- }
- else
- ether->soverflows++;
- }
- else
- etherrtrace(f, pkt, len);
- }
- }
-
- if(fx){
- if(qpass(fx->in, bp) < 0)
- ether->soverflows++;
- return 0;
- }
- if(fromwire){
- freeb(bp);
- return 0;
- }
-
- return bp;
-}
-
-static int
-etheroq(Ether* ether, Block* bp)
-{
- int len, loopback;
- Etherpkt *pkt;
-
- ether->outpackets++;
-
- /*
- * Check if the packet has to be placed back onto the input queue,
- * i.e. if it's a loopback or broadcast packet or the interface is
- * in promiscuous mode.
- * If it's a loopback packet indicate to etheriq that the data isn't
- * needed and return, etheriq will pass-on or free the block.
- * To enable bridging to work, only packets that were originated
- * by this interface are fed back.
- */
- pkt = (Etherpkt*)bp->rp;
- len = BLEN(bp);
- loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
- if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom)
- if(etheriq(ether, bp, loopback) == 0)
- return len;
-
- qbwrite(ether->oq, bp);
- if(ether->transmit != nil)
- ether->transmit(ether);
- return len;
-}
-
-static long
-etherwrite(Chan* chan, void* buf, long n, vlong)
-{
- Ether *ether;
- Block *bp;
- int nn;
-
- ether = etherxx[chan->dev];
- if(NETTYPE(chan->qid.path) != Ndataqid) {
- nn = netifwrite(ether, chan, buf, n);
- if(nn >= 0)
- return nn;
-
- if(n == sizeof("nonblocking")-1 && strncmp((char*)buf, "nonblocking", n) == 0){
- qnoblock(ether->oq, 1);
- return n;
- }
-
- if(ether->ctl!=nil)
- return ether->ctl(ether,buf,n);
-
- error(Ebadctl);
- }
-
- if(n > ether->maxmtu)
- error(Etoobig);
- if(n < ether->minmtu)
- error(Etoosmall);
-
- bp = allocb(n);
- if(waserror()){
- freeb(bp);
- nexterror();
- }
- memmove(bp->rp, buf, n);
- if(!ether->f[NETID(chan->qid.path)]->bridge)
- memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
- poperror();
- bp->wp += n;
-
- return etheroq(ether, bp);
-}
-
-static long
-etherbwrite(Chan* chan, Block* bp, ulong)
-{
- Ether *ether;
- long n;
-
- n = BLEN(bp);
- if(NETTYPE(chan->qid.path) != Ndataqid){
- if(waserror()) {
- freeb(bp);
- nexterror();
- }
- n = etherwrite(chan, bp->rp, n, 0);
- poperror();
- freeb(bp);
- return n;
- }
- ether = etherxx[chan->dev];
-
- if(n > ether->maxmtu){
- freeb(bp);
- error(Etoobig);
- }
- if(n < ether->minmtu){
- freeb(bp);
- error(Etoosmall);
- }
-
- return etheroq(ether, bp);
-}
-
-static struct {
- char* type;
- int (*reset)(Ether*);
-} cards[MaxEther+1];
-
-void
-addethercard(char* t, int (*r)(Ether*))
-{
- static int ncard;
-
- if(ncard == MaxEther)
- panic("too many ether cards");
- cards[ncard].type = t;
- cards[ncard].reset = r;
- ncard++;
-}
-
-static void
-etherreset(void)
-{
- Ether *ether;
- int i, n, ctlrno;
- char name[32], buf[128];
-
- for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
- if(ether == 0)
- ether = malloc(sizeof(Ether));
- memset(ether, 0, sizeof(Ether));
- ether->ctlrno = ctlrno;
- ether->tbdf = BUSUNKNOWN;
- ether->mbps = 10;
- ether->minmtu = ETHERMINTU;
- ether->maxmtu = ETHERMAXTU;
- if(isaconfig("ether", ctlrno, ether) == 0)
- continue;
- for(n = 0; cards[n].type; n++){
- if(cistrcmp(cards[n].type, ether->type))
- continue;
- for(i = 0; i < ether->nopt; i++){
- if(strncmp(ether->opt[i], "ea=", 3))
- continue;
- if(parseether(ether->ea, ðer->opt[i][3]) == -1)
- memset(ether->ea, 0, Eaddrlen);
- }
- if(cards[n].reset(ether))
- break;
-
- /*
- * IRQ2 doesn't really exist, it's used to gang the interrupt
- * controllers together. A device set to IRQ2 will appear on
- * the second interrupt controller as IRQ9.
- */
- if(ether->irq == 2 && BUSTYPE(ether->tbdf) != BusPCI)
- ether->irq = 9;
- snprint(name, sizeof(name), "ether%d", ctlrno);
-
- /*
- * If ether->irq is <0, it is a hack to indicate no interrupt
- * used by ethersink.
- */
- if(ether->irq >= 0)
- intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name);
-
- i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
- ctlrno, ether->type, ether->mbps, ether->port, ether->irq);
- if(ether->mem)
- i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem));
- if(ether->size)
- i += sprint(buf+i, " size 0x%luX", ether->size);
- i += sprint(buf+i, ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
- ether->ea[0], ether->ea[1], ether->ea[2],
- ether->ea[3], ether->ea[4], ether->ea[5]);
- sprint(buf+i, "\n");
- print(buf);
-
- if(ether->mbps >= 100){
- netifinit(ether, name, Ntypes, 256*1024);
- if(ether->oq == 0)
- ether->oq = qopen(256*1024, Qmsg, 0, 0);
- }
- else{
- netifinit(ether, name, Ntypes, 65*1024);
- if(ether->oq == 0)
- ether->oq = qopen(65*1024, Qmsg, 0, 0);
- }
- if(ether->oq == 0)
- panic("etherreset %s", name);
- ether->alen = Eaddrlen;
- memmove(ether->addr, ether->ea, Eaddrlen);
- memset(ether->bcast, 0xFF, Eaddrlen);
-
- etherxx[ctlrno] = ether;
- ether = 0;
- break;
- }
- }
- if(ether)
- free(ether);
-}
-
-#define POLY 0xedb88320
-
-/* really slow 32 bit crc for ethers */
-ulong
-ethercrc(uchar *p, int len)
-{
- int i, j;
- ulong crc, b;
-
- crc = 0xffffffff;
- for(i = 0; i < len; i++){
- b = *p++;
- for(j = 0; j < 8; j++){
- crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
- b >>= 1;
- }
- }
- return crc;
-}
-
-Dev etherdevtab = {
- 'l',
- "ether",
-
- etherreset,
- devinit,
- devshutdown,
- etherattach,
- etherwalk,
- etherstat,
- etheropen,
- ethercreate,
- etherclose,
- etherread,
- etherbread,
- etherwrite,
- etherbwrite,
- devremove,
- etherwstat,
-};
--- a/sys/src/9/mtx/ether2114x.c
+++ b/sys/src/9/mtx/ether2114x.c
@@ -16,9 +16,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
-
#define DEBUG (0)
#define debug if(DEBUG)print
@@ -1654,11 +1653,12 @@
*/
ether->attach = attach;
ether->transmit = transmit;
- ether->interrupt = interrupt;
ether->ifstat = ifstat;
ether->arg = ether;
ether->promiscuous = promiscuous;
+
+ intrenable(ether->irq, interrupt, ether, ether->tbdf, ether->name);
return 0;
}
--- a/sys/src/9/mtx/etherif.h
+++ /dev/null
@@ -1,35 +1,0 @@
-enum {
- MaxEther = 24,
- Ntypes = 8,
-};
-
-typedef struct Ether Ether;
-struct Ether {
- ISAConf; /* hardware info */
-
- int ctlrno;
- int tbdf; /* type+busno+devno+funcno */
- int minmtu;
- int maxmtu;
- uchar ea[Eaddrlen];
-
- void (*attach)(Ether*); /* filled in by reset routine */
- void (*transmit)(Ether*);
- void (*interrupt)(Ureg*, void*);
- long (*ifstat)(Ether*, void*, long, ulong);
- long (*ctl)(Ether*, void*, long); /* custom ctl messages */
- void *ctlr;
-
- Queue* oq;
-
- Netif;
-};
-
-extern Block* etheriq(Ether*, Block*, int);
-extern void addethercard(char*, int(*)(Ether*));
-extern ulong ethercrc(uchar*, int);
-
-#define NEXT(x, l) (((x)+1)%(l))
-#define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1)
-#define HOWMANY(x, y) (((x)+((y)-1))/(y))
-#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y))
--- a/sys/src/9/mtx/mkfile
+++ b/sys/src/9/mtx/mkfile
@@ -82,7 +82,7 @@
main.$O: /$objtype/include/ureg.h errstr.h init.h
trap.$O: /$objtype/include/ureg.h
-$ETHER: etherif.h ../port/netif.h
+$ETHER: ../port/etherif.h ../port/netif.h
init.h: initcode /sys/src/libc/9syscall/sys.h
$AS initcode
--- a/sys/src/9/omap/archomap.c
+++ b/sys/src/9/omap/archomap.c
@@ -15,7 +15,7 @@
#include "arm.h"
#include "../port/netif.h"
-#include "etherif.h"
+#include "../port/etherif.h"
#include "../port/flashif.h"
#include "../port/usb.h"
#include "../port/portusbehci.h"
--- a/sys/src/9/omap/dat.h
+++ b/sys/src/9/omap/dat.h
@@ -240,6 +240,8 @@
char *opt[NISAOPT];
};
+#define BUSUNKNOWN -1
+
#define MACHP(n) (machaddr[n])
/*
--- a/sys/src/9/omap/devether.c
+++ /dev/null
@@ -1,504 +1,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "../port/error.h"
-
-#include "../port/netif.h"
-#include "etherif.h"
-
-extern int archether(unsigned ctlno, Ether *ether);
-
-static Ether *etherxx[MaxEther];
-
-Chan*
-etherattach(char* spec)
-{
- int ctlrno;
- char *p;
- Chan *chan;
-
- ctlrno = 0;
- if(spec && *spec){
- ctlrno = strtoul(spec, &p, 0);
- if((ctlrno == 0 && p == spec) || *p != 0)
- error(Ebadarg);
- if(ctlrno < 0 || ctlrno >= MaxEther)
- error(Ebadarg);
- }
- if(etherxx[ctlrno] == 0)
- error(Enodev);
-
- chan = devattach('l', spec);
- if(waserror()){
- chanfree(chan);
- nexterror();
- }
- chan->dev = ctlrno;
- if(etherxx[ctlrno]->attach)
- etherxx[ctlrno]->attach(etherxx[ctlrno]);
- poperror();
- return chan;
-}
-
-static Walkqid*
-etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
-{
- return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
-}
-
-static int
-etherstat(Chan* chan, uchar* dp, int n)
-{
- return netifstat(etherxx[chan->dev], chan, dp, n);
-}
-
-static Chan*
-etheropen(Chan* chan, int omode)
-{
- return netifopen(etherxx[chan->dev], chan, omode);
-}
-
-static Chan*
-ethercreate(Chan*, char*, int, ulong)
-{
- error(Eperm);
- return 0;
-}
-
-static void
-etherclose(Chan* chan)
-{
- netifclose(etherxx[chan->dev], chan);
-}
-
-static long
-etherread(Chan* chan, void* buf, long n, vlong off)
-{
- Ether *ether;
- ulong offset = off;
-
- ether = etherxx[chan->dev];
- if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
- /*
- * With some controllers it is necessary to reach
- * into the chip to extract statistics.
- */
- if(NETTYPE(chan->qid.path) == Nifstatqid)
- return ether->ifstat(ether, buf, n, offset);
- else if(NETTYPE(chan->qid.path) == Nstatqid)
- ether->ifstat(ether, buf, 0, offset);
- }
-
- return netifread(ether, chan, buf, n, offset);
-}
-
-static Block*
-etherbread(Chan* chan, long n, ulong offset)
-{
- return netifbread(etherxx[chan->dev], chan, n, offset);
-}
-
-static int
-etherwstat(Chan* chan, uchar* dp, int n)
-{
- return netifwstat(etherxx[chan->dev], chan, dp, n);
-}
-
-static void
-etherrtrace(Netfile* f, Etherpkt* pkt, int len)
-{
- int i, n;
- Block *bp;
-
- if(qwindow(f->in) <= 0)
- return;
- if(len > 58)
- n = 58;
- else
- n = len;
- bp = iallocb(64);
- if(bp == nil)
- return;
- memmove(bp->wp, pkt->d, n);
- i = TK2MS(MACHP(0)->ticks);
- bp->wp[58] = len>>8;
- bp->wp[59] = len;
- bp->wp[60] = i>>24;
- bp->wp[61] = i>>16;
- bp->wp[62] = i>>8;
- bp->wp[63] = i;
- bp->wp += 64;
- qpass(f->in, bp);
-}
-
-Block*
-etheriq(Ether* ether, Block* bp, int fromwire)
-{
- Etherpkt *pkt;
- ushort type;
- int len, multi, tome, fromme;
- Netfile **ep, *f, **fp, *fx;
- Block *xbp;
-
- ether->inpackets++;
-
- pkt = (Etherpkt*)bp->rp;
- len = BLEN(bp);
- type = (pkt->type[0]<<8)|pkt->type[1];
- fx = 0;
- ep = ðer->f[Ntypes];
-
- multi = pkt->d[0] & 1;
- /* check for valid multicast addresses */
- if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 &&
- ether->prom == 0){
- if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
- if(fromwire){
- freeb(bp);
- bp = 0;
- }
- return bp;
- }
- }
- /* is it for me? */
- tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
- fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
-
- /*
- * Multiplex the packet to all the connections which want it.
- * If the packet is not to be used subsequently (fromwire != 0),
- * attempt to simply pass it into one of the connections, thereby
- * saving a copy of the data (usual case hopefully).
- */
- for(fp = ether->f; fp < ep; fp++){
- if((f = *fp) != nil && (f->type == type || f->type < 0) &&
- (tome || multi || f->prom)){
- /* Don't want to hear loopback or bridged packets */
- if(f->bridge && (tome || !fromwire && !fromme))
- continue;
- if(!f->headersonly){
- if(fromwire && fx == 0)
- fx = f;
- else if(xbp = iallocb(len)){
- memmove(xbp->wp, pkt, len);
- xbp->wp += len;
- if(qpass(f->in, xbp) < 0)
- ether->soverflows++;
- }
- else
- ether->soverflows++;
- }
- else
- etherrtrace(f, pkt, len);
- }
- }
-
- if(fx){
- if(qpass(fx->in, bp) < 0)
- ether->soverflows++;
- return 0;
- }
- if(fromwire){
- freeb(bp);
- return 0;
- }
- return bp;
-}
-
-static int
-etheroq(Ether* ether, Block* bp)
-{
- int len, loopback;
- Etherpkt *pkt;
-
- ether->outpackets++;
-
- /*
- * Check if the packet has to be placed back onto the input queue,
- * i.e. if it's a loopback or broadcast packet or the interface is
- * in promiscuous mode.
- * If it's a loopback packet indicate to etheriq that the data isn't
- * needed and return, etheriq will pass-on or free the block.
- * To enable bridging to work, only packets that were originated
- * by this interface are fed back.
- */
- pkt = (Etherpkt*)bp->rp;
- len = BLEN(bp);
- loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
- if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom)
- if(etheriq(ether, bp, loopback) == 0)
- return len;
-
- qbwrite(ether->oq, bp);
- if(ether->transmit != nil)
- ether->transmit(ether);
- return len;
-}
-
-static long
-etherwrite(Chan* chan, void* buf, long n, vlong)
-{
- Ether *ether;
- Block *bp;
- int nn, onoff;
- Cmdbuf *cb;
-
- ether = etherxx[chan->dev];
- if(NETTYPE(chan->qid.path) != Ndataqid) {
- nn = netifwrite(ether, chan, buf, n);
- if(nn >= 0)
- return nn;
- cb = parsecmd(buf, n);
- if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
- if(cb->nf <= 1)
- onoff = 1;
- else
- onoff = atoi(cb->f[1]);
- qnoblock(ether->oq, onoff);
- free(cb);
- return n;
- }
- free(cb);
- if(ether->ctl!=nil)
- return ether->ctl(ether,buf,n);
-
- error(Ebadctl);
- }
-
- if(n > ether->maxmtu)
- error(Etoobig);
- if(n < ether->minmtu)
- error(Etoosmall);
-
- bp = allocb(n);
- if(waserror()){
- freeb(bp);
- nexterror();
- }
- memmove(bp->rp, buf, n);
- if(!ether->f[NETID(chan->qid.path)]->bridge)
- memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
- poperror();
- bp->wp += n;
-
- return etheroq(ether, bp);
-}
-
-static long
-etherbwrite(Chan* chan, Block* bp, ulong)
-{
- Ether *ether;
- long n;
-
- n = BLEN(bp);
- if(NETTYPE(chan->qid.path) != Ndataqid){
- if(waserror()) {
- freeb(bp);
- nexterror();
- }
- n = etherwrite(chan, bp->rp, n, 0);
- poperror();
- freeb(bp);
- return n;
- }
- ether = etherxx[chan->dev];
-
- if(n > ether->maxmtu){
- freeb(bp);
- error(Etoobig);
- }
- if(n < ether->minmtu){
- freeb(bp);
- error(Etoosmall);
- }
-
- return etheroq(ether, bp);
-}
-
-static struct {
- char* type;
- int (*reset)(Ether*);
-} cards[MaxEther+1];
-
-void
-addethercard(char* t, int (*r)(Ether*))
-{
- static int ncard;
-
- if(ncard == MaxEther)
- panic("too many ether cards");
- cards[ncard].type = t;
- cards[ncard].reset = r;
- ncard++;
-}
-
-static void
-etherreset(void)
-{
- Ether *ether;
- int i, n, ctlrno;
- char name[KNAMELEN], buf[128];
-
- for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
- if(ether == 0)
- ether = malloc(sizeof(Ether));
- memset(ether, 0, sizeof(Ether));
- ether->ctlrno = ctlrno;
- ether->mbps = 10;
- ether->minmtu = ETHERMINTU;
- ether->maxmtu = ETHERMAXTU;
-
- if(archether(ctlrno, ether) <= 0)
- continue;
-
- if(isaconfig("ether", ctlrno, ether) == 0){
-// free(ether);
-// return nil;
- continue;
- }
- for(n = 0; cards[n].type; n++){
- if(cistrcmp(cards[n].type, ether->type))
- continue;
- for(i = 0; i < ether->nopt; i++)
- if(cistrncmp(ether->opt[i], "ea=", 3) == 0){
- if(parseether(ether->ea,
- ðer->opt[i][3]) == -1)
- memset(ether->ea, 0, Eaddrlen);
- } else if(cistrcmp(ether->opt[i],
- "100BASE-TXFD") == 0)
- ether->mbps = 100;
- if(cards[n].reset(ether))
- break;
- snprint(name, sizeof(name), "ether%d", ctlrno);
-
- if(ether->interrupt != nil && ether->irq >= 0)
- intrenable(ether->irq, ether->interrupt,
- ether, 0, name);
-
- i = snprint(buf, sizeof buf,
- "#l%d: %s: %dMbps port %#lux irq %d",
- ctlrno, ether->type, ether->mbps, ether->port,
- ether->irq);
- if(ether->mem)
- i += snprint(buf+i, sizeof buf - i,
- " addr %#lux", PADDR(ether->mem));
- if(ether->size)
- i += snprint(buf+i, sizeof buf - i,
- " size %#luX", ether->size);
- i += snprint(buf+i, sizeof buf - i,
- ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
- ether->ea[0], ether->ea[1], ether->ea[2],
- ether->ea[3], ether->ea[4], ether->ea[5]);
- snprint(buf+i, sizeof buf - i, "\n");
- iprint("%s", buf); /* it may be too early for print */
-
- if(ether->mbps >= 1000)
- netifinit(ether, name, Ntypes, 4*1024*1024);
- else if(ether->mbps >= 100)
- netifinit(ether, name, Ntypes, 1024*1024);
- else
- netifinit(ether, name, Ntypes, 65*1024);
- if(ether->oq == 0)
- ether->oq = qopen(ether->limit, Qmsg, 0, 0);
- if(ether->oq == 0)
- panic("etherreset %s", name);
- ether->alen = Eaddrlen;
- memmove(ether->addr, ether->ea, Eaddrlen);
- memset(ether->bcast, 0xFF, Eaddrlen);
-
- etherxx[ctlrno] = ether;
- ether = 0;
- break;
- }
- }
- if(ether)
- free(ether);
-}
-
-static void
-ethershutdown(void)
-{
- Ether *ether;
- int i;
-
- for(i = 0; i < MaxEther; i++){
- ether = etherxx[i];
- if(ether == nil)
- continue;
- if(ether->shutdown == nil) {
- print("#l%d: no shutdown function\n", i);
- continue;
- }
- (*ether->shutdown)(ether);
- }
-}
-
-
-#define POLY 0xedb88320
-
-/* really slow 32 bit crc for ethers */
-ulong
-ethercrc(uchar *p, int len)
-{
- int i, j;
- ulong crc, b;
-
- crc = 0xffffffff;
- for(i = 0; i < len; i++){
- b = *p++;
- for(j = 0; j < 8; j++){
- crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
- b >>= 1;
- }
- }
- return crc;
-}
-
-void
-dumpoq(Queue *oq)
-{
- if (oq == nil)
- print("no outq! ");
- else if (qisclosed(oq))
- print("outq closed ");
- else if (qfull(oq))
- print("outq full ");
- else
- print("outq %d ", qlen(oq));
-}
-
-void
-dumpnetif(Netif *netif)
-{
- print("netif %s ", netif->name);
- print("limit %d mbps %d link %d ",
- netif->limit, netif->mbps, netif->link);
- print("inpkts %lld outpkts %lld errs %d\n",
- netif->inpackets, netif->outpackets,
- netif->crcs + netif->oerrs + netif->frames + netif->overflows +
- netif->buffs + netif->soverflows);
-}
-
-Dev etherdevtab = {
- 'l',
- "ether",
-
- etherreset,
- devinit,
- ethershutdown,
- etherattach,
- etherwalk,
- etherstat,
- etheropen,
- ethercreate,
- etherclose,
- etherread,
- etherbread,
- etherwrite,
- etherbwrite,
- devremove,
- etherwstat,
-};
--- a/sys/src/9/omap/dma.c
+++ b/sys/src/9/omap/dma.c
@@ -235,7 +235,7 @@
*done = 0;
iunlock(&alloclck);
- ruplen = ROUNDUP(len, sizeof(ulong));
+ ruplen = ROUND(len, sizeof(ulong));
assert(to != from);
cp = regs->chan + chan;
--- a/sys/src/9/omap/ether9221.c
+++ b/sys/src/9/omap/ether9221.c
@@ -18,9 +18,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
-
/* currently using kprocs is a lot slower than not (87 s. to boot vs 60) */
#undef USE_KPROCS
@@ -943,7 +942,6 @@
*/
edev->attach = smcattach;
edev->transmit = smctransmitcall;
- edev->interrupt = smcinterrupt;
edev->ifstat = smcifstat;
/* edev->ctl = smcctl; /* no ctl msgs supported */
@@ -951,6 +949,9 @@
edev->promiscuous = smcpromiscuous;
edev->multicast = smcmulticast;
edev->shutdown = smcshutdown;
+
+ intrenable(edev->irq, smcinterrupt, edev, 0, edev->name);
+
return 0;
}
--- a/sys/src/9/omap/etherif.h
+++ /dev/null
@@ -1,41 +1,0 @@
-enum
-{
- MaxEther = 4,
- Ntypes = 8,
-};
-
-typedef struct Ether Ether;
-struct Ether {
- RWlock;
- ISAConf; /* hardware info */
-
- int ctlrno;
- int minmtu;
- int maxmtu;
-
- Netif;
-
- void (*attach)(Ether*); /* filled in by reset routine */
- void (*detach)(Ether*);
- void (*transmit)(Ether*);
- void (*interrupt)(Ureg*, void*);
- long (*ifstat)(Ether*, void*, long, ulong);
- long (*ctl)(Ether*, void*, long); /* custom ctl messages */
- void (*power)(Ether*, int); /* power on/off */
- void (*shutdown)(Ether*); /* shutdown hardware before reboot */
-
- void* ctlr;
- uchar ea[Eaddrlen];
- void* address;
- int irq;
-
- Queue* oq;
-};
-
-extern Block* etheriq(Ether*, Block*, int);
-extern void addethercard(char*, int(*)(Ether*));
-extern ulong ethercrc(uchar*, int);
-extern int parseether(uchar*, char*);
-
-#define NEXT(x, l) (((x)+1)%(l))
-#define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1)
--- a/sys/src/9/omap/mem.h
+++ b/sys/src/9/omap/mem.h
@@ -5,9 +5,6 @@
#define MiB 1048576u /* Mebi 0x0000000000100000 */
#define GiB 1073741824u /* Gibi 000000000040000000 */
-#define HOWMANY(x, y) (((x)+((y)-1))/(y))
-#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y)) /* ceiling */
-#define ROUNDDN(x, y) (((x)/(y))*(y)) /* floor */
#define MIN(a, b) ((a) < (b)? (a): (b))
#define MAX(a, b) ((a) > (b)? (a): (b))
@@ -36,7 +33,7 @@
*/
#define BY2PG (4*KiB) /* bytes per page */
#define PGSHIFT 12 /* log(BY2PG) */
-#define PGROUND(s) ROUNDUP(s, BY2PG)
+#define PGROUND(s) ROUND(s, BY2PG)
#define ROUND(s, sz) (((s)+(sz-1))&~(sz-1))
#define MAXMACH 1 /* max # cpus system can run */
@@ -71,7 +68,7 @@
#define UZERO 0 /* user segment */
#define UTZERO (UZERO+BY2PG) /* user text start */
-#define UTROUND(t) ROUNDUP((t), BY2PG)
+
/* moved USTKTOP down to 512MB to keep MMIO space out of user space. */
#define USTKTOP 0x20000000 /* user segment end +1 */
#define USTKSIZE (8*1024*1024) /* user stack size */
--- a/sys/src/9/omap/mkfile
+++ b/sys/src/9/omap/mkfile
@@ -101,7 +101,7 @@
arch.$O clock.$O fpiarm.$O main.$O mmu.$O screen.$O sdscsi.$O syscall.$O \
trap.$O: /$objtype/include/ureg.h
-archomap.$O devether.$0 ether9221.$O: etherif.h ../port/netif.h
+archomap.$O devether.$0 ether9221.$O: ../port/etherif.h ../port/netif.h
archomap.$O devflash.$O flashbeagle.$O flashigep.$O: ../port/flashif.h
ecc.$O flashbeagle.$O flashigep.$O: ../port/nandecc.h io.h
fpi.$O fpiarm.$O fpimem.$O: fpi.h
--- a/sys/src/9/omap/mmu.c
+++ b/sys/src/9/omap/mmu.c
@@ -439,7 +439,7 @@
o = pa & (BY2PG-1);
pa -= o;
size += o;
- size = ROUNDUP(size, BY2PG);
+ size = PGROUND(size);
va = kseg0|pa;
pae = mmukmap(va, pa, size);
--- a/sys/src/9/omap/screen.c
+++ b/sys/src/9/omap/screen.c
@@ -257,7 +257,7 @@
(sp->vsw-1);
dispc->pol_req = Ipc | Ihs | Ivs | Acb;
- dispc->divisor = 1 << 16 | HOWMANY(432000, sp->pixelclock);
+ dispc->divisor = 1 << 16 | ((432000+sp->pixelclock-1)/sp->pixelclock);
dispc->lcdsize = (sp->ht - 1) << 16 | (sp->wid - 1);
coherence();
--- a/sys/src/9/pc/devether.c
+++ /dev/null
@@ -1,672 +1,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "pool.h"
-#include "ureg.h"
-#include "../port/error.h"
-#include "../port/netif.h"
-
-#include "etherif.h"
-
-static Ether *etherxx[MaxEther];
-
-Chan*
-etherattach(char* spec)
-{
- ulong ctlrno;
- char *p;
- Chan *chan;
-
- ctlrno = 0;
- if(spec && *spec){
- ctlrno = strtoul(spec, &p, 0);
- if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther))
- error(Ebadarg);
- }
- if(etherxx[ctlrno] == 0)
- error(Enodev);
-
- chan = devattach('l', spec);
- if(waserror()){
- chanfree(chan);
- nexterror();
- }
- chan->dev = ctlrno;
- if(etherxx[ctlrno]->attach)
- etherxx[ctlrno]->attach(etherxx[ctlrno]);
- poperror();
- return chan;
-}
-
-static Walkqid*
-etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
-{
- return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
-}
-
-static int
-etherstat(Chan* chan, uchar* dp, int n)
-{
- return netifstat(etherxx[chan->dev], chan, dp, n);
-}
-
-static Chan*
-etheropen(Chan* chan, int omode)
-{
- return netifopen(etherxx[chan->dev], chan, omode);
-}
-
-static Chan*
-ethercreate(Chan*, char*, int, ulong)
-{
- error(Eperm);
- return 0;
-}
-
-static void
-etherclose(Chan* chan)
-{
- netifclose(etherxx[chan->dev], chan);
-}
-
-static long
-etherread(Chan* chan, void* buf, long n, vlong off)
-{
- Ether *ether;
- ulong offset = off;
-
- ether = etherxx[chan->dev];
- if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
- /*
- * With some controllers it is necessary to reach
- * into the chip to extract statistics.
- */
- if(NETTYPE(chan->qid.path) == Nifstatqid)
- return ether->ifstat(ether, buf, n, offset);
- else if(NETTYPE(chan->qid.path) == Nstatqid)
- ether->ifstat(ether, buf, 0, offset);
- }
-
- return netifread(ether, chan, buf, n, offset);
-}
-
-static Block*
-etherbread(Chan* chan, long n, ulong offset)
-{
- return netifbread(etherxx[chan->dev], chan, n, offset);
-}
-
-static int
-etherwstat(Chan* chan, uchar* dp, int n)
-{
- return netifwstat(etherxx[chan->dev], chan, dp, n);
-}
-
-static void
-etherrtrace(Netfile* f, Etherpkt* pkt, int len)
-{
- int i, n;
- Block *bp;
-
- if(qwindow(f->in) <= 0)
- return;
- if(len > 58)
- n = 58;
- else
- n = len;
- bp = iallocb(64);
- if(bp == nil)
- return;
- memmove(bp->wp, pkt->d, n);
- i = TK2MS(MACHP(0)->ticks);
- bp->wp[58] = len>>8;
- bp->wp[59] = len;
- bp->wp[60] = i>>24;
- bp->wp[61] = i>>16;
- bp->wp[62] = i>>8;
- bp->wp[63] = i;
- bp->wp += 64;
- qpass(f->in, bp);
-}
-
-Block*
-etheriq(Ether* ether, Block* bp, int fromwire)
-{
- Etherpkt *pkt;
- ushort type;
- int len, multi, tome, fromme;
- Netfile **ep, *f, **fp, *fx;
- Block *xbp;
-
- ether->inpackets++;
-
- pkt = (Etherpkt*)bp->rp;
- len = BLEN(bp);
- type = (pkt->type[0]<<8)|pkt->type[1];
- fx = 0;
- ep = ðer->f[Ntypes];
-
- multi = pkt->d[0] & 1;
- /* check for valid multicast addresses */
- if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 && ether->prom == 0){
- if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
- if(fromwire){
- freeb(bp);
- bp = 0;
- }
- return bp;
- }
- }
-
- /* is it for me? */
- tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
- fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
-
- /*
- * Multiplex the packet to all the connections which want it.
- * If the packet is not to be used subsequently (fromwire != 0),
- * attempt to simply pass it into one of the connections, thereby
- * saving a copy of the data (usual case hopefully).
- */
- for(fp = ether->f; fp < ep; fp++){
- if(f = *fp)
- if(f->type == type || f->type < 0)
- if(tome || multi || f->prom){
- /* Don't want to hear loopback or bridged packets */
- if(f->bridge && (tome || !fromwire && !fromme))
- continue;
- if(!f->headersonly){
- if(fromwire && fx == 0)
- fx = f;
- else if(xbp = iallocb(len)){
- memmove(xbp->wp, pkt, len);
- xbp->wp += len;
- xbp->flag = bp->flag;
- if(qpass(f->in, xbp) < 0) {
- // print("soverflow for f->in\n");
- ether->soverflows++;
- }
- }
- else {
- // print("soverflow iallocb\n");
- ether->soverflows++;
- }
- }
- else
- etherrtrace(f, pkt, len);
- }
- }
-
- if(fx){
- if(qpass(fx->in, bp) < 0) {
- // print("soverflow for fx->in\n");
- ether->soverflows++;
- }
- return 0;
- }
- if(fromwire){
- freeb(bp);
- return 0;
- }
-
- return bp;
-}
-
-static int
-etheroq(Ether* ether, Block* bp)
-{
- int len, loopback;
- Etherpkt *pkt;
-
- ether->outpackets++;
-
- /*
- * Check if the packet has to be placed back onto the input queue,
- * i.e. if it's a loopback or broadcast packet or the interface is
- * in promiscuous mode.
- * If it's a loopback packet indicate to etheriq that the data isn't
- * needed and return, etheriq will pass-on or free the block.
- * To enable bridging to work, only packets that were originated
- * by this interface are fed back.
- */
- pkt = (Etherpkt*)bp->rp;
- len = BLEN(bp);
- loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
- if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom)
- if(etheriq(ether, bp, loopback) == 0)
- return len;
-
- qbwrite(ether->oq, bp);
- if(ether->transmit != nil)
- ether->transmit(ether);
- return len;
-}
-
-static long
-etherwrite(Chan* chan, void* buf, long n, vlong)
-{
- Ether *ether;
- Block *bp;
- int nn, onoff;
- Cmdbuf *cb;
-
- ether = etherxx[chan->dev];
- if(NETTYPE(chan->qid.path) != Ndataqid) {
- nn = netifwrite(ether, chan, buf, n);
- if(nn >= 0)
- return nn;
- cb = parsecmd(buf, n);
- if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
- if(cb->nf <= 1)
- onoff = 1;
- else
- onoff = atoi(cb->f[1]);
- qnoblock(ether->oq, onoff);
- free(cb);
- return n;
- }
- free(cb);
- if(ether->ctl!=nil)
- return ether->ctl(ether,buf,n);
-
- error(Ebadctl);
- }
-
- if(n > ether->maxmtu)
- error(Etoobig);
- if(n < ether->minmtu)
- error(Etoosmall);
-
- bp = allocb(n);
- if(waserror()){
- freeb(bp);
- nexterror();
- }
- memmove(bp->rp, buf, n);
- if(!ether->f[NETID(chan->qid.path)]->bridge)
- memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
- poperror();
- bp->wp += n;
-
- return etheroq(ether, bp);
-}
-
-static long
-etherbwrite(Chan* chan, Block* bp, ulong)
-{
- Ether *ether;
- long n;
-
- n = BLEN(bp);
- if(NETTYPE(chan->qid.path) != Ndataqid){
- if(waserror()) {
- freeb(bp);
- nexterror();
- }
- n = etherwrite(chan, bp->rp, n, 0);
- poperror();
- freeb(bp);
- return n;
- }
- ether = etherxx[chan->dev];
-
- if(n > ether->maxmtu){
- freeb(bp);
- error(Etoobig);
- }
- if(n < ether->minmtu){
- freeb(bp);
- error(Etoosmall);
- }
-
- return etheroq(ether, bp);
-}
-
-static struct {
- char* type;
- int (*reset)(Ether*);
-} cards[MaxEther+1];
-
-void
-addethercard(char* t, int (*r)(Ether*))
-{
- static int ncard;
-
- if(ncard == MaxEther)
- panic("too many ether cards");
- cards[ncard].type = t;
- cards[ncard].reset = r;
- ncard++;
-}
-
-static Ether*
-etherprobe(int cardno, int ctlrno)
-{
- int i, lg;
- ulong mb, bsz;
- Ether *ether;
- char buf[128], name[32];
-
- ether = malloc(sizeof(Ether));
- if(ether == nil){
- print("etherprobe: no memory for Ether\n");
- return nil;
- }
- memset(ether, 0, sizeof(Ether));
- ether->ctlrno = ctlrno;
- ether->tbdf = BUSUNKNOWN;
- ether->mbps = 10;
- ether->minmtu = ETHERMINTU;
- ether->maxmtu = ETHERMAXTU;
-
- if(cardno < 0){
- if(isaconfig("ether", ctlrno, ether) == 0){
- free(ether);
- return nil;
- }
- for(cardno = 0; cards[cardno].type; cardno++){
- if(cistrcmp(cards[cardno].type, ether->type))
- continue;
- for(i = 0; i < ether->nopt; i++){
- if(strncmp(ether->opt[i], "ea=", 3))
- continue;
- if(parseether(ether->ea, ðer->opt[i][3]))
- memset(ether->ea, 0, Eaddrlen);
- }
- break;
- }
- }
-
- if(cardno >= MaxEther || cards[cardno].type == nil){
- free(ether);
- return nil;
- }
- if(cards[cardno].reset(ether) < 0){
- free(ether);
- return nil;
- }
-
- /*
- * IRQ2 doesn't really exist, it's used to gang the interrupt
- * controllers together. A device set to IRQ2 will appear on
- * the second interrupt controller as IRQ9.
- */
- if(ether->irq == 2)
- ether->irq = 9;
- snprint(name, sizeof(name), "ether%d", ctlrno);
-
- /*
- * If ether->irq is <0, it is a hack to indicate no interrupt
- * used by ethersink.
- */
- if(ether->irq >= 0)
- intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name);
-
- i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
- ctlrno, cards[cardno].type, ether->mbps, ether->port, ether->irq);
- if(ether->mem)
- i += sprint(buf+i, " addr 0x%luX", ether->mem);
- if(ether->size)
- i += sprint(buf+i, " size 0x%luX", ether->size);
- i += sprint(buf+i, ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
- ether->ea[0], ether->ea[1], ether->ea[2],
- ether->ea[3], ether->ea[4], ether->ea[5]);
- sprint(buf+i, "\n");
- print(buf);
-
- /* compute log10(ether->mbps) into lg */
- for(lg = 0, mb = ether->mbps; mb >= 10; lg++)
- mb /= 10;
- if (lg > 0)
- lg--;
- if (lg > 14) /* 2^(14+17) = 2³¹ */
- lg = 14;
- /* allocate larger output queues for higher-speed interfaces */
- bsz = 1UL << (lg + 17); /* 2¹⁷ = 128K, bsz = 2ⁿ × 128K */
- while (bsz > mainmem->maxsize / 8 && bsz > 128*1024)
- bsz /= 2;
-
- netifinit(ether, name, Ntypes, bsz);
- if(ether->oq == nil) {
- ether->oq = qopen(bsz, Qmsg, 0, 0);
- ether->limit = bsz;
- }
- if(ether->oq == nil)
- panic("etherreset %s: can't allocate output queue of %ld bytes", name, bsz);
- ether->alen = Eaddrlen;
- memmove(ether->addr, ether->ea, Eaddrlen);
- memset(ether->bcast, 0xFF, Eaddrlen);
-
- return ether;
-}
-
-static void
-etherreset(void)
-{
- Ether *ether;
- int cardno, ctlrno;
-
- for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){
- if((ether = etherprobe(-1, ctlrno)) == nil)
- continue;
- etherxx[ctlrno] = ether;
- }
-
- if(getconf("*noetherprobe"))
- return;
-
- cardno = ctlrno = 0;
- while(cards[cardno].type != nil && ctlrno < MaxEther){
- if(etherxx[ctlrno] != nil){
- ctlrno++;
- continue;
- }
- if((ether = etherprobe(cardno, ctlrno)) == nil){
- cardno++;
- continue;
- }
- etherxx[ctlrno] = ether;
- ctlrno++;
- }
-}
-
-static void
-ethershutdown(void)
-{
- Ether *ether;
- int i;
-
- for(i = 0; i < MaxEther; i++){
- ether = etherxx[i];
- if(ether == nil)
- continue;
- if(ether->shutdown == nil) {
- print("#l%d: no shutdown function\n", i);
- continue;
- }
- (*ether->shutdown)(ether);
- }
-}
-
-
-#define POLY 0xedb88320
-
-/* really slow 32 bit crc for ethers */
-ulong
-ethercrc(uchar *p, int len)
-{
- int i, j;
- ulong crc, b;
-
- crc = 0xffffffff;
- for(i = 0; i < len; i++){
- b = *p++;
- for(j = 0; j < 8; j++){
- crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
- b >>= 1;
- }
- }
- return crc;
-}
-
-Dev etherdevtab = {
- 'l',
- "ether",
-
- etherreset,
- devinit,
- ethershutdown,
- etherattach,
- etherwalk,
- etherstat,
- etheropen,
- ethercreate,
- etherclose,
- etherread,
- etherbread,
- etherwrite,
- etherbwrite,
- devremove,
- etherwstat,
-};
-
-enum { PktHdr = 42 };
-typedef struct Netconsole Netconsole;
-struct Netconsole {
- char buf[512];
- int n;
- Lock;
- Ether *ether;
-};
-static Netconsole *netcons;
-
-extern ushort ipcsum(uchar *);
-
-void
-netconsputc(Uart *, int c)
-{
- char *p;
- u16int cs;
-
- ilock(netcons);
- netcons->buf[netcons->n++] = c;
- if(c != '\n' && netcons->n < sizeof(netcons->buf)){
- iunlock(netcons);
- return;
- }
- p = netcons->buf;
- p[16] = netcons->n - 14 >> 8;
- p[17] = netcons->n - 14;
- p[24] = 0;
- p[25] = 0;
- cs = ipcsum((uchar*) p + 14);
- p[24] = cs >> 8;
- p[25] = cs;
- p[38] = netcons->n - 34 >> 8;
- p[39] = netcons->n - 34;
- memmove(p+Eaddrlen, netcons->ether->ea, Eaddrlen);
- qiwrite(netcons->ether->oq, p, netcons->n);
- netcons->n = PktHdr;
- iunlock(netcons);
- if(netcons->ether->transmit != nil)
- netcons->ether->transmit(netcons->ether);
-}
-
-PhysUart netconsphys = {
- .putc = netconsputc,
-};
-Uart netconsuart = { .phys = &netconsphys };
-
-void
-netconsole(void)
-{
- char *p;
- char *r;
- int i;
- int srcport, devno, dstport;
- u8int srcip[4], dstip[4];
- u64int dstmac;
- Netconsole *nc;
-
- if((p = getconf("console")) == nil || strncmp(p, "net ", 4) != 0)
- return;
- p += 4;
- for(i = 0; i < 4; i++){
- srcip[i] = strtol(p, &r, 0);
- p = r + 1;
- if(i == 3) break;
- if(*r != '.') goto err;
- }
- if(*r == '!'){
- srcport = strtol(p, &r, 0);
- p = r + 1;
- }else
- srcport = 6665;
- if(*r == '/'){
- devno = strtol(p, &r, 0);
- p = r + 1;
- }else
- devno = 0;
- if(*r != ',') goto err;
- for(i = 0; i < 4; i++){
- dstip[i] = strtol(p, &r, 0);
- p = r + 1;
- if(i == 3) break;
- if(*r != '.') goto err;
- }
- if(*r == '!'){
- dstport = strtol(p, &r, 0);
- p = r + 1;
- }else
- dstport = 6666;
- if(*r == '/'){
- dstmac = strtoull(p, &r, 16);
- if(r - p != 12) goto err;
- }else
- dstmac = ((uvlong)-1) >> 16;
- if(*r != 0) goto err;
-
- if(devno >= MaxEther || etherxx[devno] == nil){
- print("netconsole: no device #l%d\n", devno);
- return;
- }
-
- nc = malloc(sizeof(Netconsole));
- if(nc == nil){
- print("netconsole: out of memory");
- return;
- }
- memset(nc, 0, sizeof(Netconsole));
- nc->ether = etherxx[devno];
-
- uchar header[PktHdr] = {
- /* 0 */ dstmac >> 40, dstmac >> 32, dstmac >> 24, dstmac >> 16, dstmac >> 8, dstmac >> 0,
- /* 6 */ 0, 0, 0, 0, 0, 0,
- /* 12 */ 0x08, 0x00,
- /* 14 */ 0x45, 0x00,
- /* 16 */ 0x00, 0x00, /* total length */
- /* 18 */ 0x00, 0x00, 0x00, 0x00,
- /* 22 */ 64, /* ttl */
- /* 23 */ 0x11, /* protocol */
- /* 24 */ 0x00, 0x00, /* checksum */
- /* 26 */ srcip[0], srcip[1], srcip[2], srcip[3],
- /* 30 */ dstip[0], dstip[1], dstip[2], dstip[3],
- /* 34 */ srcport >> 8, srcport, dstport >> 8, dstport,
- /* 38 */ 0x00, 0x00, /* length */
- /* 40 */ 0x00, 0x00 /* checksum */
- };
-
- memmove(nc->buf, header, PktHdr);
- nc->n = PktHdr;
-
- netcons = nc;
- consuart = &netconsuart;
- return;
-
-err:
- print("netconsole: invalid string %#q\n", getconf("console"));
- print("netconsole: usage: srcip[!srcport][/srcdev],dstip[!dstport][/dstmac]\n");
-}
--- a/sys/src/9/pc/ether2000.c
+++ b/sys/src/9/pc/ether2000.c
@@ -6,8 +6,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
#include "ether8390.h"
/*
--- a/sys/src/9/pc/ether2114x.c
+++ b/sys/src/9/pc/ether2114x.c
@@ -16,9 +16,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
-
#define DEBUG (0)
#define debug if(DEBUG)print
@@ -1818,7 +1817,6 @@
*/
ether->attach = attach;
ether->transmit = transmit;
- ether->interrupt = interrupt;
ether->ifstat = ifstat;
ether->arg = ether;
@@ -1825,6 +1823,8 @@
ether->shutdown = shutdown;
ether->multicast = multicast;
ether->promiscuous = promiscuous;
+
+ intrenable(ether->irq, interrupt, ether, ether->tbdf, ether->name);
return 0;
}
--- a/sys/src/9/pc/ether589.c
+++ b/sys/src/9/pc/ether589.c
@@ -11,8 +11,7 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
-
-#include "etherif.h"
+#include "../port/etherif.h"
enum { /* all windows */
CommandR = 0x000E,
--- a/sys/src/9/pc/ether79c970.c
+++ b/sys/src/9/pc/ether79c970.c
@@ -12,9 +12,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
-
enum {
Lognrdre = 6,
Nrdre = (1<<Lognrdre),/* receive descriptor ring entries */
@@ -672,7 +671,6 @@
*/
ether->attach = attach;
ether->transmit = transmit;
- ether->interrupt = interrupt;
ether->ifstat = ifstat;
ether->arg = ether;
@@ -679,6 +677,8 @@
ether->promiscuous = promiscuous;
ether->multicast = multicast;
// ether->shutdown = shutdown;
+
+ intrenable(ether->irq, interrupt, ether, ether->tbdf, ether->name);
return 0;
}
--- a/sys/src/9/pc/ether8003.c
+++ b/sys/src/9/pc/ether8003.c
@@ -6,8 +6,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
#include "ether8390.h"
/*
--- a/sys/src/9/pc/ether8139.c
+++ b/sys/src/9/pc/ether8139.c
@@ -11,9 +11,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
-
enum { /* registers */
Idr0 = 0x0000, /* MAC address */
Mar0 = 0x0008, /* Multicast address */
@@ -817,7 +816,6 @@
edev->attach = rtl8139attach;
edev->transmit = rtl8139transmit;
- edev->interrupt = rtl8139interrupt;
edev->ifstat = rtl8139ifstat;
edev->arg = edev;
@@ -824,6 +822,8 @@
edev->promiscuous = rtl8139promiscuous;
edev->multicast = rtl8139multicast;
// edev->shutdown = rtl8139shutdown;
+
+ intrenable(edev->irq, rtl8139interrupt, edev, edev->tbdf, edev->name);
/*
* This should be much more dynamic but will do for now.
--- a/sys/src/9/pc/ether8169.c
+++ b/sys/src/9/pc/ether8169.c
@@ -15,8 +15,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
#include "ethermii.h"
enum { /* registers */
@@ -1207,7 +1207,6 @@
edev->attach = rtl8169attach;
edev->transmit = rtl8169transmit;
- edev->interrupt = rtl8169interrupt;
edev->ifstat = rtl8169ifstat;
edev->arg = edev;
@@ -1215,6 +1214,8 @@
edev->multicast = rtl8169multicast;
rtl8169link(edev);
+
+ intrenable(edev->irq, rtl8169interrupt, edev, edev->tbdf, edev->name);
return 0;
}
--- a/sys/src/9/pc/ether82543gc.c
+++ b/sys/src/9/pc/ether82543gc.c
@@ -18,8 +18,7 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
-
-#include "etherif.h"
+#include "../port/etherif.h"
enum {
Ctrl = 0x00000000, /* Device Control */
--- a/sys/src/9/pc/ether82557.c
+++ b/sys/src/9/pc/ether82557.c
@@ -16,9 +16,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
-
enum {
Nrfd = 64, /* receive frame area */
Ncb = 64, /* maximum control blocks queued */
@@ -1332,7 +1331,6 @@
*/
ether->attach = attach;
ether->transmit = transmit;
- ether->interrupt = interrupt;
ether->ifstat = ifstat;
ether->shutdown = shutdown;
@@ -1339,6 +1337,8 @@
ether->promiscuous = promiscuous;
ether->multicast = multicast;
ether->arg = ether;
+
+ intrenable(ether->irq, interrupt, ether, ether->tbdf, ether->name);
return 0;
}
--- a/sys/src/9/pc/ether82563.c
+++ b/sys/src/9/pc/ether82563.c
@@ -11,9 +11,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
-
/*
* note: the 82575, 82576 and 82580 are operated using registers aliased
* to the 82563-style architecture. many features seen in the 82598
@@ -2105,7 +2104,6 @@
*/
edev->attach = i82563attach;
// edev->transmit = i82563transmit;
- edev->interrupt = i82563interrupt;
edev->ifstat = i82563ifstat;
edev->ctl = i82563ctl;
@@ -2113,6 +2111,8 @@
edev->promiscuous = i82563promiscuous;
edev->shutdown = i82563shutdown;
edev->multicast = i82563multicast;
+
+ intrenable(edev->irq, i82563interrupt, edev, edev->tbdf, edev->name);
return 0;
}
--- a/sys/src/9/pc/ether82598.c
+++ b/sys/src/9/pc/ether82598.c
@@ -10,7 +10,7 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
-#include "etherif.h"
+#include "../port/etherif.h"
/*
* // comments note conflicts with 82563-style drivers,
@@ -953,11 +953,12 @@
e->attach = attach;
e->ctl = ctl;
e->ifstat = ifstat;
- e->interrupt = interrupt;
e->multicast = multicast;
e->promiscuous = promiscuous;
e->shutdown = shutdown;
e->transmit = transmit;
+
+ intrenable(e->irq, interrupt, e, e->tbdf, e->name);
return 0;
}
--- a/sys/src/9/pc/ether83815.c
+++ b/sys/src/9/pc/ether83815.c
@@ -24,9 +24,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
-
#define DEBUG 0
#define debug if(DEBUG)print
@@ -1219,7 +1218,6 @@
*/
ether->attach = attach;
ether->transmit = transmit;
- ether->interrupt = interrupt;
ether->ifstat = ifstat;
ether->arg = ether;
@@ -1226,6 +1224,9 @@
ether->promiscuous = promiscuous;
ether->multicast = multicast;
ether->shutdown = shutdown;
+
+ intrenable(ether->irq, interrupt, ether, ether->tbdf, ether->name);
+
return 0;
}
--- a/sys/src/9/pc/ether8390.c
+++ b/sys/src/9/pc/ether8390.c
@@ -10,8 +10,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
#include "ether8390.h"
enum { /* NIC core registers */
@@ -801,12 +801,13 @@
*/
ether->attach = attach;
ether->transmit = transmit;
- ether->interrupt = interrupt;
ether->ifstat = 0;
ether->promiscuous = promiscuous;
ether->multicast = multicast;
ether->arg = ether;
+
+ intrenable(ether->irq, interrupt, ether, ether->tbdf, ether->name);
return 0;
}
--- a/sys/src/9/pc/etherbcm.c
+++ b/sys/src/9/pc/etherbcm.c
@@ -15,9 +15,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
-
#define Rbsz ROUNDUP(sizeof(Etherpkt)+4, 4)
typedef struct Ctlr Ctlr;
@@ -873,7 +872,6 @@
edev->port = ctlr->port;
edev->irq = ctlr->pdev->intl;
edev->tbdf = ctlr->pdev->tbdf;
- edev->interrupt = bcminterrupt;
edev->transmit = bcmtransmit;
edev->multicast = bcmmulticast;
edev->promiscuous = bcmpromiscuous;
@@ -884,6 +882,9 @@
edev->ctlr = nil;
goto again;
}
+
+ intrenable(edev->irq, bcminterrupt, edev, edev->tbdf, edev->name);
+
return 0;
}
--- a/sys/src/9/pc/etherdp83820.c
+++ b/sys/src/9/pc/etherdp83820.c
@@ -12,8 +12,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
#include "ethermii.h"
enum { /* Registers */
@@ -1232,7 +1232,6 @@
edev->attach = dp83820attach;
edev->transmit = dp83820transmit;
- edev->interrupt = dp83820interrupt;
edev->ifstat = dp83820ifstat;
edev->arg = edev;
@@ -1239,6 +1238,8 @@
edev->promiscuous = dp83820promiscuous;
edev->multicast = dp83820multicast;
edev->shutdown = dp83820shutdown;
+
+ intrenable(edev->irq, dp83820interrupt, edev, edev->tbdf, edev->name);
return 0;
}
--- a/sys/src/9/pc/etherec2t.c
+++ b/sys/src/9/pc/etherec2t.c
@@ -9,8 +9,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
#include "ether8390.h"
enum {
--- a/sys/src/9/pc/etherelnk3.c
+++ b/sys/src/9/pc/etherelnk3.c
@@ -16,9 +16,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
-
#define XCVRDEBUG if(0)print
enum {
@@ -2124,7 +2123,6 @@
*/
ether->attach = attach;
ether->transmit = transmit;
- ether->interrupt = interrupt;
ether->ifstat = ifstat;
ether->promiscuous = promiscuous;
@@ -2131,6 +2129,8 @@
ether->multicast = multicast;
ether->shutdown = shutdown;
ether->arg = ether;
+
+ intrenable(ether->irq, interrupt, ether, ether->tbdf, ether->name);
return 0;
}
--- a/sys/src/9/pc/etherga620.c
+++ b/sys/src/9/pc/etherga620.c
@@ -18,10 +18,9 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
#define malign(n) xspanalloc((n), 32, 0)
-
-#include "etherif.h"
#include "etherga620fw.h"
enum {
@@ -1260,7 +1259,6 @@
*/
edev->attach = ga620attach;
edev->transmit = ga620transmit;
- edev->interrupt = ga620interrupt;
edev->ifstat = ga620ifstat;
edev->ctl = ga620ctl;
@@ -1268,6 +1266,8 @@
edev->promiscuous = ga620promiscuous;
edev->multicast = ga620multicast;
edev->shutdown = ga620shutdown;
+
+ intrenable(edev->irq, ga620interrupt, edev, edev->tbdf, edev->name);
return 0;
}
--- a/sys/src/9/pc/etherif.h
+++ /dev/null
@@ -1,39 +1,0 @@
-enum {
- MaxEther = 64,
- Ntypes = 8,
-};
-
-typedef struct Ether Ether;
-struct Ether {
- ISAConf; /* hardware info */
-
- int ctlrno;
- int tbdf; /* type+busno+devno+funcno */
- int minmtu;
- int maxmtu;
- uchar ea[Eaddrlen];
-
- void (*attach)(Ether*); /* filled in by reset routine */
- void (*detach)(Ether*);
- void (*transmit)(Ether*);
- void (*interrupt)(Ureg*, void*);
- long (*ifstat)(Ether*, void*, long, ulong);
- long (*ctl)(Ether*, void*, long); /* custom ctl messages */
- void (*power)(Ether*, int); /* power on/off */
- void (*shutdown)(Ether*); /* shutdown hardware before reboot */
- void *ctlr;
-
- Queue* oq;
-
- Netif;
-};
-
-extern Block* etheriq(Ether*, Block*, int);
-extern void addethercard(char*, int(*)(Ether*));
-extern ulong ethercrc(uchar*, int);
-extern int parseether(uchar*, char*);
-
-#define NEXT(x, l) (((x)+1)%(l))
-#define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1)
-#define HOWMANY(x, y) (((x)+((y)-1))/(y))
-#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y))
--- a/sys/src/9/pc/etherigbe.c
+++ b/sys/src/9/pc/etherigbe.c
@@ -24,8 +24,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
#include "ethermii.h"
enum {
@@ -2020,7 +2020,6 @@
*/
edev->attach = igbeattach;
edev->transmit = igbetransmit;
- edev->interrupt = igbeinterrupt;
edev->ifstat = igbeifstat;
edev->ctl = igbectl;
@@ -2028,6 +2027,8 @@
edev->promiscuous = igbepromiscuous;
edev->shutdown = igbeshutdown;
edev->multicast = igbemulticast;
+
+ intrenable(edev->irq, igbeinterrupt, edev, edev->tbdf, edev->name);
return 0;
}
--- a/sys/src/9/pc/etheriwl.c
+++ b/sys/src/9/pc/etheriwl.c
@@ -14,10 +14,9 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
+#include "../port/wifi.h"
-#include "etherif.h"
-#include "wifi.h"
-
enum {
MaxQueue = 24*1024, /* total buffer is 2*MaxQueue: 48k at 22Mbit ≅ 20ms */
@@ -2534,7 +2533,6 @@
edev->irq = ctlr->pdev->intl;
edev->tbdf = ctlr->pdev->tbdf;
edev->arg = edev;
- edev->interrupt = iwlinterrupt;
edev->attach = iwlattach;
edev->ifstat = iwlifstat;
edev->ctl = iwlctl;
@@ -2547,6 +2545,8 @@
edev->ctlr = nil;
goto again;
}
+
+ intrenable(edev->irq, iwlinterrupt, edev, edev->tbdf, edev->name);
return 0;
}
--- a/sys/src/9/pc/etherm10g.c
+++ b/sys/src/9/pc/etherm10g.c
@@ -14,8 +14,7 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
-
-#include "../pc/etherif.h"
+#include "../port/etherif.h"
#ifndef KiB
#define KiB 1024u /* Kibi 0x0000000000000400 */
--- a/sys/src/9/pc/ethermii.c
+++ b/sys/src/9/pc/ethermii.c
@@ -6,8 +6,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
#include "ethermii.h"
int
--- a/sys/src/9/pc/etherrt2860.c
+++ b/sys/src/9/pc/etherrt2860.c
@@ -14,10 +14,9 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
+#include "../port/wifi.h"
-#include "etherif.h"
-#include "wifi.h"
-
/* for consistency */
typedef signed char s8int;
@@ -3544,7 +3543,6 @@
edev->irq = ctlr->pdev->intl;
edev->tbdf = ctlr->pdev->tbdf;
edev->arg = edev;
- edev->interrupt = rt2860interrupt;
edev->attach = rt2860attach;
edev->ifstat = rt2860ifstat;
edev->ctl = rt2860ctl;
@@ -3556,6 +3554,9 @@
edev->ctlr = nil;
goto again;
}
+
+ intrenable(edev->irq, rt2860interrupt, edev, edev->tbdf, edev->name);
+
return 0;
}
--- a/sys/src/9/pc/ethersink.c
+++ /dev/null
@@ -1,65 +1,0 @@
-/*
- * An ethernet /dev/null.
- * Useful as a bridging target with ethernet-based VPN.
- */
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "../port/error.h"
-#include "../port/netif.h"
-#include "etherif.h"
-
-static long
-ctl(Ether *ether, void *buf, long n)
-{
- uchar ea[Eaddrlen];
- Cmdbuf *cb;
-
- cb = parsecmd(buf, n);
- if(cb->nf >= 2
- && strcmp(cb->f[0], "ea")==0
- && parseether(ea, cb->f[1]) == 0){
- free(cb);
- memmove(ether->ea, ea, Eaddrlen);
- memmove(ether->addr, ether->ea, Eaddrlen);
- return 0;
- }
- free(cb);
- error(Ebadctl);
- return -1; /* not reached */
-}
-
-static void
-nop(Ether*)
-{
-}
-
-static int
-reset(Ether* ether)
-{
- uchar ea[Eaddrlen];
-
- if(ether->type==nil)
- return -1;
- memset(ea, 0, sizeof ea);
- ether->mbps = 1000;
- ether->attach = nop;
- ether->transmit = nop;
- ether->irq = -1;
- ether->interrupt = nil;
- ether->ifstat = nil;
- ether->ctl = ctl;
- ether->promiscuous = nil;
- ether->multicast = nil;
- ether->arg = ether;
- return 0;
-}
-
-void
-ethersinklink(void)
-{
- addethercard("sink", reset);
-}
--- a/sys/src/9/pc/ethersmc.c
+++ b/sys/src/9/pc/ethersmc.c
@@ -10,7 +10,7 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
-#include "etherif.h"
+#include "../port/etherif.h"
enum {
IoSize = 0x10, /* port pool size */
@@ -766,12 +766,15 @@
ether->attach = attach;
ether->transmit = transmit;
- ether->interrupt = interrupt;
ether->ifstat = ifstat;
ether->promiscuous = promiscuous;
ether->multicast = multicast;
ether->arg = ether;
+
iunlock(ctlr);
+
+ intrenable(ether->irq, interrupt, ether, ether->tbdf, ether->name);
+
return 0;
}
--- a/sys/src/9/pc/ethervgbe.c
+++ b/sys/src/9/pc/ethervgbe.c
@@ -29,8 +29,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
#include "ethermii.h"
#define DEBUG
@@ -1137,14 +1137,15 @@
memmove(edev->ea, ctlr->ea, Eaddrlen);
edev->attach = vgbeattach;
edev->transmit = vgbetransmit;
- edev->interrupt = vgbeinterrupt;
edev->ifstat = vgbeifstat;
// edev->promiscuous = vgbepromiscuous;
edev->multicast = vgbemulticast;
// edev->shutdown = vgbeshutdown;
edev->ctl = vgbectl;
-
edev->arg = edev;
+
+ intrenable(edev->irq, vgbeinterrupt, edev, edev->tbdf, edev->name);
+
return 0;
}
--- a/sys/src/9/pc/ethervirtio.c
+++ b/sys/src/9/pc/ethervirtio.c
@@ -6,7 +6,7 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
-#include "etherif.h"
+#include "../port/etherif.h"
/*
* virtio ethernet driver
@@ -661,7 +661,6 @@
edev->attach = attach;
edev->shutdown = shutdown;
- edev->interrupt = interrupt;
edev->ifstat = ifstat;
if((ctlr->feat & (Fctrlvq|Fctrlrx)) == (Fctrlvq|Fctrlrx)){
@@ -668,6 +667,8 @@
edev->multicast = multicast;
edev->promiscuous = promiscuous;
}
+
+ intrenable(edev->irq, interrupt, edev, edev->tbdf, edev->name);
return 0;
}
--- a/sys/src/9/pc/ethervt6102.c
+++ b/sys/src/9/pc/ethervt6102.c
@@ -17,8 +17,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
#include "ethermii.h"
enum {
@@ -1032,7 +1032,6 @@
*/
edev->attach = vt6102attach;
edev->transmit = vt6102transmit;
- edev->interrupt = vt6102interrupt;
edev->ifstat = vt6102ifstat;
edev->ctl = nil;
@@ -1039,6 +1038,8 @@
edev->arg = edev;
edev->promiscuous = vt6102promiscuous;
edev->multicast = vt6102multicast;
+
+ intrenable(edev->irq, vt6102interrupt, edev, edev->tbdf, edev->name);
return 0;
}
--- a/sys/src/9/pc/ethervt6105m.c
+++ b/sys/src/9/pc/ethervt6105m.c
@@ -20,8 +20,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
#include "ethermii.h"
enum {
@@ -1200,7 +1200,6 @@
*/
edev->attach = vt6105Mattach;
edev->transmit = vt6105Mtransmit;
- edev->interrupt = vt6105Minterrupt;
edev->ifstat = vt6105Mifstat;
edev->ctl = nil;
@@ -1209,6 +1208,8 @@
edev->multicast = vt6105Mmulticast;
edev->maxmtu = ETHERMAXTU+Bslop;
+
+ intrenable(edev->irq, vt6105Minterrupt, edev, edev->tbdf, edev->name);
return 0;
}
--- a/sys/src/9/pc/etherwavelan.c
+++ b/sys/src/9/pc/etherwavelan.c
@@ -8,7 +8,7 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
-#include "etherif.h"
+#include "../port/etherif.h"
#include "wavelan.h"
--- a/sys/src/9/pc/etherwpi.c
+++ b/sys/src/9/pc/etherwpi.c
@@ -6,10 +6,9 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
+#include "../port/wifi.h"
-#include "etherif.h"
-#include "wifi.h"
-
enum {
MaxQueue = 24*1024, /* total buffer is 2*MaxQueue: 48k at 22Mbit ≅ 20ms */
@@ -1846,7 +1845,6 @@
edev->irq = ctlr->pdev->intl;
edev->tbdf = ctlr->pdev->tbdf;
edev->arg = edev;
- edev->interrupt = wpiinterrupt;
edev->attach = wpiattach;
edev->ifstat = wpiifstat;
edev->ctl = wpictl;
@@ -1859,6 +1857,8 @@
edev->ctlr = nil;
goto again;
}
+
+ intrenable(edev->irq, wpiinterrupt, edev, edev->tbdf, edev->name);
return 0;
}
--- a/sys/src/9/pc/etheryuk.c
+++ b/sys/src/9/pc/etheryuk.c
@@ -10,7 +10,7 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
-#include "etherif.h"
+#include "../port/etherif.h"
#define Pciwaddrh(x) 0
#define Pciwaddrl(x) PCIWADDR(x)
@@ -2247,11 +2247,12 @@
e->attach = attach;
e->ctl = ctl;
e->ifstat = ifstat;
- e->interrupt = interrupt;
e->multicast = multicast;
e->promiscuous = promiscuous;
e->shutdown = shutdown;
e->transmit = nil;
+
+ intrenable(e->irq, interrupt, e, e->tbdf, e->name);
return 0;
}
--- a/sys/src/9/pc/mkfile
+++ b/sys/src/9/pc/mkfile
@@ -100,7 +100,7 @@
<../port/portmkfile
<|../port/mkbootrules $CONF
-$ETHER: etherif.h ../port/netif.h
+$ETHER: ../port/etherif.h ../port/netif.h
$AUDIO: ../port/audioif.h
ether8003.$O ether8390.$O: ether8390.h
etheryuk.$O: yukdump.h
@@ -122,11 +122,9 @@
trap.$O: /sys/include/tos.h
uartaxp.$O: uartaxp.i
etherm10g.$O: etherm10g2k.i etherm10g4k.i
-etheriwl.$O: wifi.h
-etherwpi.$O: wifi.h
-etherrt2860.$O: wifi.h
-wifi.$O: wifi.h etherif.h ../port/netif.h /sys/include/libsec.h
-wifi.$O: ../ip/ip.h ../ip/ipv6.h
+etheriwl.$O: ../port/wifi.h
+etherwpi.$O: ../port/wifi.h
+etherrt2860.$O: ../port/wifi.h
init.h:D: ../port/initcode.c init9.c
$CC ../port/initcode.c
--- a/sys/src/9/pc/trap.c
+++ b/sys/src/9/pc/trap.c
@@ -40,7 +40,6 @@
irq, tbdf, name);
return;
}
-
if(tbdf != BUSUNKNOWN && (irq == 0xff || irq == 0)){
print("intrenable: got unassigned irq %d, tbdf 0x%uX for %s\n",
irq, tbdf, name);
@@ -47,6 +46,14 @@
irq = -1;
}
+ /*
+ * IRQ2 doesn't really exist, it's used to gang the interrupt
+ * controllers together. A device set to IRQ2 will appear on
+ * the second interrupt controller as IRQ9.
+ */
+ if(irq == 2)
+ irq = 9;
+
if((v = xalloc(sizeof(Vctl))) == nil)
panic("intrenable: out of memory");
v->isintr = 1;
@@ -83,6 +90,8 @@
Vctl **pv, *v;
int vno;
+ if(irq == 2)
+ irq = 9;
if(arch->intrvecno == nil || (tbdf != BUSUNKNOWN && (irq == 0xff || irq == 0))){
/*
* on APIC machine, irq is pretty meaningless
--- a/sys/src/9/pc/usbehcipc.c
+++ b/sys/src/9/pc/usbehcipc.c
@@ -272,16 +272,6 @@
ehcilinkage(hp);
hp->shutdown = shutdown;
hp->debug = setdebug;
- if(hp->interrupt == nil)
- return 0;
-
- /*
- * IRQ2 doesn't really exist, it's used to gang the interrupt
- * controllers together. A device set to IRQ2 will appear on
- * the second interrupt controller as IRQ9.
- */
- if(hp->irq == 2)
- hp->irq = 9;
intrenable(hp->irq, hp->interrupt, hp, hp->tbdf, hp->type);
return 0;
--- a/sys/src/9/pc/usbohci.c
+++ b/sys/src/9/pc/usbohci.c
@@ -2608,14 +2608,6 @@
hp->shutdown = shutdown;
hp->debug = usbdebug;
hp->type = "ohci";
-
- /*
- * IRQ2 doesn't really exist, it's used to gang the interrupt
- * controllers together. A device set to IRQ2 will appear on
- * the second interrupt controller as IRQ9.
- */
- if(hp->irq == 2)
- hp->irq = 9;
intrenable(hp->irq, hp->interrupt, hp, hp->tbdf, hp->type);
return 0;
--- a/sys/src/9/pc/usbuhci.c
+++ b/sys/src/9/pc/usbuhci.c
@@ -2345,14 +2345,6 @@
hp->shutdown = shutdown;
hp->debug = setdebug;
hp->type = "uhci";
-
- /*
- * IRQ2 doesn't really exist, it's used to gang the interrupt
- * controllers together. A device set to IRQ2 will appear on
- * the second interrupt controller as IRQ9.
- */
- if(hp->irq == 2)
- hp->irq = 9;
intrenable(hp->irq, hp->interrupt, hp, hp->tbdf, hp->type);
return 0;
--- a/sys/src/9/pc/wavelan.c
+++ b/sys/src/9/pc/wavelan.c
@@ -25,7 +25,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
-#include "etherif.h"
+#include "../port/etherif.h"
+
#include "wavelan.h"
enum
@@ -1234,7 +1235,6 @@
ether->mbps = 10;
ether->attach = w_attach;
ether->detach = w_detach;
- ether->interrupt = w_interrupt;
ether->transmit = w_transmit;
ether->ifstat = w_ifstat;
ether->ctl = w_ctl;
@@ -1243,6 +1243,8 @@
ether->multicast = w_multicast;
ether->scanbs = w_scanbs;
ether->arg = ether;
+
+ intrenable(ether->irq, w_interrupt, ether, ether->tbdf, ether->name);
DEBUG("#l%d: irq %d port %lx type %s",
ether->ctlrno, ether->irq, ether->port, ether->type);
--- a/sys/src/9/pc/wifi.c
+++ /dev/null
@@ -1,1881 +1,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "ureg.h"
-#include "../port/error.h"
-#include "../port/netif.h"
-
-#include "etherif.h"
-#include "wifi.h"
-
-#include <libsec.h>
-
-typedef struct SNAP SNAP;
-struct SNAP
-{
- uchar dsap;
- uchar ssap;
- uchar control;
- uchar orgcode[3];
- uchar type[2];
-};
-
-enum {
- WIFIHDRSIZE = 2+2+3*6+2,
- SNAPHDRSIZE = 8,
-};
-
-static char Sconn[] = "connecting";
-static char Sauth[] = "authenticated";
-static char Sneedauth[] = "need authentication";
-static char Sunauth[] = "unauthenticated";
-
-static char Sassoc[] = "associated";
-static char Sunassoc[] = "unassociated";
-static char Sblocked[] = "blocked"; /* no keys negotiated. only pass EAPOL frames */
-
-static uchar basicrates[] = {
- 0x80 | 2, /* 1.0 Mb/s */
- 0x80 | 4, /* 2.0 Mb/s */
- 0x80 | 11, /* 5.5 Mb/s */
- 0x80 | 22, /* 11.0 Mb/s */
-
- 0
-};
-
-static Block* wifidecrypt(Wifi *, Wnode *, Block *);
-static Block* wifiencrypt(Wifi *, Wnode *, Block *);
-static void freewifikeys(Wifi *, Wnode *);
-
-static void dmatproxy(Block *bp, int upstream, uchar proxy[Eaddrlen], DMAT *t);
-
-static uchar*
-srcaddr(Wifipkt *w)
-{
- if((w->fc[1] & 0x02) == 0)
- return w->a2;
- if((w->fc[1] & 0x01) == 0)
- return w->a3;
- return w->a4;
-}
-static uchar*
-dstaddr(Wifipkt *w)
-{
- if((w->fc[1] & 0x01) != 0)
- return w->a3;
- return w->a1;
-}
-
-int
-wifihdrlen(Wifipkt *w)
-{
- int n;
-
- n = WIFIHDRSIZE;
- if((w->fc[0] & 0x0c) == 0x08)
- if((w->fc[0] & 0xf0) == 0x80){ /* QOS */
- n += 2;
- if(w->fc[1] & 0x80)
- n += 4;
- }
- if((w->fc[1] & 3) == 0x03)
- n += Eaddrlen;
- return n;
-}
-
-void
-wifiiq(Wifi *wifi, Block *b)
-{
- SNAP s;
- Wifipkt h, *w;
- Etherpkt *e;
- int hdrlen;
-
- if(BLEN(b) < WIFIHDRSIZE)
- goto drop;
- w = (Wifipkt*)b->rp;
- hdrlen = wifihdrlen(w);
- if(BLEN(b) < hdrlen)
- goto drop;
- if(memcmp(srcaddr(w), wifi->ether->ea, Eaddrlen) == 0)
- goto drop;
- if(w->fc[1] & 0x40){
- /* encrypted */
- qpass(wifi->iq, b);
- return;
- }
- switch(w->fc[0] & 0x0c){
- case 0x00: /* management */
- if((w->fc[1] & 3) != 0x00) /* STA->STA */
- break;
- qpass(wifi->iq, b);
- return;
- case 0x04: /* control */
- break;
- case 0x08: /* data */
- b->rp += hdrlen;
- switch(w->fc[0] & 0xf0){
- default:
- goto drop;
- case 0x80: /* QOS */
- case 0x00:
- break;
- }
- if(BLEN(b) < SNAPHDRSIZE)
- break;
- memmove(&s, b->rp, SNAPHDRSIZE);
- if(s.dsap != 0xAA || s.ssap != 0xAA || s.control != 3)
- break;
- if(s.orgcode[0] != 0 || s.orgcode[1] != 0 || s.orgcode[2] != 0)
- break;
- b->rp += SNAPHDRSIZE-ETHERHDRSIZE;
- h = *w;
- e = (Etherpkt*)b->rp;
- memmove(e->d, dstaddr(&h), Eaddrlen);
- memmove(e->s, srcaddr(&h), Eaddrlen);
- memmove(e->type, s.type, 2);
-
- dmatproxy(b, 0, wifi->ether->ea, &wifi->dmat);
-
- etheriq(wifi->ether, b, 1);
- return;
- }
-drop:
- freeb(b);
-}
-
-static void
-wifitx(Wifi *wifi, Wnode *wn, Block *b)
-{
- Wifipkt *w;
- uint seq;
-
- wn->lastsend = MACHP(0)->ticks;
-
- seq = incref(&wifi->txseq);
- seq <<= 4;
-
- w = (Wifipkt*)b->rp;
- w->dur[0] = 0;
- w->dur[1] = 0;
- w->seq[0] = seq;
- w->seq[1] = seq>>8;
-
- if((w->fc[0] & 0x0c) != 0x00){
- b = wifiencrypt(wifi, wn, b);
- if(b == nil)
- return;
- }
-
- if((wn->txcount++ & 255) == 255 && wn->actrate != nil && wn->actrate != wn->maxrate){
- uchar *a, *p;
-
- for(a = wn->maxrate, p = wifi->rates; *p; p++){
- if(*p < *a && *p > *wn->actrate)
- a = p;
- }
- wn->actrate = a;
- }
-
- (*wifi->transmit)(wifi, wn, b);
-}
-
-static Wnode*
-nodelookup(Wifi *wifi, uchar *bssid, int new)
-{
- Wnode *wn, *nn;
-
- if(memcmp(bssid, wifi->ether->bcast, Eaddrlen) == 0)
- return nil;
- if((wn = wifi->bss) != nil){
- if(memcmp(wn->bssid, bssid, Eaddrlen) == 0)
- return wn;
- }
- if((nn = wifi->node) == wn)
- nn++;
- for(wn = wifi->node; wn != &wifi->node[nelem(wifi->node)]; wn++){
- if(wn == wifi->bss)
- continue;
- if(memcmp(wn->bssid, bssid, Eaddrlen) == 0)
- return wn;
- if((long)(wn->lastsend - nn->lastsend) < 0
- || (long)(wn->lastseen - nn->lastseen) < 0)
- nn = wn;
- }
- if(!new)
- return nil;
- freewifikeys(wifi, nn);
- memset(nn, 0, sizeof(Wnode));
- memmove(nn->bssid, bssid, Eaddrlen);
- return nn;
-}
-
-void
-wifitxfail(Wifi *wifi, Block *b)
-{
- Wifipkt *w;
- Wnode *wn;
-
- if(b == nil)
- return;
- w = (Wifipkt*)b->rp;
- wn = nodelookup(wifi, w->a1, 0);
- if(wn == nil)
- return;
- wn->txerror++;
- if(wn->actrate != nil && wn->minrate != wn->actrate){
- uchar *a, *p;
-
- for(a = wn->minrate, p = wifi->rates; *p; p++){
- if(*p > *a && *p < *wn->actrate)
- a = p;
- }
- wn->actrate = a;
- }
-}
-
-static uchar*
-putrates(uchar *p, uchar *rates)
-{
- int n, m;
-
- n = m = strlen((char*)rates);
- if(n > 8)
- n = 8;
- /* supported rates */
- *p++ = 1;
- *p++ = n;
- memmove(p, rates, n);
- p += n;
- if(m > 8){
- /* extended supported rates */
- *p++ = 50;
- *p++ = m;
- memmove(p, rates, m);
- p += m;
- }
- return p;
-}
-
-static void
-wifiprobe(Wifi *wifi, Wnode *wn)
-{
- Wifipkt *w;
- Block *b;
- uchar *p;
- int n;
-
- n = strlen(wifi->essid);
- if(n == 0){
- /* no specific essid, just tell driver to tune channel */
- (*wifi->transmit)(wifi, wn, nil);
- return;
- }
-
- b = allocb(WIFIHDRSIZE + 512);
- w = (Wifipkt*)b->wp;
- w->fc[0] = 0x40; /* probe request */
- w->fc[1] = 0x00; /* STA->STA */
- memmove(w->a1, wifi->ether->bcast, Eaddrlen); /* ??? */
- memmove(w->a2, wifi->ether->ea, Eaddrlen);
- memmove(w->a3, wifi->ether->bcast, Eaddrlen);
- b->wp += WIFIHDRSIZE;
- p = b->wp;
-
- *p++ = 0; /* set */
- *p++ = n;
- memmove(p, wifi->essid, n);
- p += n;
-
- p = putrates(p, wifi->rates);
-
- *p++ = 3; /* ds parameter set */
- *p++ = 1;
- *p++ = wn->channel;
-
- b->wp = p;
- wifitx(wifi, wn, b);
-}
-
-static void
-sendauth(Wifi *wifi, Wnode *bss)
-{
- Wifipkt *w;
- Block *b;
- uchar *p;
-
- b = allocb(WIFIHDRSIZE + 3*2);
- w = (Wifipkt*)b->wp;
- w->fc[0] = 0xB0; /* auth request */
- w->fc[1] = 0x00; /* STA->STA */
- memmove(w->a1, bss->bssid, Eaddrlen); /* ??? */
- memmove(w->a2, wifi->ether->ea, Eaddrlen);
- memmove(w->a3, bss->bssid, Eaddrlen);
- b->wp += WIFIHDRSIZE;
- p = b->wp;
- *p++ = 0; /* alg */
- *p++ = 0;
- *p++ = 1; /* seq */
- *p++ = 0;
- *p++ = 0; /* status */
- *p++ = 0;
- b->wp = p;
-
- bss->aid = 0;
-
- wifitx(wifi, bss, b);
-}
-
-static void
-sendassoc(Wifi *wifi, Wnode *bss)
-{
- Wifipkt *w;
- Block *b;
- uchar *p;
- int cap, n;
-
- b = allocb(WIFIHDRSIZE + 512);
- w = (Wifipkt*)b->wp;
- w->fc[0] = 0x00; /* assoc request */
- w->fc[1] = 0x00; /* STA->STA */
- memmove(w->a1, bss->bssid, Eaddrlen); /* ??? */
- memmove(w->a2, wifi->ether->ea, Eaddrlen);
- memmove(w->a3, bss->bssid, Eaddrlen);
- b->wp += WIFIHDRSIZE;
- p = b->wp;
-
- /* capinfo */
- cap = 1; // ESS
- cap |= (1<<5); // Short Preamble
- cap |= (1<<10) & bss->cap; // Short Slot Time
- *p++ = cap;
- *p++ = cap>>8;
-
- /* interval */
- *p++ = 16;
- *p++ = 16>>8;
-
- n = strlen(bss->ssid);
- *p++ = 0; /* SSID */
- *p++ = n;
- memmove(p, bss->ssid, n);
- p += n;
-
- p = putrates(p, wifi->rates);
-
- n = bss->rsnelen;
- if(n > 0){
- memmove(p, bss->rsne, n);
- p += n;
- }
-
- b->wp = p;
- wifitx(wifi, bss, b);
-}
-
-static void
-setstatus(Wifi *wifi, Wnode *wn, char *new)
-{
- char *old;
-
- old = wn->status;
- wn->status = new;
- if(wifi->debug && new != old)
- print("#l%d: status %E: %.12ld %.12ld: %s -> %s (from pc=%#p)\n",
- wifi->ether->ctlrno,
- wn->bssid,
- TK2MS(MACHP(0)->ticks), TK2MS(MACHP(0)->ticks - wn->lastsend),
- old, new,
- getcallerpc(&wifi));
-}
-
-static void
-recvassoc(Wifi *wifi, Wnode *wn, uchar *d, int len)
-{
- uint s;
-
- if(len < 2+2+2)
- return;
-
- d += 2; /* caps */
- s = d[0] | d[1]<<8;
- d += 2;
- switch(s){
- case 0x00:
- wn->aid = d[0] | d[1]<<8;
- if(wn->rsnelen > 0)
- setstatus(wifi, wn, Sblocked);
- else
- setstatus(wifi, wn, Sassoc);
- break;
- default:
- wn->aid = 0;
- setstatus(wifi, wn, Sunassoc);
- }
-}
-
-static void
-recvbeacon(Wifi *wifi, Wnode *wn, uchar *d, int len)
-{
- static uchar wpa1oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
- uchar *e, *x, *p, t;
- int rsnset;
-
- len -= 8+2+2;
- if(len < 0)
- return;
-
- d += 8; /* timestamp */
- wn->ival = d[0] | d[1]<<8;
- d += 2;
- wn->cap = d[0] | d[1]<<8;
- d += 2;
-
- rsnset = 0;
- for(e = d + len; d+2 <= e; d = x){
- d += 2;
- x = d + d[-1];
- if(x > e)
- break; /* truncated */
- t = d[-2];
- switch(t){
- case 0: /* SSID */
- len = 0;
- while(len < Essidlen && d+len < x && d[len] != 0)
- len++;
- if(len == 0)
- continue;
- if(len != strlen(wn->ssid) || strncmp(wn->ssid, (char*)d, len) != 0){
- strncpy(wn->ssid, (char*)d, len);
- wn->ssid[len] = 0;
- }
- break;
- case 1: /* supported rates */
- case 50: /* extended rates */
- if(wn->actrate != nil || wifi->rates == nil)
- break; /* already set */
- while(d < x){
- t = *d++ | 0x80;
- for(p = wifi->rates; *p != 0; p++){
- if(*p == t){
- if(wn->minrate == nil || t < *wn->minrate)
- wn->minrate = p;
- if(wn->maxrate == nil || t > *wn->maxrate)
- wn->maxrate = p;
- break;
- }
- }
- wn->actrate = wn->maxrate;
- }
- break;
- case 3: /* DSPARAMS */
- if(d != x)
- wn->channel = d[0];
- break;
- case 221: /* vendor specific */
- len = x - d;
- if(rsnset || len < sizeof(wpa1oui) || memcmp(d, wpa1oui, sizeof(wpa1oui)) != 0)
- break;
- /* no break */
- case 48: /* RSN information */
- len = x - &d[-2];
- memmove(wn->brsne, &d[-2], len);
- wn->brsnelen = len;
- rsnset = 1;
- break;
- }
- }
-}
-
-static void
-freewifikeys(Wifi *wifi, Wnode *wn)
-{
- int i;
-
- wlock(&wifi->crypt);
- for(i=0; i<nelem(wn->rxkey); i++){
- secfree(wn->rxkey[i]);
- wn->rxkey[i] = nil;
- }
- for(i=0; i<nelem(wn->txkey); i++){
- secfree(wn->txkey[i]);
- wn->txkey[i] = nil;
- }
- wunlock(&wifi->crypt);
-}
-
-static void
-wifideauth(Wifi *wifi, Wnode *wn)
-{
- Ether *ether;
- Netfile *f;
- int i;
-
- /* deassociate node, clear keys */
- setstatus(wifi, wn, Sunauth);
- freewifikeys(wifi, wn);
- memset(&wifi->dmat, 0, sizeof(wifi->dmat));
- wn->aid = 0;
-
- if(wn == wifi->bss){
- /* notify driver about node aid association */
- (*wifi->transmit)(wifi, wn, nil);
-
- /* notify aux/wpa with a zero length packet that we got deassociated from the ap */
- ether = wifi->ether;
- for(i=0; i<ether->nfile; i++){
- f = ether->f[i];
- if(f == nil || f->in == nil || f->inuse == 0 || f->type != 0x888e)
- continue;
- qflush(f->in);
- qwrite(f->in, 0, 0);
- }
- qflush(ether->oq);
- }
-}
-
-/* check if a node qualifies as our bss matching bssid and essid */
-static int
-goodbss(Wifi *wifi, Wnode *wn)
-{
- if(memcmp(wifi->bssid, wifi->ether->bcast, Eaddrlen) != 0){
- if(memcmp(wifi->bssid, wn->bssid, Eaddrlen) != 0)
- return 0; /* bssid doesnt match */
- } else if(wifi->essid[0] == 0)
- return 0; /* both bssid and essid unspecified */
- if(wifi->essid[0] != 0 && strcmp(wifi->essid, wn->ssid) != 0)
- return 0; /* essid doesnt match */
- return 1;
-}
-
-static void
-wifiproc(void *arg)
-{
- Wifi *wifi;
- Wifipkt *w;
- Wnode *wn;
- Block *b;
-
- b = nil;
- wifi = arg;
- while(waserror())
- ;
- for(;;){
- if(b != nil){
- freeb(b);
- b = nil;
- continue;
- }
- if((b = qbread(wifi->iq, 100000)) == nil)
- break;
- w = (Wifipkt*)b->rp;
- if(w->fc[1] & 0x40){
- /* encrypted */
- if((wn = nodelookup(wifi, w->a2, 0)) == nil)
- continue;
- wn->lastseen = MACHP(0)->ticks;
- if((b = wifidecrypt(wifi, wn, b)) != nil){
- w = (Wifipkt*)b->rp;
- if(w->fc[1] & 0x40)
- continue;
- wifiiq(wifi, b);
- b = nil;
- }
- continue;
- }
- /* management */
- if((w->fc[0] & 0x0c) != 0x00)
- continue;
-
- switch(w->fc[0] & 0xf0){
- case 0x50: /* probe response */
- if(wifi->debug)
- print("#l%d: got probe from %E\n", wifi->ether->ctlrno, w->a3);
- /* no break */
- case 0x80: /* beacon */
- if((wn = nodelookup(wifi, w->a3, 1)) == nil)
- continue;
- wn->lastseen = MACHP(0)->ticks;
- b->rp += wifihdrlen(w);
- recvbeacon(wifi, wn, b->rp, BLEN(b));
-
- if(wifi->bss == nil
- && TK2MS(MACHP(0)->ticks - wn->lastsend) > 1000
- && goodbss(wifi, wn)){
- setstatus(wifi, wn, Sconn);
- sendauth(wifi, wn);
- wifi->lastauth = wn->lastsend;
- }
- continue;
- }
-
- if(memcmp(w->a1, wifi->ether->ea, Eaddrlen))
- continue;
- if((wn = nodelookup(wifi, w->a3, 0)) == nil)
- continue;
- wn->lastseen = MACHP(0)->ticks;
- switch(w->fc[0] & 0xf0){
- case 0x10: /* assoc response */
- case 0x30: /* reassoc response */
- b->rp += wifihdrlen(w);
- recvassoc(wifi, wn, b->rp, BLEN(b));
- /* notify driver about node aid association */
- if(wn == wifi->bss)
- (*wifi->transmit)(wifi, wn, nil);
- break;
- case 0xb0: /* auth */
- if(wifi->debug)
- print("#l%d: got auth from %E\n", wifi->ether->ctlrno, wn->bssid);
- if(wn->brsnelen > 0 && wn->rsnelen == 0)
- setstatus(wifi, wn, Sneedauth);
- else
- setstatus(wifi, wn, Sauth);
- if(wifi->bss == nil && goodbss(wifi, wn)){
- wifi->bss = wn;
- if(wn->status == Sauth)
- sendassoc(wifi, wn);
- }
- break;
- case 0xc0: /* deauth */
- if(wifi->debug)
- print("#l%d: got deauth from %E\n", wifi->ether->ctlrno, wn->bssid);
- wifideauth(wifi, wn);
- break;
- }
- }
- pexit("wifi in queue closed", 1);
-}
-
-static void
-wifietheroq(Wifi *wifi, Block *b)
-{
- Etherpkt e;
- Wifipkt h;
- int hdrlen;
- Wnode *wn;
- SNAP *s;
-
- if(BLEN(b) < ETHERHDRSIZE)
- goto drop;
- if((wn = wifi->bss) == nil)
- goto drop;
-
- dmatproxy(b, 1, wifi->ether->ea, &wifi->dmat);
-
- memmove(&e, b->rp, ETHERHDRSIZE);
- b->rp += ETHERHDRSIZE;
- if(wn->status == Sblocked){
- /* only pass EAPOL frames when port is blocked */
- if((e.type[0]<<8 | e.type[1]) != 0x888e)
- goto drop;
- } else if(wn->status != Sassoc)
- goto drop;
-
- h.fc[0] = 0x08; /* data */
- memmove(h.a1, wn->bssid, Eaddrlen);
- if(memcmp(e.s, wifi->ether->ea, Eaddrlen) == 0) {
- h.fc[1] = 0x01; /* STA->AP */
- } else {
- h.fc[1] = 0x03; /* AP->AP (WDS) */
- memmove(h.a2, wifi->ether->ea, Eaddrlen);
- }
- memmove(dstaddr(&h), e.d, Eaddrlen);
- memmove(srcaddr(&h), e.s, Eaddrlen);
-
- hdrlen = wifihdrlen(&h);
- b = padblock(b, hdrlen + SNAPHDRSIZE);
- memmove(b->rp, &h, hdrlen);
- s = (SNAP*)(b->rp + hdrlen);
- s->dsap = s->ssap = 0xAA;
- s->control = 0x03;
- s->orgcode[0] = 0;
- s->orgcode[1] = 0;
- s->orgcode[2] = 0;
- memmove(s->type, e.type, 2);
-
- wifitx(wifi, wn, b);
- return;
-drop:
- freeb(b);
-}
-
-static void
-wifoproc(void *arg)
-{
- Ether *ether;
- Wifi *wifi;
- Block *b;
-
- wifi = arg;
- ether = wifi->ether;
- while(waserror())
- ;
- while((b = qbread(ether->oq, 1000000)) != nil)
- wifietheroq(wifi, b);
- pexit("ether out queue closed", 1);
-}
-
-static void
-wifsproc(void *arg)
-{
- Ether *ether;
- Wifi *wifi;
- Wnode wnscan;
- Wnode *wn;
- ulong now, tmout;
- uchar *rate;
-
- wifi = arg;
- ether = wifi->ether;
-
- wn = &wnscan;
- memset(wn, 0, sizeof(*wn));
- memmove(wn->bssid, ether->bcast, Eaddrlen);
-
- while(waserror())
- ;
-Scan:
- /* scan for access point */
- while(wifi->bss == nil){
- ether->link = 0;
- wnscan.channel = 1 + ((wnscan.channel+4) % 13);
- wifiprobe(wifi, &wnscan);
- do {
- tsleep(&up->sleep, return0, 0, 200);
- now = MACHP(0)->ticks;
- } while(TK2MS(now-wifi->lastauth) < 1000);
- }
-
- /* maintain access point */
- tmout = 0;
- while((wn = wifi->bss) != nil){
- ether->link = (wn->status == Sassoc) || (wn->status == Sblocked);
- if(ether->link && (rate = wn->actrate) != nil)
- ether->mbps = ((*rate & 0x7f)+3)/4;
- now = MACHP(0)->ticks;
- if(wn->status != Sneedauth && TK2SEC(now - wn->lastseen) > 20 || goodbss(wifi, wn) == 0){
- wifideauth(wifi, wn);
- wifi->bss = nil;
- break;
- }
- if(TK2MS(now - wn->lastsend) > 1000){
- if((wn->status == Sauth || wn->status == Sblocked) && (++tmout & 7) == 0)
- wifideauth(wifi, wn); /* stuck in auth, start over */
- if(wn->status == Sconn || wn->status == Sunauth)
- sendauth(wifi, wn);
- if(wn->status == Sauth)
- sendassoc(wifi, wn);
- }
- tsleep(&up->sleep, return0, 0, 500);
- }
- goto Scan;
-}
-
-Wifi*
-wifiattach(Ether *ether, void (*transmit)(Wifi*, Wnode*, Block*))
-{
- char name[32];
- Wifi *wifi;
-
- wifi = malloc(sizeof(Wifi));
- if(wifi == nil)
- error(Enomem);
- wifi->iq = qopen(ether->limit, 0, 0, 0);
- if(wifi->iq == nil){
- free(wifi);
- error(Enomem);
- }
- wifi->ether = ether;
- wifi->transmit = transmit;
-
- wifi->rates = basicrates;
-
- wifi->essid[0] = 0;
- memmove(wifi->bssid, ether->bcast, Eaddrlen);
-
- wifi->lastauth = MACHP(0)->ticks;
-
- snprint(name, sizeof(name), "#l%dwifi", ether->ctlrno);
- kproc(name, wifiproc, wifi);
- snprint(name, sizeof(name), "#l%dwifo", ether->ctlrno);
- kproc(name, wifoproc, wifi);
- snprint(name, sizeof(name), "#l%dwifs", ether->ctlrno);
- kproc(name, wifsproc, wifi);
-
- return wifi;
-}
-
-static char *ciphers[] = {
- [0] "clear",
- [TKIP] "tkip",
- [CCMP] "ccmp",
-};
-
-static Wkey*
-parsekey(char *s)
-{
- static char Ebadkey[] = "bad key";
- uchar key[32];
- int len, cipher;
- char *e;
- Wkey *k;
-
- for(cipher=0; cipher<nelem(ciphers); cipher++){
- if(strncmp(s, ciphers[cipher], len = strlen(ciphers[cipher])) == 0){
- if(cipher == 0) /* clear */
- return nil;
- if(s[len] == ':'){
- s += len+1;
- break;
- }
- }
- }
- if(cipher >= nelem(ciphers))
- error(Ebadkey);
-
- if((e = strchr(s, '@')) == nil)
- e = strchr(s, 0);
-
- len = dec16(key, sizeof(key), s, e - s);
-
- switch(cipher){
- case TKIP:
- if(len != 32)
- error(Ebadkey);
- k = secalloc(sizeof(Wkey) + len);
- memmove(k->key, key, len);
- break;
- case CCMP:
- if(len != 16)
- error(Ebadkey);
- k = secalloc(sizeof(Wkey) + sizeof(AESstate));
- setupAESstate((AESstate*)k->key, key, len, nil);
- break;
- default:
- error(Ebadkey);
- return nil;
- }
-
- memset(key, 0, sizeof(key));
-
- if(*e++ == '@')
- k->tsc = strtoull(e, nil, 16);
- k->len = len;
- k->cipher = cipher;
-
- return k;
-}
-
-void
-wificfg(Wifi *wifi, char *opt)
-{
- char *p, buf[64];
- int n;
-
- if(strncmp(opt, "debug=", 6))
- if(strncmp(opt, "essid=", 6))
- if(strncmp(opt, "bssid=", 6))
- return;
- if((p = strchr(opt, '=')) == nil)
- return;
- if(waserror())
- return;
- n = snprint(buf, sizeof(buf), "%.*s %q", (int)(p - opt), opt, p+1);
- wifictl(wifi, buf, n);
- poperror();
-}
-
-enum {
- CMdebug,
- CMessid,
- CMauth,
- CMbssid,
- CMrxkey0,
- CMrxkey1,
- CMrxkey2,
- CMrxkey3,
- CMrxkey4,
- CMtxkey0,
-};
-
-static Cmdtab wifictlmsg[] =
-{
- CMdebug, "debug", 0,
- CMessid, "essid", 0,
- CMauth, "auth", 0,
- CMbssid, "bssid", 0,
-
- CMrxkey0, "rxkey0", 0, /* group keys */
- CMrxkey1, "rxkey1", 0,
- CMrxkey2, "rxkey2", 0,
- CMrxkey3, "rxkey3", 0,
-
- CMrxkey4, "rxkey", 0, /* peerwise keys */
- CMtxkey0, "txkey", 0,
-
- CMtxkey0, "txkey0", 0,
-};
-
-long
-wifictl(Wifi *wifi, void *buf, long n)
-{
- uchar addr[Eaddrlen];
- Cmdbuf *cb;
- Cmdtab *ct;
- Wnode *wn;
- Wkey *k, **kk;
-
- cb = nil;
- if(waserror()){
- free(cb);
- nexterror();
- }
- if(wifi->debug)
- print("#l%d: wifictl: %.*s\n", wifi->ether->ctlrno, (int)n, buf);
- memmove(addr, wifi->ether->bcast, Eaddrlen);
- wn = wifi->bss;
- cb = parsecmd(buf, n);
- ct = lookupcmd(cb, wifictlmsg, nelem(wifictlmsg));
- if(ct->index >= CMauth){
- if(cb->nf > 1 && (ct->index == CMbssid || ct->index >= CMrxkey0)){
- if(parseether(addr, cb->f[1]) == 0){
- cb->f++;
- cb->nf--;
- wn = nodelookup(wifi, addr, 0);
- }
- }
- if(wn == nil && ct->index != CMbssid)
- error("missing node");
- }
- switch(ct->index){
- case CMdebug:
- if(cb->f[1] != nil)
- wifi->debug = atoi(cb->f[1]);
- else
- wifi->debug ^= 1;
- print("#l%d: debug: %d\n", wifi->ether->ctlrno, wifi->debug);
- break;
- case CMessid:
- if(cb->f[1] != nil)
- strncpy(wifi->essid, cb->f[1], Essidlen);
- else
- wifi->essid[0] = 0;
- Findbss:
- wn = wifi->bss;
- if(wn != nil){
- if(goodbss(wifi, wn))
- break;
- wifideauth(wifi, wn);
- }
- wifi->bss = nil;
- if(wifi->essid[0] == 0 && memcmp(wifi->bssid, wifi->ether->bcast, Eaddrlen) == 0)
- break;
- for(wn = wifi->node; wn != &wifi->node[nelem(wifi->node)]; wn++)
- if(goodbss(wifi, wn)){
- setstatus(wifi, wn, Sconn);
- sendauth(wifi, wn);
- }
- break;
- case CMbssid:
- memmove(wifi->bssid, addr, Eaddrlen);
- goto Findbss;
- case CMauth:
- freewifikeys(wifi, wn);
- if(cb->f[1] == nil)
- wn->rsnelen = 0;
- else
- wn->rsnelen = dec16(wn->rsne, sizeof(wn->rsne), cb->f[1], strlen(cb->f[1]));
- if(wn->aid == 0){
- setstatus(wifi, wn, Sconn);
- sendauth(wifi, wn);
- } else {
- setstatus(wifi, wn, Sauth);
- sendassoc(wifi, wn);
- }
- break;
- case CMrxkey0: case CMrxkey1: case CMrxkey2: case CMrxkey3: case CMrxkey4:
- case CMtxkey0:
- if(cb->f[1] == nil)
- error(Ebadarg);
- k = parsekey(cb->f[1]);
- memset(cb->f[1], 0, strlen(cb->f[1]));
- if(ct->index < CMtxkey0)
- kk = &wn->rxkey[ct->index - CMrxkey0];
- else
- kk = &wn->txkey[ct->index - CMtxkey0];
- wlock(&wifi->crypt);
- secfree(*kk);
- *kk = k;
- wunlock(&wifi->crypt);
- if(ct->index >= CMtxkey0 && wn->status == Sblocked)
- setstatus(wifi, wn, Sassoc);
- break;
- }
- poperror();
- free(cb);
- return n;
-}
-
-long
-wifistat(Wifi *wifi, void *buf, long n, ulong off)
-{
- static uchar zeros[Eaddrlen];
- char essid[Essidlen+1];
- char *s, *p, *e;
- Wnode *wn;
- Wkey *k;
- long now;
- int i;
-
- p = s = smalloc(4096);
- e = s + 4096;
-
- wn = wifi->bss;
- if(wn != nil){
- strncpy(essid, wn->ssid, Essidlen);
- essid[Essidlen] = 0;
- p = seprint(p, e, "essid: %s\n", essid);
- p = seprint(p, e, "bssid: %E\n", wn->bssid);
- p = seprint(p, e, "status: %s\n", wn->status);
- p = seprint(p, e, "channel: %.2d\n", wn->channel);
-
- /* only print key ciphers and key length */
- rlock(&wifi->crypt);
- for(i = 0; i<nelem(wn->rxkey); i++){
- if((k = wn->rxkey[i]) != nil)
- p = seprint(p, e, "rxkey%d: %s:[%d]\n", i,
- ciphers[k->cipher], k->len);
- }
- for(i = 0; i<nelem(wn->txkey); i++){
- if((k = wn->txkey[i]) != nil)
- p = seprint(p, e, "txkey%d: %s:[%d]\n", i,
- ciphers[k->cipher], k->len);
- }
- runlock(&wifi->crypt);
-
- if(wn->brsnelen > 0){
- p = seprint(p, e, "brsne: ");
- for(i=0; i<wn->brsnelen; i++)
- p = seprint(p, e, "%.2X", wn->brsne[i]);
- p = seprint(p, e, "\n");
- }
- } else {
- p = seprint(p, e, "essid: %s\n", wifi->essid);
- p = seprint(p, e, "bssid: %E\n", wifi->bssid);
- }
-
- now = MACHP(0)->ticks;
- for(wn = wifi->node; wn != &wifi->node[nelem(wifi->node)]; wn++){
- if(wn->lastseen == 0)
- continue;
- strncpy(essid, wn->ssid, Essidlen);
- essid[Essidlen] = 0;
- p = seprint(p, e, "node: %E %.4x %-11ld %.2d %s\n",
- wn->bssid, wn->cap, TK2MS(now - wn->lastseen), wn->channel, essid);
- }
- n = readstr(off, buf, n, s);
- free(s);
- return n;
-}
-
-static void tkipencrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc);
-static int tkipdecrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc);
-static void ccmpencrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc);
-static int ccmpdecrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc);
-
-static Block*
-wifiencrypt(Wifi *wifi, Wnode *wn, Block *b)
-{
- uvlong tsc;
- int n, kid;
- Wifipkt *w;
- Wkey *k;
-
- rlock(&wifi->crypt);
-
- kid = 0;
- k = wn->txkey[kid];
- if(k == nil){
- runlock(&wifi->crypt);
- return b;
- }
-
- n = wifihdrlen((Wifipkt*)b->rp);
-
- b = padblock(b, 8);
- b = padblock(b, -(8+4));
-
- w = (Wifipkt*)b->rp;
- memmove(w, b->rp+8, n);
- b->rp += n;
-
- tsc = ++k->tsc;
-
- switch(k->cipher){
- case TKIP:
- b->rp[0] = tsc>>8;
- b->rp[1] = (b->rp[0] | 0x20) & 0x7f;
- b->rp[2] = tsc;
- b->rp[3] = kid<<6 | 0x20;
- b->rp[4] = tsc>>16;
- b->rp[5] = tsc>>24;
- b->rp[6] = tsc>>32;
- b->rp[7] = tsc>>40;
- b->rp += 8;
- tkipencrypt(k, w, b, tsc);
- break;
- case CCMP:
- b->rp[0] = tsc;
- b->rp[1] = tsc>>8;
- b->rp[2] = 0;
- b->rp[3] = kid<<6 | 0x20;
- b->rp[4] = tsc>>16;
- b->rp[5] = tsc>>24;
- b->rp[6] = tsc>>32;
- b->rp[7] = tsc>>40;
- b->rp += 8;
- ccmpencrypt(k, w, b, tsc);
- break;
- }
- runlock(&wifi->crypt);
-
- b->rp = (uchar*)w;
- w->fc[1] |= 0x40;
- return b;
-}
-
-static Block*
-wifidecrypt(Wifi *wifi, Wnode *wn, Block *b)
-{
- uvlong tsc;
- int n, kid;
- Wifipkt *w;
- Wkey *k;
-
- rlock(&wifi->crypt);
-
- w = (Wifipkt*)b->rp;
- n = wifihdrlen(w);
- b->rp += n;
- if(BLEN(b) < 8+8)
- goto drop;
-
- kid = b->rp[3]>>6;
- if((b->rp[3] & 0x20) == 0)
- goto drop;
- if((w->a1[0] & 1) == 0)
- kid = 4; /* use peerwise key for non-unicast */
-
- k = wn->rxkey[kid];
- if(k == nil)
- goto drop;
- switch(k->cipher){
- case TKIP:
- tsc = (uvlong)b->rp[7]<<40 |
- (uvlong)b->rp[6]<<32 |
- (uvlong)b->rp[5]<<24 |
- (uvlong)b->rp[4]<<16 |
- (uvlong)b->rp[0]<<8 |
- (uvlong)b->rp[2];
- b->rp += 8;
- if(tsc <= k->tsc)
- goto drop;
- if(tkipdecrypt(k, w, b, tsc) != 0)
- goto drop;
- break;
- case CCMP:
- tsc = (uvlong)b->rp[7]<<40 |
- (uvlong)b->rp[6]<<32 |
- (uvlong)b->rp[5]<<24 |
- (uvlong)b->rp[4]<<16 |
- (uvlong)b->rp[1]<<8 |
- (uvlong)b->rp[0];
- b->rp += 8;
- if(tsc <= k->tsc)
- goto drop;
- if(ccmpdecrypt(k, w, b, tsc) != 0)
- goto drop;
- break;
- default:
- drop:
- runlock(&wifi->crypt);
- freeb(b);
- return nil;
- }
- runlock(&wifi->crypt);
-
- k->tsc = tsc;
- b->rp -= n;
- memmove(b->rp, w, n);
- w = (Wifipkt*)b->rp;
- w->fc[1] &= ~0x40;
- return b;
-}
-
-static u16int Sbox[256] = {
- 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
- 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
- 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
- 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
- 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
- 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
- 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
- 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
- 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
- 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
- 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
- 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
- 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
- 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
- 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
- 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
- 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
- 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
- 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
- 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
- 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
- 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
- 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
- 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
- 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
- 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
- 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
- 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
- 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
- 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
- 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
- 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A
-};
-
-static void
-tkipk2tk(uchar key[16], u16int tk[8])
-{
- tk[0] = (u16int)key[1]<<8 | key[0];
- tk[1] = (u16int)key[3]<<8 | key[2];
- tk[2] = (u16int)key[5]<<8 | key[4];
- tk[3] = (u16int)key[7]<<8 | key[6];
- tk[4] = (u16int)key[9]<<8 | key[8];
- tk[5] = (u16int)key[11]<<8 | key[10];
- tk[6] = (u16int)key[13]<<8 | key[12];
- tk[7] = (u16int)key[15]<<8 | key[14];
-}
-
-static void
-tkipphase1(u32int tscu, uchar ta[Eaddrlen], u16int tk[8], u16int p1k[5])
-{
- u16int *k, i, x0, x1, x2;
-
- p1k[0] = tscu;
- p1k[1] = tscu>>16;
- p1k[2] = (u16int)ta[1]<<8 | ta[0];
- p1k[3] = (u16int)ta[3]<<8 | ta[2];
- p1k[4] = (u16int)ta[5]<<8 | ta[4];
-
- for(i=0; i<8; i++){
- k = &tk[i & 1];
-
- x0 = p1k[4] ^ k[0];
- x1 = Sbox[x0 >> 8];
- x2 = Sbox[x0 & 0xFF] ^ ((x1>>8) | (x1<<8));
- p1k[0] += x2;
- x0 = p1k[0] ^ k[2];
- x1 = Sbox[x0 >> 8];
- x2 = Sbox[x0 & 0xFF] ^ ((x1>>8) | (x1<<8));
- p1k[1] += x2;
- x0 = p1k[1] ^ k[4];
- x1 = Sbox[x0 >> 8];
- x2 = Sbox[x0 & 0xFF] ^ ((x1>>8) | (x1<<8));
- p1k[2] += x2;
- x0 = p1k[2] ^ k[6];
- x1 = Sbox[x0 >> 8];
- x2 = Sbox[x0 & 0xFF] ^ ((x1>>8) | (x1<<8));
- p1k[3] += x2;
- x0 = p1k[3] ^ k[0];
- x1 = Sbox[x0 >> 8];
- x2 = Sbox[x0 & 0xFF] ^ ((x1>>8) | (x1<<8));
- p1k[4] += x2;
-
- p1k[4] += i;
- }
-}
-
-static void
-tkipphase2(u16int tscl, u16int p1k[5], u16int tk[8], uchar rc4key[16])
-{
- u16int ppk[6], x0, x1, x2;
-
- ppk[0] = p1k[0];
- ppk[1] = p1k[1];
- ppk[2] = p1k[2];
- ppk[3] = p1k[3];
- ppk[4] = p1k[4];
- ppk[5] = p1k[4] + tscl;
-
- x0 = ppk[5] ^ tk[0];
- x1 = Sbox[x0 >> 8];
- x2 = Sbox[x0 & 0xFF] ^ ((x1>>8) | (x1<<8));
- ppk[0] += x2;
- x0 = ppk[0] ^ tk[1];
- x1 = Sbox[x0 >> 8];
- x2 = Sbox[x0 & 0xFF] ^ ((x1>>8) | (x1<<8));
- ppk[1] += x2;
- x0 = ppk[1] ^ tk[2];
- x1 = Sbox[x0 >> 8];
- x2 = Sbox[x0 & 0xFF] ^ ((x1>>8) | (x1<<8));
- ppk[2] += x2;
- x0 = ppk[2] ^ tk[3];
- x1 = Sbox[x0 >> 8];
- x2 = Sbox[x0 & 0xFF] ^ ((x1>>8) | (x1<<8));
- ppk[3] += x2;
- x0 = ppk[3] ^ tk[4];
- x1 = Sbox[x0 >> 8];
- x2 = Sbox[x0 & 0xFF] ^ ((x1>>8) | (x1<<8));
- ppk[4] += x2;
- x0 = ppk[4] ^ tk[5];
- x1 = Sbox[x0 >> 8];
- x2 = Sbox[x0 & 0xFF] ^ ((x1>>8) | (x1<<8));
- ppk[5] += x2;
-
- x2 = ppk[5] ^ tk[6];
- ppk[0] += (x2 >> 1) | (x2 << 15);
- x2 = ppk[0] ^ tk[7];
- ppk[1] += (x2 >> 1) | (x2 << 15);
-
- x2 = ppk[1];
- ppk[2] += (x2 >> 1) | (x2 << 15);
- x2 = ppk[2];
- ppk[3] += (x2 >> 1) | (x2 << 15);
- x2 = ppk[3];
- ppk[4] += (x2 >> 1) | (x2 << 15);
- x2 = ppk[4];
- ppk[5] += (x2 >> 1) | (x2 << 15);
-
- rc4key[0] = tscl >> 8;
- rc4key[1] = (rc4key[0] | 0x20) & 0x7F;
- rc4key[2] = tscl;
- rc4key[3] = (ppk[5] ^ tk[0]) >> 1;
- rc4key[4] = ppk[0];
- rc4key[5] = ppk[0] >> 8;
- rc4key[6] = ppk[1];
- rc4key[7] = ppk[1] >> 8;
- rc4key[8] = ppk[2];
- rc4key[9] = ppk[2] >> 8;
- rc4key[10] = ppk[3];
- rc4key[11] = ppk[3] >> 8;
- rc4key[12] = ppk[4];
- rc4key[13] = ppk[4] >> 8;
- rc4key[14] = ppk[5];
- rc4key[15] = ppk[5] >> 8;
-}
-
-typedef struct MICstate MICstate;
-struct MICstate
-{
- u32int l;
- u32int r;
- u32int m;
- u32int n;
-};
-
-static void
-micsetup(MICstate *s, uchar key[8])
-{
- s->l = (u32int)key[0] |
- (u32int)key[1]<<8 |
- (u32int)key[2]<<16 |
- (u32int)key[3]<<24;
- s->r = (u32int)key[4] |
- (u32int)key[5]<<8 |
- (u32int)key[6]<<16 |
- (u32int)key[7]<<24;
- s->m = 0;
- s->n = 0;
-}
-
-static void
-micupdate(MICstate *s, uchar *data, ulong len)
-{
- u32int l, r, m, n, e;
-
- l = s->l;
- r = s->r;
- m = s->m;
- n = s->n;
- e = n + len;
- while(n != e){
- m >>= 8;
- m |= (u32int)*data++ << 24;
- if(++n & 3)
- continue;
- l ^= m;
- r ^= (l << 17) | (l >> 15);
- l += r;
- r ^= ((l & 0x00FF00FFUL)<<8) | ((l & 0xFF00FF00UL)>>8);
- l += r;
- r ^= (l << 3) | (l >> 29);
- l += r;
- r ^= (l >> 2) | (l << 30);
- l += r;
- }
- s->l = l;
- s->r = r;
- s->m = m;
- s->n = n;
-}
-
-static void
-micfinish(MICstate *s, uchar mic[8])
-{
- static uchar pad[8] = { 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
-
- micupdate(s, pad, sizeof(pad));
-
- mic[0] = s->l;
- mic[1] = s->l>>8;
- mic[2] = s->l>>16;
- mic[3] = s->l>>24;
- mic[4] = s->r;
- mic[5] = s->r>>8;
- mic[6] = s->r>>16;
- mic[7] = s->r>>24;
-}
-
-static uchar pad4[4] = { 0x00, 0x00, 0x00, 0x00, };
-
-static void
-tkipencrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc)
-{
- u16int tk[8], p1k[5];
- uchar seed[16];
- RC4state rs;
- MICstate ms;
- ulong crc;
-
- micsetup(&ms, k->key+24);
- micupdate(&ms, dstaddr(w), Eaddrlen);
- micupdate(&ms, srcaddr(w), Eaddrlen);
- micupdate(&ms, pad4, 4);
- micupdate(&ms, b->rp, BLEN(b));
- micfinish(&ms, b->wp);
- b->wp += 8;
-
- crc = ethercrc(b->rp, BLEN(b));
- crc = ~crc;
- b->wp[0] = crc;
- b->wp[1] = crc>>8;
- b->wp[2] = crc>>16;
- b->wp[3] = crc>>24;
- b->wp += 4;
-
- tkipk2tk(k->key, tk);
- tkipphase1(tsc >> 16, w->a2, tk, p1k);
- tkipphase2(tsc & 0xFFFF, p1k, tk, seed);
- setupRC4state(&rs, seed, sizeof(seed));
- rc4(&rs, b->rp, BLEN(b));
-}
-
-static int
-tkipdecrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc)
-{
- uchar seed[16], mic[8];
- u16int tk[8], p1k[5];
- RC4state rs;
- MICstate ms;
- ulong crc;
-
- if(BLEN(b) < 8+4)
- return -1;
-
- tkipk2tk(k->key, tk);
- tkipphase1(tsc >> 16, w->a2, tk, p1k);
- tkipphase2(tsc & 0xFFFF, p1k, tk, seed);
- setupRC4state(&rs, seed, sizeof(seed));
- rc4(&rs, b->rp, BLEN(b));
-
- b->wp -= 4;
- crc = (ulong)b->wp[0] |
- (ulong)b->wp[1]<<8 |
- (ulong)b->wp[2]<<16 |
- (ulong)b->wp[3]<<24;
- crc = ~crc;
- crc ^= ethercrc(b->rp, BLEN(b));
-
- b->wp -= 8;
- micsetup(&ms, k->key+16);
- micupdate(&ms, dstaddr(w), Eaddrlen);
- micupdate(&ms, srcaddr(w), Eaddrlen);
- micupdate(&ms, pad4, 4);
- micupdate(&ms, b->rp, BLEN(b));
- micfinish(&ms, mic);
-
- return tsmemcmp(b->wp, mic, 8) | crc;
-}
-
-static uchar*
-putbe(uchar *p, int L, uint v)
-{
- while(--L >= 0)
- *p++ = (v >> L*8) & 0xFF;
- return p;
-}
-
-static void
-xblock(int L, int M, uchar *N, uchar *a, int la, int lm, uchar t[16], AESstate *s)
-{
- uchar l[8], *p, *x, *e;
-
- assert(M >= 4 && M <= 16);
- assert(L >= 2 && L <= 4);
-
- t[0] = ((la > 0)<<6) | ((M-2)/2)<<3 | (L-1); /* flags */
- memmove(&t[1], N, 15-L);
- putbe(&t[16-L], L, lm);
- aes_encrypt(s->ekey, s->rounds, t, t);
-
- if(la > 0){
- assert(la < 0xFF00);
- for(p = l, e = putbe(l, 2, la), x = t; p < e; x++, p++)
- *x ^= *p;
- for(e = a + la; a < e; x = t){
- for(; a < e && x < &t[16]; x++, a++)
- *x ^= *a;
- aes_encrypt(s->ekey, s->rounds, t, t);
- }
- }
-}
-
-static uchar*
-sblock(int L, uchar *N, uint i, uchar b[16], AESstate *s)
-{
- b[0] = L-1; /* flags */
- memmove(&b[1], N, 15-L);
- putbe(&b[16-L], L, i);
- aes_encrypt(s->ekey, s->rounds, b, b);
- return b;
-};
-
-static void
-aesCCMencrypt(int L, int M, uchar *N /* N[15-L] */,
- uchar *a /* a[la] */, int la,
- uchar *m /* m[lm+M] */, int lm,
- AESstate *s)
-{
- uchar t[16], b[16], *p, *x;
- uint i;
-
- xblock(L, M, N, a, la, lm, t, s);
-
- for(i = 1; lm >= 16; i++, m += 16, lm -= 16){
- sblock(L, N, i, b, s);
-
- *((u32int*)&t[0]) ^= *((u32int*)&m[0]);
- *((u32int*)&m[0]) ^= *((u32int*)&b[0]);
- *((u32int*)&t[4]) ^= *((u32int*)&m[4]);
- *((u32int*)&m[4]) ^= *((u32int*)&b[4]);
- *((u32int*)&t[8]) ^= *((u32int*)&m[8]);
- *((u32int*)&m[8]) ^= *((u32int*)&b[8]);
- *((u32int*)&t[12]) ^= *((u32int*)&m[12]);
- *((u32int*)&m[12]) ^= *((u32int*)&b[12]);
-
- aes_encrypt(s->ekey, s->rounds, t, t);
- }
- if(lm > 0){
- for(p = sblock(L, N, i, b, s), x = t; p < &b[lm]; x++, m++, p++){
- *x ^= *m;
- *m ^= *p;
- }
- aes_encrypt(s->ekey, s->rounds, t, t);
- }
-
- for(p = sblock(L, N, 0, b, s), x = t; p < &b[M]; x++, p++)
- *x ^= *p;
-
- memmove(m, t, M);
-}
-
-static int
-aesCCMdecrypt(int L, int M, uchar *N /* N[15-L] */,
- uchar *a /* a[la] */, int la,
- uchar *m /* m[lm+M] */, int lm,
- AESstate *s)
-{
- uchar t[16], b[16], *p, *x;
- uint i;
-
- xblock(L, M, N, a, la, lm, t, s);
-
- for(i = 1; lm >= 16; i++, m += 16, lm -= 16){
- sblock(L, N, i, b, s);
-
- *((u32int*)&m[0]) ^= *((u32int*)&b[0]);
- *((u32int*)&t[0]) ^= *((u32int*)&m[0]);
- *((u32int*)&m[4]) ^= *((u32int*)&b[4]);
- *((u32int*)&t[4]) ^= *((u32int*)&m[4]);
- *((u32int*)&m[8]) ^= *((u32int*)&b[8]);
- *((u32int*)&t[8]) ^= *((u32int*)&m[8]);
- *((u32int*)&m[12]) ^= *((u32int*)&b[12]);
- *((u32int*)&t[12]) ^= *((u32int*)&m[12]);
-
- aes_encrypt(s->ekey, s->rounds, t, t);
- }
- if(lm > 0){
- for(p = sblock(L, N, i, b, s), x = t; p < &b[lm]; x++, m++, p++){
- *m ^= *p;
- *x ^= *m;
- }
- aes_encrypt(s->ekey, s->rounds, t, t);
- }
-
- for(p = sblock(L, N, 0, b, s), x = t; p < &b[M]; x++, p++)
- *x ^= *p;
-
- return tsmemcmp(m, t, M);
-}
-
-static int
-setupCCMP(Wifipkt *w, uvlong tsc, uchar nonce[13], uchar auth[32])
-{
- uchar *p;
-
- nonce[0] = ((w->fc[0] & 0x0c) == 0x00) << 4;
- memmove(&nonce[1], w->a2, Eaddrlen);
- nonce[7] = tsc >> 40;
- nonce[8] = tsc >> 32;
- nonce[9] = tsc >> 24;
- nonce[10] = tsc >> 16;
- nonce[11] = tsc >> 8;
- nonce[12] = tsc;
-
- p = auth;
- *p++ = (w->fc[0] & (((w->fc[0] & 0x0c) == 0x08) ? 0x0f : 0xff));
- *p++ = (w->fc[1] & ~0x38) | 0x40;
- memmove(p, w->a1, Eaddrlen); p += Eaddrlen;
- memmove(p, w->a2, Eaddrlen); p += Eaddrlen;
- memmove(p, w->a3, Eaddrlen); p += Eaddrlen;
- *p++ = w->seq[0] & 0x0f;
- *p++ = 0;
- if((w->fc[1] & 3) == 0x03) {
- memmove(p, w->a4, Eaddrlen);
- p += Eaddrlen;
- }
-
- return p - auth;
-}
-
-static void
-ccmpencrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc)
-{
- uchar auth[32], nonce[13];
-
- aesCCMencrypt(2, 8, nonce, auth,
- setupCCMP(w, tsc, nonce, auth),
- b->rp, BLEN(b), (AESstate*)k->key);
- b->wp += 8;
-}
-
-static int
-ccmpdecrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc)
-{
- uchar auth[32], nonce[13];
-
- if(BLEN(b) < 8)
- return -1;
-
- b->wp -= 8;
- return aesCCMdecrypt(2, 8, nonce, auth,
- setupCCMP(w, tsc, nonce, auth),
- b->rp, BLEN(b), (AESstate*)k->key);
-}
-
-/*
- * Dynamic Mac Address Translation (DMAT)
- *
- * Wifi does not allow spoofing of the source mac which breaks
- * bridging. To solve this we proxy mac addresses, maintaining
- * a translation table from ip address to destination mac address.
- * Upstream ARP and NDP packets get ther source mac address changed
- * to proxy and a translation entry is added with the original mac
- * for downstream translation. The proxy does not appear in the
- * table.
- */
-#include "../ip/ip.h"
-#include "../ip/ipv6.h"
-
-static void
-dmatproxy(Block *bp, int upstream, uchar proxy[Eaddrlen], DMAT *t)
-{
- static uchar arp4[] = {
- 0x00, 0x01,
- 0x08, 0x00,
- 0x06, 0x04,
- 0x00,
- };
- uchar ip[IPaddrlen], mac[Eaddrlen], *targ, *end, *a, *o;
- ulong csum, c, h;
- Etherpkt *pkt;
- int proto, i;
- DMTE *te;
-
- end = bp->wp;
- pkt = (Etherpkt*)bp->rp;
- a = pkt->data;
- if(a >= end)
- return;
-
- if(upstream)
- memmove(pkt->s, proxy, Eaddrlen);
- else if(t->map == 0 || (pkt->d[0]&1) != 0 || memcmp(pkt->d, proxy, Eaddrlen) != 0)
- return;
-
- targ = nil;
- switch(pkt->type[0]<<8 | pkt->type[1]){
- default:
- return;
- case ETIP4:
- case ETIP6:
- switch(a[0]&0xF0){
- default:
- return;
- case IP_VER4:
- if(a+IP4HDR > end || (a[0]&15) < IP_HLEN4)
- return;
- v4tov6(ip, a+12+4*(upstream==0));
- proto = a[9];
- a += (a[0]&15)*4;
- break;
- case IP_VER6:
- if(a+IP6HDR > end)
- return;
- memmove(ip, a+8+16*(upstream==0), 16);
- proto = a[6];
- a += IP6HDR;
- break;
- }
- if(!upstream)
- break;
- switch(proto){
- case ICMPv6:
- if(a+8 > end)
- return;
- switch(a[0]){
- default:
- return;
- case 133: /* Router Solicitation */
- o = a+8;
- break;
- case 134: /* Router Advertisement */
- o = a+8+8;
- break;
- case 136: /* Neighbor Advertisement */
- targ = a+8;
- /* wet floor */
- case 135: /* Neighbor Solicitation */
- o = a+8+16;
- break;
- case 137: /* Redirect */
- o = a+8+16+16;
- break;
- }
- memset(mac, 0xFF, Eaddrlen);
- csum = (a[2]<<8 | a[3])^0xFFFF;
- while(o+8 <= end && o[1] != 0){
- switch(o[0]){
- case SRC_LLADDR:
- case TARGET_LLADDR:
- for(i=0; i<Eaddrlen; i += 2)
- csum += (o[2+i]<<8 | o[3+i])^0xFFFF;
- memmove(mac, o+2, Eaddrlen);
- memmove(o+2, proxy, Eaddrlen);
- for(i=0; i<Eaddrlen; i += 2)
- csum += (o[2+i]<<8 | o[3+i]);
- break;
- }
- o += o[1]*8;
- }
- while((c = csum >> 16) != 0)
- csum = (csum & 0xFFFF) + c;
- csum ^= 0xFFFF;
- a[2] = csum>>8;
- a[3] = csum;
- break;
- case UDP: /* for BOOTP */
- if(a+42 > end
- || (a[0]<<8 | a[1]) != 68
- || (a[2]<<8 | a[3]) != 67
- || a[8] != 1
- || a[9] != 1
- || a[10] != Eaddrlen
- || (a[18]&0x80) != 0
- || memcmp(a+36, proxy, Eaddrlen) == 0)
- return;
-
- csum = (a[6]<<8 | a[7])^0xFFFF;
-
- /* set the broadcast flag so response reaches us */
- csum += (a[18]<<8)^0xFFFF;
- a[18] |= 0x80;
- csum += (a[18]<<8);
-
- while((c = csum >> 16) != 0)
- csum = (csum & 0xFFFF) + c;
- csum ^= 0xFFFF;
-
- a[6] = csum>>8;
- a[7] = csum;
- default:
- return;
- }
- break;
- case ETARP:
- if(a+26 > end || memcmp(a, arp4, sizeof(arp4)) != 0 || (a[7] != 1 && a[7] != 2))
- return;
- v4tov6(ip, a+14+10*(upstream==0));
- if(upstream){
- memmove(mac, a+8, Eaddrlen);
- memmove(a+8, proxy, Eaddrlen);
- }
- break;
- }
-
-Again:
- h = ( (ip[IPaddrlen-1] ^ proxy[2])<<24 |
- (ip[IPaddrlen-2] ^ proxy[3])<<16 |
- (ip[IPaddrlen-3] ^ proxy[4])<<8 |
- (ip[IPaddrlen-4] ^ proxy[5]) ) % nelem(t->tab);
- te = &t->tab[h];
- h &= 63;
-
- if(upstream){
- if((mac[0]&1) != 0 || memcmp(mac, proxy, Eaddrlen) == 0)
- return;
- for(i=0; te->valid && i<nelem(t->tab); i++){
- if(memcmp(te->ip, ip, IPaddrlen) == 0)
- break;
- if(++te >= &t->tab[nelem(t->tab)])
- te = t->tab;
- }
- memmove(te->mac, mac, Eaddrlen);
- memmove(te->ip, ip, IPaddrlen);
- te->valid = 1;
- t->map |= 1ULL<<h;
- if(targ != nil){
- memmove(ip, targ, IPaddrlen);
- targ = nil;
- goto Again;
- }
- } else {
- if((t->map>>h & 1) == 0)
- return;
- for(i=0; te->valid && i<nelem(t->tab); i++){
- if(memcmp(te->ip, ip, IPaddrlen) == 0){
- memmove(pkt->d, te->mac, Eaddrlen);
- return;
- }
- if(++te >= &t->tab[nelem(t->tab)])
- te = t->tab;
- }
- }
-}
--- a/sys/src/9/pc/wifi.h
+++ /dev/null
@@ -1,116 +1,0 @@
-typedef struct Wkey Wkey;
-typedef struct Wnode Wnode;
-typedef struct Wifi Wifi;
-typedef struct Wifipkt Wifipkt;
-typedef struct DMAT DMAT;
-typedef struct DMTE DMTE;
-
-enum {
- Essidlen = 32,
-};
-
-/* cipher */
-enum {
- TKIP = 1,
- CCMP = 2,
-};
-
-struct Wkey
-{
- int cipher;
- int len;
- uvlong tsc;
- uchar key[];
-};
-
-struct Wnode
-{
- uchar bssid[Eaddrlen];
- char ssid[Essidlen+2];
-
- char *status;
-
- int rsnelen;
- uchar rsne[258];
- Wkey *txkey[1];
- Wkey *rxkey[5];
-
- int aid; /* association id */
- ulong lastsend;
- ulong lastseen;
-
- uchar *minrate; /* pointers into wifi->rates */
- uchar *maxrate;
- uchar *actrate;
-
- ulong txcount; /* statistics for rate adaption */
- ulong txerror;
-
- /* stuff from beacon */
- int ival;
- int cap;
- int channel;
- int brsnelen;
- uchar brsne[258];
-};
-
-struct DMTE
-{
- uchar ip[16];
- uchar mac[6];
- uchar valid;
-};
-
-struct DMAT
-{
- DMTE tab[127]; /* prime */
- uvlong map;
-};
-
-struct Wifi
-{
- Ether *ether;
-
- int debug;
-
- RWlock crypt;
- Queue *iq;
- ulong watchdog;
- ulong lastauth;
- Ref txseq;
- void (*transmit)(Wifi*, Wnode*, Block*);
-
- /* for searching */
- uchar bssid[Eaddrlen];
- char essid[Essidlen+2];
-
- /* supported data rates by hardware */
- uchar *rates;
-
- /* effective base station */
- Wnode *bss;
-
- Wnode node[32];
-
- DMAT dmat;
-};
-
-struct Wifipkt
-{
- uchar fc[2];
- uchar dur[2];
- uchar a1[Eaddrlen];
- uchar a2[Eaddrlen];
- uchar a3[Eaddrlen];
- uchar seq[2];
- uchar a4[Eaddrlen];
-};
-
-Wifi *wifiattach(Ether *ether, void (*transmit)(Wifi*, Wnode*, Block*));
-void wifiiq(Wifi*, Block*);
-int wifihdrlen(Wifipkt*);
-void wifitxfail(Wifi*, Block*);
-
-long wifistat(Wifi*, void*, long, ulong);
-long wifictl(Wifi*, void*, long);
-void wificfg(Wifi*, char*);
--- a/sys/src/9/pc64/mkfile
+++ b/sys/src/9/pc64/mkfile
@@ -83,7 +83,7 @@
# copies generated by the rule below
-PCHEADERS=wifi.h usbehci.h screen.h etherif.h ethermii.h mp.h io.h ahci.h \
+PCHEADERS=usbehci.h screen.h ethermii.h mp.h io.h ahci.h \
yukdump.h
REPCH=`{echo $PCHEADERS | sed 's/\.h//g; s/ /|/g'}
@@ -100,7 +100,7 @@
l.$O apbootstrap.$O: mem.h
-$ETHER: etherif.h ../port/netif.h
+$ETHER: ../port/etherif.h ../port/netif.h
$AUDIO: ../port/audioif.h
ether8003.$O ether8390.$O: ether8390.h
etheryuk.$O: yukdump.h
@@ -122,11 +122,9 @@
trap.$O: /sys/include/tos.h
ethermii.$O: ethermii.h
-etheriwl.$O: wifi.h
-etherwpi.$O: wifi.h
-etherrt2860.$O: wifi.h
-wifi.$O: wifi.h etherif.h ../port/netif.h /sys/include/libsec.h
-wifi.$O: ../ip/ip.h ../ip/ipv6.h
+etheriwl.$O: ../port/wifi.h
+etherwpi.$O: ../port/wifi.h
+etherrt2860.$O: ../port/wifi.h
init.h:D: ../port/initcode.c ../pc/init9.c
$CC ../port/initcode.c
--- a/sys/src/9/pc64/trap.c
+++ b/sys/src/9/pc64/trap.c
@@ -47,6 +47,15 @@
irq = -1;
}
+
+ /*
+ * IRQ2 doesn't really exist, it's used to gang the interrupt
+ * controllers together. A device set to IRQ2 will appear on
+ * the second interrupt controller as IRQ9.
+ */
+ if(irq == 2)
+ irq = 9;
+
if((v = xalloc(sizeof(Vctl))) == nil)
panic("intrenable: out of memory");
v->isintr = 1;
@@ -83,6 +92,8 @@
Vctl **pv, *v;
int vno;
+ if(irq == 2)
+ irq = 9;
if(arch->intrvecno == nil || (tbdf != BUSUNKNOWN && (irq == 0xff || irq == 0))){
/*
* on APIC machine, irq is pretty meaningless
--- a/sys/src/9/port/devaoe.c
+++ b/sys/src/9/port/devaoe.c
@@ -12,7 +12,7 @@
#include "ureg.h"
#include "../port/error.h"
#include "../port/netif.h"
-#include "etherif.h"
+#include "../port/etherif.h"
#include "../ip/ip.h"
#include "../port/aoe.h"
#include <fis.h>
--- /dev/null
+++ b/sys/src/9/port/devether.c
@@ -1,0 +1,653 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "pool.h"
+#include "ureg.h"
+#include "../port/error.h"
+#include "../port/netif.h"
+#include "../port/etherif.h"
+
+extern int eipfmt(Fmt*);
+
+static Ether *etherxx[MaxEther];
+
+Chan*
+etherattach(char* spec)
+{
+ ulong ctlrno;
+ char *p;
+ Chan *chan;
+
+ ctlrno = 0;
+ if(spec && *spec){
+ ctlrno = strtoul(spec, &p, 0);
+ if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther))
+ error(Ebadarg);
+ }
+ if(etherxx[ctlrno] == 0)
+ error(Enodev);
+
+ chan = devattach('l', spec);
+ if(waserror()){
+ chanfree(chan);
+ nexterror();
+ }
+ chan->dev = ctlrno;
+ if(etherxx[ctlrno]->attach)
+ etherxx[ctlrno]->attach(etherxx[ctlrno]);
+ poperror();
+ return chan;
+}
+
+static Walkqid*
+etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
+{
+ return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
+}
+
+static int
+etherstat(Chan* chan, uchar* dp, int n)
+{
+ return netifstat(etherxx[chan->dev], chan, dp, n);
+}
+
+static Chan*
+etheropen(Chan* chan, int omode)
+{
+ return netifopen(etherxx[chan->dev], chan, omode);
+}
+
+static Chan*
+ethercreate(Chan*, char*, int, ulong)
+{
+ error(Eperm);
+ return 0;
+}
+
+static void
+etherclose(Chan* chan)
+{
+ netifclose(etherxx[chan->dev], chan);
+}
+
+static long
+etherread(Chan* chan, void* buf, long n, vlong off)
+{
+ Ether *ether;
+ ulong offset = off;
+
+ ether = etherxx[chan->dev];
+ if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
+ /*
+ * With some controllers it is necessary to reach
+ * into the chip to extract statistics.
+ */
+ if(NETTYPE(chan->qid.path) == Nifstatqid)
+ return ether->ifstat(ether, buf, n, offset);
+ else if(NETTYPE(chan->qid.path) == Nstatqid)
+ ether->ifstat(ether, buf, 0, offset);
+ }
+
+ return netifread(ether, chan, buf, n, offset);
+}
+
+static Block*
+etherbread(Chan* chan, long n, ulong offset)
+{
+ return netifbread(etherxx[chan->dev], chan, n, offset);
+}
+
+static int
+etherwstat(Chan* chan, uchar* dp, int n)
+{
+ return netifwstat(etherxx[chan->dev], chan, dp, n);
+}
+
+static void
+etherrtrace(Netfile* f, Etherpkt* pkt, int len)
+{
+ int i, n;
+ Block *bp;
+
+ if(qwindow(f->in) <= 0)
+ return;
+ if(len > 58)
+ n = 58;
+ else
+ n = len;
+ bp = iallocb(64);
+ if(bp == nil)
+ return;
+ memmove(bp->wp, pkt->d, n);
+ i = TK2MS(MACHP(0)->ticks);
+ bp->wp[58] = len>>8;
+ bp->wp[59] = len;
+ bp->wp[60] = i>>24;
+ bp->wp[61] = i>>16;
+ bp->wp[62] = i>>8;
+ bp->wp[63] = i;
+ bp->wp += 64;
+ qpass(f->in, bp);
+}
+
+Block*
+etheriq(Ether* ether, Block* bp, int fromwire)
+{
+ Etherpkt *pkt;
+ ushort type;
+ int len, multi, tome, fromme;
+ Netfile **ep, *f, **fp, *fx;
+ Block *xbp;
+
+ ether->inpackets++;
+
+ pkt = (Etherpkt*)bp->rp;
+ len = BLEN(bp);
+ type = (pkt->type[0]<<8)|pkt->type[1];
+ fx = 0;
+ ep = ðer->f[Ntypes];
+
+ multi = pkt->d[0] & 1;
+ /* check for valid multicast addresses */
+ if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 && ether->prom == 0){
+ if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
+ if(fromwire){
+ freeb(bp);
+ bp = 0;
+ }
+ return bp;
+ }
+ }
+
+ /* is it for me? */
+ tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
+ fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
+
+ /*
+ * Multiplex the packet to all the connections which want it.
+ * If the packet is not to be used subsequently (fromwire != 0),
+ * attempt to simply pass it into one of the connections, thereby
+ * saving a copy of the data (usual case hopefully).
+ */
+ for(fp = ether->f; fp < ep; fp++){
+ if(f = *fp)
+ if(f->type == type || f->type < 0)
+ if(tome || multi || f->prom){
+ /* Don't want to hear loopback or bridged packets */
+ if(f->bridge && (tome || !fromwire && !fromme))
+ continue;
+ if(!f->headersonly){
+ if(fromwire && fx == 0)
+ fx = f;
+ else if(xbp = iallocb(len)){
+ memmove(xbp->wp, pkt, len);
+ xbp->wp += len;
+ xbp->flag = bp->flag;
+ if(qpass(f->in, xbp) < 0) {
+ // print("soverflow for f->in\n");
+ ether->soverflows++;
+ }
+ }
+ else {
+ // print("soverflow iallocb\n");
+ ether->soverflows++;
+ }
+ }
+ else
+ etherrtrace(f, pkt, len);
+ }
+ }
+
+ if(fx){
+ if(qpass(fx->in, bp) < 0) {
+ // print("soverflow for fx->in\n");
+ ether->soverflows++;
+ }
+ return 0;
+ }
+ if(fromwire){
+ freeb(bp);
+ return 0;
+ }
+
+ return bp;
+}
+
+static int
+etheroq(Ether* ether, Block* bp)
+{
+ int len, loopback;
+ Etherpkt *pkt;
+
+ ether->outpackets++;
+
+ /*
+ * Check if the packet has to be placed back onto the input queue,
+ * i.e. if it's a loopback or broadcast packet or the interface is
+ * in promiscuous mode.
+ * If it's a loopback packet indicate to etheriq that the data isn't
+ * needed and return, etheriq will pass-on or free the block.
+ * To enable bridging to work, only packets that were originated
+ * by this interface are fed back.
+ */
+ pkt = (Etherpkt*)bp->rp;
+ len = BLEN(bp);
+ loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
+ if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom)
+ if(etheriq(ether, bp, loopback) == 0)
+ return len;
+
+ qbwrite(ether->oq, bp);
+ if(ether->transmit != nil)
+ ether->transmit(ether);
+ return len;
+}
+
+static long
+etherwrite(Chan* chan, void* buf, long n, vlong)
+{
+ Ether *ether;
+ Block *bp;
+ int nn, onoff;
+ Cmdbuf *cb;
+
+ ether = etherxx[chan->dev];
+ if(NETTYPE(chan->qid.path) != Ndataqid) {
+ nn = netifwrite(ether, chan, buf, n);
+ if(nn >= 0)
+ return nn;
+ cb = parsecmd(buf, n);
+ if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
+ if(cb->nf <= 1)
+ onoff = 1;
+ else
+ onoff = atoi(cb->f[1]);
+ qnoblock(ether->oq, onoff);
+ free(cb);
+ return n;
+ }
+ free(cb);
+ if(ether->ctl!=nil)
+ return ether->ctl(ether,buf,n);
+
+ error(Ebadctl);
+ }
+
+ if(n > ether->maxmtu)
+ error(Etoobig);
+ if(n < ether->minmtu)
+ error(Etoosmall);
+
+ bp = allocb(n);
+ if(waserror()){
+ freeb(bp);
+ nexterror();
+ }
+ memmove(bp->rp, buf, n);
+ if(!ether->f[NETID(chan->qid.path)]->bridge)
+ memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
+ poperror();
+ bp->wp += n;
+
+ return etheroq(ether, bp);
+}
+
+static long
+etherbwrite(Chan* chan, Block* bp, ulong)
+{
+ Ether *ether;
+ long n;
+
+ n = BLEN(bp);
+ if(NETTYPE(chan->qid.path) != Ndataqid){
+ if(waserror()) {
+ freeb(bp);
+ nexterror();
+ }
+ n = etherwrite(chan, bp->rp, n, 0);
+ poperror();
+ freeb(bp);
+ return n;
+ }
+ ether = etherxx[chan->dev];
+
+ if(n > ether->maxmtu){
+ freeb(bp);
+ error(Etoobig);
+ }
+ if(n < ether->minmtu){
+ freeb(bp);
+ error(Etoosmall);
+ }
+
+ return etheroq(ether, bp);
+}
+
+static struct {
+ char* type;
+ int (*reset)(Ether*);
+} cards[MaxEther+1];
+
+void
+addethercard(char* t, int (*r)(Ether*))
+{
+ static int ncard;
+
+ if(ncard == MaxEther)
+ panic("too many ether cards");
+ cards[ncard].type = t;
+ cards[ncard].reset = r;
+ ncard++;
+}
+
+static Ether*
+etherprobe(int cardno, int ctlrno)
+{
+ int i, lg;
+ ulong mb, bsz;
+ Ether *ether;
+
+ ether = malloc(sizeof(Ether));
+ if(ether == nil){
+ print("etherprobe: no memory for Ether\n");
+ return nil;
+ }
+ memset(ether, 0, sizeof(Ether));
+ ether->tbdf = BUSUNKNOWN;
+ ether->irq = -1;
+ ether->ctlrno = ctlrno;
+ ether->mbps = 10;
+ ether->minmtu = ETHERMINTU;
+ ether->maxmtu = ETHERMAXTU;
+
+ if(cardno < 0){
+ if(isaconfig("ether", ctlrno, ether) == 0){
+ free(ether);
+ return nil;
+ }
+ for(cardno = 0; cards[cardno].type; cardno++){
+ if(cistrcmp(cards[cardno].type, ether->type))
+ continue;
+ for(i = 0; i < ether->nopt; i++){
+ if(strncmp(ether->opt[i], "ea=", 3))
+ continue;
+ if(parseether(ether->ea, ðer->opt[i][3]))
+ memset(ether->ea, 0, Eaddrlen);
+ }
+ break;
+ }
+ }
+
+ if(cardno >= MaxEther || cards[cardno].type == nil){
+ free(ether);
+ return nil;
+ }
+ snprint(ether->name, sizeof(ether->name), "ether%d", ctlrno);
+ if(cards[cardno].reset(ether) < 0){
+ free(ether);
+ return nil;
+ }
+
+ print("#l%d: %s: %dMbps port 0x%luX irq %d ea %E\n",
+ ctlrno, cards[cardno].type,
+ ether->mbps, ether->port, ether->irq, ether->ea);
+
+ /* compute log10(ether->mbps) into lg */
+ for(lg = 0, mb = ether->mbps; mb >= 10; lg++)
+ mb /= 10;
+ if (lg > 0)
+ lg--;
+ if (lg > 14) /* 2^(14+17) = 2³¹ */
+ lg = 14;
+ /* allocate larger output queues for higher-speed interfaces */
+ bsz = 1UL << (lg + 17); /* 2¹⁷ = 128K, bsz = 2ⁿ × 128K */
+ while (bsz > mainmem->maxsize / 8 && bsz > 128*1024)
+ bsz /= 2;
+
+ netifinit(ether, ether->name, Ntypes, bsz);
+ if(ether->oq == nil) {
+ ether->oq = qopen(bsz, Qmsg, 0, 0);
+ ether->limit = bsz;
+ }
+ if(ether->oq == nil)
+ panic("etherreset %s: can't allocate output queue of %ld bytes", ether->name, bsz);
+
+ ether->alen = Eaddrlen;
+ memmove(ether->addr, ether->ea, Eaddrlen);
+ memset(ether->bcast, 0xFF, Eaddrlen);
+
+ return ether;
+}
+
+static void
+etherreset(void)
+{
+ Ether *ether;
+ int cardno, ctlrno;
+
+ fmtinstall('E', eipfmt);
+
+ for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){
+ if((ether = etherprobe(-1, ctlrno)) == nil)
+ continue;
+ etherxx[ctlrno] = ether;
+ }
+
+ if(getconf("*noetherprobe"))
+ return;
+
+ cardno = ctlrno = 0;
+ while(cards[cardno].type != nil && ctlrno < MaxEther){
+ if(etherxx[ctlrno] != nil){
+ ctlrno++;
+ continue;
+ }
+ if((ether = etherprobe(cardno, ctlrno)) == nil){
+ cardno++;
+ continue;
+ }
+ etherxx[ctlrno] = ether;
+ ctlrno++;
+ }
+}
+
+static void
+ethershutdown(void)
+{
+ Ether *ether;
+ int i;
+
+ for(i = 0; i < MaxEther; i++){
+ ether = etherxx[i];
+ if(ether == nil)
+ continue;
+ if(ether->shutdown == nil) {
+ print("#l%d: no shutdown function\n", i);
+ continue;
+ }
+ (*ether->shutdown)(ether);
+ }
+}
+
+
+#define POLY 0xedb88320
+
+/* really slow 32 bit crc for ethers */
+ulong
+ethercrc(uchar *p, int len)
+{
+ int i, j;
+ ulong crc, b;
+
+ crc = 0xffffffff;
+ for(i = 0; i < len; i++){
+ b = *p++;
+ for(j = 0; j < 8; j++){
+ crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
+ b >>= 1;
+ }
+ }
+ return crc;
+}
+
+Dev etherdevtab = {
+ 'l',
+ "ether",
+
+ etherreset,
+ devinit,
+ ethershutdown,
+ etherattach,
+ etherwalk,
+ etherstat,
+ etheropen,
+ ethercreate,
+ etherclose,
+ etherread,
+ etherbread,
+ etherwrite,
+ etherbwrite,
+ devremove,
+ etherwstat,
+};
+
+enum { PktHdr = 42 };
+typedef struct Netconsole Netconsole;
+struct Netconsole {
+ char buf[512];
+ int n;
+ Lock;
+ Ether *ether;
+};
+static Netconsole *netcons;
+
+extern ushort ipcsum(uchar *);
+
+void
+netconsputc(Uart *, int c)
+{
+ char *p;
+ u16int cs;
+
+ ilock(netcons);
+ netcons->buf[netcons->n++] = c;
+ if(c != '\n' && netcons->n < sizeof(netcons->buf)){
+ iunlock(netcons);
+ return;
+ }
+ p = netcons->buf;
+ p[16] = netcons->n - 14 >> 8;
+ p[17] = netcons->n - 14;
+ p[24] = 0;
+ p[25] = 0;
+ cs = ipcsum((uchar*) p + 14);
+ p[24] = cs >> 8;
+ p[25] = cs;
+ p[38] = netcons->n - 34 >> 8;
+ p[39] = netcons->n - 34;
+ memmove(p+Eaddrlen, netcons->ether->ea, Eaddrlen);
+ qiwrite(netcons->ether->oq, p, netcons->n);
+ netcons->n = PktHdr;
+ iunlock(netcons);
+ if(netcons->ether->transmit != nil)
+ netcons->ether->transmit(netcons->ether);
+}
+
+PhysUart netconsphys = {
+ .putc = netconsputc,
+};
+Uart netconsuart = { .phys = &netconsphys };
+
+void
+netconsole(void)
+{
+ char *p;
+ char *r;
+ int i;
+ int srcport, devno, dstport;
+ u8int srcip[4], dstip[4];
+ u64int dstmac;
+ Netconsole *nc;
+
+ if((p = getconf("console")) == nil || strncmp(p, "net ", 4) != 0)
+ return;
+ p += 4;
+ for(i = 0; i < 4; i++){
+ srcip[i] = strtol(p, &r, 0);
+ p = r + 1;
+ if(i == 3) break;
+ if(*r != '.') goto err;
+ }
+ if(*r == '!'){
+ srcport = strtol(p, &r, 0);
+ p = r + 1;
+ }else
+ srcport = 6665;
+ if(*r == '/'){
+ devno = strtol(p, &r, 0);
+ p = r + 1;
+ }else
+ devno = 0;
+ if(*r != ',') goto err;
+ for(i = 0; i < 4; i++){
+ dstip[i] = strtol(p, &r, 0);
+ p = r + 1;
+ if(i == 3) break;
+ if(*r != '.') goto err;
+ }
+ if(*r == '!'){
+ dstport = strtol(p, &r, 0);
+ p = r + 1;
+ }else
+ dstport = 6666;
+ if(*r == '/'){
+ dstmac = strtoull(p, &r, 16);
+ if(r - p != 12) goto err;
+ }else
+ dstmac = ((uvlong)-1) >> 16;
+ if(*r != 0) goto err;
+
+ if(devno >= MaxEther || etherxx[devno] == nil){
+ print("netconsole: no device #l%d\n", devno);
+ return;
+ }
+
+ nc = malloc(sizeof(Netconsole));
+ if(nc == nil){
+ print("netconsole: out of memory");
+ return;
+ }
+ memset(nc, 0, sizeof(Netconsole));
+ nc->ether = etherxx[devno];
+
+ uchar header[PktHdr] = {
+ /* 0 */ dstmac >> 40, dstmac >> 32, dstmac >> 24, dstmac >> 16, dstmac >> 8, dstmac >> 0,
+ /* 6 */ 0, 0, 0, 0, 0, 0,
+ /* 12 */ 0x08, 0x00,
+ /* 14 */ 0x45, 0x00,
+ /* 16 */ 0x00, 0x00, /* total length */
+ /* 18 */ 0x00, 0x00, 0x00, 0x00,
+ /* 22 */ 64, /* ttl */
+ /* 23 */ 0x11, /* protocol */
+ /* 24 */ 0x00, 0x00, /* checksum */
+ /* 26 */ srcip[0], srcip[1], srcip[2], srcip[3],
+ /* 30 */ dstip[0], dstip[1], dstip[2], dstip[3],
+ /* 34 */ srcport >> 8, srcport, dstport >> 8, dstport,
+ /* 38 */ 0x00, 0x00, /* length */
+ /* 40 */ 0x00, 0x00 /* checksum */
+ };
+
+ memmove(nc->buf, header, PktHdr);
+ nc->n = PktHdr;
+
+ netcons = nc;
+ consuart = &netconsuart;
+ return;
+
+err:
+ print("netconsole: invalid string %#q\n", getconf("console"));
+ print("netconsole: usage: srcip[!srcport][/srcdev],dstip[!dstport][/dstmac]\n");
+}
--- /dev/null
+++ b/sys/src/9/port/ethersink.c
@@ -1,0 +1,60 @@
+/*
+ * An ethernet /dev/null.
+ * Useful as a bridging target with ethernet-based VPN.
+ */
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+#include "../port/netif.h"
+#include "../port/etherif.h"
+
+static long
+ctl(Ether *ether, void *buf, long n)
+{
+ uchar ea[Eaddrlen];
+ Cmdbuf *cb;
+
+ cb = parsecmd(buf, n);
+ if(cb->nf >= 2
+ && strcmp(cb->f[0], "ea")==0
+ && parseether(ea, cb->f[1]) == 0){
+ free(cb);
+ memmove(ether->ea, ea, Eaddrlen);
+ memmove(ether->addr, ether->ea, Eaddrlen);
+ return 0;
+ }
+ free(cb);
+ error(Ebadctl);
+ return -1; /* not reached */
+}
+
+static void
+nop(Ether*)
+{
+}
+
+static int
+reset(Ether* ether)
+{
+ if(ether->type==nil)
+ return -1;
+ ether->mbps = 1000;
+ ether->attach = nop;
+ ether->transmit = nop;
+ ether->ifstat = nil;
+ ether->ctl = ctl;
+ ether->promiscuous = nil;
+ ether->multicast = nil;
+ ether->arg = ether;
+ return 0;
+}
+
+void
+ethersinklink(void)
+{
+ addethercard("sink", reset);
+}
--- a/sys/src/9/port/portmkfile
+++ b/sys/src/9/port/portmkfile
@@ -101,3 +101,6 @@
sysproc.$O: /sys/include/a.out.h
syscallfmt.$O: /sys/src/libc/9syscall/sys.h
devusb.$O: ../port/usb.h
+devether.$O: ../port/etherif.h ../port/netif.h
+wifi.$O: ../port/etherif.h ../port/netif.h ../port/wifi.h /sys/include/libsec.h
+wifi.$O: ../ip/ip.h ../ip/ipv6.h
--- /dev/null
+++ b/sys/src/9/port/wifi.c
@@ -1,0 +1,1880 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "ureg.h"
+#include "../port/error.h"
+#include "../port/netif.h"
+#include "../port/etherif.h"
+#include "../port/wifi.h"
+
+#include <libsec.h>
+
+typedef struct SNAP SNAP;
+struct SNAP
+{
+ uchar dsap;
+ uchar ssap;
+ uchar control;
+ uchar orgcode[3];
+ uchar type[2];
+};
+
+enum {
+ WIFIHDRSIZE = 2+2+3*6+2,
+ SNAPHDRSIZE = 8,
+};
+
+static char Sconn[] = "connecting";
+static char Sauth[] = "authenticated";
+static char Sneedauth[] = "need authentication";
+static char Sunauth[] = "unauthenticated";
+
+static char Sassoc[] = "associated";
+static char Sunassoc[] = "unassociated";
+static char Sblocked[] = "blocked"; /* no keys negotiated. only pass EAPOL frames */
+
+static uchar basicrates[] = {
+ 0x80 | 2, /* 1.0 Mb/s */
+ 0x80 | 4, /* 2.0 Mb/s */
+ 0x80 | 11, /* 5.5 Mb/s */
+ 0x80 | 22, /* 11.0 Mb/s */
+
+ 0
+};
+
+static Block* wifidecrypt(Wifi *, Wnode *, Block *);
+static Block* wifiencrypt(Wifi *, Wnode *, Block *);
+static void freewifikeys(Wifi *, Wnode *);
+
+static void dmatproxy(Block *bp, int upstream, uchar proxy[Eaddrlen], DMAT *t);
+
+static uchar*
+srcaddr(Wifipkt *w)
+{
+ if((w->fc[1] & 0x02) == 0)
+ return w->a2;
+ if((w->fc[1] & 0x01) == 0)
+ return w->a3;
+ return w->a4;
+}
+static uchar*
+dstaddr(Wifipkt *w)
+{
+ if((w->fc[1] & 0x01) != 0)
+ return w->a3;
+ return w->a1;
+}
+
+int
+wifihdrlen(Wifipkt *w)
+{
+ int n;
+
+ n = WIFIHDRSIZE;
+ if((w->fc[0] & 0x0c) == 0x08)
+ if((w->fc[0] & 0xf0) == 0x80){ /* QOS */
+ n += 2;
+ if(w->fc[1] & 0x80)
+ n += 4;
+ }
+ if((w->fc[1] & 3) == 0x03)
+ n += Eaddrlen;
+ return n;
+}
+
+void
+wifiiq(Wifi *wifi, Block *b)
+{
+ SNAP s;
+ Wifipkt h, *w;
+ Etherpkt *e;
+ int hdrlen;
+
+ if(BLEN(b) < WIFIHDRSIZE)
+ goto drop;
+ w = (Wifipkt*)b->rp;
+ hdrlen = wifihdrlen(w);
+ if(BLEN(b) < hdrlen)
+ goto drop;
+ if(memcmp(srcaddr(w), wifi->ether->ea, Eaddrlen) == 0)
+ goto drop;
+ if(w->fc[1] & 0x40){
+ /* encrypted */
+ qpass(wifi->iq, b);
+ return;
+ }
+ switch(w->fc[0] & 0x0c){
+ case 0x00: /* management */
+ if((w->fc[1] & 3) != 0x00) /* STA->STA */
+ break;
+ qpass(wifi->iq, b);
+ return;
+ case 0x04: /* control */
+ break;
+ case 0x08: /* data */
+ b->rp += hdrlen;
+ switch(w->fc[0] & 0xf0){
+ default:
+ goto drop;
+ case 0x80: /* QOS */
+ case 0x00:
+ break;
+ }
+ if(BLEN(b) < SNAPHDRSIZE)
+ break;
+ memmove(&s, b->rp, SNAPHDRSIZE);
+ if(s.dsap != 0xAA || s.ssap != 0xAA || s.control != 3)
+ break;
+ if(s.orgcode[0] != 0 || s.orgcode[1] != 0 || s.orgcode[2] != 0)
+ break;
+ b->rp += SNAPHDRSIZE-ETHERHDRSIZE;
+ h = *w;
+ e = (Etherpkt*)b->rp;
+ memmove(e->d, dstaddr(&h), Eaddrlen);
+ memmove(e->s, srcaddr(&h), Eaddrlen);
+ memmove(e->type, s.type, 2);
+
+ dmatproxy(b, 0, wifi->ether->ea, &wifi->dmat);
+
+ etheriq(wifi->ether, b, 1);
+ return;
+ }
+drop:
+ freeb(b);
+}
+
+static void
+wifitx(Wifi *wifi, Wnode *wn, Block *b)
+{
+ Wifipkt *w;
+ uint seq;
+
+ wn->lastsend = MACHP(0)->ticks;
+
+ seq = incref(&wifi->txseq);
+ seq <<= 4;
+
+ w = (Wifipkt*)b->rp;
+ w->dur[0] = 0;
+ w->dur[1] = 0;
+ w->seq[0] = seq;
+ w->seq[1] = seq>>8;
+
+ if((w->fc[0] & 0x0c) != 0x00){
+ b = wifiencrypt(wifi, wn, b);
+ if(b == nil)
+ return;
+ }
+
+ if((wn->txcount++ & 255) == 255 && wn->actrate != nil && wn->actrate != wn->maxrate){
+ uchar *a, *p;
+
+ for(a = wn->maxrate, p = wifi->rates; *p; p++){
+ if(*p < *a && *p > *wn->actrate)
+ a = p;
+ }
+ wn->actrate = a;
+ }
+
+ (*wifi->transmit)(wifi, wn, b);
+}
+
+static Wnode*
+nodelookup(Wifi *wifi, uchar *bssid, int new)
+{
+ Wnode *wn, *nn;
+
+ if(memcmp(bssid, wifi->ether->bcast, Eaddrlen) == 0)
+ return nil;
+ if((wn = wifi->bss) != nil){
+ if(memcmp(wn->bssid, bssid, Eaddrlen) == 0)
+ return wn;
+ }
+ if((nn = wifi->node) == wn)
+ nn++;
+ for(wn = wifi->node; wn != &wifi->node[nelem(wifi->node)]; wn++){
+ if(wn == wifi->bss)
+ continue;
+ if(memcmp(wn->bssid, bssid, Eaddrlen) == 0)
+ return wn;
+ if((long)(wn->lastsend - nn->lastsend) < 0
+ || (long)(wn->lastseen - nn->lastseen) < 0)
+ nn = wn;
+ }
+ if(!new)
+ return nil;
+ freewifikeys(wifi, nn);
+ memset(nn, 0, sizeof(Wnode));
+ memmove(nn->bssid, bssid, Eaddrlen);
+ return nn;
+}
+
+void
+wifitxfail(Wifi *wifi, Block *b)
+{
+ Wifipkt *w;
+ Wnode *wn;
+
+ if(b == nil)
+ return;
+ w = (Wifipkt*)b->rp;
+ wn = nodelookup(wifi, w->a1, 0);
+ if(wn == nil)
+ return;
+ wn->txerror++;
+ if(wn->actrate != nil && wn->minrate != wn->actrate){
+ uchar *a, *p;
+
+ for(a = wn->minrate, p = wifi->rates; *p; p++){
+ if(*p > *a && *p < *wn->actrate)
+ a = p;
+ }
+ wn->actrate = a;
+ }
+}
+
+static uchar*
+putrates(uchar *p, uchar *rates)
+{
+ int n, m;
+
+ n = m = strlen((char*)rates);
+ if(n > 8)
+ n = 8;
+ /* supported rates */
+ *p++ = 1;
+ *p++ = n;
+ memmove(p, rates, n);
+ p += n;
+ if(m > 8){
+ /* extended supported rates */
+ *p++ = 50;
+ *p++ = m;
+ memmove(p, rates, m);
+ p += m;
+ }
+ return p;
+}
+
+static void
+wifiprobe(Wifi *wifi, Wnode *wn)
+{
+ Wifipkt *w;
+ Block *b;
+ uchar *p;
+ int n;
+
+ n = strlen(wifi->essid);
+ if(n == 0){
+ /* no specific essid, just tell driver to tune channel */
+ (*wifi->transmit)(wifi, wn, nil);
+ return;
+ }
+
+ b = allocb(WIFIHDRSIZE + 512);
+ w = (Wifipkt*)b->wp;
+ w->fc[0] = 0x40; /* probe request */
+ w->fc[1] = 0x00; /* STA->STA */
+ memmove(w->a1, wifi->ether->bcast, Eaddrlen); /* ??? */
+ memmove(w->a2, wifi->ether->ea, Eaddrlen);
+ memmove(w->a3, wifi->ether->bcast, Eaddrlen);
+ b->wp += WIFIHDRSIZE;
+ p = b->wp;
+
+ *p++ = 0; /* set */
+ *p++ = n;
+ memmove(p, wifi->essid, n);
+ p += n;
+
+ p = putrates(p, wifi->rates);
+
+ *p++ = 3; /* ds parameter set */
+ *p++ = 1;
+ *p++ = wn->channel;
+
+ b->wp = p;
+ wifitx(wifi, wn, b);
+}
+
+static void
+sendauth(Wifi *wifi, Wnode *bss)
+{
+ Wifipkt *w;
+ Block *b;
+ uchar *p;
+
+ b = allocb(WIFIHDRSIZE + 3*2);
+ w = (Wifipkt*)b->wp;
+ w->fc[0] = 0xB0; /* auth request */
+ w->fc[1] = 0x00; /* STA->STA */
+ memmove(w->a1, bss->bssid, Eaddrlen); /* ??? */
+ memmove(w->a2, wifi->ether->ea, Eaddrlen);
+ memmove(w->a3, bss->bssid, Eaddrlen);
+ b->wp += WIFIHDRSIZE;
+ p = b->wp;
+ *p++ = 0; /* alg */
+ *p++ = 0;
+ *p++ = 1; /* seq */
+ *p++ = 0;
+ *p++ = 0; /* status */
+ *p++ = 0;
+ b->wp = p;
+
+ bss->aid = 0;
+
+ wifitx(wifi, bss, b);
+}
+
+static void
+sendassoc(Wifi *wifi, Wnode *bss)
+{
+ Wifipkt *w;
+ Block *b;
+ uchar *p;
+ int cap, n;
+
+ b = allocb(WIFIHDRSIZE + 512);
+ w = (Wifipkt*)b->wp;
+ w->fc[0] = 0x00; /* assoc request */
+ w->fc[1] = 0x00; /* STA->STA */
+ memmove(w->a1, bss->bssid, Eaddrlen); /* ??? */
+ memmove(w->a2, wifi->ether->ea, Eaddrlen);
+ memmove(w->a3, bss->bssid, Eaddrlen);
+ b->wp += WIFIHDRSIZE;
+ p = b->wp;
+
+ /* capinfo */
+ cap = 1; // ESS
+ cap |= (1<<5); // Short Preamble
+ cap |= (1<<10) & bss->cap; // Short Slot Time
+ *p++ = cap;
+ *p++ = cap>>8;
+
+ /* interval */
+ *p++ = 16;
+ *p++ = 16>>8;
+
+ n = strlen(bss->ssid);
+ *p++ = 0; /* SSID */
+ *p++ = n;
+ memmove(p, bss->ssid, n);
+ p += n;
+
+ p = putrates(p, wifi->rates);
+
+ n = bss->rsnelen;
+ if(n > 0){
+ memmove(p, bss->rsne, n);
+ p += n;
+ }
+
+ b->wp = p;
+ wifitx(wifi, bss, b);
+}
+
+static void
+setstatus(Wifi *wifi, Wnode *wn, char *new)
+{
+ char *old;
+
+ old = wn->status;
+ wn->status = new;
+ if(wifi->debug && new != old)
+ print("#l%d: status %E: %.12ld %.12ld: %s -> %s (from pc=%#p)\n",
+ wifi->ether->ctlrno,
+ wn->bssid,
+ TK2MS(MACHP(0)->ticks), TK2MS(MACHP(0)->ticks - wn->lastsend),
+ old, new,
+ getcallerpc(&wifi));
+}
+
+static void
+recvassoc(Wifi *wifi, Wnode *wn, uchar *d, int len)
+{
+ uint s;
+
+ if(len < 2+2+2)
+ return;
+
+ d += 2; /* caps */
+ s = d[0] | d[1]<<8;
+ d += 2;
+ switch(s){
+ case 0x00:
+ wn->aid = d[0] | d[1]<<8;
+ if(wn->rsnelen > 0)
+ setstatus(wifi, wn, Sblocked);
+ else
+ setstatus(wifi, wn, Sassoc);
+ break;
+ default:
+ wn->aid = 0;
+ setstatus(wifi, wn, Sunassoc);
+ }
+}
+
+static void
+recvbeacon(Wifi *wifi, Wnode *wn, uchar *d, int len)
+{
+ static uchar wpa1oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
+ uchar *e, *x, *p, t;
+ int rsnset;
+
+ len -= 8+2+2;
+ if(len < 0)
+ return;
+
+ d += 8; /* timestamp */
+ wn->ival = d[0] | d[1]<<8;
+ d += 2;
+ wn->cap = d[0] | d[1]<<8;
+ d += 2;
+
+ rsnset = 0;
+ for(e = d + len; d+2 <= e; d = x){
+ d += 2;
+ x = d + d[-1];
+ if(x > e)
+ break; /* truncated */
+ t = d[-2];
+ switch(t){
+ case 0: /* SSID */
+ len = 0;
+ while(len < Essidlen && d+len < x && d[len] != 0)
+ len++;
+ if(len == 0)
+ continue;
+ if(len != strlen(wn->ssid) || strncmp(wn->ssid, (char*)d, len) != 0){
+ strncpy(wn->ssid, (char*)d, len);
+ wn->ssid[len] = 0;
+ }
+ break;
+ case 1: /* supported rates */
+ case 50: /* extended rates */
+ if(wn->actrate != nil || wifi->rates == nil)
+ break; /* already set */
+ while(d < x){
+ t = *d++ | 0x80;
+ for(p = wifi->rates; *p != 0; p++){
+ if(*p == t){
+ if(wn->minrate == nil || t < *wn->minrate)
+ wn->minrate = p;
+ if(wn->maxrate == nil || t > *wn->maxrate)
+ wn->maxrate = p;
+ break;
+ }
+ }
+ wn->actrate = wn->maxrate;
+ }
+ break;
+ case 3: /* DSPARAMS */
+ if(d != x)
+ wn->channel = d[0];
+ break;
+ case 221: /* vendor specific */
+ len = x - d;
+ if(rsnset || len < sizeof(wpa1oui) || memcmp(d, wpa1oui, sizeof(wpa1oui)) != 0)
+ break;
+ /* no break */
+ case 48: /* RSN information */
+ len = x - &d[-2];
+ memmove(wn->brsne, &d[-2], len);
+ wn->brsnelen = len;
+ rsnset = 1;
+ break;
+ }
+ }
+}
+
+static void
+freewifikeys(Wifi *wifi, Wnode *wn)
+{
+ int i;
+
+ wlock(&wifi->crypt);
+ for(i=0; i<nelem(wn->rxkey); i++){
+ secfree(wn->rxkey[i]);
+ wn->rxkey[i] = nil;
+ }
+ for(i=0; i<nelem(wn->txkey); i++){
+ secfree(wn->txkey[i]);
+ wn->txkey[i] = nil;
+ }
+ wunlock(&wifi->crypt);
+}
+
+static void
+wifideauth(Wifi *wifi, Wnode *wn)
+{
+ Ether *ether;
+ Netfile *f;
+ int i;
+
+ /* deassociate node, clear keys */
+ setstatus(wifi, wn, Sunauth);
+ freewifikeys(wifi, wn);
+ memset(&wifi->dmat, 0, sizeof(wifi->dmat));
+ wn->aid = 0;
+
+ if(wn == wifi->bss){
+ /* notify driver about node aid association */
+ (*wifi->transmit)(wifi, wn, nil);
+
+ /* notify aux/wpa with a zero length packet that we got deassociated from the ap */
+ ether = wifi->ether;
+ for(i=0; i<ether->nfile; i++){
+ f = ether->f[i];
+ if(f == nil || f->in == nil || f->inuse == 0 || f->type != 0x888e)
+ continue;
+ qflush(f->in);
+ qwrite(f->in, 0, 0);
+ }
+ qflush(ether->oq);
+ }
+}
+
+/* check if a node qualifies as our bss matching bssid and essid */
+static int
+goodbss(Wifi *wifi, Wnode *wn)
+{
+ if(memcmp(wifi->bssid, wifi->ether->bcast, Eaddrlen) != 0){
+ if(memcmp(wifi->bssid, wn->bssid, Eaddrlen) != 0)
+ return 0; /* bssid doesnt match */
+ } else if(wifi->essid[0] == 0)
+ return 0; /* both bssid and essid unspecified */
+ if(wifi->essid[0] != 0 && strcmp(wifi->essid, wn->ssid) != 0)
+ return 0; /* essid doesnt match */
+ return 1;
+}
+
+static void
+wifiproc(void *arg)
+{
+ Wifi *wifi;
+ Wifipkt *w;
+ Wnode *wn;
+ Block *b;
+
+ b = nil;
+ wifi = arg;
+ while(waserror())
+ ;
+ for(;;){
+ if(b != nil){
+ freeb(b);
+ b = nil;
+ continue;
+ }
+ if((b = qbread(wifi->iq, 100000)) == nil)
+ break;
+ w = (Wifipkt*)b->rp;
+ if(w->fc[1] & 0x40){
+ /* encrypted */
+ if((wn = nodelookup(wifi, w->a2, 0)) == nil)
+ continue;
+ wn->lastseen = MACHP(0)->ticks;
+ if((b = wifidecrypt(wifi, wn, b)) != nil){
+ w = (Wifipkt*)b->rp;
+ if(w->fc[1] & 0x40)
+ continue;
+ wifiiq(wifi, b);
+ b = nil;
+ }
+ continue;
+ }
+ /* management */
+ if((w->fc[0] & 0x0c) != 0x00)
+ continue;
+
+ switch(w->fc[0] & 0xf0){
+ case 0x50: /* probe response */
+ if(wifi->debug)
+ print("#l%d: got probe from %E\n", wifi->ether->ctlrno, w->a3);
+ /* no break */
+ case 0x80: /* beacon */
+ if((wn = nodelookup(wifi, w->a3, 1)) == nil)
+ continue;
+ wn->lastseen = MACHP(0)->ticks;
+ b->rp += wifihdrlen(w);
+ recvbeacon(wifi, wn, b->rp, BLEN(b));
+
+ if(wifi->bss == nil
+ && TK2MS(MACHP(0)->ticks - wn->lastsend) > 1000
+ && goodbss(wifi, wn)){
+ setstatus(wifi, wn, Sconn);
+ sendauth(wifi, wn);
+ wifi->lastauth = wn->lastsend;
+ }
+ continue;
+ }
+
+ if(memcmp(w->a1, wifi->ether->ea, Eaddrlen))
+ continue;
+ if((wn = nodelookup(wifi, w->a3, 0)) == nil)
+ continue;
+ wn->lastseen = MACHP(0)->ticks;
+ switch(w->fc[0] & 0xf0){
+ case 0x10: /* assoc response */
+ case 0x30: /* reassoc response */
+ b->rp += wifihdrlen(w);
+ recvassoc(wifi, wn, b->rp, BLEN(b));
+ /* notify driver about node aid association */
+ if(wn == wifi->bss)
+ (*wifi->transmit)(wifi, wn, nil);
+ break;
+ case 0xb0: /* auth */
+ if(wifi->debug)
+ print("#l%d: got auth from %E\n", wifi->ether->ctlrno, wn->bssid);
+ if(wn->brsnelen > 0 && wn->rsnelen == 0)
+ setstatus(wifi, wn, Sneedauth);
+ else
+ setstatus(wifi, wn, Sauth);
+ if(wifi->bss == nil && goodbss(wifi, wn)){
+ wifi->bss = wn;
+ if(wn->status == Sauth)
+ sendassoc(wifi, wn);
+ }
+ break;
+ case 0xc0: /* deauth */
+ if(wifi->debug)
+ print("#l%d: got deauth from %E\n", wifi->ether->ctlrno, wn->bssid);
+ wifideauth(wifi, wn);
+ break;
+ }
+ }
+ pexit("wifi in queue closed", 1);
+}
+
+static void
+wifietheroq(Wifi *wifi, Block *b)
+{
+ Etherpkt e;
+ Wifipkt h;
+ int hdrlen;
+ Wnode *wn;
+ SNAP *s;
+
+ if(BLEN(b) < ETHERHDRSIZE)
+ goto drop;
+ if((wn = wifi->bss) == nil)
+ goto drop;
+
+ dmatproxy(b, 1, wifi->ether->ea, &wifi->dmat);
+
+ memmove(&e, b->rp, ETHERHDRSIZE);
+ b->rp += ETHERHDRSIZE;
+ if(wn->status == Sblocked){
+ /* only pass EAPOL frames when port is blocked */
+ if((e.type[0]<<8 | e.type[1]) != 0x888e)
+ goto drop;
+ } else if(wn->status != Sassoc)
+ goto drop;
+
+ h.fc[0] = 0x08; /* data */
+ memmove(h.a1, wn->bssid, Eaddrlen);
+ if(memcmp(e.s, wifi->ether->ea, Eaddrlen) == 0) {
+ h.fc[1] = 0x01; /* STA->AP */
+ } else {
+ h.fc[1] = 0x03; /* AP->AP (WDS) */
+ memmove(h.a2, wifi->ether->ea, Eaddrlen);
+ }
+ memmove(dstaddr(&h), e.d, Eaddrlen);
+ memmove(srcaddr(&h), e.s, Eaddrlen);
+
+ hdrlen = wifihdrlen(&h);
+ b = padblock(b, hdrlen + SNAPHDRSIZE);
+ memmove(b->rp, &h, hdrlen);
+ s = (SNAP*)(b->rp + hdrlen);
+ s->dsap = s->ssap = 0xAA;
+ s->control = 0x03;
+ s->orgcode[0] = 0;
+ s->orgcode[1] = 0;
+ s->orgcode[2] = 0;
+ memmove(s->type, e.type, 2);
+
+ wifitx(wifi, wn, b);
+ return;
+drop:
+ freeb(b);
+}
+
+static void
+wifoproc(void *arg)
+{
+ Ether *ether;
+ Wifi *wifi;
+ Block *b;
+
+ wifi = arg;
+ ether = wifi->ether;
+ while(waserror())
+ ;
+ while((b = qbread(ether->oq, 1000000)) != nil)
+ wifietheroq(wifi, b);
+ pexit("ether out queue closed", 1);
+}
+
+static void
+wifsproc(void *arg)
+{
+ Ether *ether;
+ Wifi *wifi;
+ Wnode wnscan;
+ Wnode *wn;
+ ulong now, tmout;
+ uchar *rate;
+
+ wifi = arg;
+ ether = wifi->ether;
+
+ wn = &wnscan;
+ memset(wn, 0, sizeof(*wn));
+ memmove(wn->bssid, ether->bcast, Eaddrlen);
+
+ while(waserror())
+ ;
+Scan:
+ /* scan for access point */
+ while(wifi->bss == nil){
+ ether->link = 0;
+ wnscan.channel = 1 + ((wnscan.channel+4) % 13);
+ wifiprobe(wifi, &wnscan);
+ do {
+ tsleep(&up->sleep, return0, 0, 200);
+ now = MACHP(0)->ticks;
+ } while(TK2MS(now-wifi->lastauth) < 1000);
+ }
+
+ /* maintain access point */
+ tmout = 0;
+ while((wn = wifi->bss) != nil){
+ ether->link = (wn->status == Sassoc) || (wn->status == Sblocked);
+ if(ether->link && (rate = wn->actrate) != nil)
+ ether->mbps = ((*rate & 0x7f)+3)/4;
+ now = MACHP(0)->ticks;
+ if(wn->status != Sneedauth && TK2SEC(now - wn->lastseen) > 20 || goodbss(wifi, wn) == 0){
+ wifideauth(wifi, wn);
+ wifi->bss = nil;
+ break;
+ }
+ if(TK2MS(now - wn->lastsend) > 1000){
+ if((wn->status == Sauth || wn->status == Sblocked) && (++tmout & 7) == 0)
+ wifideauth(wifi, wn); /* stuck in auth, start over */
+ if(wn->status == Sconn || wn->status == Sunauth)
+ sendauth(wifi, wn);
+ if(wn->status == Sauth)
+ sendassoc(wifi, wn);
+ }
+ tsleep(&up->sleep, return0, 0, 500);
+ }
+ goto Scan;
+}
+
+Wifi*
+wifiattach(Ether *ether, void (*transmit)(Wifi*, Wnode*, Block*))
+{
+ char name[32];
+ Wifi *wifi;
+
+ wifi = malloc(sizeof(Wifi));
+ if(wifi == nil)
+ error(Enomem);
+ wifi->iq = qopen(ether->limit, 0, 0, 0);
+ if(wifi->iq == nil){
+ free(wifi);
+ error(Enomem);
+ }
+ wifi->ether = ether;
+ wifi->transmit = transmit;
+
+ wifi->rates = basicrates;
+
+ wifi->essid[0] = 0;
+ memmove(wifi->bssid, ether->bcast, Eaddrlen);
+
+ wifi->lastauth = MACHP(0)->ticks;
+
+ snprint(name, sizeof(name), "#l%dwifi", ether->ctlrno);
+ kproc(name, wifiproc, wifi);
+ snprint(name, sizeof(name), "#l%dwifo", ether->ctlrno);
+ kproc(name, wifoproc, wifi);
+ snprint(name, sizeof(name), "#l%dwifs", ether->ctlrno);
+ kproc(name, wifsproc, wifi);
+
+ return wifi;
+}
+
+static char *ciphers[] = {
+ [0] "clear",
+ [TKIP] "tkip",
+ [CCMP] "ccmp",
+};
+
+static Wkey*
+parsekey(char *s)
+{
+ static char Ebadkey[] = "bad key";
+ uchar key[32];
+ int len, cipher;
+ char *e;
+ Wkey *k;
+
+ for(cipher=0; cipher<nelem(ciphers); cipher++){
+ if(strncmp(s, ciphers[cipher], len = strlen(ciphers[cipher])) == 0){
+ if(cipher == 0) /* clear */
+ return nil;
+ if(s[len] == ':'){
+ s += len+1;
+ break;
+ }
+ }
+ }
+ if(cipher >= nelem(ciphers))
+ error(Ebadkey);
+
+ if((e = strchr(s, '@')) == nil)
+ e = strchr(s, 0);
+
+ len = dec16(key, sizeof(key), s, e - s);
+
+ switch(cipher){
+ case TKIP:
+ if(len != 32)
+ error(Ebadkey);
+ k = secalloc(sizeof(Wkey) + len);
+ memmove(k->key, key, len);
+ break;
+ case CCMP:
+ if(len != 16)
+ error(Ebadkey);
+ k = secalloc(sizeof(Wkey) + sizeof(AESstate));
+ setupAESstate((AESstate*)k->key, key, len, nil);
+ break;
+ default:
+ error(Ebadkey);
+ return nil;
+ }
+
+ memset(key, 0, sizeof(key));
+
+ if(*e++ == '@')
+ k->tsc = strtoull(e, nil, 16);
+ k->len = len;
+ k->cipher = cipher;
+
+ return k;
+}
+
+void
+wificfg(Wifi *wifi, char *opt)
+{
+ char *p, buf[64];
+ int n;
+
+ if(strncmp(opt, "debug=", 6))
+ if(strncmp(opt, "essid=", 6))
+ if(strncmp(opt, "bssid=", 6))
+ return;
+ if((p = strchr(opt, '=')) == nil)
+ return;
+ if(waserror())
+ return;
+ n = snprint(buf, sizeof(buf), "%.*s %q", (int)(p - opt), opt, p+1);
+ wifictl(wifi, buf, n);
+ poperror();
+}
+
+enum {
+ CMdebug,
+ CMessid,
+ CMauth,
+ CMbssid,
+ CMrxkey0,
+ CMrxkey1,
+ CMrxkey2,
+ CMrxkey3,
+ CMrxkey4,
+ CMtxkey0,
+};
+
+static Cmdtab wifictlmsg[] =
+{
+ CMdebug, "debug", 0,
+ CMessid, "essid", 0,
+ CMauth, "auth", 0,
+ CMbssid, "bssid", 0,
+
+ CMrxkey0, "rxkey0", 0, /* group keys */
+ CMrxkey1, "rxkey1", 0,
+ CMrxkey2, "rxkey2", 0,
+ CMrxkey3, "rxkey3", 0,
+
+ CMrxkey4, "rxkey", 0, /* peerwise keys */
+ CMtxkey0, "txkey", 0,
+
+ CMtxkey0, "txkey0", 0,
+};
+
+long
+wifictl(Wifi *wifi, void *buf, long n)
+{
+ uchar addr[Eaddrlen];
+ Cmdbuf *cb;
+ Cmdtab *ct;
+ Wnode *wn;
+ Wkey *k, **kk;
+
+ cb = nil;
+ if(waserror()){
+ free(cb);
+ nexterror();
+ }
+ if(wifi->debug)
+ print("#l%d: wifictl: %.*s\n", wifi->ether->ctlrno, (int)n, buf);
+ memmove(addr, wifi->ether->bcast, Eaddrlen);
+ wn = wifi->bss;
+ cb = parsecmd(buf, n);
+ ct = lookupcmd(cb, wifictlmsg, nelem(wifictlmsg));
+ if(ct->index >= CMauth){
+ if(cb->nf > 1 && (ct->index == CMbssid || ct->index >= CMrxkey0)){
+ if(parseether(addr, cb->f[1]) == 0){
+ cb->f++;
+ cb->nf--;
+ wn = nodelookup(wifi, addr, 0);
+ }
+ }
+ if(wn == nil && ct->index != CMbssid)
+ error("missing node");
+ }
+ switch(ct->index){
+ case CMdebug:
+ if(cb->f[1] != nil)
+ wifi->debug = atoi(cb->f[1]);
+ else
+ wifi->debug ^= 1;
+ print("#l%d: debug: %d\n", wifi->ether->ctlrno, wifi->debug);
+ break;
+ case CMessid:
+ if(cb->f[1] != nil)
+ strncpy(wifi->essid, cb->f[1], Essidlen);
+ else
+ wifi->essid[0] = 0;
+ Findbss:
+ wn = wifi->bss;
+ if(wn != nil){
+ if(goodbss(wifi, wn))
+ break;
+ wifideauth(wifi, wn);
+ }
+ wifi->bss = nil;
+ if(wifi->essid[0] == 0 && memcmp(wifi->bssid, wifi->ether->bcast, Eaddrlen) == 0)
+ break;
+ for(wn = wifi->node; wn != &wifi->node[nelem(wifi->node)]; wn++)
+ if(goodbss(wifi, wn)){
+ setstatus(wifi, wn, Sconn);
+ sendauth(wifi, wn);
+ }
+ break;
+ case CMbssid:
+ memmove(wifi->bssid, addr, Eaddrlen);
+ goto Findbss;
+ case CMauth:
+ freewifikeys(wifi, wn);
+ if(cb->f[1] == nil)
+ wn->rsnelen = 0;
+ else
+ wn->rsnelen = dec16(wn->rsne, sizeof(wn->rsne), cb->f[1], strlen(cb->f[1]));
+ if(wn->aid == 0){
+ setstatus(wifi, wn, Sconn);
+ sendauth(wifi, wn);
+ } else {
+ setstatus(wifi, wn, Sauth);
+ sendassoc(wifi, wn);
+ }
+ break;
+ case CMrxkey0: case CMrxkey1: case CMrxkey2: case CMrxkey3: case CMrxkey4:
+ case CMtxkey0:
+ if(cb->f[1] == nil)
+ error(Ebadarg);
+ k = parsekey(cb->f[1]);
+ memset(cb->f[1], 0, strlen(cb->f[1]));
+ if(ct->index < CMtxkey0)
+ kk = &wn->rxkey[ct->index - CMrxkey0];
+ else
+ kk = &wn->txkey[ct->index - CMtxkey0];
+ wlock(&wifi->crypt);
+ secfree(*kk);
+ *kk = k;
+ wunlock(&wifi->crypt);
+ if(ct->index >= CMtxkey0 && wn->status == Sblocked)
+ setstatus(wifi, wn, Sassoc);
+ break;
+ }
+ poperror();
+ free(cb);
+ return n;
+}
+
+long
+wifistat(Wifi *wifi, void *buf, long n, ulong off)
+{
+ static uchar zeros[Eaddrlen];
+ char essid[Essidlen+1];
+ char *s, *p, *e;
+ Wnode *wn;
+ Wkey *k;
+ long now;
+ int i;
+
+ p = s = smalloc(4096);
+ e = s + 4096;
+
+ wn = wifi->bss;
+ if(wn != nil){
+ strncpy(essid, wn->ssid, Essidlen);
+ essid[Essidlen] = 0;
+ p = seprint(p, e, "essid: %s\n", essid);
+ p = seprint(p, e, "bssid: %E\n", wn->bssid);
+ p = seprint(p, e, "status: %s\n", wn->status);
+ p = seprint(p, e, "channel: %.2d\n", wn->channel);
+
+ /* only print key ciphers and key length */
+ rlock(&wifi->crypt);
+ for(i = 0; i<nelem(wn->rxkey); i++){
+ if((k = wn->rxkey[i]) != nil)
+ p = seprint(p, e, "rxkey%d: %s:[%d]\n", i,
+ ciphers[k->cipher], k->len);
+ }
+ for(i = 0; i<nelem(wn->txkey); i++){
+ if((k = wn->txkey[i]) != nil)
+ p = seprint(p, e, "txkey%d: %s:[%d]\n", i,
+ ciphers[k->cipher], k->len);
+ }
+ runlock(&wifi->crypt);
+
+ if(wn->brsnelen > 0){
+ p = seprint(p, e, "brsne: ");
+ for(i=0; i<wn->brsnelen; i++)
+ p = seprint(p, e, "%.2X", wn->brsne[i]);
+ p = seprint(p, e, "\n");
+ }
+ } else {
+ p = seprint(p, e, "essid: %s\n", wifi->essid);
+ p = seprint(p, e, "bssid: %E\n", wifi->bssid);
+ }
+
+ now = MACHP(0)->ticks;
+ for(wn = wifi->node; wn != &wifi->node[nelem(wifi->node)]; wn++){
+ if(wn->lastseen == 0)
+ continue;
+ strncpy(essid, wn->ssid, Essidlen);
+ essid[Essidlen] = 0;
+ p = seprint(p, e, "node: %E %.4x %-11ld %.2d %s\n",
+ wn->bssid, wn->cap, TK2MS(now - wn->lastseen), wn->channel, essid);
+ }
+ n = readstr(off, buf, n, s);
+ free(s);
+ return n;
+}
+
+static void tkipencrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc);
+static int tkipdecrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc);
+static void ccmpencrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc);
+static int ccmpdecrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc);
+
+static Block*
+wifiencrypt(Wifi *wifi, Wnode *wn, Block *b)
+{
+ uvlong tsc;
+ int n, kid;
+ Wifipkt *w;
+ Wkey *k;
+
+ rlock(&wifi->crypt);
+
+ kid = 0;
+ k = wn->txkey[kid];
+ if(k == nil){
+ runlock(&wifi->crypt);
+ return b;
+ }
+
+ n = wifihdrlen((Wifipkt*)b->rp);
+
+ b = padblock(b, 8);
+ b = padblock(b, -(8+4));
+
+ w = (Wifipkt*)b->rp;
+ memmove(w, b->rp+8, n);
+ b->rp += n;
+
+ tsc = ++k->tsc;
+
+ switch(k->cipher){
+ case TKIP:
+ b->rp[0] = tsc>>8;
+ b->rp[1] = (b->rp[0] | 0x20) & 0x7f;
+ b->rp[2] = tsc;
+ b->rp[3] = kid<<6 | 0x20;
+ b->rp[4] = tsc>>16;
+ b->rp[5] = tsc>>24;
+ b->rp[6] = tsc>>32;
+ b->rp[7] = tsc>>40;
+ b->rp += 8;
+ tkipencrypt(k, w, b, tsc);
+ break;
+ case CCMP:
+ b->rp[0] = tsc;
+ b->rp[1] = tsc>>8;
+ b->rp[2] = 0;
+ b->rp[3] = kid<<6 | 0x20;
+ b->rp[4] = tsc>>16;
+ b->rp[5] = tsc>>24;
+ b->rp[6] = tsc>>32;
+ b->rp[7] = tsc>>40;
+ b->rp += 8;
+ ccmpencrypt(k, w, b, tsc);
+ break;
+ }
+ runlock(&wifi->crypt);
+
+ b->rp = (uchar*)w;
+ w->fc[1] |= 0x40;
+ return b;
+}
+
+static Block*
+wifidecrypt(Wifi *wifi, Wnode *wn, Block *b)
+{
+ uvlong tsc;
+ int n, kid;
+ Wifipkt *w;
+ Wkey *k;
+
+ rlock(&wifi->crypt);
+
+ w = (Wifipkt*)b->rp;
+ n = wifihdrlen(w);
+ b->rp += n;
+ if(BLEN(b) < 8+8)
+ goto drop;
+
+ kid = b->rp[3]>>6;
+ if((b->rp[3] & 0x20) == 0)
+ goto drop;
+ if((w->a1[0] & 1) == 0)
+ kid = 4; /* use peerwise key for non-unicast */
+
+ k = wn->rxkey[kid];
+ if(k == nil)
+ goto drop;
+ switch(k->cipher){
+ case TKIP:
+ tsc = (uvlong)b->rp[7]<<40 |
+ (uvlong)b->rp[6]<<32 |
+ (uvlong)b->rp[5]<<24 |
+ (uvlong)b->rp[4]<<16 |
+ (uvlong)b->rp[0]<<8 |
+ (uvlong)b->rp[2];
+ b->rp += 8;
+ if(tsc <= k->tsc)
+ goto drop;
+ if(tkipdecrypt(k, w, b, tsc) != 0)
+ goto drop;
+ break;
+ case CCMP:
+ tsc = (uvlong)b->rp[7]<<40 |
+ (uvlong)b->rp[6]<<32 |
+ (uvlong)b->rp[5]<<24 |
+ (uvlong)b->rp[4]<<16 |
+ (uvlong)b->rp[1]<<8 |
+ (uvlong)b->rp[0];
+ b->rp += 8;
+ if(tsc <= k->tsc)
+ goto drop;
+ if(ccmpdecrypt(k, w, b, tsc) != 0)
+ goto drop;
+ break;
+ default:
+ drop:
+ runlock(&wifi->crypt);
+ freeb(b);
+ return nil;
+ }
+ runlock(&wifi->crypt);
+
+ k->tsc = tsc;
+ b->rp -= n;
+ memmove(b->rp, w, n);
+ w = (Wifipkt*)b->rp;
+ w->fc[1] &= ~0x40;
+ return b;
+}
+
+static u16int Sbox[256] = {
+ 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
+ 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
+ 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
+ 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
+ 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
+ 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
+ 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
+ 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
+ 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
+ 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
+ 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
+ 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
+ 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
+ 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
+ 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
+ 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
+ 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
+ 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
+ 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
+ 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
+ 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
+ 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
+ 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
+ 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
+ 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
+ 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
+ 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
+ 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
+ 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
+ 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
+ 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
+ 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A
+};
+
+static void
+tkipk2tk(uchar key[16], u16int tk[8])
+{
+ tk[0] = (u16int)key[1]<<8 | key[0];
+ tk[1] = (u16int)key[3]<<8 | key[2];
+ tk[2] = (u16int)key[5]<<8 | key[4];
+ tk[3] = (u16int)key[7]<<8 | key[6];
+ tk[4] = (u16int)key[9]<<8 | key[8];
+ tk[5] = (u16int)key[11]<<8 | key[10];
+ tk[6] = (u16int)key[13]<<8 | key[12];
+ tk[7] = (u16int)key[15]<<8 | key[14];
+}
+
+static void
+tkipphase1(u32int tscu, uchar ta[Eaddrlen], u16int tk[8], u16int p1k[5])
+{
+ u16int *k, i, x0, x1, x2;
+
+ p1k[0] = tscu;
+ p1k[1] = tscu>>16;
+ p1k[2] = (u16int)ta[1]<<8 | ta[0];
+ p1k[3] = (u16int)ta[3]<<8 | ta[2];
+ p1k[4] = (u16int)ta[5]<<8 | ta[4];
+
+ for(i=0; i<8; i++){
+ k = &tk[i & 1];
+
+ x0 = p1k[4] ^ k[0];
+ x1 = Sbox[x0 >> 8];
+ x2 = Sbox[x0 & 0xFF] ^ ((x1>>8) | (x1<<8));
+ p1k[0] += x2;
+ x0 = p1k[0] ^ k[2];
+ x1 = Sbox[x0 >> 8];
+ x2 = Sbox[x0 & 0xFF] ^ ((x1>>8) | (x1<<8));
+ p1k[1] += x2;
+ x0 = p1k[1] ^ k[4];
+ x1 = Sbox[x0 >> 8];
+ x2 = Sbox[x0 & 0xFF] ^ ((x1>>8) | (x1<<8));
+ p1k[2] += x2;
+ x0 = p1k[2] ^ k[6];
+ x1 = Sbox[x0 >> 8];
+ x2 = Sbox[x0 & 0xFF] ^ ((x1>>8) | (x1<<8));
+ p1k[3] += x2;
+ x0 = p1k[3] ^ k[0];
+ x1 = Sbox[x0 >> 8];
+ x2 = Sbox[x0 & 0xFF] ^ ((x1>>8) | (x1<<8));
+ p1k[4] += x2;
+
+ p1k[4] += i;
+ }
+}
+
+static void
+tkipphase2(u16int tscl, u16int p1k[5], u16int tk[8], uchar rc4key[16])
+{
+ u16int ppk[6], x0, x1, x2;
+
+ ppk[0] = p1k[0];
+ ppk[1] = p1k[1];
+ ppk[2] = p1k[2];
+ ppk[3] = p1k[3];
+ ppk[4] = p1k[4];
+ ppk[5] = p1k[4] + tscl;
+
+ x0 = ppk[5] ^ tk[0];
+ x1 = Sbox[x0 >> 8];
+ x2 = Sbox[x0 & 0xFF] ^ ((x1>>8) | (x1<<8));
+ ppk[0] += x2;
+ x0 = ppk[0] ^ tk[1];
+ x1 = Sbox[x0 >> 8];
+ x2 = Sbox[x0 & 0xFF] ^ ((x1>>8) | (x1<<8));
+ ppk[1] += x2;
+ x0 = ppk[1] ^ tk[2];
+ x1 = Sbox[x0 >> 8];
+ x2 = Sbox[x0 & 0xFF] ^ ((x1>>8) | (x1<<8));
+ ppk[2] += x2;
+ x0 = ppk[2] ^ tk[3];
+ x1 = Sbox[x0 >> 8];
+ x2 = Sbox[x0 & 0xFF] ^ ((x1>>8) | (x1<<8));
+ ppk[3] += x2;
+ x0 = ppk[3] ^ tk[4];
+ x1 = Sbox[x0 >> 8];
+ x2 = Sbox[x0 & 0xFF] ^ ((x1>>8) | (x1<<8));
+ ppk[4] += x2;
+ x0 = ppk[4] ^ tk[5];
+ x1 = Sbox[x0 >> 8];
+ x2 = Sbox[x0 & 0xFF] ^ ((x1>>8) | (x1<<8));
+ ppk[5] += x2;
+
+ x2 = ppk[5] ^ tk[6];
+ ppk[0] += (x2 >> 1) | (x2 << 15);
+ x2 = ppk[0] ^ tk[7];
+ ppk[1] += (x2 >> 1) | (x2 << 15);
+
+ x2 = ppk[1];
+ ppk[2] += (x2 >> 1) | (x2 << 15);
+ x2 = ppk[2];
+ ppk[3] += (x2 >> 1) | (x2 << 15);
+ x2 = ppk[3];
+ ppk[4] += (x2 >> 1) | (x2 << 15);
+ x2 = ppk[4];
+ ppk[5] += (x2 >> 1) | (x2 << 15);
+
+ rc4key[0] = tscl >> 8;
+ rc4key[1] = (rc4key[0] | 0x20) & 0x7F;
+ rc4key[2] = tscl;
+ rc4key[3] = (ppk[5] ^ tk[0]) >> 1;
+ rc4key[4] = ppk[0];
+ rc4key[5] = ppk[0] >> 8;
+ rc4key[6] = ppk[1];
+ rc4key[7] = ppk[1] >> 8;
+ rc4key[8] = ppk[2];
+ rc4key[9] = ppk[2] >> 8;
+ rc4key[10] = ppk[3];
+ rc4key[11] = ppk[3] >> 8;
+ rc4key[12] = ppk[4];
+ rc4key[13] = ppk[4] >> 8;
+ rc4key[14] = ppk[5];
+ rc4key[15] = ppk[5] >> 8;
+}
+
+typedef struct MICstate MICstate;
+struct MICstate
+{
+ u32int l;
+ u32int r;
+ u32int m;
+ u32int n;
+};
+
+static void
+micsetup(MICstate *s, uchar key[8])
+{
+ s->l = (u32int)key[0] |
+ (u32int)key[1]<<8 |
+ (u32int)key[2]<<16 |
+ (u32int)key[3]<<24;
+ s->r = (u32int)key[4] |
+ (u32int)key[5]<<8 |
+ (u32int)key[6]<<16 |
+ (u32int)key[7]<<24;
+ s->m = 0;
+ s->n = 0;
+}
+
+static void
+micupdate(MICstate *s, uchar *data, ulong len)
+{
+ u32int l, r, m, n, e;
+
+ l = s->l;
+ r = s->r;
+ m = s->m;
+ n = s->n;
+ e = n + len;
+ while(n != e){
+ m >>= 8;
+ m |= (u32int)*data++ << 24;
+ if(++n & 3)
+ continue;
+ l ^= m;
+ r ^= (l << 17) | (l >> 15);
+ l += r;
+ r ^= ((l & 0x00FF00FFUL)<<8) | ((l & 0xFF00FF00UL)>>8);
+ l += r;
+ r ^= (l << 3) | (l >> 29);
+ l += r;
+ r ^= (l >> 2) | (l << 30);
+ l += r;
+ }
+ s->l = l;
+ s->r = r;
+ s->m = m;
+ s->n = n;
+}
+
+static void
+micfinish(MICstate *s, uchar mic[8])
+{
+ static uchar pad[8] = { 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
+
+ micupdate(s, pad, sizeof(pad));
+
+ mic[0] = s->l;
+ mic[1] = s->l>>8;
+ mic[2] = s->l>>16;
+ mic[3] = s->l>>24;
+ mic[4] = s->r;
+ mic[5] = s->r>>8;
+ mic[6] = s->r>>16;
+ mic[7] = s->r>>24;
+}
+
+static uchar pad4[4] = { 0x00, 0x00, 0x00, 0x00, };
+
+static void
+tkipencrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc)
+{
+ u16int tk[8], p1k[5];
+ uchar seed[16];
+ RC4state rs;
+ MICstate ms;
+ ulong crc;
+
+ micsetup(&ms, k->key+24);
+ micupdate(&ms, dstaddr(w), Eaddrlen);
+ micupdate(&ms, srcaddr(w), Eaddrlen);
+ micupdate(&ms, pad4, 4);
+ micupdate(&ms, b->rp, BLEN(b));
+ micfinish(&ms, b->wp);
+ b->wp += 8;
+
+ crc = ethercrc(b->rp, BLEN(b));
+ crc = ~crc;
+ b->wp[0] = crc;
+ b->wp[1] = crc>>8;
+ b->wp[2] = crc>>16;
+ b->wp[3] = crc>>24;
+ b->wp += 4;
+
+ tkipk2tk(k->key, tk);
+ tkipphase1(tsc >> 16, w->a2, tk, p1k);
+ tkipphase2(tsc & 0xFFFF, p1k, tk, seed);
+ setupRC4state(&rs, seed, sizeof(seed));
+ rc4(&rs, b->rp, BLEN(b));
+}
+
+static int
+tkipdecrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc)
+{
+ uchar seed[16], mic[8];
+ u16int tk[8], p1k[5];
+ RC4state rs;
+ MICstate ms;
+ ulong crc;
+
+ if(BLEN(b) < 8+4)
+ return -1;
+
+ tkipk2tk(k->key, tk);
+ tkipphase1(tsc >> 16, w->a2, tk, p1k);
+ tkipphase2(tsc & 0xFFFF, p1k, tk, seed);
+ setupRC4state(&rs, seed, sizeof(seed));
+ rc4(&rs, b->rp, BLEN(b));
+
+ b->wp -= 4;
+ crc = (ulong)b->wp[0] |
+ (ulong)b->wp[1]<<8 |
+ (ulong)b->wp[2]<<16 |
+ (ulong)b->wp[3]<<24;
+ crc = ~crc;
+ crc ^= ethercrc(b->rp, BLEN(b));
+
+ b->wp -= 8;
+ micsetup(&ms, k->key+16);
+ micupdate(&ms, dstaddr(w), Eaddrlen);
+ micupdate(&ms, srcaddr(w), Eaddrlen);
+ micupdate(&ms, pad4, 4);
+ micupdate(&ms, b->rp, BLEN(b));
+ micfinish(&ms, mic);
+
+ return tsmemcmp(b->wp, mic, 8) | crc;
+}
+
+static uchar*
+putbe(uchar *p, int L, uint v)
+{
+ while(--L >= 0)
+ *p++ = (v >> L*8) & 0xFF;
+ return p;
+}
+
+static void
+xblock(int L, int M, uchar *N, uchar *a, int la, int lm, uchar t[16], AESstate *s)
+{
+ uchar l[8], *p, *x, *e;
+
+ assert(M >= 4 && M <= 16);
+ assert(L >= 2 && L <= 4);
+
+ t[0] = ((la > 0)<<6) | ((M-2)/2)<<3 | (L-1); /* flags */
+ memmove(&t[1], N, 15-L);
+ putbe(&t[16-L], L, lm);
+ aes_encrypt(s->ekey, s->rounds, t, t);
+
+ if(la > 0){
+ assert(la < 0xFF00);
+ for(p = l, e = putbe(l, 2, la), x = t; p < e; x++, p++)
+ *x ^= *p;
+ for(e = a + la; a < e; x = t){
+ for(; a < e && x < &t[16]; x++, a++)
+ *x ^= *a;
+ aes_encrypt(s->ekey, s->rounds, t, t);
+ }
+ }
+}
+
+static uchar*
+sblock(int L, uchar *N, uint i, uchar b[16], AESstate *s)
+{
+ b[0] = L-1; /* flags */
+ memmove(&b[1], N, 15-L);
+ putbe(&b[16-L], L, i);
+ aes_encrypt(s->ekey, s->rounds, b, b);
+ return b;
+};
+
+static void
+aesCCMencrypt(int L, int M, uchar *N /* N[15-L] */,
+ uchar *a /* a[la] */, int la,
+ uchar *m /* m[lm+M] */, int lm,
+ AESstate *s)
+{
+ uchar t[16], b[16], *p, *x;
+ uint i;
+
+ xblock(L, M, N, a, la, lm, t, s);
+
+ for(i = 1; lm >= 16; i++, m += 16, lm -= 16){
+ sblock(L, N, i, b, s);
+
+ *((u32int*)&t[0]) ^= *((u32int*)&m[0]);
+ *((u32int*)&m[0]) ^= *((u32int*)&b[0]);
+ *((u32int*)&t[4]) ^= *((u32int*)&m[4]);
+ *((u32int*)&m[4]) ^= *((u32int*)&b[4]);
+ *((u32int*)&t[8]) ^= *((u32int*)&m[8]);
+ *((u32int*)&m[8]) ^= *((u32int*)&b[8]);
+ *((u32int*)&t[12]) ^= *((u32int*)&m[12]);
+ *((u32int*)&m[12]) ^= *((u32int*)&b[12]);
+
+ aes_encrypt(s->ekey, s->rounds, t, t);
+ }
+ if(lm > 0){
+ for(p = sblock(L, N, i, b, s), x = t; p < &b[lm]; x++, m++, p++){
+ *x ^= *m;
+ *m ^= *p;
+ }
+ aes_encrypt(s->ekey, s->rounds, t, t);
+ }
+
+ for(p = sblock(L, N, 0, b, s), x = t; p < &b[M]; x++, p++)
+ *x ^= *p;
+
+ memmove(m, t, M);
+}
+
+static int
+aesCCMdecrypt(int L, int M, uchar *N /* N[15-L] */,
+ uchar *a /* a[la] */, int la,
+ uchar *m /* m[lm+M] */, int lm,
+ AESstate *s)
+{
+ uchar t[16], b[16], *p, *x;
+ uint i;
+
+ xblock(L, M, N, a, la, lm, t, s);
+
+ for(i = 1; lm >= 16; i++, m += 16, lm -= 16){
+ sblock(L, N, i, b, s);
+
+ *((u32int*)&m[0]) ^= *((u32int*)&b[0]);
+ *((u32int*)&t[0]) ^= *((u32int*)&m[0]);
+ *((u32int*)&m[4]) ^= *((u32int*)&b[4]);
+ *((u32int*)&t[4]) ^= *((u32int*)&m[4]);
+ *((u32int*)&m[8]) ^= *((u32int*)&b[8]);
+ *((u32int*)&t[8]) ^= *((u32int*)&m[8]);
+ *((u32int*)&m[12]) ^= *((u32int*)&b[12]);
+ *((u32int*)&t[12]) ^= *((u32int*)&m[12]);
+
+ aes_encrypt(s->ekey, s->rounds, t, t);
+ }
+ if(lm > 0){
+ for(p = sblock(L, N, i, b, s), x = t; p < &b[lm]; x++, m++, p++){
+ *m ^= *p;
+ *x ^= *m;
+ }
+ aes_encrypt(s->ekey, s->rounds, t, t);
+ }
+
+ for(p = sblock(L, N, 0, b, s), x = t; p < &b[M]; x++, p++)
+ *x ^= *p;
+
+ return tsmemcmp(m, t, M);
+}
+
+static int
+setupCCMP(Wifipkt *w, uvlong tsc, uchar nonce[13], uchar auth[32])
+{
+ uchar *p;
+
+ nonce[0] = ((w->fc[0] & 0x0c) == 0x00) << 4;
+ memmove(&nonce[1], w->a2, Eaddrlen);
+ nonce[7] = tsc >> 40;
+ nonce[8] = tsc >> 32;
+ nonce[9] = tsc >> 24;
+ nonce[10] = tsc >> 16;
+ nonce[11] = tsc >> 8;
+ nonce[12] = tsc;
+
+ p = auth;
+ *p++ = (w->fc[0] & (((w->fc[0] & 0x0c) == 0x08) ? 0x0f : 0xff));
+ *p++ = (w->fc[1] & ~0x38) | 0x40;
+ memmove(p, w->a1, Eaddrlen); p += Eaddrlen;
+ memmove(p, w->a2, Eaddrlen); p += Eaddrlen;
+ memmove(p, w->a3, Eaddrlen); p += Eaddrlen;
+ *p++ = w->seq[0] & 0x0f;
+ *p++ = 0;
+ if((w->fc[1] & 3) == 0x03) {
+ memmove(p, w->a4, Eaddrlen);
+ p += Eaddrlen;
+ }
+
+ return p - auth;
+}
+
+static void
+ccmpencrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc)
+{
+ uchar auth[32], nonce[13];
+
+ aesCCMencrypt(2, 8, nonce, auth,
+ setupCCMP(w, tsc, nonce, auth),
+ b->rp, BLEN(b), (AESstate*)k->key);
+ b->wp += 8;
+}
+
+static int
+ccmpdecrypt(Wkey *k, Wifipkt *w, Block *b, uvlong tsc)
+{
+ uchar auth[32], nonce[13];
+
+ if(BLEN(b) < 8)
+ return -1;
+
+ b->wp -= 8;
+ return aesCCMdecrypt(2, 8, nonce, auth,
+ setupCCMP(w, tsc, nonce, auth),
+ b->rp, BLEN(b), (AESstate*)k->key);
+}
+
+/*
+ * Dynamic Mac Address Translation (DMAT)
+ *
+ * Wifi does not allow spoofing of the source mac which breaks
+ * bridging. To solve this we proxy mac addresses, maintaining
+ * a translation table from ip address to destination mac address.
+ * Upstream ARP and NDP packets get ther source mac address changed
+ * to proxy and a translation entry is added with the original mac
+ * for downstream translation. The proxy does not appear in the
+ * table.
+ */
+#include "../ip/ip.h"
+#include "../ip/ipv6.h"
+
+static void
+dmatproxy(Block *bp, int upstream, uchar proxy[Eaddrlen], DMAT *t)
+{
+ static uchar arp4[] = {
+ 0x00, 0x01,
+ 0x08, 0x00,
+ 0x06, 0x04,
+ 0x00,
+ };
+ uchar ip[IPaddrlen], mac[Eaddrlen], *targ, *end, *a, *o;
+ ulong csum, c, h;
+ Etherpkt *pkt;
+ int proto, i;
+ DMTE *te;
+
+ end = bp->wp;
+ pkt = (Etherpkt*)bp->rp;
+ a = pkt->data;
+ if(a >= end)
+ return;
+
+ if(upstream)
+ memmove(pkt->s, proxy, Eaddrlen);
+ else if(t->map == 0 || (pkt->d[0]&1) != 0 || memcmp(pkt->d, proxy, Eaddrlen) != 0)
+ return;
+
+ targ = nil;
+ switch(pkt->type[0]<<8 | pkt->type[1]){
+ default:
+ return;
+ case ETIP4:
+ case ETIP6:
+ switch(a[0]&0xF0){
+ default:
+ return;
+ case IP_VER4:
+ if(a+IP4HDR > end || (a[0]&15) < IP_HLEN4)
+ return;
+ v4tov6(ip, a+12+4*(upstream==0));
+ proto = a[9];
+ a += (a[0]&15)*4;
+ break;
+ case IP_VER6:
+ if(a+IP6HDR > end)
+ return;
+ memmove(ip, a+8+16*(upstream==0), 16);
+ proto = a[6];
+ a += IP6HDR;
+ break;
+ }
+ if(!upstream)
+ break;
+ switch(proto){
+ case ICMPv6:
+ if(a+8 > end)
+ return;
+ switch(a[0]){
+ default:
+ return;
+ case 133: /* Router Solicitation */
+ o = a+8;
+ break;
+ case 134: /* Router Advertisement */
+ o = a+8+8;
+ break;
+ case 136: /* Neighbor Advertisement */
+ targ = a+8;
+ /* wet floor */
+ case 135: /* Neighbor Solicitation */
+ o = a+8+16;
+ break;
+ case 137: /* Redirect */
+ o = a+8+16+16;
+ break;
+ }
+ memset(mac, 0xFF, Eaddrlen);
+ csum = (a[2]<<8 | a[3])^0xFFFF;
+ while(o+8 <= end && o[1] != 0){
+ switch(o[0]){
+ case SRC_LLADDR:
+ case TARGET_LLADDR:
+ for(i=0; i<Eaddrlen; i += 2)
+ csum += (o[2+i]<<8 | o[3+i])^0xFFFF;
+ memmove(mac, o+2, Eaddrlen);
+ memmove(o+2, proxy, Eaddrlen);
+ for(i=0; i<Eaddrlen; i += 2)
+ csum += (o[2+i]<<8 | o[3+i]);
+ break;
+ }
+ o += o[1]*8;
+ }
+ while((c = csum >> 16) != 0)
+ csum = (csum & 0xFFFF) + c;
+ csum ^= 0xFFFF;
+ a[2] = csum>>8;
+ a[3] = csum;
+ break;
+ case UDP: /* for BOOTP */
+ if(a+42 > end
+ || (a[0]<<8 | a[1]) != 68
+ || (a[2]<<8 | a[3]) != 67
+ || a[8] != 1
+ || a[9] != 1
+ || a[10] != Eaddrlen
+ || (a[18]&0x80) != 0
+ || memcmp(a+36, proxy, Eaddrlen) == 0)
+ return;
+
+ csum = (a[6]<<8 | a[7])^0xFFFF;
+
+ /* set the broadcast flag so response reaches us */
+ csum += (a[18]<<8)^0xFFFF;
+ a[18] |= 0x80;
+ csum += (a[18]<<8);
+
+ while((c = csum >> 16) != 0)
+ csum = (csum & 0xFFFF) + c;
+ csum ^= 0xFFFF;
+
+ a[6] = csum>>8;
+ a[7] = csum;
+ default:
+ return;
+ }
+ break;
+ case ETARP:
+ if(a+26 > end || memcmp(a, arp4, sizeof(arp4)) != 0 || (a[7] != 1 && a[7] != 2))
+ return;
+ v4tov6(ip, a+14+10*(upstream==0));
+ if(upstream){
+ memmove(mac, a+8, Eaddrlen);
+ memmove(a+8, proxy, Eaddrlen);
+ }
+ break;
+ }
+
+Again:
+ h = ( (ip[IPaddrlen-1] ^ proxy[2])<<24 |
+ (ip[IPaddrlen-2] ^ proxy[3])<<16 |
+ (ip[IPaddrlen-3] ^ proxy[4])<<8 |
+ (ip[IPaddrlen-4] ^ proxy[5]) ) % nelem(t->tab);
+ te = &t->tab[h];
+ h &= 63;
+
+ if(upstream){
+ if((mac[0]&1) != 0 || memcmp(mac, proxy, Eaddrlen) == 0)
+ return;
+ for(i=0; te->valid && i<nelem(t->tab); i++){
+ if(memcmp(te->ip, ip, IPaddrlen) == 0)
+ break;
+ if(++te >= &t->tab[nelem(t->tab)])
+ te = t->tab;
+ }
+ memmove(te->mac, mac, Eaddrlen);
+ memmove(te->ip, ip, IPaddrlen);
+ te->valid = 1;
+ t->map |= 1ULL<<h;
+ if(targ != nil){
+ memmove(ip, targ, IPaddrlen);
+ targ = nil;
+ goto Again;
+ }
+ } else {
+ if((t->map>>h & 1) == 0)
+ return;
+ for(i=0; te->valid && i<nelem(t->tab); i++){
+ if(memcmp(te->ip, ip, IPaddrlen) == 0){
+ memmove(pkt->d, te->mac, Eaddrlen);
+ return;
+ }
+ if(++te >= &t->tab[nelem(t->tab)])
+ te = t->tab;
+ }
+ }
+}
--- /dev/null
+++ b/sys/src/9/port/wifi.h
@@ -1,0 +1,116 @@
+typedef struct Wkey Wkey;
+typedef struct Wnode Wnode;
+typedef struct Wifi Wifi;
+typedef struct Wifipkt Wifipkt;
+typedef struct DMAT DMAT;
+typedef struct DMTE DMTE;
+
+enum {
+ Essidlen = 32,
+};
+
+/* cipher */
+enum {
+ TKIP = 1,
+ CCMP = 2,
+};
+
+struct Wkey
+{
+ int cipher;
+ int len;
+ uvlong tsc;
+ uchar key[];
+};
+
+struct Wnode
+{
+ uchar bssid[Eaddrlen];
+ char ssid[Essidlen+2];
+
+ char *status;
+
+ int rsnelen;
+ uchar rsne[258];
+ Wkey *txkey[1];
+ Wkey *rxkey[5];
+
+ int aid; /* association id */
+ ulong lastsend;
+ ulong lastseen;
+
+ uchar *minrate; /* pointers into wifi->rates */
+ uchar *maxrate;
+ uchar *actrate;
+
+ ulong txcount; /* statistics for rate adaption */
+ ulong txerror;
+
+ /* stuff from beacon */
+ int ival;
+ int cap;
+ int channel;
+ int brsnelen;
+ uchar brsne[258];
+};
+
+struct DMTE
+{
+ uchar ip[16];
+ uchar mac[6];
+ uchar valid;
+};
+
+struct DMAT
+{
+ DMTE tab[127]; /* prime */
+ uvlong map;
+};
+
+struct Wifi
+{
+ Ether *ether;
+
+ int debug;
+
+ RWlock crypt;
+ Queue *iq;
+ ulong watchdog;
+ ulong lastauth;
+ Ref txseq;
+ void (*transmit)(Wifi*, Wnode*, Block*);
+
+ /* for searching */
+ uchar bssid[Eaddrlen];
+ char essid[Essidlen+2];
+
+ /* supported data rates by hardware */
+ uchar *rates;
+
+ /* effective base station */
+ Wnode *bss;
+
+ Wnode node[32];
+
+ DMAT dmat;
+};
+
+struct Wifipkt
+{
+ uchar fc[2];
+ uchar dur[2];
+ uchar a1[Eaddrlen];
+ uchar a2[Eaddrlen];
+ uchar a3[Eaddrlen];
+ uchar seq[2];
+ uchar a4[Eaddrlen];
+};
+
+Wifi *wifiattach(Ether *ether, void (*transmit)(Wifi*, Wnode*, Block*));
+void wifiiq(Wifi*, Block*);
+int wifihdrlen(Wifipkt*);
+void wifitxfail(Wifi*, Block*);
+
+long wifistat(Wifi*, void*, long, ulong);
+long wifictl(Wifi*, void*, long);
+void wificfg(Wifi*, char*);
--- a/sys/src/9/ppc/devether.c
+++ /dev/null
@@ -1,446 +1,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "ureg.h"
-#include "../port/error.h"
-#include "../port/netif.h"
-
-#include "etherif.h"
-
-static Ether *etherxx[MaxEther];
-extern uchar etheraddr[];
-
-Chan*
-etherattach(char* spec)
-{
- ulong ctlrno;
- char *p;
- Chan *chan;
-
- ctlrno = 0;
- if(spec && *spec){
- ctlrno = strtoul(spec, &p, 0);
- if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther))
- error(Ebadarg);
- }
- if(etherxx[ctlrno] == 0)
- error(Enodev);
-
- chan = devattach('l', spec);
- chan->dev = ctlrno;
- if(etherxx[ctlrno]->attach)
- etherxx[ctlrno]->attach(etherxx[ctlrno]);
- return chan;
-}
-
-static Walkqid*
-etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
-{
- return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
-}
-
-static int
-etherstat(Chan* chan, uchar* dp, int n)
-{
- return netifstat(etherxx[chan->dev], chan, dp, n);
-}
-
-static Chan*
-etheropen(Chan* chan, int omode)
-{
- return netifopen(etherxx[chan->dev], chan, omode);
-}
-
-static Chan*
-ethercreate(Chan*, char*, int, ulong)
-{
- error(Eperm);
- return 0;
-}
-
-static void
-etherclose(Chan* chan)
-{
- netifclose(etherxx[chan->dev], chan);
-}
-
-static long
-etherread(Chan* chan, void* buf, long n, vlong off)
-{
- Ether *ether;
- ulong offset = off;
-
- ether = etherxx[chan->dev];
- if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
- /*
- * With some controllers it is necessary to reach
- * into the chip to extract statistics.
- */
- if(NETTYPE(chan->qid.path) == Nifstatqid)
- return ether->ifstat(ether, buf, n, offset);
- else if(NETTYPE(chan->qid.path) == Nstatqid)
- ether->ifstat(ether, buf, 0, offset);
- }
-
- return netifread(ether, chan, buf, n, offset);
-}
-
-static Block*
-etherbread(Chan* chan, long n, ulong offset)
-{
- return netifbread(etherxx[chan->dev], chan, n, offset);
-}
-
-static int
-etherwstat(Chan* chan, uchar* dp, int n)
-{
- return netifwstat(etherxx[chan->dev], chan, dp, n);
-}
-
-static void
-etherrtrace(Netfile* f, Etherpkt* pkt, int len)
-{
- int i, n;
- Block *bp;
-
- if(qwindow(f->in) <= 0)
- return;
- if(len > 58)
- n = 58;
- else
- n = len;
- bp = iallocb(64);
- if(bp == nil)
- return;
- memmove(bp->wp, pkt->d, n);
- i = TK2MS(MACHP(0)->ticks);
- bp->wp[58] = len>>8;
- bp->wp[59] = len;
- bp->wp[60] = i>>24;
- bp->wp[61] = i>>16;
- bp->wp[62] = i>>8;
- bp->wp[63] = i;
- bp->wp += 64;
- qpass(f->in, bp);
-}
-
-Block*
-etheriq(Ether* ether, Block* bp, int fromwire)
-{
- Etherpkt *pkt;
- ushort type;
- int len, multi, tome, fromme;
- Netfile **ep, *f, **fp, *fx;
- Block *xbp;
-
- ether->inpackets++;
-
- pkt = (Etherpkt*)bp->rp;
- len = BLEN(bp);
- type = (pkt->type[0]<<8)|pkt->type[1];
- fx = 0;
- ep = ðer->f[Ntypes];
-
- multi = pkt->d[0] & 1;
- /* check for valid multicast addresses */
- if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){
- if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
- if(fromwire){
- freeb(bp);
- bp = 0;
- }
- return bp;
- }
- }
-
- /* is it for me? */
- tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
- fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
-
- /*
- * Multiplex the packet to all the connections which want it.
- * If the packet is not to be used subsequently (fromwire != 0),
- * attempt to simply pass it into one of the connections, thereby
- * saving a copy of the data (usual case hopefully).
- */
- for(fp = ether->f; fp < ep; fp++){
- if(f = *fp)
- if(f->type == type || f->type < 0)
- if(tome || multi || f->prom){
- /* Don't want to hear loopback or bridged packets */
- if(f->bridge && (tome || !fromwire && !fromme))
- continue;
- if(!f->headersonly){
- if(fromwire && fx == 0)
- fx = f;
- else if(xbp = iallocb(len)){
- memmove(xbp->wp, pkt, len);
- xbp->wp += len;
- qpass(f->in, xbp);
- }
- else
- ether->soverflows++;
- }
- else
- etherrtrace(f, pkt, len);
- }
- }
-
- if(fx){
- if(qpass(fx->in, bp) < 0)
- ether->soverflows++;
- return 0;
- }
- if(fromwire){
- freeb(bp);
- return 0;
- }
-
- return bp;
-}
-
-static int
-etheroq(Ether* ether, Block* bp)
-{
- int len, loopback;
- Etherpkt *pkt;
-
- ether->outpackets++;
-
- /*
- * Check if the packet has to be placed back onto the input queue,
- * i.e. if it's a loopback or broadcast packet or the interface is
- * in promiscuous mode.
- * If it's a loopback packet indicate to etheriq that the data isn't
- * needed and return, etheriq will pass-on or free the block.
- * To enable bridging to work, only packets that were originated
- * by this interface are fed back.
- */
- pkt = (Etherpkt*)bp->rp;
- len = BLEN(bp);
- loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
- if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom)
- if(etheriq(ether, bp, loopback) == 0)
- return len;
-
- qbwrite(ether->oq, bp);
- if(ether->transmit != nil)
- ether->transmit(ether);
- return len;
-}
-
-static long
-etherwrite(Chan* chan, void* buf, long n, vlong)
-{
- Ether *ether;
- Block *bp;
- int nn;
-
- ether = etherxx[chan->dev];
- if(NETTYPE(chan->qid.path) != Ndataqid) {
- nn = netifwrite(ether, chan, buf, n);
- if(nn >= 0)
- return nn;
- if(n == sizeof("nonblocking")-1 && strncmp((char*)buf, "nonblocking", n) == 0){
- qnoblock(ether->oq, 1);
- return n;
- }
- if(ether->ctl!=nil)
- return ether->ctl(ether,buf,n);
-
- error(Ebadctl);
- }
-
- if(n > ether->maxmtu)
- error(Etoobig);
- if(n < ether->minmtu)
- error(Etoosmall);
-
- bp = allocb(n);
- if(waserror()){
- freeb(bp);
- nexterror();
- }
- memmove(bp->rp, buf, n);
- if(!ether->f[NETID(chan->qid.path)]->bridge)
- memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
- poperror();
- bp->wp += n;
-
- return etheroq(ether, bp);
-}
-
-static long
-etherbwrite(Chan* chan, Block* bp, ulong)
-{
- Ether *ether;
- long n;
-
- n = BLEN(bp);
- if(NETTYPE(chan->qid.path) != Ndataqid){
- if(waserror()) {
- freeb(bp);
- nexterror();
- }
- n = etherwrite(chan, bp->rp, n, 0);
- poperror();
- freeb(bp);
- return n;
- }
- ether = etherxx[chan->dev];
-
- if(n > ether->maxmtu){
- freeb(bp);
- error(Etoobig);
- }
- if(n < ether->minmtu){
- freeb(bp);
- error(Etoosmall);
- }
-
- return etheroq(ether, bp);
-}
-
-static struct {
- char* type;
- int (*reset)(Ether*);
-} cards[MaxEther+1];
-
-void
-addethercard(char* t, int (*r)(Ether*))
-{
- static int ncard;
-
- if(ncard == MaxEther)
- panic("too many ether cards");
- cards[ncard].type = t;
- cards[ncard].reset = r;
- ncard++;
-}
-
-static void
-etherreset(void)
-{
- Ether *ether;
- int i, n, ctlrno;
- char name[32], buf[128];
-
- for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
- if(ether == 0)
- ether = malloc(sizeof(Ether));
- memset(ether, 0, sizeof(Ether));
- ether->ctlrno = ctlrno;
- ether->tbdf = BUSUNKNOWN;
- ether->mbps = 10;
- ether->minmtu = ETHERMINTU;
- ether->maxmtu = ETHERMAXTU;
- if(isaconfig("ether", ctlrno, ether) == 0)
- continue;
- for(n = 0; cards[n].type; n++){
- if(cistrcmp(cards[n].type, ether->type))
- continue;
- memmove(ether->ea, etheraddr, 6);
- for(i = 0; i < ether->nopt; i++){
- if(strncmp(ether->opt[i], "ea=", 3))
- continue;
- if(parseether(ether->ea, ðer->opt[i][3]) == -1)
- memset(ether->ea, 0, Eaddrlen);
- }
- if(cards[n].reset(ether))
- break;
-
- /*
- * IRQ2 doesn't really exist, it's used to gang the interrupt
- * controllers together. A device set to IRQ2 will appear on
- * the second interrupt controller as IRQ9.
- */
- if(ether->irq == 2 && BUSTYPE(ether->tbdf) != BusPCI)
- ether->irq = 9;
- snprint(name, sizeof(name), "ether%d", ctlrno);
-
- /*
- * If ether->irq is <0, it is a hack to indicate no interrupt
- * used by ethersink.
- */
- if(ether->irq >= 0)
- intrenable(ether->irq, ether->interrupt, ether, name);
- i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
- ctlrno, ether->type, ether->mbps, ether->port, ether->irq);
- if(ether->mem)
- i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem));
- if(ether->size)
- i += sprint(buf+i, " size 0x%luX", ether->size);
- i += sprint(buf+i, ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
- ether->ea[0], ether->ea[1], ether->ea[2],
- ether->ea[3], ether->ea[4], ether->ea[5]);
- sprint(buf+i, "\n");
- print(buf);
-
- if(ether->mbps >= 100){
- netifinit(ether, name, Ntypes, 256*1024);
- if(ether->oq == 0)
- ether->oq = qopen(256*1024, Qmsg, 0, 0);
- }
- else{
- netifinit(ether, name, Ntypes, 65*1024);
- if(ether->oq == 0)
- ether->oq = qopen(65*1024, Qmsg, 0, 0);
- }
- if(ether->oq == 0)
- panic("etherreset %s", name);
- ether->alen = Eaddrlen;
- memmove(ether->addr, ether->ea, Eaddrlen);
- memset(ether->bcast, 0xFF, Eaddrlen);
-
- etherxx[ctlrno] = ether;
- ether = 0;
- break;
- }
- }
- if(ether)
- free(ether);
-}
-
-#define POLY 0xedb88320
-
-/* really slow 32 bit crc for ethers */
-ulong
-ethercrc(uchar *p, int len)
-{
- int i, j;
- ulong crc, b;
-
- crc = 0xffffffff;
- for(i = 0; i < len; i++){
- b = *p++;
- for(j = 0; j < 8; j++){
- crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
- b >>= 1;
- }
- }
- return crc;
-}
-
-Dev etherdevtab = {
- 'l',
- "ether",
-
- etherreset,
- devinit,
- devshutdown,
- etherattach,
- etherwalk,
- etherstat,
- etheropen,
- ethercreate,
- etherclose,
- etherread,
- etherbread,
- etherwrite,
- etherbwrite,
- devremove,
- etherwstat,
-};
--- a/sys/src/9/ppc/etherfcc.c
+++ b/sys/src/9/ppc/etherfcc.c
@@ -11,8 +11,8 @@
#include "imm.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
#include "../ppc/ethermii.h"
#define DBG 1
@@ -719,7 +719,6 @@
ether->mbps = 100; /* TO DO: could be 10mbps */
ether->attach = attach;
ether->transmit = transmit;
- ether->interrupt = interrupt;
ether->ifstat = ifstat;
ether->arg = ether;
@@ -735,6 +734,8 @@
print("no ether address");
return -1;
}
+
+ intrenable(ether->irq, interrupt, ether, ether->name);
return 0;
}
--- a/sys/src/9/ppc/etherif.h
+++ /dev/null
@@ -1,35 +1,0 @@
-enum {
- MaxEther = 24,
- Ntypes = 8,
-};
-
-typedef struct Ether Ether;
-struct Ether {
- ISAConf; /* hardware info */
-
- int ctlrno;
- int tbdf; /* type+busno+devno+funcno */
- int minmtu;
- int maxmtu;
- uchar ea[Eaddrlen];
-
- void (*attach)(Ether*); /* filled in by reset routine */
- void (*transmit)(Ether*);
- void (*interrupt)(Ureg*, void*);
- long (*ifstat)(Ether*, void*, long, ulong);
- long (*ctl)(Ether*, void*, long); /* custom ctl messages */
- void *ctlr;
-
- Queue* oq;
-
- Netif;
-};
-
-extern Block* etheriq(Ether*, Block*, int);
-extern void addethercard(char*, int(*)(Ether*));
-extern ulong ethercrc(uchar*, int);
-
-#define NEXT(x, l) (((x)+1)%(l))
-#define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1)
-#define HOWMANY(x, y) (((x)+((y)-1))/(y))
-#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y))
--- a/sys/src/9/ppc/ethersaturn.c
+++ b/sys/src/9/ppc/ethersaturn.c
@@ -6,10 +6,10 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
+
#include "msaturn.h"
-#include "etherif.h"
-
enum{
Etcr = Saturn + 0x0c00,
Etsr = Saturn + 0x0c02,
@@ -209,7 +209,6 @@
ether->ctlr = ctlr;
ether->transmit = transmit;
- ether->interrupt = interrupt;
ether->irq = Vecether;
ether->arg = ether;
memmove(ether->ea, (ushort*)Emacaddr0, Eaddrlen);
@@ -218,6 +217,9 @@
*eimr = Ei_rxdone|Ei_txretry|Ei_txdone;
iprint("reset: ercr %.4uX\n", *ercr);
+
+ intrenable(ether->irq, interrupt, ether, ether->name);
+
return 0;
}
--- a/sys/src/9/ppc/mkfile
+++ b/sys/src/9/ppc/mkfile
@@ -52,7 +52,6 @@
HFILES=\
dat.h\
errstr.h\
- etherif.h\
fns.h\
init.h\
io.h\
@@ -94,7 +93,7 @@
%.$O: $HFILES
-$ETHER: etherif.h ../port/netif.h
+$ETHER: ../port/etherif.h ../port/netif.h
init.h: ../port/initcode.c init9.s
$CC ../port/initcode.c
--- a/sys/src/9/sgi/dat.h
+++ b/sys/src/9/sgi/dat.h
@@ -13,6 +13,7 @@
typedef struct Softtlb Softtlb;
typedef struct Ureg Ureg;
typedef struct Proc Proc;
+typedef struct ISAConf ISAConf;
typedef uvlong Tval;
#define MAXSYSARG 5 /* for mount(fd, afd, mpt, flag, arg) */
@@ -69,6 +70,16 @@
int monitor;
int keyboard;
};
+
+struct ISAConf
+{
+ char *type;
+ ulong port;
+ int irq;
+ int nopt;
+ char *opt[1];
+};
+#define BUSUNKNOWN -1
/*
* floating point registers
--- a/sys/src/9/sgi/devether.c
+++ /dev/null
@@ -1,489 +1,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "pool.h"
-#include "ureg.h"
-#include "../port/error.h"
-#include "../port/netif.h"
-
-#include "etherif.h"
-
-static Ether *etherxx[MaxEther];
-
-Chan*
-etherattach(char* spec)
-{
- ulong ctlrno;
- char *p;
- Chan *chan;
-
- ctlrno = 0;
- if(spec && *spec){
- ctlrno = strtoul(spec, &p, 0);
- if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther))
- error(Ebadarg);
- }
- if(etherxx[ctlrno] == 0)
- error(Enodev);
-
- chan = devattach('l', spec);
- if(waserror()){
- chanfree(chan);
- nexterror();
- }
- chan->dev = ctlrno;
- if(etherxx[ctlrno]->attach)
- etherxx[ctlrno]->attach(etherxx[ctlrno]);
- poperror();
- return chan;
-}
-
-static Walkqid*
-etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
-{
- return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
-}
-
-static int
-etherstat(Chan* chan, uchar* dp, int n)
-{
- return netifstat(etherxx[chan->dev], chan, dp, n);
-}
-
-static Chan*
-etheropen(Chan* chan, int omode)
-{
- return netifopen(etherxx[chan->dev], chan, omode);
-}
-
-static Chan*
-ethercreate(Chan*, char*, int, ulong)
-{
- error(Eperm);
- return 0;
-}
-
-static void
-etherclose(Chan* chan)
-{
- netifclose(etherxx[chan->dev], chan);
-}
-
-static long
-etherread(Chan* chan, void* buf, long n, vlong off)
-{
- Ether *ether;
- ulong offset = off;
-
- ether = etherxx[chan->dev];
- if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
- /*
- * With some controllers it is necessary to reach
- * into the chip to extract statistics.
- */
- if(NETTYPE(chan->qid.path) == Nifstatqid)
- return ether->ifstat(ether, buf, n, offset);
- else if(NETTYPE(chan->qid.path) == Nstatqid)
- ether->ifstat(ether, buf, 0, offset);
- }
-
- return netifread(ether, chan, buf, n, offset);
-}
-
-static Block*
-etherbread(Chan* chan, long n, ulong offset)
-{
- return netifbread(etherxx[chan->dev], chan, n, offset);
-}
-
-static int
-etherwstat(Chan* chan, uchar* dp, int n)
-{
- return netifwstat(etherxx[chan->dev], chan, dp, n);
-}
-
-static void
-etherrtrace(Netfile* f, Etherpkt* pkt, int len)
-{
- int i, n;
- Block *bp;
-
- if(qwindow(f->in) <= 0)
- return;
- if(len > 58)
- n = 58;
- else
- n = len;
- bp = iallocb(64);
- if(bp == nil)
- return;
- memmove(bp->wp, pkt->d, n);
- i = TK2MS(MACHP(0)->ticks);
- bp->wp[58] = len>>8;
- bp->wp[59] = len;
- bp->wp[60] = i>>24;
- bp->wp[61] = i>>16;
- bp->wp[62] = i>>8;
- bp->wp[63] = i;
- bp->wp += 64;
- qpass(f->in, bp);
-}
-
-Block*
-etheriq(Ether* ether, Block* bp, int fromwire)
-{
- Etherpkt *pkt;
- ushort type;
- int len, multi, tome, fromme;
- Netfile **ep, *f, **fp, *fx;
- Block *xbp;
-
- ether->inpackets++;
-
- pkt = (Etherpkt*)bp->rp;
- len = BLEN(bp);
- type = (pkt->type[0]<<8)|pkt->type[1];
- fx = 0;
- ep = ðer->f[Ntypes];
-
- multi = pkt->d[0] & 1;
- /* check for valid multicast addresses */
- if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 && ether->prom == 0){
- if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
- if(fromwire){
- freeb(bp);
- bp = 0;
- }
- return bp;
- }
- }
-
- /* is it for me? */
- tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
- fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
-
- /*
- * Multiplex the packet to all the connections which want it.
- * If the packet is not to be used subsequently (fromwire != 0),
- * attempt to simply pass it into one of the connections, thereby
- * saving a copy of the data (usual case hopefully).
- */
- for(fp = ether->f; fp < ep; fp++){
- if(f = *fp)
- if(f->type == type || f->type < 0)
- if(tome || multi || f->prom){
- /* Don't want to hear loopback or bridged packets */
- if(f->bridge && (tome || !fromwire && !fromme))
- continue;
- if(!f->headersonly){
- if(fromwire && fx == 0)
- fx = f;
- else if(xbp = iallocb(len)){
- memmove(xbp->wp, pkt, len);
- xbp->wp += len;
- if(qpass(f->in, xbp) < 0) {
- // print("soverflow for f->in\n");
- ether->soverflows++;
- }
- }
- else {
- // print("soverflow iallocb\n");
- ether->soverflows++;
- }
- }
- else
- etherrtrace(f, pkt, len);
- }
- }
-
- if(fx){
- if(qpass(fx->in, bp) < 0) {
- // print("soverflow for fx->in\n");
- ether->soverflows++;
- }
- return 0;
- }
- if(fromwire){
- freeb(bp);
- return 0;
- }
-
- return bp;
-}
-
-static int
-etheroq(Ether* ether, Block* bp)
-{
- int len, loopback;
- Etherpkt *pkt;
-
- ether->outpackets++;
-
- /*
- * Check if the packet has to be placed back onto the input queue,
- * i.e. if it's a loopback or broadcast packet or the interface is
- * in promiscuous mode.
- * If it's a loopback packet indicate to etheriq that the data isn't
- * needed and return, etheriq will pass-on or free the block.
- * To enable bridging to work, only packets that were originated
- * by this interface are fed back.
- */
- pkt = (Etherpkt*)bp->rp;
- len = BLEN(bp);
- loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
- if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom)
- if(etheriq(ether, bp, loopback) == 0)
- return len;
-
- qbwrite(ether->oq, bp);
- if(ether->transmit != nil)
- ether->transmit(ether);
- return len;
-}
-
-static long
-etherwrite(Chan* chan, void* buf, long n, vlong)
-{
- Ether *ether;
- Block *bp;
- int nn, onoff;
- Cmdbuf *cb;
-
- ether = etherxx[chan->dev];
- if(NETTYPE(chan->qid.path) != Ndataqid) {
- nn = netifwrite(ether, chan, buf, n);
- if(nn >= 0)
- return nn;
- cb = parsecmd(buf, n);
- if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
- if(cb->nf <= 1)
- onoff = 1;
- else
- onoff = atoi(cb->f[1]);
- qnoblock(ether->oq, onoff);
- free(cb);
- return n;
- }
- free(cb);
- if(ether->ctl!=nil)
- return ether->ctl(ether,buf,n);
-
- error(Ebadctl);
- }
-
- if(n > ether->maxmtu)
- error(Etoobig);
- if(n < ether->minmtu)
- error(Etoosmall);
-
- bp = allocb(n);
- if(waserror()){
- freeb(bp);
- nexterror();
- }
- memmove(bp->rp, buf, n);
- if(!ether->f[NETID(chan->qid.path)]->bridge)
- memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
- poperror();
- bp->wp += n;
-
- return etheroq(ether, bp);
-}
-
-static long
-etherbwrite(Chan* chan, Block* bp, ulong)
-{
- Ether *ether;
- long n;
-
- n = BLEN(bp);
- if(NETTYPE(chan->qid.path) != Ndataqid){
- if(waserror()) {
- freeb(bp);
- nexterror();
- }
- n = etherwrite(chan, bp->rp, n, 0);
- poperror();
- freeb(bp);
- return n;
- }
- ether = etherxx[chan->dev];
-
- if(n > ether->maxmtu){
- freeb(bp);
- error(Etoobig);
- }
- if(n < ether->minmtu){
- freeb(bp);
- error(Etoosmall);
- }
-
- return etheroq(ether, bp);
-}
-
-static struct {
- char* type;
- int (*reset)(Ether*);
-} cards[MaxEther+1];
-
-void
-addethercard(char* t, int (*r)(Ether*))
-{
- static int ncard;
-
- if(ncard == MaxEther)
- panic("too many ether cards");
- cards[ncard].type = t;
- cards[ncard].reset = r;
- ncard++;
-}
-
-static Ether*
-etherprobe(int cardno, int ctlrno)
-{
- int i, lg;
- ulong mb, bsz;
- Ether *ether;
- char buf[128], name[32];
-
- ether = malloc(sizeof(Ether));
- if(ether == nil){
- print("etherprobe: no memory for Ether\n");
- return nil;
- }
- memset(ether, 0, sizeof(Ether));
- ether->ctlrno = ctlrno;
- ether->mbps = 10;
- ether->minmtu = ETHERMINTU;
- ether->maxmtu = ETHERMAXTU;
-
- if(cardno >= MaxEther || cards[cardno].type == nil){
- free(ether);
- return nil;
- }
- if(cards[cardno].reset(ether) < 0){
- free(ether);
- return nil;
- }
-
- snprint(name, sizeof(name), "ether%d", ctlrno);
-
- intrenable(ether->irqlevel, ether->interrupt, ether);
-
- i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
- ctlrno, cards[cardno].type, ether->mbps, ether->port, ether->irq);
- i += sprint(buf+i, ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
- ether->ea[0], ether->ea[1], ether->ea[2],
- ether->ea[3], ether->ea[4], ether->ea[5]);
- sprint(buf+i, "\n");
- print(buf);
-
- /* compute log10(ether->mbps) into lg */
- for(lg = 0, mb = ether->mbps; mb >= 10; lg++)
- mb /= 10;
- if (lg > 0)
- lg--;
- if (lg > 14) /* 2^(14+17) = 2³¹ */
- lg = 14;
- /* allocate larger output queues for higher-speed interfaces */
- bsz = 1UL << (lg + 17); /* 2¹⁷ = 128K, bsz = 2ⁿ × 128K */
- while (bsz > mainmem->maxsize / 8 && bsz > 128*1024)
- bsz /= 2;
-
- netifinit(ether, name, Ntypes, bsz);
- if(ether->oq == nil) {
- ether->oq = qopen(bsz, Qmsg, 0, 0);
- ether->limit = bsz;
- }
- if(ether->oq == nil)
- panic("etherreset %s: can't allocate output queue of %ld bytes", name, bsz);
- ether->alen = Eaddrlen;
- memmove(ether->addr, ether->ea, Eaddrlen);
- memset(ether->bcast, 0xFF, Eaddrlen);
-
- return ether;
-}
-
-static void
-etherreset(void)
-{
- Ether *ether;
- int cardno, ctlrno;
-
- cardno = ctlrno = 0;
- while(cards[cardno].type != nil && ctlrno < MaxEther){
- if(etherxx[ctlrno] != nil){
- ctlrno++;
- continue;
- }
- if((ether = etherprobe(cardno, ctlrno)) == nil){
- cardno++;
- continue;
- }
- etherxx[ctlrno] = ether;
- ctlrno++;
- }
-}
-
-static void
-ethershutdown(void)
-{
- Ether *ether;
- int i;
-
- for(i = 0; i < MaxEther; i++){
- ether = etherxx[i];
- if(ether == nil)
- continue;
- if(ether->shutdown == nil) {
- print("#l%d: no shutdown function\n", i);
- continue;
- }
- (*ether->shutdown)(ether);
- }
-}
-
-
-#define POLY 0xedb88320
-
-/* really slow 32 bit crc for ethers */
-ulong
-ethercrc(uchar *p, int len)
-{
- int i, j;
- ulong crc, b;
-
- crc = 0xffffffff;
- for(i = 0; i < len; i++){
- b = *p++;
- for(j = 0; j < 8; j++){
- crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
- b >>= 1;
- }
- }
- return crc;
-}
-
-Dev etherdevtab = {
- 'l',
- "ether",
-
- etherreset,
- devinit,
- ethershutdown,
- etherattach,
- etherwalk,
- etherstat,
- etheropen,
- ethercreate,
- etherclose,
- etherread,
- etherbread,
- etherwrite,
- etherbwrite,
- devremove,
- etherwstat,
-};
--- a/sys/src/9/sgi/etherif.h
+++ /dev/null
@@ -1,40 +1,0 @@
-enum {
- MaxEther = 1,
- Ntypes = 8,
-};
-
-typedef struct Ether Ether;
-struct Ether {
-
- int ctlrno;
- int minmtu;
- int maxmtu;
- uchar ea[Eaddrlen];
-
- int irq, irqlevel;
- uintptr port;
-
- void (*attach)(Ether*); /* filled in by reset routine */
- void (*detach)(Ether*);
- void (*transmit)(Ether*);
- void (*interrupt)(Ureg*, void*);
- long (*ifstat)(Ether*, void*, long, ulong);
- long (*ctl)(Ether*, void*, long); /* custom ctl messages */
- void (*power)(Ether*, int); /* power on/off */
- void (*shutdown)(Ether*); /* shutdown hardware before reboot */
- void *ctlr;
-
- Queue* oq;
-
- Netif;
-};
-
-extern Block* etheriq(Ether*, Block*, int);
-extern void addethercard(char*, int(*)(Ether*));
-extern ulong ethercrc(uchar*, int);
-extern int parseether(uchar*, char*);
-
-#define NEXT(x, l) (((x)+1)%(l))
-#define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1)
-#define HOWMANY(x, y) (((x)+((y)-1))/(y))
-#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y))
--- a/sys/src/9/sgi/etherseeq.c
+++ b/sys/src/9/sgi/etherseeq.c
@@ -5,7 +5,7 @@
#include "fns.h"
#include "io.h"
#include "../port/netif.h"
-#include "etherif.h"
+#include "../port/etherif.h"
typedef struct Hio Hio;
typedef struct Desc Desc;
@@ -451,19 +451,21 @@
edev->ctlr = &ct;
edev->port = HPC3_ETHER;
edev->irq = IRQENET;
- edev->irqlevel = hpc3irqlevel(edev->irq);
edev->ctlr = &ct;
edev->promiscuous = promiscuous;
edev->multicast = multicast;
- edev->interrupt = interrupt;
edev->attach = attach;
edev->arg = edev;
edev->mbps = 10;
edev->link = 1;
+
if(init(edev) < 0){
edev->ctlr = nil;
return -1;
}
+
+ intrenable(hpc3irqlevel(edev->irq), interrupt, edev);
+
return 0;
}
--- a/sys/src/9/sgi/fns.h
+++ b/sys/src/9/sgi/fns.h
@@ -22,6 +22,7 @@
int gettlbp(ulong, ulong*);
ulong gettlbvirt(int);
int hpc3irqlevel(int);
+int isaconfig(char*, int, ISAConf*);
void icflush(void *, ulong);
void idlehands(void);
void introff(int);
--- a/sys/src/9/sgi/indy
+++ b/sys/src/9/sgi/indy
@@ -10,8 +10,8 @@
env
pipe
dup
- ether netif
- ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno
+ ether netif
+ ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno
ssl
tls
cap
--- a/sys/src/9/sgi/main.c
+++ b/sys/src/9/sgi/main.c
@@ -502,3 +502,9 @@
if(n > 0)
error("no watchpoints");
}
+
+int
+isaconfig(char *, int, ISAConf*)
+{
+ return 0;
+}
--- a/sys/src/9/teg2/archtegra.c
+++ b/sys/src/9/teg2/archtegra.c
@@ -12,7 +12,7 @@
#include "arm.h"
#include "../port/netif.h"
-#include "etherif.h"
+#include "../port/etherif.h"
#include "../port/flashif.h"
#include "../port/usb.h"
#include "../port/portusbehci.h"
--- a/sys/src/9/teg2/devether.c
+++ /dev/null
@@ -1,502 +1,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "../port/error.h"
-
-#include "../port/netif.h"
-#include "etherif.h"
-
-static Ether *etherxx[MaxEther];
-
-Chan*
-etherattach(char* spec)
-{
- int ctlrno;
- char *p;
- Chan *chan;
-
- ctlrno = 0;
- if(spec && *spec){
- ctlrno = strtoul(spec, &p, 0);
- if((ctlrno == 0 && p == spec) || *p != 0)
- error(Ebadarg);
- if(ctlrno < 0 || ctlrno >= MaxEther)
- error(Ebadarg);
- }
- if(etherxx[ctlrno] == 0)
- error(Enodev);
-
- chan = devattach('l', spec);
- if(waserror()){
- chanfree(chan);
- nexterror();
- }
- chan->dev = ctlrno;
- if(etherxx[ctlrno]->attach)
- etherxx[ctlrno]->attach(etherxx[ctlrno]);
- poperror();
- return chan;
-}
-
-static Walkqid*
-etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
-{
- return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
-}
-
-static int
-etherstat(Chan* chan, uchar* dp, int n)
-{
- return netifstat(etherxx[chan->dev], chan, dp, n);
-}
-
-static Chan*
-etheropen(Chan* chan, int omode)
-{
- return netifopen(etherxx[chan->dev], chan, omode);
-}
-
-static Chan*
-ethercreate(Chan*, char*, int, ulong)
-{
- error(Eperm);
- return 0;
-}
-
-static void
-etherclose(Chan* chan)
-{
- netifclose(etherxx[chan->dev], chan);
-}
-
-static long
-etherread(Chan* chan, void* buf, long n, vlong off)
-{
- Ether *ether;
- ulong offset = off;
-
- ether = etherxx[chan->dev];
- if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
- /*
- * With some controllers it is necessary to reach
- * into the chip to extract statistics.
- */
- if(NETTYPE(chan->qid.path) == Nifstatqid)
- return ether->ifstat(ether, buf, n, offset);
- else if(NETTYPE(chan->qid.path) == Nstatqid)
- ether->ifstat(ether, buf, 0, offset);
- }
-
- return netifread(ether, chan, buf, n, offset);
-}
-
-static Block*
-etherbread(Chan* chan, long n, ulong offset)
-{
- return netifbread(etherxx[chan->dev], chan, n, offset);
-}
-
-static int
-etherwstat(Chan* chan, uchar* dp, int n)
-{
- return netifwstat(etherxx[chan->dev], chan, dp, n);
-}
-
-static void
-etherrtrace(Netfile* f, Etherpkt* pkt, int len)
-{
- int i, n;
- Block *bp;
-
- if(qwindow(f->in) <= 0)
- return;
- if(len > 58)
- n = 58;
- else
- n = len;
- bp = iallocb(64);
- if(bp == nil)
- return;
- memmove(bp->wp, pkt->d, n);
- i = TK2MS(MACHP(0)->ticks);
- bp->wp[58] = len>>8;
- bp->wp[59] = len;
- bp->wp[60] = i>>24;
- bp->wp[61] = i>>16;
- bp->wp[62] = i>>8;
- bp->wp[63] = i;
- bp->wp += 64;
- qpass(f->in, bp);
-}
-
-Block*
-etheriq(Ether* ether, Block* bp, int fromwire)
-{
- Etherpkt *pkt;
- ushort type;
- int len, multi, tome, fromme;
- Netfile **ep, *f, **fp, *fx;
- Block *xbp;
-
- ether->inpackets++;
-
- pkt = (Etherpkt*)bp->rp;
- len = BLEN(bp);
- type = (pkt->type[0]<<8)|pkt->type[1];
- fx = 0;
- ep = ðer->f[Ntypes];
-
- multi = pkt->d[0] & 1;
- /* check for valid multicast addresses */
- if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 &&
- ether->prom == 0){
- if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
- if(fromwire){
- freeb(bp);
- bp = 0;
- }
- return bp;
- }
- }
- /* is it for me? */
- tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
- fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
-
- /*
- * Multiplex the packet to all the connections which want it.
- * If the packet is not to be used subsequently (fromwire != 0),
- * attempt to simply pass it into one of the connections, thereby
- * saving a copy of the data (usual case hopefully).
- */
- for(fp = ether->f; fp < ep; fp++){
- if((f = *fp) != nil && (f->type == type || f->type < 0) &&
- (tome || multi || f->prom)){
- /* Don't want to hear loopback or bridged packets */
- if(f->bridge && (tome || !fromwire && !fromme))
- continue;
- if(!f->headersonly){
- if(fromwire && fx == 0)
- fx = f;
- else if(xbp = iallocb(len)){
- memmove(xbp->wp, pkt, len);
- xbp->wp += len;
- if(qpass(f->in, xbp) < 0)
- ether->soverflows++;
- }
- else
- ether->soverflows++;
- }
- else
- etherrtrace(f, pkt, len);
- }
- }
-
- if(fx){
- if(qpass(fx->in, bp) < 0)
- ether->soverflows++;
- return 0;
- }
- if(fromwire){
- freeb(bp);
- return 0;
- }
- return bp;
-}
-
-static int
-etheroq(Ether* ether, Block* bp)
-{
- int len, loopback;
- Etherpkt *pkt;
-
- ether->outpackets++;
-
- /*
- * Check if the packet has to be placed back onto the input queue,
- * i.e. if it's a loopback or broadcast packet or the interface is
- * in promiscuous mode.
- * If it's a loopback packet indicate to etheriq that the data isn't
- * needed and return, etheriq will pass-on or free the block.
- * To enable bridging to work, only packets that were originated
- * by this interface are fed back.
- */
- pkt = (Etherpkt*)bp->rp;
- len = BLEN(bp);
- loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
- if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom)
- if(etheriq(ether, bp, loopback) == 0)
- return len;
-
- qbwrite(ether->oq, bp);
- if(ether->transmit != nil)
- ether->transmit(ether);
- return len;
-}
-
-static long
-etherwrite(Chan* chan, void* buf, long n, vlong)
-{
- Ether *ether;
- Block *bp;
- int nn, onoff;
- Cmdbuf *cb;
-
- ether = etherxx[chan->dev];
- if(NETTYPE(chan->qid.path) != Ndataqid) {
- nn = netifwrite(ether, chan, buf, n);
- if(nn >= 0)
- return nn;
- cb = parsecmd(buf, n);
- if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
- if(cb->nf <= 1)
- onoff = 1;
- else
- onoff = atoi(cb->f[1]);
- qnoblock(ether->oq, onoff);
- free(cb);
- return n;
- }
- free(cb);
- if(ether->ctl!=nil)
- return ether->ctl(ether,buf,n);
-
- error(Ebadctl);
- }
-
- if(n > ether->maxmtu)
- error(Etoobig);
- if(n < ether->minmtu)
- error(Etoosmall);
-
- bp = allocb(n);
- if(waserror()){
- freeb(bp);
- nexterror();
- }
- memmove(bp->rp, buf, n);
- if(!ether->f[NETID(chan->qid.path)]->bridge)
- memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
- poperror();
- bp->wp += n;
-
- return etheroq(ether, bp);
-}
-
-static long
-etherbwrite(Chan* chan, Block* bp, ulong)
-{
- Ether *ether;
- long n;
-
- n = BLEN(bp);
- if(NETTYPE(chan->qid.path) != Ndataqid){
- if(waserror()) {
- freeb(bp);
- nexterror();
- }
- n = etherwrite(chan, bp->rp, n, 0);
- poperror();
- freeb(bp);
- return n;
- }
- ether = etherxx[chan->dev];
-
- if(n > ether->maxmtu){
- freeb(bp);
- error(Etoobig);
- }
- if(n < ether->minmtu){
- freeb(bp);
- error(Etoosmall);
- }
-
- return etheroq(ether, bp);
-}
-
-static struct {
- char* type;
- int (*reset)(Ether*);
-} cards[MaxEther+1];
-
-void
-addethercard(char* t, int (*r)(Ether*))
-{
- static int ncard;
-
- if(ncard == MaxEther)
- panic("too many ether cards");
- cards[ncard].type = t;
- cards[ncard].reset = r;
- ncard++;
-}
-
-static void
-etherreset(void)
-{
- Ether *ether;
- int i, n, ctlrno;
- char name[KNAMELEN], buf[128];
-
- for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
- if(ether == 0)
- ether = malloc(sizeof(Ether));
- memset(ether, 0, sizeof(Ether));
- ether->ctlrno = ctlrno;
- ether->mbps = 10;
- ether->minmtu = ETHERMINTU;
- ether->maxmtu = ETHERMAXTU;
-
- if(archether(ctlrno, ether) <= 0)
- continue;
-
- if(isaconfig("ether", ctlrno, ether) == 0){
-// free(ether);
-// return nil;
- continue;
- }
- for(n = 0; cards[n].type; n++){
- if(cistrcmp(cards[n].type, ether->type))
- continue;
- for(i = 0; i < ether->nopt; i++)
- if(cistrncmp(ether->opt[i], "ea=", 3) == 0){
- if(parseether(ether->ea,
- ðer->opt[i][3]) == -1)
- memset(ether->ea, 0, Eaddrlen);
- } else if(cistrcmp(ether->opt[i],
- "100BASE-TXFD") == 0)
- ether->mbps = 100;
- if(cards[n].reset(ether))
- break;
- snprint(name, sizeof(name), "ether%d", ctlrno);
-
- if(ether->interrupt != nil && ether->irq >= 0)
- intrenable(ether->irq, ether->interrupt,
- ether, 0, name);
-
- i = snprint(buf, sizeof buf,
- "#l%d: %s: %dMbps port %#lux irq %d",
- ctlrno, ether->type, ether->mbps, ether->port,
- ether->irq);
- if(ether->mem)
- i += snprint(buf+i, sizeof buf - i,
- " addr %#lux", PADDR(ether->mem));
- if(ether->size)
- i += snprint(buf+i, sizeof buf - i,
- " size %#luX", ether->size);
- i += snprint(buf+i, sizeof buf - i,
- ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
- ether->ea[0], ether->ea[1], ether->ea[2],
- ether->ea[3], ether->ea[4], ether->ea[5]);
- snprint(buf+i, sizeof buf - i, "\n");
- iprint("%s", buf); /* it may be too early for print */
-
- if(ether->mbps >= 1000)
- netifinit(ether, name, Ntypes, 4*1024*1024);
- else if(ether->mbps >= 100)
- netifinit(ether, name, Ntypes, 1024*1024);
- else
- netifinit(ether, name, Ntypes, 65*1024);
- if(ether->oq == 0)
- ether->oq = qopen(ether->limit, Qmsg, 0, 0);
- if(ether->oq == 0)
- panic("etherreset %s", name);
- ether->alen = Eaddrlen;
- memmove(ether->addr, ether->ea, Eaddrlen);
- memset(ether->bcast, 0xFF, Eaddrlen);
-
- etherxx[ctlrno] = ether;
- ether = 0;
- break;
- }
- }
- if(ether)
- free(ether);
-}
-
-static void
-ethershutdown(void)
-{
- Ether *ether;
- int i;
-
- for(i = 0; i < MaxEther; i++){
- ether = etherxx[i];
- if(ether == nil)
- continue;
- if(ether->shutdown == nil) {
- print("#l%d: no shutdown function\n", i);
- continue;
- }
- (*ether->shutdown)(ether);
- }
-}
-
-
-#define POLY 0xedb88320
-
-/* really slow 32 bit crc for ethers */
-ulong
-ethercrc(uchar *p, int len)
-{
- int i, j;
- ulong crc, b;
-
- crc = 0xffffffff;
- for(i = 0; i < len; i++){
- b = *p++;
- for(j = 0; j < 8; j++){
- crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
- b >>= 1;
- }
- }
- return crc;
-}
-
-void
-dumpoq(Queue *oq)
-{
- if (oq == nil)
- print("no outq! ");
- else if (qisclosed(oq))
- print("outq closed ");
- else if (qfull(oq))
- print("outq full ");
- else
- print("outq %d ", qlen(oq));
-}
-
-void
-dumpnetif(Netif *netif)
-{
- print("netif %s ", netif->name);
- print("limit %d mbps %d link %d ",
- netif->limit, netif->mbps, netif->link);
- print("inpkts %lld outpkts %lld errs %d\n",
- netif->inpackets, netif->outpackets,
- netif->crcs + netif->oerrs + netif->frames + netif->overflows +
- netif->buffs + netif->soverflows);
-}
-
-Dev etherdevtab = {
- 'l',
- "ether",
-
- etherreset,
- devinit,
- ethershutdown,
- etherattach,
- etherwalk,
- etherstat,
- etheropen,
- ethercreate,
- etherclose,
- etherread,
- etherbread,
- etherwrite,
- etherbwrite,
- devremove,
- etherwstat,
-};
--- a/sys/src/9/teg2/ether8169.c
+++ b/sys/src/9/teg2/ether8169.c
@@ -15,8 +15,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
#include "ethermii.h"
typedef struct Ctlr Ctlr;
@@ -1655,7 +1655,6 @@
edev->attach = rtl8169attach;
edev->transmit = rtl8169transmit;
- edev->interrupt = rtl8169interrupt;
edev->ifstat = rtl8169ifstat;
edev->arg = edev;
@@ -1666,6 +1665,9 @@
ilock(&ctlr->reglock);
rtl8169link(edev);
iunlock(&ctlr->reglock);
+
+ intrenable(edev->irq, rtl8169interrupt, edev, 0, edev->name);
+
return 0;
}
--- a/sys/src/9/teg2/etherif.h
+++ /dev/null
@@ -1,42 +1,0 @@
-enum
-{
- MaxEther = 4,
- Ntypes = 8,
-};
-
-typedef struct Ether Ether;
-struct Ether {
- RWlock;
- ISAConf; /* hardware info */
-
- int ctlrno;
- ulong tbdf;
- int minmtu;
- int maxmtu;
-
- Netif;
-
- void (*attach)(Ether*); /* filled in by reset routine */
- void (*detach)(Ether*);
- void (*transmit)(Ether*);
- void (*interrupt)(Ureg*, void*);
- long (*ifstat)(Ether*, void*, long, ulong);
- long (*ctl)(Ether*, void*, long); /* custom ctl messages */
- void (*power)(Ether*, int); /* power on/off */
- void (*shutdown)(Ether*); /* shutdown hardware before reboot */
-
- void* ctlr;
- uchar ea[Eaddrlen];
- void* address;
- int irq;
-
- Queue* oq;
-};
-
-extern Block* etheriq(Ether*, Block*, int);
-extern void addethercard(char*, int(*)(Ether*));
-extern ulong ethercrc(uchar*, int);
-extern int parseether(uchar*, char*);
-
-#define NEXT(x, l) (((x)+1)%(l))
-#define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1)
--- a/sys/src/9/teg2/ethermii.c
+++ b/sys/src/9/teg2/ethermii.c
@@ -6,8 +6,8 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
+#include "../port/etherif.h"
-#include "etherif.h"
#include "ethermii.h"
int
--- a/sys/src/9/teg2/mem.h
+++ b/sys/src/9/teg2/mem.h
@@ -5,9 +5,6 @@
#define MiB 1048576u /* Mebi 0x0000000000100000 */
#define GiB 1073741824u /* Gibi 000000000040000000 */
-#define HOWMANY(x, y) (((x)+((y)-1))/(y))
-#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y)) /* ceiling */
-#define ROUNDDN(x, y) (((x)/(y))*(y)) /* floor */
#define MIN(a, b) ((a) < (b)? (a): (b))
#define MAX(a, b) ((a) > (b)? (a): (b))
@@ -36,7 +33,7 @@
*/
#define BY2PG (4*KiB) /* bytes per page */
#define PGSHIFT 12 /* log(BY2PG) */
-#define PGROUND(s) ROUNDUP(s, BY2PG)
+#define PGROUND(s) ROUND(s, BY2PG)
#define ROUND(s, sz) (((s)+(sz-1))&~(sz-1))
/* max # of cpus system can run. tegra2 cpu ids are two bits wide. */
@@ -85,7 +82,6 @@
#define UZERO 0 /* user segment */
#define UTZERO (UZERO+BY2PG) /* user text start */
-#define UTROUND(t) ROUNDUP((t), BY2PG)
/*
* moved USTKTOP down to 1GB to keep MMIO space out of user space.
* moved it down another MB to utterly avoid KADDR(stack_base) mapping
--- a/sys/src/9/teg2/mkfile
+++ b/sys/src/9/teg2/mkfile
@@ -117,7 +117,7 @@
arch.$O clock.$O fpiarm.$O main.$O mmu.$O screen.$O sdscsi.$O syscall.$O \
trap.$O: /$objtype/include/ureg.h
-archtegra.$O devether.$0 ether9221.$O: etherif.h ../port/netif.h
+archtegra.$O devether.$0 ether9221.$O: ../port/etherif.h ../port/netif.h
archtegra.$O devflash.$O flashtegra.$O flashigep.$O: ../port/flashif.h
ecc.$O flashtegra.$O flashigep.$O: ../port/nandecc.h io.h
fpi.$O fpiarm.$O fpimem.$O: fpi.h
--- a/sys/src/9/teg2/mmu.c
+++ b/sys/src/9/teg2/mmu.c
@@ -693,7 +693,7 @@
o = pa & (BY2PG-1);
pa -= o;
size += o;
- size = ROUNDUP(size, BY2PG);
+ size = PGROUND(size);
va = kseg0|pa;
pae = mmukmap(va, pa, size);
--- a/sys/src/9/xen/etherxen.c
+++ b/sys/src/9/xen/etherxen.c
@@ -10,7 +10,7 @@
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"
-#include "etherif.h"
+#include "../port/etherif.h"
#define LOG(a)
@@ -478,12 +478,14 @@
ether->transmit = etherxentransmit;
ether->irq = -1;
ether->tbdf = BUSUNKNOWN;
- ether->interrupt = etherxenintr;
ether->ifstat = ifstat;
ether->ctl = etherxenctl;
ether->promiscuous = nil;
ether->multicast = etherxenmulticast;
ether->arg = ether;
+
+ intrenable(ether->irq, etherxenintr, ether, ether->tbdf, ether->name);
+
return 0;
}
--- a/sys/src/9/xen/mkfile
+++ b/sys/src/9/xen/mkfile
@@ -114,7 +114,7 @@
# import lookout / /n/lookout && cp $p$CONF $p$CONF.gz /n/lookout/$objtype/
# copies generated by the rule below
-PCHEADERS=uncached.h etherif.h ethermii.h mp.h io.h
+PCHEADERS=uncached.h ethermii.h mp.h io.h
REPCH=`{echo $PCHEADERS | sed 's/\.h//g; s/ /|/g'}
^($REPCH)\.h:R: '../pc/\1.h'
@@ -132,7 +132,7 @@
$AS $AFLAGS ../pc/ptclbsum386.s
# we inherited these.. revisit.
-$ETHER: etherif.h ../port/netif.h
+$ETHER: ../port/etherif.h ../port/netif.h
$SDEV: ../port/sd.h
main.$O: init.h reboot.h
trap.$O: /sys/include/tos.h
--- a/sys/src/9/xen/xenpcf
+++ b/sys/src/9/xen/xenpcf
@@ -20,7 +20,7 @@
xenstore
ether netif
- ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum386 inferno
+ ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum386 inferno
sd
--- a/sys/src/9/zynq/dat.h
+++ b/sys/src/9/zynq/dat.h
@@ -161,10 +161,11 @@
struct ISAConf
{
- int dummy;
- char *type;
- ulong port;
- int irq;
+ char *type;
+ ulong port;
+ int irq;
+ int nopt;
+ char *opt[1];
};
#define BUSUNKNOWN -1
--- a/sys/src/9/zynq/devether.c
+++ /dev/null
@@ -1,489 +1,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "pool.h"
-#include "ureg.h"
-#include "../port/error.h"
-#include "../port/netif.h"
-
-#include "etherif.h"
-
-static Ether *etherxx[MaxEther];
-
-Chan*
-etherattach(char* spec)
-{
- ulong ctlrno;
- char *p;
- Chan *chan;
-
- ctlrno = 0;
- if(spec && *spec){
- ctlrno = strtoul(spec, &p, 0);
- if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther))
- error(Ebadarg);
- }
- if(etherxx[ctlrno] == 0)
- error(Enodev);
-
- chan = devattach('l', spec);
- if(waserror()){
- chanfree(chan);
- nexterror();
- }
- chan->dev = ctlrno;
- if(etherxx[ctlrno]->attach)
- etherxx[ctlrno]->attach(etherxx[ctlrno]);
- poperror();
- return chan;
-}
-
-static Walkqid*
-etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
-{
- return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
-}
-
-static int
-etherstat(Chan* chan, uchar* dp, int n)
-{
- return netifstat(etherxx[chan->dev], chan, dp, n);
-}
-
-static Chan*
-etheropen(Chan* chan, int omode)
-{
- return netifopen(etherxx[chan->dev], chan, omode);
-}
-
-static Chan*
-ethercreate(Chan*, char*, int, ulong)
-{
- error(Eperm);
- return 0;
-}
-
-static void
-etherclose(Chan* chan)
-{
- netifclose(etherxx[chan->dev], chan);
-}
-
-static long
-etherread(Chan* chan, void* buf, long n, vlong off)
-{
- Ether *ether;
- ulong offset = off;
-
- ether = etherxx[chan->dev];
- if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
- /*
- * With some controllers it is necessary to reach
- * into the chip to extract statistics.
- */
- if(NETTYPE(chan->qid.path) == Nifstatqid)
- return ether->ifstat(ether, buf, n, offset);
- else if(NETTYPE(chan->qid.path) == Nstatqid)
- ether->ifstat(ether, buf, 0, offset);
- }
-
- return netifread(ether, chan, buf, n, offset);
-}
-
-static Block*
-etherbread(Chan* chan, long n, ulong offset)
-{
- return netifbread(etherxx[chan->dev], chan, n, offset);
-}
-
-static int
-etherwstat(Chan* chan, uchar* dp, int n)
-{
- return netifwstat(etherxx[chan->dev], chan, dp, n);
-}
-
-static void
-etherrtrace(Netfile* f, Etherpkt* pkt, int len)
-{
- int i, n;
- Block *bp;
-
- if(qwindow(f->in) <= 0)
- return;
- if(len > 58)
- n = 58;
- else
- n = len;
- bp = iallocb(64);
- if(bp == nil)
- return;
- memmove(bp->wp, pkt->d, n);
- i = TK2MS(MACHP(0)->ticks);
- bp->wp[58] = len>>8;
- bp->wp[59] = len;
- bp->wp[60] = i>>24;
- bp->wp[61] = i>>16;
- bp->wp[62] = i>>8;
- bp->wp[63] = i;
- bp->wp += 64;
- qpass(f->in, bp);
-}
-
-Block*
-etheriq(Ether* ether, Block* bp, int fromwire)
-{
- Etherpkt *pkt;
- ushort type;
- int len, multi, tome, fromme;
- Netfile **ep, *f, **fp, *fx;
- Block *xbp;
-
- ether->inpackets++;
-
- pkt = (Etherpkt*)bp->rp;
- len = BLEN(bp);
- type = (pkt->type[0]<<8)|pkt->type[1];
- fx = 0;
- ep = ðer->f[Ntypes];
-
- multi = pkt->d[0] & 1;
- /* check for valid multicast addresses */
- if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 && ether->prom == 0){
- if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
- if(fromwire){
- freeb(bp);
- bp = 0;
- }
- return bp;
- }
- }
-
- /* is it for me? */
- tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
- fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
-
- /*
- * Multiplex the packet to all the connections which want it.
- * If the packet is not to be used subsequently (fromwire != 0),
- * attempt to simply pass it into one of the connections, thereby
- * saving a copy of the data (usual case hopefully).
- */
- for(fp = ether->f; fp < ep; fp++){
- if(f = *fp)
- if(f->type == type || f->type < 0)
- if(tome || multi || f->prom){
- /* Don't want to hear loopback or bridged packets */
- if(f->bridge && (tome || !fromwire && !fromme))
- continue;
- if(!f->headersonly){
- if(fromwire && fx == 0)
- fx = f;
- else if(xbp = iallocb(len)){
- memmove(xbp->wp, pkt, len);
- xbp->wp += len;
- if(qpass(f->in, xbp) < 0) {
- // print("soverflow for f->in\n");
- ether->soverflows++;
- }
- }
- else {
- // print("soverflow iallocb\n");
- ether->soverflows++;
- }
- }
- else
- etherrtrace(f, pkt, len);
- }
- }
-
- if(fx){
- if(qpass(fx->in, bp) < 0) {
- // print("soverflow for fx->in\n");
- ether->soverflows++;
- }
- return 0;
- }
- if(fromwire){
- freeb(bp);
- return 0;
- }
-
- return bp;
-}
-
-static int
-etheroq(Ether* ether, Block* bp)
-{
- int len, loopback;
- Etherpkt *pkt;
-
- ether->outpackets++;
-
- /*
- * Check if the packet has to be placed back onto the input queue,
- * i.e. if it's a loopback or broadcast packet or the interface is
- * in promiscuous mode.
- * If it's a loopback packet indicate to etheriq that the data isn't
- * needed and return, etheriq will pass-on or free the block.
- * To enable bridging to work, only packets that were originated
- * by this interface are fed back.
- */
- pkt = (Etherpkt*)bp->rp;
- len = BLEN(bp);
- loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
- if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom)
- if(etheriq(ether, bp, loopback) == 0)
- return len;
-
- qbwrite(ether->oq, bp);
- if(ether->transmit != nil)
- ether->transmit(ether);
- return len;
-}
-
-static long
-etherwrite(Chan* chan, void* buf, long n, vlong)
-{
- Ether *ether;
- Block *bp;
- int nn, onoff;
- Cmdbuf *cb;
-
- ether = etherxx[chan->dev];
- if(NETTYPE(chan->qid.path) != Ndataqid) {
- nn = netifwrite(ether, chan, buf, n);
- if(nn >= 0)
- return nn;
- cb = parsecmd(buf, n);
- if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
- if(cb->nf <= 1)
- onoff = 1;
- else
- onoff = atoi(cb->f[1]);
- qnoblock(ether->oq, onoff);
- free(cb);
- return n;
- }
- free(cb);
- if(ether->ctl!=nil)
- return ether->ctl(ether,buf,n);
-
- error(Ebadctl);
- }
-
- if(n > ether->maxmtu)
- error(Etoobig);
- if(n < ether->minmtu)
- error(Etoosmall);
-
- bp = allocb(n);
- if(waserror()){
- freeb(bp);
- nexterror();
- }
- memmove(bp->rp, buf, n);
- if(!ether->f[NETID(chan->qid.path)]->bridge)
- memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
- poperror();
- bp->wp += n;
-
- return etheroq(ether, bp);
-}
-
-static long
-etherbwrite(Chan* chan, Block* bp, ulong)
-{
- Ether *ether;
- long n;
-
- n = BLEN(bp);
- if(NETTYPE(chan->qid.path) != Ndataqid){
- if(waserror()) {
- freeb(bp);
- nexterror();
- }
- n = etherwrite(chan, bp->rp, n, 0);
- poperror();
- freeb(bp);
- return n;
- }
- ether = etherxx[chan->dev];
-
- if(n > ether->maxmtu){
- freeb(bp);
- error(Etoobig);
- }
- if(n < ether->minmtu){
- freeb(bp);
- error(Etoosmall);
- }
-
- return etheroq(ether, bp);
-}
-
-static struct {
- char* type;
- int (*reset)(Ether*);
-} cards[MaxEther+1];
-
-void
-addethercard(char* t, int (*r)(Ether*))
-{
- static int ncard;
-
- if(ncard == MaxEther)
- panic("too many ether cards");
- cards[ncard].type = t;
- cards[ncard].reset = r;
- ncard++;
-}
-
-static Ether*
-etherprobe(int cardno, int ctlrno)
-{
- int i, lg;
- ulong mb, bsz;
- Ether *ether;
- char buf[128], name[32];
-
- ether = malloc(sizeof(Ether));
- if(ether == nil){
- print("etherprobe: no memory for Ether\n");
- return nil;
- }
- memset(ether, 0, sizeof(Ether));
- ether->ctlrno = ctlrno;
- ether->mbps = 10;
- ether->minmtu = ETHERMINTU;
- ether->maxmtu = ETHERMAXTU;
-
- if(cardno >= MaxEther || cards[cardno].type == nil){
- free(ether);
- return nil;
- }
- if(cards[cardno].reset(ether) < 0){
- free(ether);
- return nil;
- }
-
- snprint(name, sizeof(name), "ether%d", ctlrno);
-
- intrenable(ether->irq, ether->interrupt, ether, ether->irqlevel, name);
-
- i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
- ctlrno, cards[cardno].type, ether->mbps, ether->port, ether->irq);
- i += sprint(buf+i, ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
- ether->ea[0], ether->ea[1], ether->ea[2],
- ether->ea[3], ether->ea[4], ether->ea[5]);
- sprint(buf+i, "\n");
- print(buf);
-
- /* compute log10(ether->mbps) into lg */
- for(lg = 0, mb = ether->mbps; mb >= 10; lg++)
- mb /= 10;
- if (lg > 0)
- lg--;
- if (lg > 14) /* 2^(14+17) = 2³¹ */
- lg = 14;
- /* allocate larger output queues for higher-speed interfaces */
- bsz = 1UL << (lg + 17); /* 2¹⁷ = 128K, bsz = 2ⁿ × 128K */
- while (bsz > mainmem->maxsize / 8 && bsz > 128*1024)
- bsz /= 2;
-
- netifinit(ether, name, Ntypes, bsz);
- if(ether->oq == nil) {
- ether->oq = qopen(bsz, Qmsg, 0, 0);
- ether->limit = bsz;
- }
- if(ether->oq == nil)
- panic("etherreset %s: can't allocate output queue of %ld bytes", name, bsz);
- ether->alen = Eaddrlen;
- memmove(ether->addr, ether->ea, Eaddrlen);
- memset(ether->bcast, 0xFF, Eaddrlen);
-
- return ether;
-}
-
-static void
-etherreset(void)
-{
- Ether *ether;
- int cardno, ctlrno;
-
- cardno = ctlrno = 0;
- while(cards[cardno].type != nil && ctlrno < MaxEther){
- if(etherxx[ctlrno] != nil){
- ctlrno++;
- continue;
- }
- if((ether = etherprobe(cardno, ctlrno)) == nil){
- cardno++;
- continue;
- }
- etherxx[ctlrno] = ether;
- ctlrno++;
- }
-}
-
-static void
-ethershutdown(void)
-{
- Ether *ether;
- int i;
-
- for(i = 0; i < MaxEther; i++){
- ether = etherxx[i];
- if(ether == nil)
- continue;
- if(ether->shutdown == nil) {
- print("#l%d: no shutdown function\n", i);
- continue;
- }
- (*ether->shutdown)(ether);
- }
-}
-
-
-#define POLY 0xedb88320
-
-/* really slow 32 bit crc for ethers */
-ulong
-ethercrc(uchar *p, int len)
-{
- int i, j;
- ulong crc, b;
-
- crc = 0xffffffff;
- for(i = 0; i < len; i++){
- b = *p++;
- for(j = 0; j < 8; j++){
- crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
- b >>= 1;
- }
- }
- return crc;
-}
-
-Dev etherdevtab = {
- 'l',
- "ether",
-
- etherreset,
- devinit,
- ethershutdown,
- etherattach,
- etherwalk,
- etherstat,
- etheropen,
- ethercreate,
- etherclose,
- etherread,
- etherbread,
- etherwrite,
- etherbwrite,
- devremove,
- etherwstat,
-};
--- a/sys/src/9/zynq/etherif.h
+++ /dev/null
@@ -1,40 +1,0 @@
-enum {
- MaxEther = 1,
- Ntypes = 8,
-};
-
-typedef struct Ether Ether;
-struct Ether {
-
- int ctlrno;
- int minmtu;
- int maxmtu;
- uchar ea[Eaddrlen];
-
- int irq, irqlevel;
- uintptr port;
-
- void (*attach)(Ether*); /* filled in by reset routine */
- void (*detach)(Ether*);
- void (*transmit)(Ether*);
- void (*interrupt)(Ureg*, void*);
- long (*ifstat)(Ether*, void*, long, ulong);
- long (*ctl)(Ether*, void*, long); /* custom ctl messages */
- void (*power)(Ether*, int); /* power on/off */
- void (*shutdown)(Ether*); /* shutdown hardware before reboot */
- void *ctlr;
-
- Queue* oq;
-
- Netif;
-};
-
-extern Block* etheriq(Ether*, Block*, int);
-extern void addethercard(char*, int(*)(Ether*));
-extern ulong ethercrc(uchar*, int);
-extern int parseether(uchar*, char*);
-
-#define NEXT(x, l) (((x)+1)%(l))
-#define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1)
-#define HOWMANY(x, y) (((x)+((y)-1))/(y))
-#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y))
--- a/sys/src/9/zynq/etherzynq.c
+++ b/sys/src/9/zynq/etherzynq.c
@@ -5,7 +5,7 @@
#include "fns.h"
#include "io.h"
#include "../port/netif.h"
-#include "etherif.h"
+#include "../port/etherif.h"
#define Rbsz ROUNDUP(sizeof(Etherpkt)+16, 64)
@@ -409,9 +409,7 @@
edev->port = ETH0_BASE;
ct.r = vmap(edev->port, BY2PG);
edev->irq = ETH0IRQ;
- edev->irqlevel = LEVEL;
edev->ctlr = &ct;
- edev->interrupt = ethirq;
edev->transmit = ethtx;
edev->attach = ethattach;
edev->promiscuous = ethprom;
@@ -423,6 +421,8 @@
edev->ctlr = nil;
return -1;
}
+
+ intrenable(edev->irq, ethirq, edev, LEVEL, edev->name);
return 0;
}
--- a/sys/src/9/zynq/main.c
+++ b/sys/src/9/zynq/main.c
@@ -306,7 +306,7 @@
int
isaconfig(char *, int, ISAConf*)
{
- return 1;
+ return 0;
}
void