summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/an/if_an.c348
-rw-r--r--usr.sbin/ancontrol/ancontrol.818
-rw-r--r--usr.sbin/ancontrol/ancontrol.c23
3 files changed, 291 insertions, 98 deletions
diff --git a/sys/dev/an/if_an.c b/sys/dev/an/if_an.c
index 406be21..7749d86 100644
--- a/sys/dev/an/if_an.c
+++ b/sys/dev/an/if_an.c
@@ -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;
+
+ /* read header */
+ if (an_read_data(sc, id, 0x0, (caddr_t)&rx_frame,
+ sizeof(rx_frame))) {
+ ifp->if_ierrors++;
+ return;
+ }
+
+ /*
+ * 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;
+ }
- m->m_pkthdr.rcvif = ifp;
+ 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;
- eh = mtod(m, struct ether_header *);
+ 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;
- }
-
- if (rx_frame_802_3.an_rx_802_3_status != 0) {
- 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;
- /* Check for insane frame length */
- if (rx_frame_802_3.an_rx_802_3_payload_len > MCLBYTES) {
- ifp->if_ierrors++;
- return;
- }
+ eh = mtod(m, struct ether_header *);
- m->m_pkthdr.len = m->m_len =
- rx_frame_802_3.an_rx_802_3_payload_len + 12;
+ 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);
-
- 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);
-
- /* 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;
- }
+ /* 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);
- ifp->if_ipackets++;
+ if (error) {
+ 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,28 +1156,39 @@ 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);
return;
@@ -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));
diff --git a/usr.sbin/ancontrol/ancontrol.8 b/usr.sbin/ancontrol/ancontrol.8
index 150ede8..f88baa8 100644
--- a/usr.sbin/ancontrol/ancontrol.8
+++ b/usr.sbin/ancontrol/ancontrol.8
@@ -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
diff --git a/usr.sbin/ancontrol/ancontrol.c b/usr.sbin/ancontrol/ancontrol.c
index 15ef266..07fe170 100644
--- a/usr.sbin/ancontrol/ancontrol.c
+++ b/usr.sbin/ancontrol/ancontrol.c
@@ -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);
OpenPOWER on IntegriCloud