Commit 3b85875a authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

nl80211: rework locking

When I added scanning to cfg80211, we got a lock dependency like this:
	rtnl --> cfg80211_mtx

nl80211, on the other hand, has the reverse lock dependency:
	cfg80211_mtx --> rtnl

which clearly is a bad idea. This patch reworks nl80211 to take these
two locks in the other order to fix the possible, and easily
triggerable, deadlock.
Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 8f655dde
...@@ -602,9 +602,12 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) ...@@ -602,9 +602,12 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
memset(&params, 0, sizeof(params)); memset(&params, 0, sizeof(params));
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err) if (err)
return err; goto unlock_rtnl;
ifindex = dev->ifindex; ifindex = dev->ifindex;
type = dev->ieee80211_ptr->iftype; type = dev->ieee80211_ptr->iftype;
dev_put(dev); dev_put(dev);
...@@ -641,17 +644,17 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) ...@@ -641,17 +644,17 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
if (!err) if (!err)
flags = &_flags; flags = &_flags;
} }
rtnl_lock();
err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex,
type, flags, &params); type, flags, &params);
dev = __dev_get_by_index(&init_net, ifindex); dev = __dev_get_by_index(&init_net, ifindex);
WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != type)); WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != type));
rtnl_unlock();
unlock: unlock:
cfg80211_put_dev(drv); cfg80211_put_dev(drv);
unlock_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -674,9 +677,13 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) ...@@ -674,9 +677,13 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
return -EINVAL; return -EINVAL;
} }
rtnl_lock();
drv = cfg80211_get_dev_from_info(info); drv = cfg80211_get_dev_from_info(info);
if (IS_ERR(drv)) if (IS_ERR(drv)) {
return PTR_ERR(drv); err = PTR_ERR(drv);
goto unlock_rtnl;
}
if (!drv->ops->add_virtual_intf || if (!drv->ops->add_virtual_intf ||
!(drv->wiphy.interface_modes & (1 << type))) { !(drv->wiphy.interface_modes & (1 << type))) {
...@@ -690,18 +697,17 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) ...@@ -690,18 +697,17 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
} }
rtnl_lock();
err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
&flags); &flags);
err = drv->ops->add_virtual_intf(&drv->wiphy, err = drv->ops->add_virtual_intf(&drv->wiphy,
nla_data(info->attrs[NL80211_ATTR_IFNAME]), nla_data(info->attrs[NL80211_ATTR_IFNAME]),
type, err ? NULL : &flags, &params); type, err ? NULL : &flags, &params);
rtnl_unlock();
unlock: unlock:
cfg80211_put_dev(drv); cfg80211_put_dev(drv);
unlock_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -711,9 +717,11 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) ...@@ -711,9 +717,11 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
int ifindex, err; int ifindex, err;
struct net_device *dev; struct net_device *dev;
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err) if (err)
return err; goto unlock_rtnl;
ifindex = dev->ifindex; ifindex = dev->ifindex;
dev_put(dev); dev_put(dev);
...@@ -722,12 +730,12 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) ...@@ -722,12 +730,12 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
goto out; goto out;
} }
rtnl_lock();
err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex); err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex);
rtnl_unlock();
out: out:
cfg80211_put_dev(drv); cfg80211_put_dev(drv);
unlock_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -779,9 +787,11 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) ...@@ -779,9 +787,11 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_MAC]) if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err) if (err)
return err; goto unlock_rtnl;
if (!drv->ops->get_key) { if (!drv->ops->get_key) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
...@@ -809,10 +819,8 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) ...@@ -809,10 +819,8 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
if (mac_addr) if (mac_addr)
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
rtnl_lock();
err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr, err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr,
&cookie, get_key_callback); &cookie, get_key_callback);
rtnl_unlock();
if (err) if (err)
goto out; goto out;
...@@ -830,6 +838,9 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) ...@@ -830,6 +838,9 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
out: out:
cfg80211_put_dev(drv); cfg80211_put_dev(drv);
dev_put(dev); dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -858,9 +869,11 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) ...@@ -858,9 +869,11 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) !info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT])
return -EINVAL; return -EINVAL;
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err) if (err)
return err; goto unlock_rtnl;
if (info->attrs[NL80211_ATTR_KEY_DEFAULT]) if (info->attrs[NL80211_ATTR_KEY_DEFAULT])
func = drv->ops->set_default_key; func = drv->ops->set_default_key;
...@@ -872,13 +885,15 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) ...@@ -872,13 +885,15 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
goto out; goto out;
} }
rtnl_lock();
err = func(&drv->wiphy, dev, key_idx); err = func(&drv->wiphy, dev, key_idx);
rtnl_unlock();
out: out:
cfg80211_put_dev(drv); cfg80211_put_dev(drv);
dev_put(dev); dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -948,22 +963,25 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) ...@@ -948,22 +963,25 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
return -EINVAL; return -EINVAL;
} }
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err) if (err)
return err; goto unlock_rtnl;
if (!drv->ops->add_key) { if (!drv->ops->add_key) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto out; goto out;
} }
rtnl_lock();
err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, &params); err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, &params);
rtnl_unlock();
out: out:
cfg80211_put_dev(drv); cfg80211_put_dev(drv);
dev_put(dev); dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -984,22 +1002,26 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) ...@@ -984,22 +1002,26 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_MAC]) if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err) if (err)
return err; goto unlock_rtnl;
if (!drv->ops->del_key) { if (!drv->ops->del_key) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto out; goto out;
} }
rtnl_lock();
err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr); err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr);
rtnl_unlock();
out: out:
cfg80211_put_dev(drv); cfg80211_put_dev(drv);
dev_put(dev); dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -1013,9 +1035,11 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) ...@@ -1013,9 +1035,11 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
struct beacon_parameters params; struct beacon_parameters params;
int haveinfo = 0; int haveinfo = 0;
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err) if (err)
return err; goto unlock_rtnl;
switch (info->genlhdr->cmd) { switch (info->genlhdr->cmd) {
case NL80211_CMD_NEW_BEACON: case NL80211_CMD_NEW_BEACON:
...@@ -1076,13 +1100,14 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) ...@@ -1076,13 +1100,14 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
goto out; goto out;
} }
rtnl_lock();
err = call(&drv->wiphy, dev, &params); err = call(&drv->wiphy, dev, &params);
rtnl_unlock();
out: out:
cfg80211_put_dev(drv); cfg80211_put_dev(drv);
dev_put(dev); dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -1092,22 +1117,25 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) ...@@ -1092,22 +1117,25 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
int err; int err;
struct net_device *dev; struct net_device *dev;
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err) if (err)
return err; goto unlock_rtnl;
if (!drv->ops->del_beacon) { if (!drv->ops->del_beacon) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto out; goto out;
} }
rtnl_lock();
err = drv->ops->del_beacon(&drv->wiphy, dev); err = drv->ops->del_beacon(&drv->wiphy, dev);
rtnl_unlock();
out: out:
cfg80211_put_dev(drv); cfg80211_put_dev(drv);
dev_put(dev); dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -1273,14 +1301,18 @@ static int nl80211_dump_station(struct sk_buff *skb, ...@@ -1273,14 +1301,18 @@ static int nl80211_dump_station(struct sk_buff *skb,
return -EINVAL; return -EINVAL;
} }
netdev = dev_get_by_index(&init_net, ifidx); rtnl_lock();
if (!netdev)
return -ENODEV; netdev = __dev_get_by_index(&init_net, ifidx);
if (!netdev) {
err = -ENODEV;
goto out_rtnl;
}
dev = cfg80211_get_dev_from_ifindex(ifidx); dev = cfg80211_get_dev_from_ifindex(ifidx);
if (IS_ERR(dev)) { if (IS_ERR(dev)) {
err = PTR_ERR(dev); err = PTR_ERR(dev);
goto out_put_netdev; goto out_rtnl;
} }
if (!dev->ops->dump_station) { if (!dev->ops->dump_station) {
...@@ -1288,15 +1320,13 @@ static int nl80211_dump_station(struct sk_buff *skb, ...@@ -1288,15 +1320,13 @@ static int nl80211_dump_station(struct sk_buff *skb,
goto out_err; goto out_err;
} }
rtnl_lock();
while (1) { while (1) {
err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx, err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx,
mac_addr, &sinfo); mac_addr, &sinfo);
if (err == -ENOENT) if (err == -ENOENT)
break; break;
if (err) if (err)
goto out_err_rtnl; goto out_err;
if (nl80211_send_station(skb, if (nl80211_send_station(skb,
NETLINK_CB(cb->skb).pid, NETLINK_CB(cb->skb).pid,
...@@ -1312,12 +1342,10 @@ static int nl80211_dump_station(struct sk_buff *skb, ...@@ -1312,12 +1342,10 @@ static int nl80211_dump_station(struct sk_buff *skb,
out: out:
cb->args[1] = sta_idx; cb->args[1] = sta_idx;
err = skb->len; err = skb->len;
out_err_rtnl:
rtnl_unlock();
out_err: out_err:
cfg80211_put_dev(dev); cfg80211_put_dev(dev);
out_put_netdev: out_rtnl:
dev_put(netdev); rtnl_unlock();
return err; return err;
} }
...@@ -1338,19 +1366,18 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) ...@@ -1338,19 +1366,18 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err) if (err)
return err; goto out_rtnl;
if (!drv->ops->get_station) { if (!drv->ops->get_station) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto out; goto out;
} }
rtnl_lock();
err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &sinfo); err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &sinfo);
rtnl_unlock();
if (err) if (err)
goto out; goto out;
...@@ -1367,10 +1394,12 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) ...@@ -1367,10 +1394,12 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
out_free: out_free:
nlmsg_free(msg); nlmsg_free(msg);
out: out:
cfg80211_put_dev(drv); cfg80211_put_dev(drv);
dev_put(dev); dev_put(dev);
out_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -1438,9 +1467,11 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) ...@@ -1438,9 +1467,11 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
params.plink_action = params.plink_action =
nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err) if (err)
return err; goto out_rtnl;
err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan); err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
if (err) if (err)
...@@ -1451,15 +1482,16 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) ...@@ -1451,15 +1482,16 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
goto out; goto out;
} }
rtnl_lock();
err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, &params); err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, &params);
rtnl_unlock();
out: out:
if (params.vlan) if (params.vlan)
dev_put(params.vlan); dev_put(params.vlan);
cfg80211_put_dev(drv); cfg80211_put_dev(drv);
dev_put(dev); dev_put(dev);
out_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -1501,9 +1533,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) ...@@ -1501,9 +1533,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
&params.station_flags)) &params.station_flags))
return -EINVAL; return -EINVAL;
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err) if (err)
return err; goto out_rtnl;
err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan); err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
if (err) if (err)
...@@ -1514,15 +1548,16 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) ...@@ -1514,15 +1548,16 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
goto out; goto out;
} }
rtnl_lock();
err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, &params); err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, &params);
rtnl_unlock();
out: out:
if (params.vlan) if (params.vlan)
dev_put(params.vlan); dev_put(params.vlan);
cfg80211_put_dev(drv); cfg80211_put_dev(drv);
dev_put(dev); dev_put(dev);
out_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -1536,22 +1571,25 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) ...@@ -1536,22 +1571,25 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_MAC]) if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err) if (err)
return err; goto out_rtnl;
if (!drv->ops->del_station) { if (!drv->ops->del_station) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto out; goto out;
} }
rtnl_lock();
err = drv->ops->del_station(&drv->wiphy, dev, mac_addr); err = drv->ops->del_station(&drv->wiphy, dev, mac_addr);
rtnl_unlock();
out: out:
cfg80211_put_dev(drv); cfg80211_put_dev(drv);
dev_put(dev); dev_put(dev);
out_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -1632,14 +1670,18 @@ static int nl80211_dump_mpath(struct sk_buff *skb, ...@@ -1632,14 +1670,18 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
return -EINVAL; return -EINVAL;
} }
netdev = dev_get_by_index(&init_net, ifidx); rtnl_lock();
if (!netdev)
return -ENODEV; netdev = __dev_get_by_index(&init_net, ifidx);
if (!netdev) {
err = -ENODEV;
goto out_rtnl;
}
dev = cfg80211_get_dev_from_ifindex(ifidx); dev = cfg80211_get_dev_from_ifindex(ifidx);
if (IS_ERR(dev)) { if (IS_ERR(dev)) {
err = PTR_ERR(dev); err = PTR_ERR(dev);
goto out_put_netdev; goto out_rtnl;
} }
if (!dev->ops->dump_mpath) { if (!dev->ops->dump_mpath) {
...@@ -1647,15 +1689,13 @@ static int nl80211_dump_mpath(struct sk_buff *skb, ...@@ -1647,15 +1689,13 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
goto out_err; goto out_err;
} }
rtnl_lock();
while (1) { while (1) {
err = dev->ops->dump_mpath(&dev->wiphy, netdev, path_idx, err = dev->ops->dump_mpath(&dev->wiphy, netdev, path_idx,
dst, next_hop, &pinfo); dst, next_hop, &pinfo);
if (err == -ENOENT) if (err == -ENOENT)
break; break;
if (err) if (err)
goto out_err_rtnl; goto out_err;
if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).pid, if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh->nlmsg_seq, NLM_F_MULTI,
...@@ -1670,12 +1710,10 @@ static int nl80211_dump_mpath(struct sk_buff *skb, ...@@ -1670,12 +1710,10 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
out: out:
cb->args[1] = path_idx; cb->args[1] = path_idx;
err = skb->len; err = skb->len;
out_err_rtnl:
rtnl_unlock();
out_err: out_err:
cfg80211_put_dev(dev); cfg80211_put_dev(dev);
out_put_netdev: out_rtnl:
dev_put(netdev); rtnl_unlock();
return err; return err;
} }
...@@ -1697,19 +1735,18 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) ...@@ -1697,19 +1735,18 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
dst = nla_data(info->attrs[NL80211_ATTR_MAC]); dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err) if (err)
return err; goto out_rtnl;
if (!drv->ops->get_mpath) { if (!drv->ops->get_mpath) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto out; goto out;
} }
rtnl_lock();
err = drv->ops->get_mpath(&drv->wiphy, dev, dst, next_hop, &pinfo); err = drv->ops->get_mpath(&drv->wiphy, dev, dst, next_hop, &pinfo);
rtnl_unlock();
if (err) if (err)
goto out; goto out;
...@@ -1726,10 +1763,12 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) ...@@ -1726,10 +1763,12 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
out_free: out_free:
nlmsg_free(msg); nlmsg_free(msg);
out: out:
cfg80211_put_dev(drv); cfg80211_put_dev(drv);
dev_put(dev); dev_put(dev);
out_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -1750,22 +1789,25 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) ...@@ -1750,22 +1789,25 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
dst = nla_data(info->attrs[NL80211_ATTR_MAC]); dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err) if (err)
return err; goto out_rtnl;
if (!drv->ops->change_mpath) { if (!drv->ops->change_mpath) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto out; goto out;
} }
rtnl_lock();
err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop); err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop);
rtnl_unlock();
out: out:
cfg80211_put_dev(drv); cfg80211_put_dev(drv);
dev_put(dev); dev_put(dev);
out_rtnl:
rtnl_unlock();
return err; return err;
} }
static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
...@@ -1785,22 +1827,25 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) ...@@ -1785,22 +1827,25 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
dst = nla_data(info->attrs[NL80211_ATTR_MAC]); dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err) if (err)
return err; goto out_rtnl;
if (!drv->ops->add_mpath) { if (!drv->ops->add_mpath) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto out; goto out;
} }
rtnl_lock();
err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop); err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop);
rtnl_unlock();
out: out:
cfg80211_put_dev(drv); cfg80211_put_dev(drv);
dev_put(dev); dev_put(dev);
out_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -1814,22 +1859,25 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) ...@@ -1814,22 +1859,25 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_MAC]) if (info->attrs[NL80211_ATTR_MAC])
dst = nla_data(info->attrs[NL80211_ATTR_MAC]); dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err) if (err)
return err; goto out_rtnl;
if (!drv->ops->del_mpath) { if (!drv->ops->del_mpath) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto out; goto out;
} }
rtnl_lock();
err = drv->ops->del_mpath(&drv->wiphy, dev, dst); err = drv->ops->del_mpath(&drv->wiphy, dev, dst);
rtnl_unlock();
out: out:
cfg80211_put_dev(drv); cfg80211_put_dev(drv);
dev_put(dev); dev_put(dev);
out_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -1862,22 +1910,25 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) ...@@ -1862,22 +1910,25 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
} }
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err) if (err)
return err; goto out_rtnl;
if (!drv->ops->change_bss) { if (!drv->ops->change_bss) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto out; goto out;
} }
rtnl_lock();
err = drv->ops->change_bss(&drv->wiphy, dev, &params); err = drv->ops->change_bss(&drv->wiphy, dev, &params);
rtnl_unlock();
out: out:
cfg80211_put_dev(drv); cfg80211_put_dev(drv);
dev_put(dev); dev_put(dev);
out_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -1972,10 +2023,12 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, ...@@ -1972,10 +2023,12 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
struct nlattr *pinfoattr; struct nlattr *pinfoattr;
struct sk_buff *msg; struct sk_buff *msg;
rtnl_lock();
/* Look up our device */ /* Look up our device */
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err) if (err)
return err; goto out_rtnl;
if (!drv->ops->get_mesh_params) { if (!drv->ops->get_mesh_params) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
...@@ -1983,9 +2036,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, ...@@ -1983,9 +2036,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
} }
/* Get the mesh params */ /* Get the mesh params */
rtnl_lock();
err = drv->ops->get_mesh_params(&drv->wiphy, dev, &cur_params); err = drv->ops->get_mesh_params(&drv->wiphy, dev, &cur_params);
rtnl_unlock();
if (err) if (err)
goto out; goto out;
...@@ -2034,13 +2085,16 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, ...@@ -2034,13 +2085,16 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
err = genlmsg_unicast(msg, info->snd_pid); err = genlmsg_unicast(msg, info->snd_pid);
goto out; goto out;
nla_put_failure: nla_put_failure:
genlmsg_cancel(msg, hdr); genlmsg_cancel(msg, hdr);
err = -EMSGSIZE; err = -EMSGSIZE;
out: out:
/* Cleanup */ /* Cleanup */
cfg80211_put_dev(drv); cfg80211_put_dev(drv);
dev_put(dev); dev_put(dev);
out_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -2087,9 +2141,11 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) ...@@ -2087,9 +2141,11 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
parent_attr, nl80211_meshconf_params_policy)) parent_attr, nl80211_meshconf_params_policy))
return -EINVAL; return -EINVAL;
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err) if (err)
return err; goto out_rtnl;
if (!drv->ops->set_mesh_params) { if (!drv->ops->set_mesh_params) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
...@@ -2136,14 +2192,15 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) ...@@ -2136,14 +2192,15 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
nla_get_u16); nla_get_u16);
/* Apply changes */ /* Apply changes */
rtnl_lock();
err = drv->ops->set_mesh_params(&drv->wiphy, dev, &cfg, mask); err = drv->ops->set_mesh_params(&drv->wiphy, dev, &cfg, mask);
rtnl_unlock();
out: out:
/* cleanup */ /* cleanup */
cfg80211_put_dev(drv); cfg80211_put_dev(drv);
dev_put(dev); dev_put(dev);
out_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -2310,19 +2367,22 @@ static int nl80211_set_mgmt_extra_ie(struct sk_buff *skb, ...@@ -2310,19 +2367,22 @@ static int nl80211_set_mgmt_extra_ie(struct sk_buff *skb,
params.ies_len = nla_len(info->attrs[NL80211_ATTR_IE]); params.ies_len = nla_len(info->attrs[NL80211_ATTR_IE]);
} }
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err) if (err)
return err; goto out_rtnl;
if (drv->ops->set_mgmt_extra_ie) { if (drv->ops->set_mgmt_extra_ie)
rtnl_lock();
err = drv->ops->set_mgmt_extra_ie(&drv->wiphy, dev, &params); err = drv->ops->set_mgmt_extra_ie(&drv->wiphy, dev, &params);
rtnl_unlock(); else
} else
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
cfg80211_put_dev(drv); cfg80211_put_dev(drv);
dev_put(dev); dev_put(dev);
out_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -2339,9 +2399,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) ...@@ -2339,9 +2399,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
enum ieee80211_band band; enum ieee80211_band band;
size_t ie_len; size_t ie_len;
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
if (err) if (err)
return err; goto out_rtnl;
wiphy = &drv->wiphy; wiphy = &drv->wiphy;
...@@ -2350,11 +2412,9 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) ...@@ -2350,11 +2412,9 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
goto out; goto out;
} }
rtnl_lock();
if (drv->scan_req) { if (drv->scan_req) {
err = -EBUSY; err = -EBUSY;
goto out_unlock; goto out;
} }
if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
...@@ -2362,7 +2422,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) ...@@ -2362,7 +2422,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
n_channels++; n_channels++;
if (!n_channels) { if (!n_channels) {
err = -EINVAL; err = -EINVAL;
goto out_unlock; goto out;
} }
} else { } else {
for (band = 0; band < IEEE80211_NUM_BANDS; band++) for (band = 0; band < IEEE80211_NUM_BANDS; band++)
...@@ -2376,7 +2436,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) ...@@ -2376,7 +2436,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
if (n_ssids > wiphy->max_scan_ssids) { if (n_ssids > wiphy->max_scan_ssids) {
err = -EINVAL; err = -EINVAL;
goto out_unlock; goto out;
} }
if (info->attrs[NL80211_ATTR_IE]) if (info->attrs[NL80211_ATTR_IE])
...@@ -2390,7 +2450,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) ...@@ -2390,7 +2450,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
+ ie_len, GFP_KERNEL); + ie_len, GFP_KERNEL);
if (!request) { if (!request) {
err = -ENOMEM; err = -ENOMEM;
goto out_unlock; goto out;
} }
request->channels = (void *)((char *)request + sizeof(*request)); request->channels = (void *)((char *)request + sizeof(*request));
...@@ -2461,11 +2521,12 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) ...@@ -2461,11 +2521,12 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
drv->scan_req = NULL; drv->scan_req = NULL;
kfree(request); kfree(request);
} }
out_unlock:
rtnl_unlock();
out: out:
cfg80211_put_dev(drv); cfg80211_put_dev(drv);
dev_put(dev); dev_put(dev);
out_rtnl:
rtnl_unlock();
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment