This patch allows monitor interfaces to be set by SIOCSIWMODE and to receive
frames.

Also, "soft" and "hard" monitor modes are introduced.  

Signed-off-by: Jiri Benc <[EMAIL PROTECTED]>

Index: dscape/include/net/d80211.h
===================================================================
--- dscape.orig/include/net/d80211.h    2006-03-06 14:18:01.000000000 +0100
+++ dscape/include/net/d80211.h 2006-03-06 14:18:10.000000000 +0100
@@ -430,6 +430,10 @@ struct ieee80211_hw {
         */
        unsigned int device_strips_mic:1;
 
+       /* Device is capable of performing full monitor mode even during
+        * normal operation. */
+       unsigned int monitor_during_oper:1;
+
        /* 1 = low-level driver supports skb fraglist (NETIF_F_FRAGLIST), i.e.,
         * more than one skb per frame */
        unsigned int fraglist;
@@ -465,7 +469,9 @@ struct ieee80211_hw {
         * more exactly, set UP). If the handler returns zero, the interface
         * is added. Driver should perform any initialization it needs prior
         * to returning zero. By returning non-zero, adding of the interface
-        * is not permitted. The open() handler is called after
+        * is not permitted. Unless monitor_during_oper is set, it is
+        * guaranteed that monitor interfaces and normal interfaces are
+        * mutually exclusive. The open() handler is called after
         * add_interface() if this is the first device added. At least one
         * of open() and add_interface() handler has to be non-NULL. If
         * add_interface() is NULL, one STA interface is permitted only. */
Index: dscape/net/d80211/ieee80211.c
===================================================================
--- dscape.orig/net/d80211/ieee80211.c  2006-03-06 14:18:06.000000000 +0100
+++ dscape/net/d80211/ieee80211.c       2006-03-06 14:18:10.000000000 +0100
@@ -1872,7 +1872,9 @@ static struct net_device_stats *ieee8021
 
 static inline int identical_mac_addr_allowed(int type1, int type2)
 {
-       return ((type1 == IEEE80211_SUB_IF_TYPE_AP &&
+       return (type1 == IEEE80211_SUB_IF_TYPE_MNTR ||
+               type2 == IEEE80211_SUB_IF_TYPE_MNTR ||
+               (type1 == IEEE80211_SUB_IF_TYPE_AP &&
                 type2 == IEEE80211_SUB_IF_TYPE_WDS) ||
                (type1 == IEEE80211_SUB_IF_TYPE_WDS &&
                 (type2 == IEEE80211_SUB_IF_TYPE_WDS ||
@@ -1906,6 +1908,34 @@ static int ieee80211_master_stop(struct 
        return 0;
 }
 
+/* Check if running monitor interfaces should go to a "soft monitor" mode
+ * and switch them if necessary. */
+static inline void ieee80211_start_soft_monitor(struct ieee80211_local *local)
+{
+       struct ieee80211_if_conf conf;
+
+       if (local->open_count && local->open_count == local->monitors &&
+           !local->hw->monitor_during_oper && local->hw->remove_interface) {
+               conf.type = IEEE80211_SUB_IF_TYPE_MNTR;
+               conf.mac_addr = NULL;
+               local->hw->remove_interface(local->mdev, &conf);
+       }
+}
+
+/* Check if running monitor interfaces should go to a "hard monitor" mode
+ * and switch them if necessary. */
+static void ieee80211_start_hard_monitor(struct ieee80211_local *local)
+{
+       struct ieee80211_if_conf conf;
+
+       if (local->open_count && local->open_count == local->monitors &&
+           !local->hw->monitor_during_oper && local->hw->add_interface) {
+               conf.type = IEEE80211_SUB_IF_TYPE_MNTR;
+               conf.mac_addr = NULL;
+               local->hw->add_interface(local->mdev, &conf);
+       }
+}
+
 static int ieee80211_open(struct net_device *dev)
 {
        struct ieee80211_sub_if_data *sdata, *nsdata;
@@ -1929,12 +1959,24 @@ static int ieee80211_open(struct net_dev
            memcmp(sdata->u.wds.remote_addr, "\0\0\0\0\0\0", ETH_ALEN) == 0)
                return -ENOLINK;
 
+       if (sdata->type == IEEE80211_SUB_IF_TYPE_MNTR && local->open_count &&
+           !local->hw->monitor_during_oper) {
+               /* run the interface in a "soft monitor" mode */
+               local->monitors++;
+               local->open_count++;
+               return 0;
+       }
+       ieee80211_start_soft_monitor(local);
+
        if (local->hw->add_interface) {
                conf.type = sdata->type;
                conf.mac_addr = dev->dev_addr;
                res = local->hw->add_interface(sdata->master, &conf);
-               if (res)
+               if (res) {
+                       if (sdata->type == IEEE80211_SUB_IF_TYPE_MNTR)
+                               ieee80211_start_hard_monitor(local);
                        return res;
+               }
        } else {
                if (sdata->type != IEEE80211_SUB_IF_TYPE_STA)
                        return -EOPNOTSUPP;
@@ -1972,6 +2014,14 @@ static int ieee80211_stop(struct net_dev
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
+       if (sdata->type == IEEE80211_SUB_IF_TYPE_MNTR &&
+           local->open_count > 1 && !local->hw->monitor_during_oper) {
+               /* remove "soft monitor" interface */
+               local->open_count--;
+               local->monitors--;
+               return 0;
+       }
+
         netif_stop_queue(dev);
 
        local->open_count--;
@@ -1989,6 +2039,8 @@ static int ieee80211_stop(struct net_dev
                local->hw->remove_interface(sdata->master, &conf);
        }
 
+       ieee80211_start_hard_monitor(local);
+
        return 0;
 }
 
@@ -2221,7 +2273,8 @@ ieee80211_rx_mgmt(struct net_device *dev
         size_t hlen;
         struct ieee80211_sub_if_data *sdata;
 
-        dev = local->apdev;
+       if (msg_type != ieee80211_msg_monitor)
+               dev = local->apdev;
         skb->dev = dev;
 
         sdata = IEEE80211_DEV_TO_SUB_IF(dev);
Index: dscape/net/d80211/ieee80211_i.h
===================================================================
--- dscape.orig/net/d80211/ieee80211_i.h        2006-03-06 14:18:01.000000000 
+0100
+++ dscape/net/d80211/ieee80211_i.h     2006-03-06 14:18:10.000000000 +0100
@@ -305,6 +305,7 @@ struct ieee80211_local {
         struct net_device *wdev; /* wlan# - default Ethernet (data) devide */
        struct net_device *apdev; /* wlan#ap - management frames (hostapd) */
        int open_count;
+       int monitors;
        struct ieee80211_conf conf;
 
        int dev_index;
Index: dscape/net/d80211/ieee80211_iface.c
===================================================================
--- dscape.orig/net/d80211/ieee80211_iface.c    2006-03-06 14:18:01.000000000 
+0100
+++ dscape/net/d80211/ieee80211_iface.c 2006-03-06 14:18:10.000000000 +0100
@@ -8,6 +8,7 @@
  * published by the Free Software Foundation.
  */
 #include <linux/kernel.h>
+#include <linux/if_arp.h>
 #include <linux/netdevice.h>
 #include <linux/rtnetlink.h>
 #include <net/d80211.h>
@@ -125,6 +126,9 @@ void ieee80211_if_set_type(struct net_de
                ifsta->wmm_enabled = 1;
                break;
        }
+       case IEEE80211_SUB_IF_TYPE_MNTR:
+               dev->type = ARPHRD_IEEE80211_PRISM;
+               break;
        default:
                printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x",
                       dev->name, __FUNCTION__, type);
@@ -212,6 +216,9 @@ void ieee80211_if_reinit(struct net_devi
                }
 
                break;
+       case IEEE80211_SUB_IF_TYPE_MNTR:
+               dev->type = ARPHRD_ETHER;
+               break;
        }
 
        /* remove all STAs that are bound to this virtual interface */
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to