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.c45
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(&params, 0, sizeof(params)); 423 memset(&params, 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, &params); 466 type, flags, &params);
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: