diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 151 |
1 files changed, 59 insertions, 92 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ca8d04c..0c94971 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -198,6 +198,47 @@ static int nl80211_get_ifidx(struct netlink_callback *cb) return res; } +static int nl80211_prepare_netdev_dump(struct sk_buff *skb, + struct netlink_callback *cb, + struct cfg80211_registered_device **rdev, + struct net_device **dev) +{ + int ifidx = cb->args[0]; + int err; + + if (!ifidx) + ifidx = nl80211_get_ifidx(cb); + if (ifidx < 0) + return ifidx; + + cb->args[0] = ifidx; + + rtnl_lock(); + + *dev = __dev_get_by_index(sock_net(skb->sk), ifidx); + if (!*dev) { + err = -ENODEV; + goto out_rtnl; + } + + *rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); + if (IS_ERR(dev)) { + err = PTR_ERR(dev); + goto out_rtnl; + } + + return 0; + out_rtnl: + rtnl_unlock(); + return err; +} + +static void nl80211_finish_netdev_dump(struct cfg80211_registered_device *rdev) +{ + cfg80211_unlock_rdev(rdev); + rtnl_unlock(); +} + /* IE validation */ static bool is_valid_ie_attr(const struct nlattr *attr) { @@ -1796,28 +1837,12 @@ static int nl80211_dump_station(struct sk_buff *skb, struct cfg80211_registered_device *dev; struct net_device *netdev; u8 mac_addr[ETH_ALEN]; - int ifidx = cb->args[0]; int sta_idx = cb->args[1]; int err; - if (!ifidx) - ifidx = nl80211_get_ifidx(cb); - if (ifidx < 0) - return ifidx; - - rtnl_lock(); - - netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); - if (!netdev) { - err = -ENODEV; - goto out_rtnl; - } - - dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); - if (IS_ERR(dev)) { - err = PTR_ERR(dev); - goto out_rtnl; - } + err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); + if (err) + return err; if (!dev->ops->dump_station) { err = -EOPNOTSUPP; @@ -1847,9 +1872,7 @@ static int nl80211_dump_station(struct sk_buff *skb, cb->args[1] = sta_idx; err = skb->len; out_err: - cfg80211_unlock_rdev(dev); - out_rtnl: - rtnl_unlock(); + nl80211_finish_netdev_dump(dev); return err; } @@ -2169,28 +2192,12 @@ static int nl80211_dump_mpath(struct sk_buff *skb, struct net_device *netdev; u8 dst[ETH_ALEN]; u8 next_hop[ETH_ALEN]; - int ifidx = cb->args[0]; int path_idx = cb->args[1]; int err; - if (!ifidx) - ifidx = nl80211_get_ifidx(cb); - if (ifidx < 0) - return ifidx; - - rtnl_lock(); - - netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); - if (!netdev) { - err = -ENODEV; - goto out_rtnl; - } - - dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); - if (IS_ERR(dev)) { - err = PTR_ERR(dev); - goto out_rtnl; - } + err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); + if (err) + return err; if (!dev->ops->dump_mpath) { err = -EOPNOTSUPP; @@ -2224,10 +2231,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb, cb->args[1] = path_idx; err = skb->len; out_err: - cfg80211_unlock_rdev(dev); - out_rtnl: - rtnl_unlock(); - + nl80211_finish_netdev_dump(dev); return err; } @@ -3034,25 +3038,12 @@ static int nl80211_dump_scan(struct sk_buff *skb, struct net_device *dev; struct cfg80211_internal_bss *scan; struct wireless_dev *wdev; - int ifidx = cb->args[0]; int start = cb->args[1], idx = 0; int err; - if (!ifidx) - ifidx = nl80211_get_ifidx(cb); - if (ifidx < 0) - return ifidx; - cb->args[0] = ifidx; - - dev = dev_get_by_index(sock_net(skb->sk), ifidx); - if (!dev) - return -ENODEV; - - rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); - if (IS_ERR(rdev)) { - err = PTR_ERR(rdev); - goto out_put_netdev; - } + err = nl80211_prepare_netdev_dump(skb, cb, &rdev, &dev); + if (err) + return err; wdev = dev->ieee80211_ptr; @@ -3068,21 +3059,17 @@ static int nl80211_dump_scan(struct sk_buff *skb, cb->nlh->nlmsg_seq, NLM_F_MULTI, rdev, wdev, scan) < 0) { idx--; - goto out; + break; } } - out: spin_unlock_bh(&rdev->bss_lock); wdev_unlock(wdev); cb->args[1] = idx; - err = skb->len; - cfg80211_unlock_rdev(rdev); - out_put_netdev: - dev_put(dev); + nl80211_finish_netdev_dump(rdev); - return err; + return skb->len; } static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, @@ -3130,29 +3117,12 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct survey_info survey; struct cfg80211_registered_device *dev; struct net_device *netdev; - int ifidx = cb->args[0]; int survey_idx = cb->args[1]; int res; - if (!ifidx) - ifidx = nl80211_get_ifidx(cb); - if (ifidx < 0) - return ifidx; - cb->args[0] = ifidx; - - rtnl_lock(); - - netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); - if (!netdev) { - res = -ENODEV; - goto out_rtnl; - } - - dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); - if (IS_ERR(dev)) { - res = PTR_ERR(dev); - goto out_rtnl; - } + res = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev); + if (res) + return res; if (!dev->ops->dump_survey) { res = -EOPNOTSUPP; @@ -3180,10 +3150,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, cb->args[1] = survey_idx; res = skb->len; out_err: - cfg80211_unlock_rdev(dev); - out_rtnl: - rtnl_unlock(); - + nl80211_finish_netdev_dump(dev); return res; } |