Add support for monitor mode. This means that after enabling the

correct mode via ancontrol, you can use bpf to sniff raw 802.11 frames.
Who want's to port AirSnort. ;-)

Submitted by:	Doug Ambrisko <ambrisko@ambrisko.com> (author)
		David Wolfskill <david@catwhisker.org> (port to current)
This commit is contained in:
Brooks Davis 2001-09-10 02:05:10 +00:00
parent 8cdfefbd0c
commit 51331cf32a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=83269
3 changed files with 291 additions and 98 deletions

View File

@ -102,6 +102,7 @@
#endif #endif
#include <sys/module.h> #include <sys/module.h>
#include <sys/sysctl.h>
#include <sys/bus.h> #include <sys/bus.h>
#include <machine/bus.h> #include <machine/bus.h>
#include <sys/rman.h> #include <sys/rman.h>
@ -169,6 +170,68 @@ static int an_media_change __P((struct ifnet *));
static void an_media_status __P((struct ifnet *, struct ifmediareq *)); static void an_media_status __P((struct ifnet *, struct ifmediareq *));
static int an_dump = 0; static int an_dump = 0;
static char an_conf[256];
/* sysctl vars */
SYSCTL_NODE(_machdep, OID_AUTO, an, CTLFLAG_RD, 0, "dump RID");
static int
sysctl_an_dump(SYSCTL_HANDLER_ARGS)
{
int error, r, last;
char *s = an_conf;
last = an_dump;
bzero(an_conf, sizeof(an_conf));
switch (an_dump){
case 0:
strcat(an_conf, "off");
break;
case 1:
strcat(an_conf, "type");
break;
case 2:
strcat(an_conf, "dump");
break;
default:
snprintf(an_conf, 5, "%x", an_dump);
break;
}
error = sysctl_handle_string(oidp, an_conf, sizeof(an_conf), req);
if (strncmp(an_conf,"off", 4) == 0){
an_dump = 0;
}
if (strncmp(an_conf,"dump", 4) == 0){
an_dump = 1;
}
if (strncmp(an_conf,"type", 4) == 0){
an_dump = 2;
}
if (*s == 'f'){
r = 0;
for(;;s++){
if((*s >= '0') && (*s <= '9')){
r = r * 16 + (*s - '0');
}else if ((*s >= 'a') && (*s <= 'f')) {
r = r * 16 + (*s - 'a' + 10);
}else{
break;
}
}
an_dump = r;
}
if (an_dump != last)
printf("Sysctl changed for Aironet driver\n");
return error;
}
SYSCTL_PROC(_machdep, OID_AUTO, an_dump, CTLTYPE_STRING | CTLFLAG_RW,
0, sizeof(an_conf), sysctl_an_dump, "A", "");
/* /*
* We probe for an Aironet 4500/4800 card by attempting to * We probe for an Aironet 4500/4800 card by attempting to
* read the default SSID list. On reset, the first entry in * read the default SSID list. On reset, the first entry in
@ -303,6 +366,8 @@ int an_attach(sc, unit, flags)
sc->an_gone = 0; sc->an_gone = 0;
sc->an_associated = 0; sc->an_associated = 0;
sc->an_monitor = 0;
sc->an_was_monitor = 0;
/* Reset the NIC. */ /* Reset the NIC. */
an_reset(sc); an_reset(sc);
@ -424,90 +489,160 @@ int an_attach(sc, unit, flags)
return(0); return(0);
} }
static void an_rxeof(sc) static void
struct an_softc *sc; an_rxeof(sc)
struct an_softc *sc;
{ {
struct ifnet *ifp; struct ifnet *ifp;
struct ether_header *eh; struct ether_header *eh;
#ifdef ANCACHE struct ieee80211_frame *ih;
struct an_rxframe rx_frame; struct an_rxframe rx_frame;
#endif struct an_rxframe_802_3 rx_frame_802_3;
struct an_rxframe_802_3 rx_frame_802_3; struct mbuf *m;
struct mbuf *m; int len, id, error = 0;
int id, error = 0; int ieee80211_header_len;
u_char *bpf_buf;
u_short fc1;
ifp = &sc->arpcom.ac_if; ifp = &sc->arpcom.ac_if;
id = CSR_READ_2(sc, AN_RX_FID); id = CSR_READ_2(sc, AN_RX_FID);
MGETHDR(m, M_DONTWAIT, MT_DATA); if (sc->an_monitor && (ifp->if_flags & IFF_PROMISC)) {
if (m == NULL) { /* read raw 802.11 packet */
ifp->if_ierrors++; bpf_buf = sc->buf_802_11;
return;
}
MCLGET(m, M_DONTWAIT);
if (!(m->m_flags & M_EXT)) {
m_freem(m);
ifp->if_ierrors++;
return;
}
m->m_pkthdr.rcvif = ifp; /* read header */
if (an_read_data(sc, id, 0x0, (caddr_t)&rx_frame,
sizeof(rx_frame))) {
ifp->if_ierrors++;
return;
}
eh = mtod(m, struct ether_header *); /*
* skip beacon by default since this increases the
* system load a lot
*/
if(!(sc->an_monitor & AN_MONITOR_INCLUDE_BEACON) &&
(rx_frame.an_frame_ctl & IEEE80211_FC0_SUBTYPE_BEACON)){
return;
}
if (sc->an_monitor & AN_MONITOR_AIRONET_HEADER){
len = rx_frame.an_rx_payload_len
+ sizeof(rx_frame);
/* Check for insane frame length */
if (len > sizeof(sc->buf_802_11)) {
printf("an%d: oversized packet received (%d, %d)\n",
sc->an_unit, len, MCLBYTES);
ifp->if_ierrors++;
return;
}
bcopy((char *)&rx_frame,
bpf_buf, sizeof(rx_frame));
error = an_read_data(sc, id, sizeof(rx_frame),
(caddr_t)bpf_buf+sizeof(rx_frame),
rx_frame.an_rx_payload_len);
}else{
fc1=rx_frame.an_frame_ctl >> 8;
ieee80211_header_len = sizeof(struct ieee80211_frame);
if ((fc1 & IEEE80211_FC1_DIR_TODS) &&
(fc1 & IEEE80211_FC1_DIR_FROMDS)) {
ieee80211_header_len += ETHER_ADDR_LEN;
}
len = rx_frame.an_rx_payload_len
+ ieee80211_header_len;
/* Check for insane frame length */
if (len > sizeof(sc->buf_802_11)) {
printf("an%d: oversized packet received (%d, %d)\n",
sc->an_unit, len, MCLBYTES);
ifp->if_ierrors++;
return;
}
ih = (struct ieee80211_frame *)bpf_buf;
bcopy((char *)&rx_frame.an_frame_ctl,
(char *)ih, ieee80211_header_len);
error = an_read_data(sc, id, sizeof(rx_frame) +
rx_frame.an_gaplen,
(caddr_t)ih +ieee80211_header_len,
rx_frame.an_rx_payload_len);
}
/* dump raw 802.11 packet to bpf and skip ip stack */
if (ifp->if_bpf != NULL) {
bpf_tap(ifp, bpf_buf, len);
}
} else {
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL) {
ifp->if_ierrors++;
return;
}
MCLGET(m, M_DONTWAIT);
if (!(m->m_flags & M_EXT)) {
m_freem(m);
ifp->if_ierrors++;
return;
}
m->m_pkthdr.rcvif = ifp;
/* Read Ethenet encapsulated packet */
#ifdef ANCACHE #ifdef ANCACHE
/* Read NIC frame header */ /* Read NIC frame header */
if (an_read_data(sc, id, 0, (caddr_t)&rx_frame, sizeof(rx_frame))) { if (an_read_data(sc, id, 0, (caddr_t) & rx_frame, sizeof(rx_frame))) {
ifp->if_ierrors++; ifp->if_ierrors++;
return; return;
} }
#endif #endif
/* Read in the 802_3 frame header */ /* Read in the 802_3 frame header */
if (an_read_data(sc, id, 0x34, (caddr_t)&rx_frame_802_3, if (an_read_data(sc, id, 0x34, (caddr_t) & rx_frame_802_3,
sizeof(rx_frame_802_3))) { sizeof(rx_frame_802_3))) {
ifp->if_ierrors++; ifp->if_ierrors++;
return; return;
} }
if (rx_frame_802_3.an_rx_802_3_status != 0) {
ifp->if_ierrors++;
return;
}
/* Check for insane frame length */
if (rx_frame_802_3.an_rx_802_3_payload_len > MCLBYTES) {
ifp->if_ierrors++;
return;
}
m->m_pkthdr.len = m->m_len =
rx_frame_802_3.an_rx_802_3_payload_len + 12;
if (rx_frame_802_3.an_rx_802_3_status != 0) { eh = mtod(m, struct ether_header *);
ifp->if_ierrors++;
return;
}
/* Check for insane frame length */ bcopy((char *)&rx_frame_802_3.an_rx_dst_addr,
if (rx_frame_802_3.an_rx_802_3_payload_len > MCLBYTES) { (char *)&eh->ether_dhost, ETHER_ADDR_LEN);
ifp->if_ierrors++; bcopy((char *)&rx_frame_802_3.an_rx_src_addr,
return; (char *)&eh->ether_shost, ETHER_ADDR_LEN);
}
m->m_pkthdr.len = m->m_len = /* in mbuf header type is just before payload */
rx_frame_802_3.an_rx_802_3_payload_len + 12; error = an_read_data(sc, id, 0x44, (caddr_t)&(eh->ether_type),
rx_frame_802_3.an_rx_802_3_payload_len);
if (error) {
bcopy((char *)&rx_frame_802_3.an_rx_dst_addr, m_freem(m);
(char *)&eh->ether_dhost, ETHER_ADDR_LEN); ifp->if_ierrors++;
bcopy((char *)&rx_frame_802_3.an_rx_src_addr, return;
(char *)&eh->ether_shost, ETHER_ADDR_LEN); }
ifp->if_ipackets++;
/* in mbuf header type is just before payload */ /* Receive packet. */
error = an_read_data(sc, id, 0x44, (caddr_t)&(eh->ether_type), m_adj(m, sizeof(struct ether_header));
rx_frame_802_3.an_rx_802_3_payload_len);
if (error != 0) {
m_freem(m);
ifp->if_ierrors++;
return;
}
ifp->if_ipackets++;
/* Receive packet. */
m_adj(m, sizeof(struct ether_header));
#ifdef ANCACHE #ifdef ANCACHE
an_cache_store(sc, eh, m, rx_frame.an_rx_signal_strength); an_cache_store(sc, eh, m, rx_frame.an_rx_signal_strength);
#endif #endif
ether_input(ifp, eh, m); ether_input(ifp, eh, m);
}
} }
static void an_txeof(sc, status) static void an_txeof(sc, status)
@ -517,10 +652,6 @@ static void an_txeof(sc, status)
struct ifnet *ifp; struct ifnet *ifp;
int id, i; int id, i;
/* TX DONE enable lan monitor DJA
an_enable_sniff();
*/
ifp = &sc->arpcom.ac_if; ifp = &sc->arpcom.ac_if;
ifp->if_timer = 0; ifp->if_timer = 0;
@ -1025,27 +1156,38 @@ static void an_setdef(sc, areq)
sc->an_tx_rate = sp->an_val; sc->an_tx_rate = sp->an_val;
break; break;
case AN_RID_WEP_TEMP: case AN_RID_WEP_TEMP:
/* Disable the MAC. */
an_cmd(sc, AN_CMD_DISABLE, 0);
/* Just write the Key, we don't want to save it */
an_write_record(sc, (struct an_ltv_gen *)areq);
/* Turn the MAC back on. */
an_cmd(sc, AN_CMD_ENABLE, 0);
break;
case AN_RID_WEP_PERM: case AN_RID_WEP_PERM:
/* Disable the MAC. */ /* Disable the MAC. */
an_cmd(sc, AN_CMD_DISABLE, 0); an_cmd(sc, AN_CMD_DISABLE, 0);
/* Just write the Key, the card will save it in this mode */ /* Write the key */
an_write_record(sc, (struct an_ltv_gen *)areq); an_write_record(sc, (struct an_ltv_gen *)areq);
/* Turn the MAC back on. */ /* Turn the MAC back on. */
an_cmd(sc, AN_CMD_ENABLE, 0); an_cmd(sc, AN_CMD_ENABLE, 0);
break;
case AN_RID_MONITOR_MODE:
cfg = (struct an_ltv_genconfig *)areq;
bpfdetach(ifp);
if (ng_ether_detach_p != NULL)
(*ng_ether_detach_p) (ifp);
sc->an_monitor = cfg->an_len;
if (sc->an_monitor & AN_MONITOR){
if (sc->an_monitor & AN_MONITOR_AIRONET_HEADER){
bpfattach(ifp, DLT_AIRONET_HEADER,
sizeof(struct ether_header));
} else {
bpfattach(ifp, DLT_IEEE802_11,
sizeof(struct ether_header));
}
} else {
bpfattach(ifp, DLT_EN10MB,
sizeof(struct ether_header));
if (ng_ether_attach_p != NULL)
(*ng_ether_attach_p) (ifp);
}
break; break;
default: default:
printf("an%d: unknown RID: %x\n", sc->an_unit, areq->an_type); printf("an%d: unknown RID: %x\n", sc->an_unit, areq->an_type);
@ -1062,16 +1204,21 @@ static void an_setdef(sc, areq)
} }
/* /*
* We can't change the NIC configuration while the MAC is enabled, * Derived from Linux driver to enable promiscious mode.
* so in order to turn on RX monitor mode, we have to turn the MAC
* off first.
*/ */
static void an_promisc(sc, promisc) static void an_promisc(sc, promisc)
struct an_softc *sc; struct an_softc *sc;
int promisc; int promisc;
{ {
an_cmd(sc, AN_CMD_SET_MODE, promisc ? 0xffff : 0); if(sc->an_was_monitor)
an_reset(sc);
if (sc->an_monitor ||sc->an_was_monitor )
an_init(sc);
sc->an_was_monitor = sc->an_monitor;
an_cmd(sc, AN_CMD_SET_MODE, promisc ? 0xffff : 0);
return; return;
} }
@ -1634,13 +1781,19 @@ static void an_init(xsc)
if (ifp->if_flags & IFF_MULTICAST) if (ifp->if_flags & IFF_MULTICAST)
sc->an_config.an_rxmode = AN_RXMODE_BC_MC_ADDR; sc->an_config.an_rxmode = AN_RXMODE_BC_MC_ADDR;
/* Initialize promisc mode. */ if (ifp->if_flags & IFF_PROMISC) {
/* Kills card DJA can't TX packet in sniff mode if (sc->an_monitor & AN_MONITOR) {
if (ifp->if_flags & IFF_PROMISC) if (sc->an_monitor & AN_MONITOR_ANY_BSS) {
sc->an_config.an_rxmode |= AN_RXMODE_LAN_MONITOR_CURBSS; sc->an_config.an_rxmode |=
*/ AN_RXMODE_80211_MONITOR_ANYBSS |
AN_RXMODE_NO_8023_HEADER;
sc->an_rxmode = sc->an_config.an_rxmode; } else {
sc->an_config.an_rxmode |=
AN_RXMODE_80211_MONITOR_CURBSS |
AN_RXMODE_NO_8023_HEADER;
}
}
}
/* Set the ssid list */ /* Set the ssid list */
sc->an_ssidlist.an_type = AN_RID_SSIDLIST; sc->an_ssidlist.an_type = AN_RID_SSIDLIST;
@ -1713,6 +1866,15 @@ static void an_start(ifp)
if (!sc->an_associated) if (!sc->an_associated)
return; return;
if (sc->an_monitor && (ifp->if_flags & IFF_PROMISC)) {
for(;;) {
IF_DEQUEUE(&ifp->if_snd, m0);
if (m0 == NULL)
break;
}
return;
}
idx = sc->an_rdata.an_tx_prod; idx = sc->an_rdata.an_tx_prod;
bzero((char *)&tx_frame_802_3, sizeof(tx_frame_802_3)); bzero((char *)&tx_frame_802_3, sizeof(tx_frame_802_3));

View File

@ -96,6 +96,8 @@
.Nm .Nm
.Fl i Ar iface Fl r Ar RTS threshold .Fl i Ar iface Fl r Ar RTS threshold
.Nm .Nm
.Fl i Ar iface Fl M Ar 0-15 (set monitor mode)
.Nm
.Fl h .Fl h
.Sh DESCRIPTION .Sh DESCRIPTION
The The
@ -394,6 +396,22 @@ need to be retransmitted instead of the whole packet.
The fragmentation The fragmentation
threshold can be anything from 64 to 2312 bytes. threshold can be anything from 64 to 2312 bytes.
The default is 2312. The default is 2312.
.It Fl i Ar iface Fl M Ar 0-15
Set monitor mode via bit mask, meaning:
.Bl -tag -offset indent -compact -width 0x000000
.Em "Bit Mask Meaning"
.It 0
to not dump 802.11 packet.
.It 1
to enable 802.11 monitor.
.It 2
to monitor any SSID.
.It 4
to not skip beacons, monitor beacons produces a high system load.
.It 8
to enable full Aironet header returned via BPF.
Note it appears that a SSID must be set.
.El
.It Fl i Ar iface Fl r Ar RTS threshold .It Fl i Ar iface Fl r Ar RTS threshold
Set the RTS/CTS threshold for a given interface. Set the RTS/CTS threshold for a given interface.
This controls the This controls the

View File

@ -125,6 +125,7 @@ int main __P((int, char **));
#define ACT_SET_KEY_TYPE 34 #define ACT_SET_KEY_TYPE 34
#define ACT_SET_KEYS 35 #define ACT_SET_KEYS 35
#define ACT_ENABLE_TX_KEY 36 #define ACT_ENABLE_TX_KEY 36
#define ACT_SET_MONITOR_MODE 37
static void an_getval(iface, areq) static void an_getval(iface, areq)
const char *iface; const char *iface;
@ -283,6 +284,7 @@ static void an_dumpstatus(iface)
an_printhex((char *)&sts->an_errcode, 1); an_printhex((char *)&sts->an_errcode, 1);
printf("\nSignal quality:\t\t"); printf("\nSignal quality:\t\t");
an_printhex((char *)&sts->an_cur_signal_quality, 1); an_printhex((char *)&sts->an_cur_signal_quality, 1);
printf("\nSignal strength:\t[ %d%% ]",sts->an_normalized_rssi);
/* /*
* XXX: This uses the old definition of the rate field (units of * XXX: This uses the old definition of the rate field (units of
* 500kbps). Technically the new definition is that this field * 500kbps). Technically the new definition is that this field
@ -839,6 +841,7 @@ static void usage(p)
fprintf(stderr, "\t%s -i iface -c val (set ad-hoc channel)\n", p); fprintf(stderr, "\t%s -i iface -c val (set ad-hoc channel)\n", p);
fprintf(stderr, "\t%s -i iface -f val (set frag threshold)\n", p); fprintf(stderr, "\t%s -i iface -f val (set frag threshold)\n", p);
fprintf(stderr, "\t%s -i iface -r val (set RTS threshold)\n", p); fprintf(stderr, "\t%s -i iface -r val (set RTS threshold)\n", p);
fprintf(stderr, "\t%s -i iface -M 0-15 (set monitor mode)\n", p);
#ifdef ANCACHE #ifdef ANCACHE
fprintf(stderr, "\t%s -i iface -Q print signal quality cache\n", p); fprintf(stderr, "\t%s -i iface -Q print signal quality cache\n", p);
fprintf(stderr, "\t%s -i iface -Z zero out signal cache\n", p); fprintf(stderr, "\t%s -i iface -Z zero out signal cache\n", p);
@ -977,6 +980,10 @@ static void an_setconfig(iface, act, arg)
cfg->an_authtype = (cfg->an_authtype & ~AN_AUTHTYPE_MASK) cfg->an_authtype = (cfg->an_authtype & ~AN_AUTHTYPE_MASK)
| atoi(arg); | atoi(arg);
break; break;
case ACT_SET_MONITOR_MODE:
areq.an_type = AN_RID_MONITOR_MODE;
cfg->an_len = atoi(arg); /* mode is put in length */
break;
default: default:
errx(1, "unknown action"); errx(1, "unknown action");
break; break;
@ -1282,18 +1289,20 @@ static void an_readkeyinfo(iface)
printf("WEP Key status:\n"); printf("WEP Key status:\n");
areq.an_type = AN_RID_WEP_TEMP; /* read first key */ areq.an_type = AN_RID_WEP_TEMP; /* read first key */
for(i=0; i<4; i++){ for(i=0; i<5; i++){
areq.an_len = sizeof(struct an_ltv_key); areq.an_len = sizeof(struct an_ltv_key);
an_getval(iface, &areq); an_getval(iface, &areq);
if(k->kindex == 0xffff)
break;
switch (k->klen){ switch (k->klen){
case 0: case 0:
printf("\tKey %d is unset\n",i); printf("\tKey %d is unset\n",k->kindex);
break; break;
case 5: case 5:
printf("\tKey %d is set 40 bits\n",i); printf("\tKey %d is set 40 bits\n",k->kindex);
break; break;
case 13: case 13:
printf("\tKey %d is set 128 bits\n",i); printf("\tKey %d is set 128 bits\n",k->kindex);
break; break;
default: default:
printf("\tWEP Key %d has an unknown size %d\n", printf("\tWEP Key %d has an unknown size %d\n",
@ -1369,7 +1378,7 @@ int main(argc, argv)
opterr = 1; opterr = 1;
while ((ch = getopt(argc, argv, while ((ch = getopt(argc, argv,
"ANISCTht:a:e:o:s:n:v:d:j:b:c:r:p:w:m:l:k:K:W:QZ")) != -1) { "ANISCTht:a:e:o:s:n:v:d:j:b:c:r:p:w:m:l:k:K:W:QZM:")) != -1) {
switch(ch) { switch(ch) {
case 'Z': case 'Z':
#ifdef ANCACHE #ifdef ANCACHE
@ -1532,6 +1541,10 @@ int main(argc, argv)
act = ACT_SET_WAKE_DURATION; act = ACT_SET_WAKE_DURATION;
arg = optarg; arg = optarg;
break; break;
case 'M':
act = ACT_SET_MONITOR_MODE;
arg = optarg;
break;
case 'h': case 'h':
default: default:
usage(p); usage(p);