diff options
author | Michael Wu <flamingice@sourmilk.net> | 2008-01-31 13:48:22 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-02-29 15:37:02 -0500 |
commit | 66f7ac50ed7cc5c19a62bc97e8f6e7891004a03a (patch) | |
tree | 92c4756ae29b64aee4a76a043fd46bb02472cfd9 /net/wireless/nl80211.c | |
parent | e4c26add8893e40e6e809b8c1ebc81e37762af2b (diff) |
nl80211: Add monitor interface configuration flags
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>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 44 |
1 files changed, 42 insertions, 2 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b123f58d3909..5b3474798b8d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -82,6 +82,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
82 | [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY, | 82 | [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY, |
83 | .len = NL80211_MAX_SUPP_RATES }, | 83 | .len = NL80211_MAX_SUPP_RATES }, |
84 | [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, | 84 | [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, |
85 | [NL80211_ATTR_MNTR_FLAGS] = { .type = NLA_NESTED }, | ||
85 | }; | 86 | }; |
86 | 87 | ||
87 | /* message building helper */ | 88 | /* message building helper */ |
@@ -336,12 +337,42 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) | |||
336 | return -ENOBUFS; | 337 | return -ENOBUFS; |
337 | } | 338 | } |
338 | 339 | ||
340 | static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = { | ||
341 | [NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG }, | ||
342 | [NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG }, | ||
343 | [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG }, | ||
344 | [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG }, | ||
345 | [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG }, | ||
346 | }; | ||
347 | |||
348 | static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags) | ||
349 | { | ||
350 | struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1]; | ||
351 | int flag; | ||
352 | |||
353 | *mntrflags = 0; | ||
354 | |||
355 | if (!nla) | ||
356 | return -EINVAL; | ||
357 | |||
358 | if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX, | ||
359 | nla, mntr_flags_policy)) | ||
360 | return -EINVAL; | ||
361 | |||
362 | for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++) | ||
363 | if (flags[flag]) | ||
364 | *mntrflags |= (1<<flag); | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | |||
339 | static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | 369 | static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) |
340 | { | 370 | { |
341 | struct cfg80211_registered_device *drv; | 371 | struct cfg80211_registered_device *drv; |
342 | int err, ifindex; | 372 | int err, ifindex; |
343 | enum nl80211_iftype type; | 373 | enum nl80211_iftype type; |
344 | struct net_device *dev; | 374 | struct net_device *dev; |
375 | u32 flags; | ||
345 | 376 | ||
346 | if (info->attrs[NL80211_ATTR_IFTYPE]) { | 377 | if (info->attrs[NL80211_ATTR_IFTYPE]) { |
347 | type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); | 378 | 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) | |||
362 | } | 393 | } |
363 | 394 | ||
364 | rtnl_lock(); | 395 | rtnl_lock(); |
365 | err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, type); | 396 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? |
397 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, | ||
398 | &flags); | ||
399 | err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, | ||
400 | type, err ? NULL : &flags); | ||
366 | rtnl_unlock(); | 401 | rtnl_unlock(); |
367 | 402 | ||
368 | unlock: | 403 | unlock: |
@@ -375,6 +410,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
375 | struct cfg80211_registered_device *drv; | 410 | struct cfg80211_registered_device *drv; |
376 | int err; | 411 | int err; |
377 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; | 412 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; |
413 | u32 flags; | ||
378 | 414 | ||
379 | if (!info->attrs[NL80211_ATTR_IFNAME]) | 415 | if (!info->attrs[NL80211_ATTR_IFNAME]) |
380 | return -EINVAL; | 416 | return -EINVAL; |
@@ -395,8 +431,12 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
395 | } | 431 | } |
396 | 432 | ||
397 | rtnl_lock(); | 433 | rtnl_lock(); |
434 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | ||
435 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, | ||
436 | &flags); | ||
398 | err = drv->ops->add_virtual_intf(&drv->wiphy, | 437 | err = drv->ops->add_virtual_intf(&drv->wiphy, |
399 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), type); | 438 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), |
439 | type, err ? NULL : &flags); | ||
400 | rtnl_unlock(); | 440 | rtnl_unlock(); |
401 | 441 | ||
402 | unlock: | 442 | unlock: |