* [PATCH 11/12] orinoco: monitor mode support
@ 2005-05-14 15:31 Christoph Hellwig
2005-05-14 17:39 ` Francois Romieu
0 siblings, 1 reply; 5+ messages in thread
From: Christoph Hellwig @ 2005-05-14 15:31 UTC (permalink / raw)
To: jgarzik, proski, hermes; +Cc: netdev
Patch from Pavel Roskin
Index: linux-2.6/drivers/net/wireless/orinoco.c
===================================================================
--- linux-2.6.orig/drivers/net/wireless/orinoco.c 2005-05-14 17:07:45.000000000 +0200
+++ linux-2.6/drivers/net/wireless/orinoco.c 2005-05-14 17:08:39.000000000 +0200
@@ -499,6 +499,10 @@
module_param(ignore_disconnect, int, 0644);
MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer");
+static int force_monitor; /* = 0 */
+module_param(force_monitor, int, 0644);
+MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions");
+
/********************************************************************/
/* Compile time configuration and compatibility stuff */
/********************************************************************/
@@ -670,6 +674,10 @@
priv->createibss = 1;
}
break;
+ case IW_MODE_MONITOR:
+ priv->port_type = 3;
+ priv->createibss = 0;
+ break;
default:
printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
priv->ndev->name);
@@ -856,7 +864,7 @@
return 1;
}
- if (! netif_carrier_ok(dev)) {
+ if (! netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) {
/* Oops, the firmware hasn't established a connection,
silently drop the packet (this seems to be the
safest approach). */
@@ -1118,6 +1126,114 @@
}
}
+/*
+ * orinoco_rx_monitor - handle received monitor frames.
+ *
+ * Arguments:
+ * dev network device
+ * rxfid received FID
+ * desc rx descriptor of the frame
+ *
+ * Call context: interrupt
+ */
+static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
+ struct hermes_rx_descriptor *desc)
+{
+ u32 hdrlen = 30; /* return full header by default */
+ u32 datalen = 0;
+ u16 fc;
+ int err;
+ int len;
+ struct sk_buff *skb;
+ struct orinoco_private *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &priv->stats;
+ hermes_t *hw = &priv->hw;
+
+ len = le16_to_cpu(desc->data_len);
+
+ /* Determine the size of the header and the data */
+ fc = le16_to_cpu(desc->frame_ctl);
+ switch (fc & IEEE80211_FCTL_FTYPE) {
+ case IEEE80211_FTYPE_DATA:
+ if ((fc & IEEE80211_FCTL_TODS)
+ && (fc & IEEE80211_FCTL_FROMDS))
+ hdrlen = 30;
+ else
+ hdrlen = 24;
+ datalen = len;
+ break;
+ case IEEE80211_FTYPE_MGMT:
+ hdrlen = 24;
+ datalen = len;
+ break;
+ case IEEE80211_FTYPE_CTL:
+ switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_PSPOLL:
+ case IEEE80211_STYPE_RTS:
+ case IEEE80211_STYPE_CFEND:
+ case IEEE80211_STYPE_CFENDACK:
+ hdrlen = 16;
+ break;
+ case IEEE80211_STYPE_CTS:
+ case IEEE80211_STYPE_ACK:
+ hdrlen = 10;
+ break;
+ }
+ break;
+ default:
+ /* Unknown frame type */
+ break;
+ }
+
+ /* sanity check the length */
+ if (datalen > IEEE80211_DATA_LEN + 12) {
+ printk(KERN_DEBUG "%s: oversized monitor frame, "
+ "data length = %d\n", dev->name, datalen);
+ err = -EIO;
+ goto drop;
+ }
+
+ skb = dev_alloc_skb(hdrlen + datalen);
+ if (!skb) {
+ printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n",
+ dev->name);
+ err = -ENOMEM;
+ goto drop;
+ }
+
+ /* Copy the 802.11 header to the skb */
+ memcpy(skb_put(skb, hdrlen), &(desc->frame_ctl), hdrlen);
+ skb->mac.raw = skb->data;
+
+ /* If any, copy the data from the card to the skb */
+ if (datalen > 0) {
+ err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
+ ALIGN(datalen, 2), rxfid,
+ HERMES_802_2_OFFSET);
+ if (err) {
+ printk(KERN_ERR "%s: error %d reading monitor frame\n",
+ dev->name, err);
+ goto drop;
+ }
+ }
+
+ skb->dev = dev;
+ skb->ip_summed = CHECKSUM_NONE;
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = __constant_htons(ETH_P_802_2);
+
+ dev->last_rx = jiffies;
+ stats->rx_packets++;
+ stats->rx_bytes += skb->len;
+
+ netif_rx(skb);
+ return;
+
+ drop:
+ stats->rx_errors++;
+ stats->rx_dropped++;
+}
+
static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
{
struct orinoco_private *priv = netdev_priv(dev);
@@ -1143,16 +1259,24 @@
status = le16_to_cpu(desc.status);
- if (status & HERMES_RXSTAT_ERR) {
- if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
- wstats->discard.code++;
- DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n",
- dev->name);
- } else {
- stats->rx_crc_errors++;
- DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name);
- }
+ if (status & HERMES_RXSTAT_BADCRC) {
+ DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n",
+ dev->name);
+ stats->rx_crc_errors++;
+ stats->rx_errors++;
+ goto drop;
+ }
+ /* Handle frames in monitor mode */
+ if (priv->iw_mode == IW_MODE_MONITOR) {
+ orinoco_rx_monitor(dev, rxfid, &desc);
+ return;
+ }
+
+ if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
+ DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n",
+ dev->name);
+ wstats->discard.code++;
stats->rx_errors++;
goto drop;
}
@@ -2065,6 +2189,20 @@
}
}
+ if (priv->iw_mode == IW_MODE_MONITOR) {
+ /* Enable monitor mode */
+ dev->type = ARPHRD_IEEE80211;
+ err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+ HERMES_TEST_MONITOR, 0, NULL);
+ } else {
+ /* Disable monitor mode */
+ dev->type = ARPHRD_ETHER;
+ err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+ HERMES_TEST_STOP, 0, NULL);
+ }
+ if (err)
+ return err;
+
/* Set promiscuity / multicast*/
priv->promiscuous = 0;
priv->mc_count = 0;
@@ -2413,6 +2551,7 @@
priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
priv->ibss_port = 1;
priv->has_hostscan = (firmver >= 0x8000a);
+ priv->broken_monitor = (firmver >= 0x80000);
/* Tested with Agere firmware :
* 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
@@ -2980,6 +3119,15 @@
case IW_MODE_INFRA:
break;
+ case IW_MODE_MONITOR:
+ if (priv->broken_monitor && !force_monitor) {
+ printk(KERN_WARNING "%s: Monitor mode support is "
+ "buggy in this firmware, not enabling\n",
+ dev->name);
+ err = -EOPNOTSUPP;
+ }
+ break;
+
default:
err = -EOPNOTSUPP;
break;
@@ -3355,11 +3503,9 @@
unsigned long flags;
int err = -EINPROGRESS; /* Call commit handler */
- /* We can only use this in Ad-Hoc demo mode to set the operating
- * frequency, or in IBSS mode to set the frequency where the IBSS
- * will be created - Jean II */
- if (priv->iw_mode != IW_MODE_ADHOC)
- return -EOPNOTSUPP;
+ /* In infrastructure mode the AP sets the channel */
+ if (priv->iw_mode == IW_MODE_INFRA)
+ return -EBUSY;
if ( (frq->e == 0) && (frq->m <= 1000) ) {
/* Setting by channel number */
@@ -3383,7 +3529,15 @@
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
+
priv->channel = chan;
+ if (priv->iw_mode == IW_MODE_MONITOR) {
+ /* Fast channel change - no commit if successful */
+ hermes_t *hw = &priv->hw;
+ err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+ HERMES_TEST_SET_CHANNEL,
+ chan, NULL);
+ }
orinoco_unlock(priv, &flags);
return err;
Index: linux-2.6/drivers/net/wireless/orinoco.h
===================================================================
--- linux-2.6.orig/drivers/net/wireless/orinoco.h 2005-05-14 17:05:42.000000000 +0200
+++ linux-2.6/drivers/net/wireless/orinoco.h 2005-05-14 17:07:57.000000000 +0200
@@ -94,6 +94,7 @@
unsigned int has_sensitivity:1;
unsigned int has_hostscan:1;
unsigned int broken_disableport:1;
+ unsigned int broken_monitor:1;
/* Configuration paramaters */
u32 iw_mode;
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH 11/12] orinoco: monitor mode support
2005-05-14 15:31 [PATCH 11/12] orinoco: monitor mode support Christoph Hellwig
@ 2005-05-14 17:39 ` Francois Romieu
2005-05-17 19:43 ` Pavel Roskin
0 siblings, 1 reply; 5+ messages in thread
From: Francois Romieu @ 2005-05-14 17:39 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: jgarzik, proski, hermes, netdev
Christoph Hellwig <hch@lst.de> :
[...]
> + skb = dev_alloc_skb(hdrlen + datalen);
> + if (!skb) {
> + printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n",
> + dev->name);
> + err = -ENOMEM;
> + goto drop;
> + }
> +
> + /* Copy the 802.11 header to the skb */
> + memcpy(skb_put(skb, hdrlen), &(desc->frame_ctl), hdrlen);
> + skb->mac.raw = skb->data;
> +
> + /* If any, copy the data from the card to the skb */
> + if (datalen > 0) {
> + err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
> + ALIGN(datalen, 2), rxfid,
> + HERMES_802_2_OFFSET);
> + if (err) {
> + printk(KERN_ERR "%s: error %d reading monitor frame\n",
> + dev->name, err);
> + goto drop;
[...]
> + drop:
> + stats->rx_errors++;
> + stats->rx_dropped++;
> +}
-> leak (skb).
--
Ueimor
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH 11/12] orinoco: monitor mode support
2005-05-14 17:39 ` Francois Romieu
@ 2005-05-17 19:43 ` Pavel Roskin
2005-05-17 21:22 ` Francois Romieu
0 siblings, 1 reply; 5+ messages in thread
From: Pavel Roskin @ 2005-05-17 19:43 UTC (permalink / raw)
To: Francois Romieu; +Cc: Christoph Hellwig, jgarzik, hermes, netdev
On Sat, 2005-05-14 at 19:39 +0200, Francois Romieu wrote:
> > + drop:
> > + stats->rx_errors++;
> > + stats->rx_dropped++;
> > +}
>
> -> leak (skb).
Indeed. Thank you! Please apply this on top of the original patches:
Signed-off-by: Pavel Roskin <proski@gnu.org>
--- orinoco.c
+++ orinoco.c
@@ -1180,7 +1180,7 @@ static void orinoco_rx_monitor(struct ne
u16 fc;
int err;
int len;
- struct sk_buff *skb;
+ struct sk_buff *skb = NULL;
struct orinoco_private *priv = netdev_priv(dev);
struct net_device_stats *stats = &priv->stats;
hermes_t *hw = &priv->hw;
@@ -1268,6 +1268,8 @@ static void orinoco_rx_monitor(struct ne
drop:
stats->rx_errors++;
stats->rx_dropped++;
+ if (skb)
+ dev_kfree_skb_irq(skb);
}
static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
--
Regards,
Pavel Roskin
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 11/12] orinoco: monitor mode support
2005-05-17 19:43 ` Pavel Roskin
@ 2005-05-17 21:22 ` Francois Romieu
2005-05-23 3:40 ` Pavel Roskin
0 siblings, 1 reply; 5+ messages in thread
From: Francois Romieu @ 2005-05-17 21:22 UTC (permalink / raw)
To: Pavel Roskin; +Cc: Christoph Hellwig, jgarzik, hermes, netdev
Pavel Roskin <proski@gnu.org> :
> On Sat, 2005-05-14 at 19:39 +0200, Francois Romieu wrote:
> > > + drop:
> > > + stats->rx_errors++;
> > > + stats->rx_dropped++;
> > > +}
> >
> > -> leak (skb).
>
> Indeed. Thank you! Please apply this on top of the original patches:
>
> Signed-off-by: Pavel Roskin <proski@gnu.org>
>
> --- orinoco.c
> +++ orinoco.c
> @@ -1180,7 +1180,7 @@ static void orinoco_rx_monitor(struct ne
> u16 fc;
> int err;
> int len;
> - struct sk_buff *skb;
> + struct sk_buff *skb = NULL;
> struct orinoco_private *priv = netdev_priv(dev);
> struct net_device_stats *stats = &priv->stats;
> hermes_t *hw = &priv->hw;
> @@ -1268,6 +1268,8 @@ static void orinoco_rx_monitor(struct ne
> drop:
> stats->rx_errors++;
> stats->rx_dropped++;
> + if (skb)
> + dev_kfree_skb_irq(skb);
> }
>
> static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
>
>
I am not fond of unneeded/hidden state variable. What about:
+ /* sanity check the length */
+ if (datalen > IEEE80211_DATA_LEN + 12) {
+ printk(KERN_DEBUG "%s: oversized monitor frame, "
+ "data length = %d\n", dev->name, datalen);
+ err = -EIO;
+ goto drop;
^^^^^^^^^^ -> let's replace by 'goto update_stats;'
And turn:
+ drop:
+ stats->rx_errors++;
+ stats->rx_dropped++;
into:
+ drop:
+ dev_kfree_skb_irq(skb);
+ update_stats:
+ stats->rx_errors++;
+ stats->rx_dropped++;
This way 'goto drop' really drops and the code does not issue a 'goto drop'
when it actually want to update the stats.
--
Ueimor
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH 11/12] orinoco: monitor mode support
2005-05-17 21:22 ` Francois Romieu
@ 2005-05-23 3:40 ` Pavel Roskin
0 siblings, 0 replies; 5+ messages in thread
From: Pavel Roskin @ 2005-05-23 3:40 UTC (permalink / raw)
To: Francois Romieu; +Cc: Christoph Hellwig, jgarzik, hermes, netdev
Hello, Francois!
On Tue, 2005-05-17 at 23:22 +0200, Francois Romieu wrote:
> I am not fond of unneeded/hidden state variable. What about:
>
> + /* sanity check the length */
> + if (datalen > IEEE80211_DATA_LEN + 12) {
> + printk(KERN_DEBUG "%s: oversized monitor frame, "
> + "data length = %d\n", dev->name, datalen);
> + err = -EIO;
> + goto drop;
> ^^^^^^^^^^ -> let's replace by 'goto update_stats;'
> And turn:
> + drop:
> + stats->rx_errors++;
> + stats->rx_dropped++;
>
> into:
>
> + drop:
> + dev_kfree_skb_irq(skb);
> + update_stats:
> + stats->rx_errors++;
> + stats->rx_dropped++;
>
> This way 'goto drop' really drops and the code does not issue a 'goto drop'
> when it actually want to update the stats.
I agree. Closer look shows that orinoco needs a complete overhaul of
stats in the rx path. I'm going to fix it in CVS, and I'll post the
patch to netdev after it receives some testing.
--
Regards,
Pavel Roskin
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2005-05-23 3:40 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-05-14 15:31 [PATCH 11/12] orinoco: monitor mode support Christoph Hellwig
2005-05-14 17:39 ` Francois Romieu
2005-05-17 19:43 ` Pavel Roskin
2005-05-17 21:22 ` Francois Romieu
2005-05-23 3:40 ` Pavel Roskin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).