diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 45 |
1 files changed, 30 insertions, 15 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 1221d726ed50..572793c8c7ab 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -299,7 +299,7 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
299 | 299 | ||
300 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 300 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
301 | NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); | 301 | NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); |
302 | /* TODO: interface type */ | 302 | NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype); |
303 | return genlmsg_end(msg, hdr); | 303 | return genlmsg_end(msg, hdr); |
304 | 304 | ||
305 | nla_put_failure: | 305 | nla_put_failure: |
@@ -418,41 +418,56 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
418 | int err, ifindex; | 418 | int err, ifindex; |
419 | enum nl80211_iftype type; | 419 | enum nl80211_iftype type; |
420 | struct net_device *dev; | 420 | struct net_device *dev; |
421 | u32 flags; | 421 | u32 _flags, *flags = NULL; |
422 | 422 | ||
423 | memset(¶ms, 0, sizeof(params)); | 423 | memset(¶ms, 0, sizeof(params)); |
424 | 424 | ||
425 | if (info->attrs[NL80211_ATTR_IFTYPE]) { | ||
426 | type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); | ||
427 | if (type > NL80211_IFTYPE_MAX) | ||
428 | return -EINVAL; | ||
429 | } else | ||
430 | return -EINVAL; | ||
431 | |||
432 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 425 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
433 | if (err) | 426 | if (err) |
434 | return err; | 427 | return err; |
435 | ifindex = dev->ifindex; | 428 | ifindex = dev->ifindex; |
429 | type = dev->ieee80211_ptr->iftype; | ||
436 | dev_put(dev); | 430 | dev_put(dev); |
437 | 431 | ||
432 | err = -EINVAL; | ||
433 | if (info->attrs[NL80211_ATTR_IFTYPE]) { | ||
434 | type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); | ||
435 | if (type > NL80211_IFTYPE_MAX) | ||
436 | goto unlock; | ||
437 | } | ||
438 | |||
438 | if (!drv->ops->change_virtual_intf || | 439 | if (!drv->ops->change_virtual_intf || |
439 | !(drv->wiphy.interface_modes & (1 << type))) { | 440 | !(drv->wiphy.interface_modes & (1 << type))) { |
440 | err = -EOPNOTSUPP; | 441 | err = -EOPNOTSUPP; |
441 | goto unlock; | 442 | goto unlock; |
442 | } | 443 | } |
443 | 444 | ||
444 | if (type == NL80211_IFTYPE_MESH_POINT && | 445 | if (info->attrs[NL80211_ATTR_MESH_ID]) { |
445 | info->attrs[NL80211_ATTR_MESH_ID]) { | 446 | if (type != NL80211_IFTYPE_MESH_POINT) { |
447 | err = -EINVAL; | ||
448 | goto unlock; | ||
449 | } | ||
446 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); | 450 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); |
447 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | 451 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); |
448 | } | 452 | } |
449 | 453 | ||
454 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { | ||
455 | if (type != NL80211_IFTYPE_MONITOR) { | ||
456 | err = -EINVAL; | ||
457 | goto unlock; | ||
458 | } | ||
459 | err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], | ||
460 | &_flags); | ||
461 | if (!err) | ||
462 | flags = &_flags; | ||
463 | } | ||
450 | rtnl_lock(); | 464 | rtnl_lock(); |
451 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | ||
452 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, | ||
453 | &flags); | ||
454 | err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, | 465 | err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, |
455 | type, err ? NULL : &flags, ¶ms); | 466 | type, flags, ¶ms); |
467 | |||
468 | dev = __dev_get_by_index(&init_net, ifindex); | ||
469 | WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != type)); | ||
470 | |||
456 | rtnl_unlock(); | 471 | rtnl_unlock(); |
457 | 472 | ||
458 | unlock: | 473 | unlock: |