Subject: PRISM2 monitor mode patch
To: None <tech-net@netbsd.org>
From: Kevin Lahey <kml@patheticgeek.net>
List: tech-net
Date: 11/08/2002 01:54:18
This patch introduces a new mediaopt, "monitor" for 802.11 wireless 
devices.  This option will put the wireless device into monitor mode,
where it can see all incoming packets.  (We can see *most* packets
in "hostap" mode, except for probes.)

This currently only works for the 'wi' device driver, for PRISM2 
wireless devices.  It doesn't yet put the Orinoco based cards into 
monitor mode, but that doesn't seem like it'd be too hard to add this.

Does this seem useful?

Kevin
kml@patheticgeek.net


Index: dev/ic/wi.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/ic/wi.c,v
retrieving revision 1.101
diff -c -r1.101 wi.c
*** dev/ic/wi.c	2002/10/25 01:35:12	1.101
--- dev/ic/wi.c	2002/11/03 02:56:53
***************
*** 292,297 ****
--- 292,298 ----
  		if (sc->sc_sta_firmware_ver >= 800) {
  			ic->ic_flags |= IEEE80211_F_HASHOSTAP;
  			ic->ic_flags |= IEEE80211_F_HASIBSS;
+ 			ic->ic_flags |= IEEE80211_F_HASMONITOR;
  		}
  		sc->sc_ibss_port = 0;
  		break;
***************
*** 337,342 ****
--- 338,345 ----
  		ADD(IFM_AUTO, IFM_IEEE80211_HOSTAP);
  	if (ic->ic_flags & IEEE80211_F_HASIBSS)
  		ADD(IFM_AUTO, IFM_IEEE80211_ADHOC);
+ 	if (ic->ic_flags & IEEE80211_F_HASMONITOR)
+ 		ADD(IFM_AUTO, IFM_IEEE80211_MONITOR);
  	ADD(IFM_AUTO, IFM_IEEE80211_ADHOC | IFM_FLAG0);
  	for (i = 0; i < nrate; i++) {
  		r = ic->ic_sup_rates[i];
***************
*** 350,355 ****
--- 353,360 ----
  			ADD(mword, IFM_IEEE80211_HOSTAP);
  		if (ic->ic_flags & IEEE80211_F_HASIBSS)
  			ADD(mword, IFM_IEEE80211_ADHOC);
+ 		if (ic->ic_flags & IEEE80211_F_HASMONITOR)
+ 			ADD(mword, IFM_IEEE80211_MONITOR);
  		ADD(mword, IFM_IEEE80211_ADHOC | IFM_FLAG0);
  	}
  	printf("\n");
***************
*** 544,549 ****
--- 549,557 ----
  	case IEEE80211_M_HOSTAP:
  		wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_HOSTAP);
  		break;
+ 	case IEEE80211_M_MONITOR:
+ 		wi_cmd(sc, WI_CMD_TEST | (WI_TEST_MONITOR << 8), 0, 0, 0);
+ 		break;
  	}
  
  	/* Intersil interprets this RID as joining ESS even in IBSS mode */
***************
*** 630,635 ****
--- 638,644 ----
  	ifp->if_flags |= IFF_RUNNING;
  	ifp->if_flags &= ~IFF_OACTIVE;
  	if (ic->ic_opmode == IEEE80211_M_AHDEMO ||
+ 	    ic->ic_opmode == IEEE80211_M_MONITOR ||
  	    ic->ic_opmode == IEEE80211_M_HOSTAP)
  		wi_newstate(sc, IEEE80211_S_RUN);
  
***************
*** 981,986 ****
--- 990,997 ----
  		newmode = IEEE80211_M_IBSS;
  	else if (ime->ifm_media & IFM_IEEE80211_HOSTAP)
  		newmode = IEEE80211_M_HOSTAP;
+ 	else if (ime->ifm_media & IFM_IEEE80211_MONITOR)
+ 		newmode = IEEE80211_M_MONITOR;
  	else
  		newmode = IEEE80211_M_STA;
  	if (ic->ic_opmode != newmode) {
***************
*** 1046,1051 ****
--- 1057,1065 ----
  	case IEEE80211_M_HOSTAP:
  		imr->ifm_active |= IFM_IEEE80211_HOSTAP;
  		break;
+ 	case IEEE80211_M_MONITOR:
+ 		imr->ifm_active |= IFM_IEEE80211_MONITOR;
+ 		break;
  	}
  }
  
***************
*** 1087,1092 ****
--- 1101,1115 ----
  
  	len = le16toh(frmhdr.wi_dat_len);
  	off = ALIGN(sizeof(struct ieee80211_frame));
