aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c44
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
340static 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
348static 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
339static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) 369static 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: