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
#include <sys/module.h>
#include <sys/sysctl.h>
#include <sys/bus.h>
#include <machine/bus.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 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
* 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_associated = 0;
sc->an_monitor = 0;
sc->an_was_monitor = 0;
/* Reset the NIC. */
an_reset(sc);
@ -424,90 +489,160 @@ int an_attach(sc, unit, flags)
return(0);
}
static void an_rxeof(sc)
struct an_softc *sc;
static void
an_rxeof(sc)
struct an_softc *sc;
{
struct ifnet *ifp;
struct ether_header *eh;
#ifdef ANCACHE
struct an_rxframe rx_frame;
#endif
struct an_rxframe_802_3 rx_frame_802_3;
struct mbuf *m;
int id, error = 0;
struct ifnet *ifp;
struct ether_header *eh;
struct ieee80211_frame *ih;
struct an_rxframe rx_frame;
struct an_rxframe_802_3 rx_frame_802_3;
struct mbuf *m;
int len, id, error = 0;
int ieee80211_header_len;
u_char *bpf_buf;
u_short fc1;
ifp = &sc->arpcom.ac_if;
id = CSR_READ_2(sc, AN_RX_FID);
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;
}
if (sc->an_monitor && (ifp->if_flags & IFF_PROMISC)) {
/* read raw 802.11 packet */
bpf_buf = sc->buf_802_11;
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
/* Read NIC frame header */
if (an_read_data(sc, id, 0, (caddr_t)&rx_frame, sizeof(rx_frame))) {
ifp->if_ierrors++;
return;
}
/* Read NIC frame header */
if (an_read_data(sc, id, 0, (caddr_t) & rx_frame, sizeof(rx_frame))) {
ifp->if_ierrors++;
return;
}
#endif
/* Read in the 802_3 frame header */
if (an_read_data(sc, id, 0x34, (caddr_t)&rx_frame_802_3,
sizeof(rx_frame_802_3))) {
ifp->if_ierrors++;
return;
}
/* Read in the 802_3 frame header */
if (an_read_data(sc, id, 0x34, (caddr_t) & rx_frame_802_3,
sizeof(rx_frame_802_3))) {
ifp->if_ierrors++;
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) {
ifp->if_ierrors++;
return;
}
eh = mtod(m, struct ether_header *);
/* Check for insane frame length */
if (rx_frame_802_3.an_rx_802_3_payload_len > MCLBYTES) {
ifp->if_ierrors++;
return;
}
bcopy((char *)&rx_frame_802_3.an_rx_dst_addr,
(char *)&eh->ether_dhost, ETHER_ADDR_LEN);
bcopy((char *)&rx_frame_802_3.an_rx_src_addr,
(char *)&eh->ether_shost, ETHER_ADDR_LEN);
m->m_pkthdr.len = m->m_len =
rx_frame_802_3.an_rx_802_3_payload_len + 12;
/* in mbuf header type is just before payload */
error = an_read_data(sc, id, 0x44, (caddr_t)&(eh->ether_type),
rx_frame_802_3.an_rx_802_3_payload_len);
bcopy((char *)&rx_frame_802_3.an_rx_dst_addr,
(char *)&eh->ether_dhost, ETHER_ADDR_LEN);
bcopy((char *)&rx_frame_802_3.an_rx_src_addr,
(char *)&eh->ether_shost, ETHER_ADDR_LEN);
if (error) {
m_freem(m);
ifp->if_ierrors++;
return;
}
ifp->if_ipackets++;
/* in mbuf header type is just before payload */
error = an_read_data(sc, id, 0x44, (caddr_t)&(eh->ether_type),
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));
/* Receive packet. */
m_adj(m, sizeof(struct ether_header));
#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
ether_input(ifp, eh, m);
ether_input(ifp, eh, m);
}
}
static void an_txeof(sc, status)
@ -517,10 +652,6 @@ static void an_txeof(sc, status)
struct ifnet *ifp;
int id, i;
/* TX DONE enable lan monitor DJA
an_enable_sniff();
*/
ifp = &sc->arpcom.ac_if;
ifp->if_timer = 0;
@ -1025,27 +1156,38 @@ static void an_setdef(sc, areq)
sc->an_tx_rate = sp->an_val;
break;
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:
/* Disable the MAC. */
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);
/* Turn the MAC back on. */
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;
default:
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,
* so in order to turn on RX monitor mode, we have to turn the MAC
* off first.
* Derived from Linux driver to enable promiscious mode.
*/
static void an_promisc(sc, promisc)
struct an_softc *sc;
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;
}
@ -1634,13 +1781,19 @@ static void an_init(xsc)
if (ifp->if_flags & IFF_MULTICAST)
sc->an_config.an_rxmode = AN_RXMODE_BC_MC_ADDR;
/* Initialize promisc mode. */
/* Kills card DJA can't TX packet in sniff mode
if (ifp->if_flags & IFF_PROMISC)
sc->an_config.an_rxmode |= AN_RXMODE_LAN_MONITOR_CURBSS;
*/
sc->an_rxmode = sc->an_config.an_rxmode;
if (ifp->if_flags & IFF_PROMISC) {
if (sc->an_monitor & AN_MONITOR) {
if (sc->an_monitor & AN_MONITOR_ANY_BSS) {
sc->an_config.an_rxmode |=
AN_RXMODE_80211_MONITOR_ANYBSS |
AN_RXMODE_NO_8023_HEADER;
} else {
sc->an_config.an_rxmode |=
AN_RXMODE_80211_MONITOR_CURBSS |
AN_RXMODE_NO_8023_HEADER;
}
}
}
/* Set the ssid list */
sc->an_ssidlist.an_type = AN_RID_SSIDLIST;
@ -1713,6 +1866,15 @@ static void an_start(ifp)
if (!sc->an_associated)
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;
bzero((char *)&tx_frame_802_3, sizeof(tx_frame_802_3));

View File

@ -96,6 +96,8 @@
.Nm
.Fl i Ar iface Fl r Ar RTS threshold
.Nm
.Fl i Ar iface Fl M Ar 0-15 (set monitor mode)
.Nm
.Fl h
.Sh DESCRIPTION
The
@ -394,6 +396,22 @@ need to be retransmitted instead of the whole packet.
The fragmentation
threshold can be anything from 64 to 2312 bytes.
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
Set the RTS/CTS threshold for a given interface.
This controls the

View File

@ -125,6 +125,7 @@ int main __P((int, char **));
#define ACT_SET_KEY_TYPE 34
#define ACT_SET_KEYS 35
#define ACT_ENABLE_TX_KEY 36
#define ACT_SET_MONITOR_MODE 37
static void an_getval(iface, areq)
const char *iface;
@ -283,6 +284,7 @@ static void an_dumpstatus(iface)
an_printhex((char *)&sts->an_errcode, 1);
printf("\nSignal quality:\t\t");
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
* 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 -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 -M 0-15 (set monitor mode)\n", p);
#ifdef ANCACHE
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);
@ -977,6 +980,10 @@ static void an_setconfig(iface, act, arg)
cfg->an_authtype = (cfg->an_authtype & ~AN_AUTHTYPE_MASK)
| atoi(arg);
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:
errx(1, "unknown action");
break;
@ -1282,18 +1289,20 @@ static void an_readkeyinfo(iface)
printf("WEP Key status:\n");
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);
an_getval(iface, &areq);
if(k->kindex == 0xffff)
break;
switch (k->klen){
case 0:
printf("\tKey %d is unset\n",i);
printf("\tKey %d is unset\n",k->kindex);
break;
case 5:
printf("\tKey %d is set 40 bits\n",i);
printf("\tKey %d is set 40 bits\n",k->kindex);
break;
case 13:
printf("\tKey %d is set 128 bits\n",i);
printf("\tKey %d is set 128 bits\n",k->kindex);
break;
default:
printf("\tWEP Key %d has an unknown size %d\n",
@ -1369,7 +1378,7 @@ int main(argc, argv)
opterr = 1;
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) {
case 'Z':
#ifdef ANCACHE
@ -1532,6 +1541,10 @@ int main(argc, argv)
act = ACT_SET_WAKE_DURATION;
arg = optarg;
break;
case 'M':
act = ACT_SET_MONITOR_MODE;
arg = optarg;
break;
case 'h':
default:
usage(p);