+ 
+ 	/* 
+ 	 * Sometimes the PRISM2 returns bogusly large frames, especially
+ 	 * in monitor mode.  This will try to fix them up so that we can
+ 	 * read at least the IEEE 802.11 header.
+ 	 */
+ 
+ 	if (len > IEEE80211_MAX_LEN)
+ 		len = 0;
  
  	MGETHDR(m, M_DONTWAIT, MT_DATA);
  	if (m == NULL) {
Index: dev/ic/wireg.h
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/ic/wireg.h,v
retrieving revision 1.42
diff -c -r1.42 wireg.h
*** dev/ic/wireg.h	2002/10/21 11:57:25	1.42
--- dev/ic/wireg.h	2002/11/03 02:56:55
***************
*** 117,122 ****
--- 117,123 ----
  #define WI_CMD_ACCESS		0x0021
  #define WI_CMD_PROGRAM		0x0022
  #define WI_CMD_READEE		0x0030
+ #define WI_CMD_TEST		0x0038 /* PRISM2 test mode */
  
  #define WI_CMD_CODE_MASK	0x003F
  
***************
*** 139,144 ****
--- 140,150 ----
  #define WI_PROGRAM_ENABLE_RAM	0x0100
  #define WI_PROGRAM_ENABLE_NVRAM	0x0200
  #define WI_PROGRAM_NVRAM	0x0300
+ 
+ /*
+  * DEBUG mode options.
+  */
+ #define WI_TEST_MONITOR		0x0B /* monitor mode for testing */
  
  /* Status register values */
  #define WI_STAT_CMD_CODE	0x003F
Index: net/if_ieee80211.h
===================================================================
RCS file: /cvsroot/syssrc/sys/net/if_ieee80211.h,v
retrieving revision 1.23
diff -c -r1.23 if_ieee80211.h
*** net/if_ieee80211.h	2002/10/15 08:51:50	1.23
--- net/if_ieee80211.h	2002/11/03 02:57:03
***************
*** 377,383 ****
  	IEEE80211_M_STA = 1,		/* infrastructure station */
  	IEEE80211_M_IBSS = 0,		/* IBSS (adhoc) station */
  	IEEE80211_M_AHDEMO = 3,		/* Old lucent compatible adhoc demo */
! 	IEEE80211_M_HOSTAP = 6		/* Software Access Point */
  };
  
  enum ieee80211_state {
--- 377,385 ----
  	IEEE80211_M_STA = 1,		/* infrastructure station */
  	IEEE80211_M_IBSS = 0,		/* IBSS (adhoc) station */
  	IEEE80211_M_AHDEMO = 3,		/* Old lucent compatible adhoc demo */
! 	IEEE80211_M_HOSTAP = 6,		/* Software Access Point */
! 	IEEE80211_M_MONITOR = 8		/* Monitor mode (doesn't correspond
! 					   to a PRISM port like the others) */
  };
  
  enum ieee80211_state {
***************
*** 502,507 ****
--- 504,510 ----
  #define	IEEE80211_F_HASPMGT	0x00040000	/* CAPABILITY: Power mgmt */
  #define	IEEE80211_F_HASHOSTAP	0x00080000	/* CAPABILITY: HOSTAP avail */
  #define	IEEE80211_F_HASAHDEMO	0x00100000	/* CAPABILITY: Old Adhoc Demo */
+ #define	IEEE80211_F_HASMONITOR	0x00200000	/* CAPABILITY: Monitor mode */
  
  /* flags for ieee80211_fix_rate() */
  #define	IEEE80211_F_DOSORT	0x00000001	/* sort rate list */
Index: net/if_ieee80211subr.c
===================================================================
RCS file: /cvsroot/syssrc/sys/net/if_ieee80211subr.c,v
retrieving revision 1.22
diff -c -r1.22 if_ieee80211subr.c
*** net/if_ieee80211subr.c	2002/10/16 11:29:30	1.22
--- net/if_ieee80211subr.c	2002/11/03 02:57:08
***************
*** 288,293 ****
--- 288,295 ----
  				ni = &ic->ic_bss;	/* XXX allocate? */
  			}
  			break;
+ 		case IEEE80211_M_MONITOR:
+ 			goto out;
  		}
  		ni->ni_rssi = rssi;
  		ni->ni_rstamp = rstamp;
***************
*** 354,359 ****
--- 356,364 ----
  				goto err;
  			}
  			break;
+ 		case IEEE80211_M_MONITOR:
+ 			/* Should never get here */
+ 			break;
  		}
  		if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
  			if (ic->ic_flags & IEEE80211_F_WEPON) {
***************
*** 601,606 ****
--- 606,615 ----
  		IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid);
  		IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost);
  		break;
+ 	case IEEE80211_M_MONITOR:
+ 		/* Should never get here! */
+ 		m_freem(m);
+ 		return NULL;
  	}
  	return m;
  }
***************
*** 1884,1889 ****
--- 1893,1899 ----
  		break;
  
  	case IEEE80211_M_AHDEMO:
+ 	case IEEE80211_M_MONITOR:
  		/* should not come here */
  		break;
  
Index: net/if_media.h
===================================================================
RCS file: /cvsroot/syssrc/sys/net/if_media.h,v
retrieving revision 1.29
diff -c -r1.29 if_media.h
*** net/if_media.h	2002/09/27 05:27:20	1.29
--- net/if_media.h	2002/11/03 02:57:09
***************
*** 216,221 ****
--- 216,222 ----
  
  #define	IFM_IEEE80211_ADHOC	 0x00000100	/* Operate in Adhoc mode */
  #define	IFM_IEEE80211_HOSTAP	 0x00000200	/* Operate in Host AP mode */
+ #define	IFM_IEEE80211_MONITOR	 0x00000400	/* Operate in Monitor mode */
  
  /*
   * Shared media sub-types
***************
*** 418,423 ****
--- 419,425 ----
  	{ IFM_IEEE80211|IFM_IEEE80211_ADHOC,	"adhoc" },		\
  	{ IFM_IEEE80211|IFM_IEEE80211_ADHOC,	"ibss" },		\
  	{ IFM_IEEE80211|IFM_IEEE80211_HOSTAP,	"hostap" },		\
+ 	{ IFM_IEEE80211|IFM_IEEE80211_MONITOR,	"monitor" },		\
  									\
  	{ 0, NULL },							\
  }