diff options
author | Johannes Berg <johannes.berg@intel.com> | 2012-06-15 18:19:54 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2012-08-20 07:58:21 -0400 |
commit | 98104fdeda63d57631c9f89e90a7b83b58fcee40 (patch) | |
tree | 22d0f75c2f369fd02695ea8051ddc68e6f8b8390 /net/wireless/nl80211.c | |
parent | cc74c0c7d6d623d0d3f13ef64895937edb7b3177 (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.c | 122 |
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 | ||
6839 | static 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 | |||
6872 | static 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 | ||
7445 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 7555 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |