Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 24a47dbd authored by Mike Kershaw's avatar Mike Kershaw Committed by James Ketrenos
Browse files

Adds radiotap support to ipw2200 in monitor mode..

parent a4f6bbb3
Loading
Loading
Loading
Loading
+185 −0
Original line number Original line Diff line number Diff line
@@ -7918,6 +7918,173 @@ static void ipw_handle_data_packet(struct ipw_priv *priv,
	}
	}
}
}


#ifdef CONFIG_IEEE80211_RADIOTAP
static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
					   struct ipw_rx_mem_buffer *rxb,
					   struct ieee80211_rx_stats *stats)
{
	struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data;
	struct ipw_rx_frame *frame = &pkt->u.frame;

	/* initial pull of some data */
	u16 received_channel = frame->received_channel;
	u8 antennaAndPhy = frame->antennaAndPhy;
	s8 antsignal = frame->rssi_dbm - IPW_RSSI_TO_DBM;	/* call it signed anyhow */
	u16 pktrate = frame->rate;

	/* Magic struct that slots into the radiotap header -- no reason
	 * to build this manually element by element, we can write it much
	 * more efficiently than we can parse it. ORDER MATTERS HERE */
	struct ipw_rt_hdr {
		struct ieee80211_radiotap_header rt_hdr;
		u8 rt_flags;	/* radiotap packet flags */
		u8 rt_rate;	/* rate in 500kb/s */
		u16 rt_channel;	/* channel in mhz */
		u16 rt_chbitmask;	/* channel bitfield */
		s8 rt_dbmsignal;	/* signal in dbM, kluged to signed */
		u8 rt_antenna;	/* antenna number */
	} *ipw_rt;

	short len = le16_to_cpu(pkt->u.frame.length);

	/* We received data from the HW, so stop the watchdog */
	priv->net_dev->trans_start = jiffies;

	/* We only process data packets if the
	 * interface is open */
	if (unlikely((le16_to_cpu(pkt->u.frame.length) + IPW_RX_FRAME_SIZE) >
		     skb_tailroom(rxb->skb))) {
		priv->ieee->stats.rx_errors++;
		priv->wstats.discard.misc++;
		IPW_DEBUG_DROP("Corruption detected! Oh no!\n");
		return;
	} else if (unlikely(!netif_running(priv->net_dev))) {
		priv->ieee->stats.rx_dropped++;
		priv->wstats.discard.misc++;
		IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
		return;
	}

	/* Libpcap 0.9.3+ can handle variable length radiotap, so we'll use
	 * that now */
	if (len > IPW_RX_BUF_SIZE - sizeof(struct ipw_rt_hdr)) {
		/* FIXME: Should alloc bigger skb instead */
		priv->ieee->stats.rx_dropped++;
		priv->wstats.discard.misc++;
		IPW_DEBUG_DROP("Dropping too large packet in monitor\n");
		return;
	}

	/* copy the frame itself */
	memmove(rxb->skb->data + sizeof(struct ipw_rt_hdr),
		rxb->skb->data + IPW_RX_FRAME_SIZE, len);

	/* Zero the radiotap static buffer  ...  We only need to zero the bytes NOT
	 * part of our real header, saves a little time.
	 *
	 * No longer necessary since we fill in all our data.  Purge before merging
	 * patch officially.
	 * memset(rxb->skb->data + sizeof(struct ipw_rt_hdr), 0,
	 *        IEEE80211_RADIOTAP_HDRLEN - sizeof(struct ipw_rt_hdr));
	 */

	ipw_rt = (struct ipw_rt_hdr *)rxb->skb->data;

	ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
	ipw_rt->rt_hdr.it_pad = 0;	/* always good to zero */
	ipw_rt->rt_hdr.it_len = sizeof(struct ipw_rt_hdr);	/* total header+data */

	/* Big bitfield of all the fields we provide in radiotap */
	ipw_rt->rt_hdr.it_present =
	    ((1 << IEEE80211_RADIOTAP_FLAGS) |
	     (1 << IEEE80211_RADIOTAP_RATE) |
	     (1 << IEEE80211_RADIOTAP_CHANNEL) |
	     (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
	     (1 << IEEE80211_RADIOTAP_ANTENNA));

	/* Zero the flags, we'll add to them as we go */
	ipw_rt->rt_flags = 0;

	/* Convert signal to DBM */
	ipw_rt->rt_dbmsignal = antsignal;

	/* Convert the channel data and set the flags */
	ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(received_channel));
	if (received_channel > 14) {	/* 802.11a */
		ipw_rt->rt_chbitmask =
		    cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
	} else if (antennaAndPhy & 32) {	/* 802.11b */
		ipw_rt->rt_chbitmask =
		    cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
	} else {		/* 802.11g */
		ipw_rt->rt_chbitmask =
		    (IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ);
	}

