aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-06-15 08:33:17 -0400
committerJohannes Berg <johannes.berg@intel.com>2012-07-09 08:51:46 -0400
commit89a54e48b9cbb44aed1bf6cd712e087b96b6ae65 (patch)
treef605a69704d49c5535adf2906b276ca2207a078f /net/wireless/nl80211.c
parentf72b85b8eb6657fae95ac8f5cb20954b4d87a520 (diff)
nl80211: prepare for non-netdev wireless devs
In order to support a P2P device abstraction and Bluetooth high-speed AMPs, we need to have a way to identify virtual interfaces that don't have a netdev associated. Do this by adding a NL80211_ATTR_WDEV attribute to identify a wdev which may or may not also be a netdev. To simplify things, use a 64-bit value with the high 32 bits being the wiphy index for this new wdev identifier in the nl80211 API. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c135
1 files changed, 108 insertions, 27 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 2a5cdb60bc6..35a9b15289f 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -46,28 +46,60 @@ static struct genl_family nl80211_fam = {
46 .post_doit = nl80211_post_doit, 46 .post_doit = nl80211_post_doit,
47}; 47};
48 48
49/* internal helper: get rdev and dev */ 49/* returns ERR_PTR values */
50static int get_rdev_dev_by_ifindex(struct net *netns, struct nlattr **attrs, 50static struct wireless_dev *
51 struct cfg80211_registered_device **rdev, 51__cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs)
52 struct net_device **dev)
53{ 52{
54 int ifindex; 53 struct cfg80211_registered_device *rdev;
54 struct wireless_dev *result = NULL;
55 bool have_ifidx = attrs[NL80211_ATTR_IFINDEX];
56 bool have_wdev_id = attrs[NL80211_ATTR_WDEV];
57 u64 wdev_id;
58 int wiphy_idx = -1;
59 int ifidx = -1;
55 60
56 if (!attrs[NL80211_ATTR_IFINDEX]) 61 assert_cfg80211_lock();
57 return -EINVAL;
58 62
59 ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); 63 if (!have_ifidx && !have_wdev_id)
60 *dev = dev_get_by_index(netns, ifindex); 64 return ERR_PTR(-EINVAL);
61 if (!*dev)
62 return -ENODEV;
63 65
64 *rdev = cfg80211_get_dev_from_ifindex(netns, ifindex); 66 if (have_ifidx)
65 if (IS_ERR(*rdev)) { 67 ifidx = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
66 dev_put(*dev); 68 if (have_wdev_id) {
67 return PTR_ERR(*rdev); 69 wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]);
70 wiphy_idx = wdev_id >> 32;
68 } 71 }
69 72
70 return 0; 73 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
74 struct wireless_dev *wdev;
75
76 if (wiphy_net(&rdev->wiphy) != netns)
77 continue;
78
79 if (have_wdev_id && rdev->wiphy_idx != wiphy_idx)
80 continue;
81
82 mutex_lock(&rdev->devlist_mtx);
83 list_for_each_entry(wdev, &rdev->wdev_list, list) {
84 if (have_ifidx && wdev->netdev &&
85 wdev->netdev->ifindex == ifidx) {
86 result = wdev;
87 break;
88 }
89 if (have_wdev_id && wdev->identifier == (u32)wdev_id) {
90 result = wdev;
91 break;
92 }
93 }
94 mutex_unlock(&rdev->devlist_mtx);
95
96 if (result)
97 break;
98 }
99
100 if (result)
101 return result;
102 return ERR_PTR(-ENODEV);
71} 103}
72 104
73static struct cfg80211_registered_device * 105static struct cfg80211_registered_device *
@@ -79,13 +111,40 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
79 assert_cfg80211_lock(); 111 assert_cfg80211_lock();
80 112
81 if (!attrs[NL80211_ATTR_WIPHY] && 113 if (!attrs[NL80211_ATTR_WIPHY] &&
82 !attrs[NL80211_ATTR_IFINDEX]) 114 !attrs[NL80211_ATTR_IFINDEX] &&
115 !attrs[NL80211_ATTR_WDEV])
83 return ERR_PTR(-EINVAL); 116 return ERR_PTR(-EINVAL);
84 117
85 if (attrs[NL80211_ATTR_WIPHY]) 118 if (attrs[NL80211_ATTR_WIPHY])
86 rdev = cfg80211_rdev_by_wiphy_idx( 119 rdev = cfg80211_rdev_by_wiphy_idx(
87 nla_get_u32(attrs[NL80211_ATTR_WIPHY])); 120 nla_get_u32(attrs[NL80211_ATTR_WIPHY]));
88 121
122 if (attrs[NL80211_ATTR_WDEV]) {
123 u64 wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]);
124 struct wireless_dev *wdev;
125 bool found = false;
126
127 tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32);
128 if (tmp) {
129 /* make sure wdev exists */
130 mutex_lock(&tmp->devlist_mtx);
131 list_for_each_entry(wdev, &tmp->wdev_list, list) {
132 if (wdev->identifier != (u32)wdev_id)
133 continue;
134 found = true;
135 break;
136 }
137 mutex_unlock(&tmp->devlist_mtx);
138
139 if (!found)
140 tmp = NULL;
141
142 if (rdev && tmp != rdev)
143 return ERR_PTR(-EINVAL);
144 rdev = tmp;
145 }
146 }
147
89 if (attrs[NL80211_ATTR_IFINDEX]) { 148 if (attrs[NL80211_ATTR_IFINDEX]) {
90 int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); 149 int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
91 netdev = dev_get_by_index(netns, ifindex); 150 netdev = dev_get_by_index(netns, ifindex);
@@ -294,6 +353,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
294 [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 }, 353 [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 },
295 [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 }, 354 [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 },
296 [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 }, 355 [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
356 [NL80211_ATTR_WDEV] = { .type = NLA_U64 },
297}; 357};
298 358
299/* policy for the key attributes */ 359/* policy for the key attributes */
@@ -1674,6 +1734,8 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
1674 struct net_device *dev) 1734 struct net_device *dev)
1675{ 1735{
1676 void *hdr; 1736 void *hdr;
1737 u64 wdev_id = (u64)dev->ieee80211_ptr->identifier |
1738 ((u64)rdev->wiphy_idx << 32);
1677 1739
1678 hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE); 1740 hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE);
1679 if (!hdr) 1741 if (!hdr)
@@ -1684,6 +1746,7 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
1684 nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) || 1746 nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) ||
1685 nla_put_u32(msg, NL80211_ATTR_IFTYPE, 1747 nla_put_u32(msg, NL80211_ATTR_IFTYPE,
1686 dev->ieee80211_ptr->iftype) || 1748 dev->ieee80211_ptr->iftype) ||
1749 nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id) ||
1687 nla_put_u32(msg, NL80211_ATTR_GENERATION, 1750 nla_put_u32(msg, NL80211_ATTR_GENERATION,
1688 rdev->devlist_generation ^ 1751 rdev->devlist_generation ^
1689 (cfg80211_rdev_list_generation << 2))) 1752 (cfg80211_rdev_list_generation << 2)))
@@ -1724,7 +1787,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
1724 if_idx = 0; 1787 if_idx = 0;
1725 1788
1726 mutex_lock(&rdev->devlist_mtx); 1789 mutex_lock(&rdev->devlist_mtx);
1727 list_for_each_entry(wdev, &rdev->netdev_list, list) { 1790 list_for_each_entry(wdev, &rdev->wdev_list, list) {
1728 if (if_idx < if_start) { 1791 if (if_idx < if_start) {
1729 if_idx++; 1792 if_idx++;
1730 continue; 1793 continue;
@@ -2350,7 +2413,7 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
2350 2413
2351 mutex_lock(&rdev->devlist_mtx); 2414 mutex_lock(&rdev->devlist_mtx);
2352 2415
2353 list_for_each_entry(wdev, &rdev->netdev_list, list) { 2416 list_for_each_entry(wdev, &rdev->wdev_list, list) {
2354 if (wdev->iftype != NL80211_IFTYPE_AP && 2417 if (wdev->iftype != NL80211_IFTYPE_AP &&
2355 wdev->iftype != NL80211_IFTYPE_P2P_GO) 2418 wdev->iftype != NL80211_IFTYPE_P2P_GO)
2356 continue; 2419 continue;
@@ -6660,8 +6723,8 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
6660 struct genl_info *info) 6723 struct genl_info *info)
6661{ 6724{
6662 struct cfg80211_registered_device *rdev; 6725 struct cfg80211_registered_device *rdev;
6726 struct wireless_dev *wdev;
6663 struct net_device *dev; 6727 struct net_device *dev;
6664 int err;
6665 bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL; 6728 bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL;
6666 6729
6667 if (rtnl) 6730 if (rtnl)
@@ -6676,21 +6739,39 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
6676 } 6739 }
6677 info->user_ptr[0] = rdev; 6740 info->user_ptr[0] = rdev;
6678 } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { 6741 } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
6679 err = get_rdev_dev_by_ifindex(genl_info_net(info), info->attrs, 6742 mutex_lock(&cfg80211_mutex);
6680 &rdev, &dev); 6743 wdev = __cfg80211_wdev_from_attrs(genl_info_net(info),
6681 if (err) { 6744 info->attrs);
6745 if (IS_ERR(wdev)) {
6746 mutex_unlock(&cfg80211_mutex);
6682 if (rtnl) 6747 if (rtnl)
6683 rtnl_unlock(); 6748 rtnl_unlock();
6684 return err; 6749 return PTR_ERR(wdev);
6685 } 6750 }
6751
6752 if (!wdev->netdev) {
6753 mutex_unlock(&cfg80211_mutex);
6754 if (rtnl)
6755 rtnl_unlock();
6756 return -EINVAL;
6757 }
6758
6759 dev = wdev->netdev;
6760 rdev = wiphy_to_dev(wdev->wiphy);
6761
6686 if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && 6762 if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
6687 !netif_running(dev)) { 6763 !netif_running(dev)) {
6688 cfg80211_unlock_rdev(rdev); 6764 mutex_unlock(&cfg80211_mutex);
6689 dev_put(dev);
6690 if (rtnl) 6765 if (rtnl)
6691 rtnl_unlock(); 6766 rtnl_unlock();
6692 return -ENETDOWN; 6767 return -ENETDOWN;
6693 } 6768 }
6769
6770 dev_hold(dev);
6771 cfg80211_lock_rdev(rdev);
6772
6773 mutex_unlock(&cfg80211_mutex);
6774
6694 info->user_ptr[0] = rdev; 6775 info->user_ptr[0] = rdev;
6695 info->user_ptr[1] = dev; 6776 info->user_ptr[1] = dev;
6696 } 6777 }
@@ -8483,7 +8564,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
8483 rcu_read_lock(); 8564 rcu_read_lock();
8484 8565
8485 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { 8566 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
8486 list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) 8567 list_for_each_entry_rcu(wdev, &rdev->wdev_list, list)
8487 cfg80211_mlme_unregister_socket(wdev, notify->pid); 8568 cfg80211_mlme_unregister_socket(wdev, notify->pid);
8488 if (rdev->ap_beacons_nlpid == notify->pid) 8569 if (rdev->ap_beacons_nlpid == notify->pid)
8489 rdev->ap_beacons_nlpid = 0; 8570 rdev->ap_beacons_nlpid = 0;