aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-06-15 18:19:54 -0400
committerJohannes Berg <johannes.berg@intel.com>2012-08-20 07:58:21 -0400
commit98104fdeda63d57631c9f89e90a7b83b58fcee40 (patch)
tree22d0f75c2f369fd02695ea8051ddc68e6f8b8390 /net/wireless/nl80211.c
parentcc74c0c7d6d623d0d3f13ef64895937edb7b3177 (diff)
cfg80211: add P2P Device abstraction
In order to support using a different MAC address for the P2P Device address we must first have a P2P Device abstraction that can be assigned a MAC address. This abstraction will also be useful to support offloading P2P operations to the device, e.g. periodic listen for discoverability. Currently, the driver is responsible for assigning a MAC address to the P2P Device, but this could be changed by allowing a MAC address to be given to the NEW_INTERFACE command. As it has no associated netdev, a P2P Device can only be identified by its wdev identifier but the previous patches allowed using the wdev identifier in various APIs, e.g. remain-on-channel. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c122
1 files changed, 116 insertions, 6 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 97026f3b215a..787aeaa902fe 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1100,6 +1100,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
1100 if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS)) 1100 if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS))
1101 goto nla_put_failure; 1101 goto nla_put_failure;
1102 } 1102 }
1103 CMD(start_p2p_device, START_P2P_DEVICE);
1103 1104
1104#ifdef CONFIG_NL80211_TESTMODE 1105#ifdef CONFIG_NL80211_TESTMODE
1105 CMD(testmode_cmd, TESTMODE); 1106 CMD(testmode_cmd, TESTMODE);
@@ -1748,13 +1749,13 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
1748 1749
1749 if (dev && 1750 if (dev &&
1750 (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || 1751 (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
1751 nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) || 1752 nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name)))
1752 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dev->dev_addr)))
1753 goto nla_put_failure; 1753 goto nla_put_failure;
1754 1754
1755 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || 1755 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
1756 nla_put_u32(msg, NL80211_ATTR_IFTYPE, wdev->iftype) || 1756 nla_put_u32(msg, NL80211_ATTR_IFTYPE, wdev->iftype) ||
1757 nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) || 1757 nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) ||
1758 nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, wdev_address(wdev)) ||
1758 nla_put_u32(msg, NL80211_ATTR_GENERATION, 1759 nla_put_u32(msg, NL80211_ATTR_GENERATION,
1759 rdev->devlist_generation ^ 1760 rdev->devlist_generation ^
1760 (cfg80211_rdev_list_generation << 2))) 1761 (cfg80211_rdev_list_generation << 2)))
@@ -2021,8 +2022,10 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
2021 return PTR_ERR(wdev); 2022 return PTR_ERR(wdev);
2022 } 2023 }
2023 2024
2024 if (type == NL80211_IFTYPE_MESH_POINT && 2025 switch (type) {
2025 info->attrs[NL80211_ATTR_MESH_ID]) { 2026 case NL80211_IFTYPE_MESH_POINT:
2027 if (!info->attrs[NL80211_ATTR_MESH_ID])
2028 break;
2026 wdev_lock(wdev); 2029 wdev_lock(wdev);
2027 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != 2030 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
2028 IEEE80211_MAX_MESH_ID_LEN); 2031 IEEE80211_MAX_MESH_ID_LEN);
@@ -2031,6 +2034,26 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
2031 memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]), 2034 memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
2032 wdev->mesh_id_up_len); 2035 wdev->mesh_id_up_len);
2033 wdev_unlock(wdev); 2036 wdev_unlock(wdev);
2037 break;
2038 case NL80211_IFTYPE_P2P_DEVICE:
2039 /*
2040 * P2P Device doesn't have a netdev, so doesn't go
2041 * through the netdev notifier and must be added here
2042 */
2043 mutex_init(&wdev->mtx);
2044 INIT_LIST_HEAD(&wdev->event_list);
2045 spin_lock_init(&wdev->event_lock);
2046 INIT_LIST_HEAD(&wdev->mgmt_registrations);
2047 spin_lock_init(&wdev->mgmt_registrations_lock);
2048
2049 mutex_lock(&rdev->devlist_mtx);
2050 wdev->identifier = ++rdev->wdev_id;
2051 list_add_rcu(&wdev->list, &rdev->wdev_list);
2052 rdev->devlist_generation++;
2053 mutex_unlock(&rdev->devlist_mtx);
2054 break;
2055 default:
2056 break;
2034 } 2057 }
2035 2058
2036 if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, 2059 if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0,
@@ -6053,6 +6076,7 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
6053 case NL80211_IFTYPE_AP_VLAN: 6076 case NL80211_IFTYPE_AP_VLAN:
6054 case NL80211_IFTYPE_MESH_POINT: 6077 case NL80211_IFTYPE_MESH_POINT:
6055 case NL80211_IFTYPE_P2P_GO: 6078 case NL80211_IFTYPE_P2P_GO:
6079 case NL80211_IFTYPE_P2P_DEVICE:
6056 break; 6080 break;
6057 default: 6081 default:
6058 return -EOPNOTSUPP; 6082 return -EOPNOTSUPP;
@@ -6099,6 +6123,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
6099 case NL80211_IFTYPE_AP_VLAN: 6123 case NL80211_IFTYPE_AP_VLAN:
6100 case NL80211_IFTYPE_MESH_POINT: 6124 case NL80211_IFTYPE_MESH_POINT:
6101 case NL80211_IFTYPE_P2P_GO: 6125 case NL80211_IFTYPE_P2P_GO:
6126 case NL80211_IFTYPE_P2P_DEVICE:
6102 break; 6127 break;
6103 default: 6128 default:
6104 return -EOPNOTSUPP; 6129 return -EOPNOTSUPP;
@@ -6195,6 +6220,7 @@ static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *in
6195 case NL80211_IFTYPE_AP: 6220 case NL80211_IFTYPE_AP:
6196 case NL80211_IFTYPE_AP_VLAN: 6221 case NL80211_IFTYPE_AP_VLAN:
6197 case NL80211_IFTYPE_P2P_GO: 6222 case NL80211_IFTYPE_P2P_GO:
6223 case NL80211_IFTYPE_P2P_DEVICE:
6198 break; 6224 break;
6199 default: 6225 default:
6200 return -EOPNOTSUPP; 6226 return -EOPNOTSUPP;
@@ -6810,6 +6836,68 @@ static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
6810 return 0; 6836 return 0;
6811} 6837}
6812 6838
6839static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
6840{
6841 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6842 struct wireless_dev *wdev = info->user_ptr[1];
6843 int err;
6844
6845 if (!rdev->ops->start_p2p_device)
6846 return -EOPNOTSUPP;
6847
6848 if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
6849 return -EOPNOTSUPP;
6850
6851 if (wdev->p2p_started)
6852 return 0;
6853
6854 mutex_lock(&rdev->devlist_mtx);
6855 err = cfg80211_can_add_interface(rdev, wdev->iftype);
6856 mutex_unlock(&rdev->devlist_mtx);
6857 if (err)
6858 return err;
6859
6860 err = rdev->ops->start_p2p_device(&rdev->wiphy, wdev);
6861 if (err)
6862 return err;
6863
6864 wdev->p2p_started = true;
6865 mutex_lock(&rdev->devlist_mtx);
6866 rdev->opencount++;
6867 mutex_unlock(&rdev->devlist_mtx);
6868
6869 return 0;
6870}
6871
6872static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info)
6873{
6874 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6875 struct wireless_dev *wdev = info->user_ptr[1];
6876
6877 if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
6878 return -EOPNOTSUPP;
6879
6880 if (!rdev->ops->stop_p2p_device)
6881 return -EOPNOTSUPP;
6882
6883 if (!wdev->p2p_started)
6884 return 0;
6885
6886 rdev->ops->stop_p2p_device(&rdev->wiphy, wdev);
6887 wdev->p2p_started = false;
6888
6889 mutex_lock(&rdev->devlist_mtx);
6890 rdev->opencount--;
6891 mutex_unlock(&rdev->devlist_mtx);
6892
6893 if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) {
6894 rdev->scan_req->aborted = true;
6895 ___cfg80211_scan_done(rdev, true);
6896 }
6897
6898 return 0;
6899}
6900
6813#define NL80211_FLAG_NEED_WIPHY 0x01 6901#define NL80211_FLAG_NEED_WIPHY 0x01
6814#define NL80211_FLAG_NEED_NETDEV 0x02 6902#define NL80211_FLAG_NEED_NETDEV 0x02
6815#define NL80211_FLAG_NEED_RTNL 0x04 6903#define NL80211_FLAG_NEED_RTNL 0x04
@@ -6817,7 +6905,7 @@ static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
6817#define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\ 6905#define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\
6818 NL80211_FLAG_CHECK_NETDEV_UP) 6906 NL80211_FLAG_CHECK_NETDEV_UP)
6819#define NL80211_FLAG_NEED_WDEV 0x10 6907#define NL80211_FLAG_NEED_WDEV 0x10
6820/* If a netdev is associated, it must be UP */ 6908/* If a netdev is associated, it must be UP, P2P must be started */
6821#define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\ 6909#define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\
6822 NL80211_FLAG_CHECK_NETDEV_UP) 6910 NL80211_FLAG_CHECK_NETDEV_UP)
6823 6911
@@ -6878,6 +6966,13 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
6878 } 6966 }
6879 6967
6880 dev_hold(dev); 6968 dev_hold(dev);
6969 } else if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP) {
6970 if (!wdev->p2p_started) {
6971 mutex_unlock(&cfg80211_mutex);
6972 if (rtnl)
6973 rtnl_unlock();
6974 return -ENETDOWN;
6975 }
6881 } 6976 }
6882 6977
6883 cfg80211_lock_rdev(rdev); 6978 cfg80211_lock_rdev(rdev);
@@ -7439,7 +7534,22 @@ static struct genl_ops nl80211_ops[] = {
7439 .internal_flags = NL80211_FLAG_NEED_NETDEV | 7534 .internal_flags = NL80211_FLAG_NEED_NETDEV |
7440 NL80211_FLAG_NEED_RTNL, 7535 NL80211_FLAG_NEED_RTNL,
7441 }, 7536 },
7442 7537 {
7538 .cmd = NL80211_CMD_START_P2P_DEVICE,
7539 .doit = nl80211_start_p2p_device,
7540 .policy = nl80211_policy,
7541 .flags = GENL_ADMIN_PERM,
7542 .internal_flags = NL80211_FLAG_NEED_WDEV |
7543 NL80211_FLAG_NEED_RTNL,
7544 },
7545 {
7546 .cmd = NL80211_CMD_STOP_P2P_DEVICE,
7547 .doit = nl80211_stop_p2p_device,
7548 .policy = nl80211_policy,
7549 .flags = GENL_ADMIN_PERM,
7550 .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
7551 NL80211_FLAG_NEED_RTNL,
7552 },
7443}; 7553};
7444 7554
7445static struct genl_multicast_group nl80211_mlme_mcgrp = { 7555static struct genl_multicast_group nl80211_mlme_mcgrp = {