ref: 8e924edeeb15d6350e531e73cf519f2bd6ed5a74
parent: 8c1417228c9714edd28a6946a95ed4203537ce52
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Thu Mar 6 16:36:14 EST 2014
wifi: decode AP->AP (WDS / bridge) data frames.
--- a/sys/src/9/pc/wifi.c
+++ b/sys/src/9/pc/wifi.c
@@ -43,18 +43,18 @@
static uchar*
srcaddr(Wifipkt *w)
{
- if((w->fc[1] & 3) == 0x02)
- return w->a3;
- else
+ 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] & 3) == 0x01)
+ if((w->fc[1] & 0x01) != 0)
return w->a3;
- else
- return w->a1;
+ return w->a1;
}
int
@@ -69,6 +69,8 @@
if(w->fc[1] & 0x80)
n += 4;
}
+ if((w->fc[1] & 3) == 0x03)
+ n += Eaddrlen;
return n;
}
@@ -78,10 +80,14 @@
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(w->fc[1] & 0x40){
/* encrypted */
qpass(wifi->iq, b);
@@ -96,9 +102,7 @@
case 0x04: /* control */
break;
case 0x08: /* data */
- if((w->fc[1] & 3) == 0x03) /* AP->AP */
- break;
- b->rp += wifihdrlen(w);
+ b->rp += hdrlen;
switch(w->fc[0] & 0xf0){
default:
goto drop;
@@ -538,7 +542,8 @@
wifietheroq(Wifi *wifi, Block *b)
{
Etherpkt e;
- Wifipkt *w;
+ Wifipkt h;
+ int hdrlen;
Wnode *wn;
SNAP *s;
@@ -557,16 +562,21 @@
} else if(wn->status != Sassoc)
goto drop;
- b = padblock(b, WIFIHDRSIZE + SNAPHDRSIZE);
+ 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);
- w = (Wifipkt*)b->rp;
- w->fc[0] = 0x08; /* data */
- w->fc[1] = 0x01; /* STA->AP */
- memmove(w->a1, wn->bssid, Eaddrlen);
- memmove(w->a2, e.s, Eaddrlen);
- memmove(w->a3, e.d, Eaddrlen);
-
- s = (SNAP*)(b->rp + WIFIHDRSIZE);
+ 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;
@@ -998,7 +1008,7 @@
kid = b->rp[3]>>6;
if((b->rp[3] & 0x20) == 0)
goto drop;
- if((dstaddr(w)[0] & 1) == 0)
+ if((w->a1[0] & 1) == 0)
kid = 4; /* use peerwise key for non-unicast */
k = &wn->rxkey[kid];
@@ -1488,6 +1498,10 @@
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;
}
--- a/sys/src/9/pc/wifi.h
+++ b/sys/src/9/pc/wifi.h
@@ -74,6 +74,7 @@
uchar a2[Eaddrlen];
uchar a3[Eaddrlen];
uchar seq[2];
+ uchar a4[Eaddrlen];
};
Wifi *wifiattach(Ether *ether, void (*transmit)(Wifi*, Wnode*, Block*));