nl80211: Add monitor interface configuration flags
authorMichael Wu <flamingice@sourmilk.net>
Thu, 31 Jan 2008 18:48:22 +0000 (19:48 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 29 Feb 2008 20:37:02 +0000 (15:37 -0500)
This allows precise control over what a monitor interface shows.

Signed-off-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
include/linux/nl80211.h
include/net/cfg80211.h
net/mac80211/cfg.c
net/wireless/nl80211.c

index 6369506..a9f0b93 100644 (file)
@@ -164,6 +164,9 @@ enum nl80211_commands {
  * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands,
  *     consisting of a nested array.
  *
+ * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of
+ *      &enum nl80211_mntr_flags.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -200,6 +203,8 @@ enum nl80211_attrs {
 
        NL80211_ATTR_WIPHY_BANDS,
 
+       NL80211_ATTR_MNTR_FLAGS,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -344,4 +349,34 @@ enum nl80211_bitrate_attr {
        NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1
 };
 
+/**
+ * enum nl80211_mntr_flags - monitor configuration flags
+ *
+ * Monitor configuration flags.
+ *
+ * @__NL80211_MNTR_FLAG_INVALID: reserved
+ *
+ * @NL80211_MNTR_FLAG_FCSFAIL: pass frames with bad FCS
+ * @NL80211_MNTR_FLAG_PLCPFAIL: pass frames with bad PLCP
+ * @NL80211_MNTR_FLAG_CONTROL: pass control frames
+ * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering
+ * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing.
+ *     overrides all other flags.
+ *
+ * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use
+ * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag
+ */
+enum nl80211_mntr_flags {
+       __NL80211_MNTR_FLAG_INVALID,
+       NL80211_MNTR_FLAG_FCSFAIL,
+       NL80211_MNTR_FLAG_PLCPFAIL,
+       NL80211_MNTR_FLAG_CONTROL,
+       NL80211_MNTR_FLAG_OTHER_BSS,
+       NL80211_MNTR_FLAG_COOK_FRAMES,
+
+       /* keep last */
+       __NL80211_MNTR_FLAG_AFTER_LAST,
+       NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1
+};
+
 #endif /* __LINUX_NL80211_H */
index bcc480b..ab4caf6 100644 (file)
@@ -163,6 +163,26 @@ struct station_stats {
        u32 tx_bytes;
 };
 
+/**
+ * enum monitor_flags - monitor flags
+ *
+ * Monitor interface configuration flags. Note that these must be the bits
+ * according to the nl80211 flags.
+ *
+ * @MONITOR_FLAG_FCSFAIL: pass frames with bad FCS
+ * @MONITOR_FLAG_PLCPFAIL: pass frames with bad PLCP
+ * @MONITOR_FLAG_CONTROL: pass control frames
+ * @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering
+ * @MONITOR_FLAG_COOK_FRAMES: report frames after processing
+ */
+enum monitor_flags {
+       MONITOR_FLAG_FCSFAIL            = 1<<NL80211_MNTR_FLAG_FCSFAIL,
+       MONITOR_FLAG_PLCPFAIL           = 1<<NL80211_MNTR_FLAG_PLCPFAIL,
+       MONITOR_FLAG_CONTROL            = 1<<NL80211_MNTR_FLAG_CONTROL,
+       MONITOR_FLAG_OTHER_BSS          = 1<<NL80211_MNTR_FLAG_OTHER_BSS,
+       MONITOR_FLAG_COOK_FRAMES        = 1<<NL80211_MNTR_FLAG_COOK_FRAMES,
+};
+
 /* from net/wireless.h */
 struct wiphy;
 
@@ -213,10 +233,10 @@ struct wiphy;
  */
 struct cfg80211_ops {
        int     (*add_virtual_intf)(struct wiphy *wiphy, char *name,
-                                   enum nl80211_iftype type);
+                                   enum nl80211_iftype type, u32 *flags);
        int     (*del_virtual_intf)(struct wiphy *wiphy, int ifindex);
        int     (*change_virtual_intf)(struct wiphy *wiphy, int ifindex,
-                                      enum nl80211_iftype type);
+                                      enum nl80211_iftype type, u32 *flags);
 
        int     (*add_key)(struct wiphy *wiphy, struct net_device *netdev,
                           u8 key_index, u8 *mac_addr,
index 15b8cf9..706418d 100644 (file)
@@ -34,7 +34,7 @@ nl80211_type_to_mac80211_type(enum nl80211_iftype type)
 }
 
 static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
-                              enum nl80211_iftype type)
+                              enum nl80211_iftype type, u32 *flags)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
        enum ieee80211_if_types itype;
@@ -69,7 +69,7 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
 }
 
 static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
-                                 enum nl80211_iftype type)
+                                 enum nl80211_iftype type, u32 *flags)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
        struct net_device *dev;
index b123f58..5b34747 100644 (file)
@@ -82,6 +82,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
        [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
                                               .len = NL80211_MAX_SUPP_RATES },
        [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
+       [NL80211_ATTR_MNTR_FLAGS] = { .type = NLA_NESTED },
 };
 
 /* message building helper */
@@ -336,12 +337,42 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
        return -ENOBUFS;
 }
 
+static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
+       [NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG },
+       [NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG },
+       [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG },
+       [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
+       [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
+};
+
+static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
+{
+       struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1];
+       int flag;
+
+       *mntrflags = 0;
+
+       if (!nla)
+               return -EINVAL;
+
+       if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX,
+                            nla, mntr_flags_policy))
+               return -EINVAL;
+
+       for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++)
+               if (flags[flag])
+                       *mntrflags |= (1<<flag);
+
+       return 0;
+}
+
 static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *drv;
        int err, ifindex;
        enum nl80211_iftype type;
        struct net_device *dev;
+       u32 flags;
 
        if (info->attrs[NL80211_ATTR_IFTYPE]) {
                type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
@@ -362,7 +393,11 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
        }
 
        rtnl_lock();
-       err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, type);
+       err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
+                                 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
+                                 &flags);
+       err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex,
+                                           type, err ? NULL : &flags);
        rtnl_unlock();
 
  unlock:
@@ -375,6 +410,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
        struct cfg80211_registered_device *drv;
        int err;
        enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
+       u32 flags;
 
        if (!info->attrs[NL80211_ATTR_IFNAME])
                return -EINVAL;
@@ -395,8 +431,12 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
        }
 
        rtnl_lock();
+       err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
+                                 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
+                                 &flags);
        err = drv->ops->add_virtual_intf(&drv->wiphy,
-               nla_data(info->attrs[NL80211_ATTR_IFNAME]), type);
+               nla_data(info->attrs[NL80211_ATTR_IFNAME]),
+               type, err ? NULL : &flags);
        rtnl_unlock();
 
  unlock: