if_ath raw 802.11 packet injection patch when in monitor mode

Andrea Bittau a.bittau at cs.ucl.ac.uk
Sat Jun 24 12:41:25 UTC 2006


I think it would be useful to have 802.11 packet injection support in the
mainstream driver.  This would allow people, amongst other things, to run
user-land access points and clients.  Below is a crude patch for doing so.  The
only problem is that ACKs are not sent in time.  I know a fix, but it's a bit of
a hack and a better solution is needed.  I've tried contacting Sam but failed
[e-mail bounced].  Hopefully he will see this, and if he's interested, I could
make the patch better.

---

*** /sys/dev/ath/if_ath.c	Tue May  2 18:08:34 2006
--- /root/programmi/ath/if_ath.c	Sat Jun 24 13:11:10 2006
*************** ath_start(struct ifnet *ifp)
*** 1141,1146 ****
--- 1141,1147 ----
  	struct mbuf *m;
  	struct ieee80211_frame *wh;
  	struct ether_header *eh;
+ 	int monitor = ic->ic_opmode == IEEE80211_M_MONITOR;
  
  	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid)
  		return;
*************** ath_start(struct ifnet *ifp)
*** 1191,1204 ****
  			 * Find the node for the destination so we can do
  			 * things like power save and fast frames aggregation.
  			 */
! 			if (m->m_len < sizeof(struct ether_header) &&
  			   (m = m_pullup(m, sizeof(struct ether_header))) == NULL) {
  				ic->ic_stats.is_tx_nobuf++;	/* XXX */
  				ni = NULL;
  				goto bad;
  			}
  			eh = mtod(m, struct ether_header *);
! 			ni = ieee80211_find_txnode(ic, eh->ether_dhost);
  			if (ni == NULL) {
  				/* NB: ieee80211_find_txnode does stat+msg */
  				m_freem(m);
--- 1192,1208 ----
  			 * Find the node for the destination so we can do
  			 * things like power save and fast frames aggregation.
  			 */
! 			if (!monitor && m->m_len < sizeof(struct ether_header) &&
  			   (m = m_pullup(m, sizeof(struct ether_header))) == NULL) {
  				ic->ic_stats.is_tx_nobuf++;	/* XXX */
  				ni = NULL;
  				goto bad;
  			}
  			eh = mtod(m, struct ether_header *);
! 			if (monitor)
! 				ni = ieee80211_ref_node(ic->ic_bss);
! 			else
! 				ni = ieee80211_find_txnode(ic, eh->ether_dhost);
  			if (ni == NULL) {
  				/* NB: ieee80211_find_txnode does stat+msg */
  				m_freem(m);
*************** ath_start(struct ifnet *ifp)
*** 1227,1239 ****
  			/*
  			 * Encapsulate the packet in prep for transmission.
  			 */
! 			m = ieee80211_encap(ic, m, ni);
! 			if (m == NULL) {
! 				DPRINTF(sc, ATH_DEBUG_XMIT,
! 					"%s: encapsulation failure\n",
! 					__func__);
! 				sc->sc_stats.ast_tx_encap++;
! 				goto bad;
  			}
  		} else {
  			/*
--- 1231,1245 ----
  			/*
  			 * Encapsulate the packet in prep for transmission.
  			 */
! 			if (!monitor) {
! 				m = ieee80211_encap(ic, m, ni);
! 				if (m == NULL) {
! 					DPRINTF(sc, ATH_DEBUG_XMIT,
! 						"%s: encapsulation failure\n",
! 						__func__);
! 					sc->sc_stats.ast_tx_encap++;
! 					goto bad;
! 				}
  			}
  		} else {
  			/*
*************** ath_calcrxfilter(struct ath_softc *sc, e
*** 1713,1718 ****
--- 1719,1726 ----
  	    ic->ic_opmode == IEEE80211_M_IBSS ||
  	    state == IEEE80211_S_SCAN)
  		rfilt |= HAL_RX_FILTER_BEACON;
+ 	if (ic->ic_opmode == IEEE80211_M_MONITOR)
+ 		rfilt |= HAL_RX_FILTER_CONTROL;
  	return rfilt;
  #undef RX_FILTER_PRESERVE
  }
*************** ath_tx_start(struct ath_softc *sc, struc
*** 3307,3312 ****
--- 3315,3321 ----
  	struct ath_node *an;
  	struct mbuf *m;
  	u_int pri;
+ 	int monitor = ic->ic_opmode == IEEE80211_M_MONITOR;
  
  	wh = mtod(m0, struct ieee80211_frame *);
  	iswep = wh->i_fc[1] & IEEE80211_FC1_WEP;
*************** ath_tx_start(struct ath_softc *sc, struc
*** 3317,3324 ****
  	 * pad bytes; deduct them here.
  	 */
  	pktlen = m0->m_pkthdr.len - (hdrlen & 3);
! 
! 	if (iswep) {
  		const struct ieee80211_cipher *cip;
  		struct ieee80211_key *k;
  
--- 3326,3343 ----
  	 * pad bytes; deduct them here.
  	 */
  	pktlen = m0->m_pkthdr.len - (hdrlen & 3);
! 	/* ACK frames are shorter than Ethernet header, so userland needs to pad
! 	 * ACKs with 4 bytes.  We get rid of those bytes here.
! 	 */
! 	if (monitor &&
! 	    (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL &&
! 	    (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
! 	    IEEE80211_FC0_SUBTYPE_ACK) {
! 		m_adj(m0, -4);
! 		pktlen = m0->m_pkthdr.len;
! 	}	
! 	
! 	if (iswep && !monitor) {
  		const struct ieee80211_cipher *cip;
  		struct ieee80211_key *k;
  
*************** ath_tx_start(struct ath_softc *sc, struc
*** 3522,3527 ****
--- 3541,3550 ----
  	}
  	txq = sc->sc_ac2q[pri];
  
+ 	/* Set packet type to PSPOLL so fragment & seqnos are not mangled */
+ 	if (monitor)
+ 		atype = HAL_PKT_TYPE_PSPOLL;
+ 
  	/*
  	 * When servicing one or more stations in power-save mode
  	 * multicast frames must be buffered until after the beacon.
*************** ath_tx_start(struct ath_softc *sc, struc
*** 3535,3541 ****
  	/*
  	 * Calculate miscellaneous flags.
  	 */
! 	if (ismcast) {
  		flags |= HAL_TXDESC_NOACK;	/* no ack on broad/multicast */
  	} else if (pktlen > ic->ic_rtsthreshold) {
  		flags |= HAL_TXDESC_RTSENA;	/* RTS based on frame length */
--- 3558,3564 ----
  	/*
  	 * Calculate miscellaneous flags.
  	 */
! 	if (ismcast || monitor) {
  		flags |= HAL_TXDESC_NOACK;	/* no ack on broad/multicast */
  	} else if (pktlen > ic->ic_rtsthreshold) {
  		flags |= HAL_TXDESC_RTSENA;	/* RTS based on frame length */


More information about the freebsd-mobile mailing list