	/* set the rate in multiples of 500k/s */
	switch (pktrate) {
	case IPW_TX_RATE_1MB:
		ipw_rt->rt_rate = 2;
		break;
	case IPW_TX_RATE_2MB:
		ipw_rt->rt_rate = 4;
		break;
	case IPW_TX_RATE_5MB:
		ipw_rt->rt_rate = 10;
		break;
	case IPW_TX_RATE_6MB:
		ipw_rt->rt_rate = 12;
		break;
	case IPW_TX_RATE_9MB:
		ipw_rt->rt_rate = 18;
		break;
	case IPW_TX_RATE_11MB:
		ipw_rt->rt_rate = 22;
		break;
	case IPW_TX_RATE_12MB:
		ipw_rt->rt_rate = 24;
		break;
	case IPW_TX_RATE_18MB:
		ipw_rt->rt_rate = 36;
		break;
	case IPW_TX_RATE_24MB:
		ipw_rt->rt_rate = 48;
		break;
	case IPW_TX_RATE_36MB:
		ipw_rt->rt_rate = 72;
		break;
	case IPW_TX_RATE_48MB:
		ipw_rt->rt_rate = 96;
		break;
	case IPW_TX_RATE_54MB:
		ipw_rt->rt_rate = 108;
		break;
	default:
		ipw_rt->rt_rate = 0;
		break;
	}

	/* antenna number */
	ipw_rt->rt_antenna = (antennaAndPhy & 3);	/* Is this right? */

	/* set the preamble flag if we have it */
	if ((antennaAndPhy & 64))
		ipw_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;

	/* Set the size of the skb to the size of the frame */
	skb_put(rxb->skb, len + sizeof(struct ipw_rt_hdr));

	IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);

	if (!ieee80211_rx(priv->ieee, rxb->skb, stats))
		priv->ieee->stats.rx_errors++;
	else {			/* ieee80211_rx succeeded, so it now owns the SKB */
		rxb->skb = NULL;
		/* no LED during capture */
	}
}
#endif

static inline int is_network_packet(struct ipw_priv *priv,
static inline int is_network_packet(struct ipw_priv *priv,
				    struct ieee80211_hdr_4addr *header)
				    struct ieee80211_hdr_4addr *header)
{
{
@@ -8147,8 +8314,14 @@ static void ipw_rx(struct ipw_priv *priv)


#ifdef CONFIG_IPW2200_MONITOR
#ifdef CONFIG_IPW2200_MONITOR
				if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
				if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
#ifdef CONFIG_IEEE80211_RADIOTAP
					ipw_handle_data_packet_monitor(priv,
								       rxb,
								       &stats);
#else
					ipw_handle_data_packet(priv, rxb,
					ipw_handle_data_packet(priv, rxb,
							       &stats);
							       &stats);
#endif
					break;
					break;
				}
				}
#endif
#endif
@@ -8315,7 +8488,11 @@ static int ipw_sw_reset(struct ipw_priv *priv, int init)
#ifdef CONFIG_IPW2200_MONITOR
#ifdef CONFIG_IPW2200_MONITOR
	case 2:
	case 2:
		priv->ieee->iw_mode = IW_MODE_MONITOR;
		priv->ieee->iw_mode = IW_MODE_MONITOR;
#ifdef CONFIG_IEEE80211_RADIOTAP
		priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
#else
		priv->net_dev->type = ARPHRD_IEEE80211;
		priv->net_dev->type = ARPHRD_IEEE80211;
#endif
		break;
		break;
#endif
#endif
	default:
	default:
@@ -8565,7 +8742,11 @@ static int ipw_wx_set_mode(struct net_device *dev,
		priv->net_dev->type = ARPHRD_ETHER;
		priv->net_dev->type = ARPHRD_ETHER;


	if (wrqu->mode == IW_MODE_MONITOR)
	if (wrqu->mode == IW_MODE_MONITOR)
#ifdef CONFIG_IEEE80211_RADIOTAP
		priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
#else
		priv->net_dev->type = ARPHRD_IEEE80211;
		priv->net_dev->type = ARPHRD_IEEE80211;
#endif
#endif				/* CONFIG_IPW2200_MONITOR */
#endif				/* CONFIG_IPW2200_MONITOR */


	/* Free the existing firmware and reset the fw_loaded
	/* Free the existing firmware and reset the fw_loaded
@@ -9598,7 +9779,11 @@ static int ipw_wx_set_monitor(struct net_device *dev,
	IPW_DEBUG_WX("SET MONITOR: %d %d\n", enable, parms[1]);
	IPW_DEBUG_WX("SET MONITOR: %d %d\n", enable, parms[1]);
	if (enable) {
	if (enable) {
		if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
		if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
#ifdef CONFIG_IEEE80211_RADIOTAP
			priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
#else
			priv->net_dev->type = ARPHRD_IEEE80211;
			priv->net_dev->type = ARPHRD_IEEE80211;
#endif
			queue_work(priv->workqueue, &priv->adapter_restart);
			queue_work(priv->workqueue, &priv->adapter_restart);
		}
		}


+1 −0
Original line number Original line Diff line number Diff line
@@ -50,6 +50,7 @@
#include <asm/io.h>
#include <asm/io.h>


#include <net/ieee80211.h>
#include <net/ieee80211.h>
#include <net/ieee80211_radiotap.h>


#define DRV_NAME	"ipw2200"
#define DRV_NAME	"ipw2200"