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 | |
| 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')
| -rw-r--r-- | net/wireless/chan.c | 7 | ||||
| -rw-r--r-- | net/wireless/core.c | 53 | ||||
| -rw-r--r-- | net/wireless/mlme.c | 10 | ||||
| -rw-r--r-- | net/wireless/nl80211.c | 122 | ||||
| -rw-r--r-- | net/wireless/util.c | 18 |
5 files changed, 196 insertions, 14 deletions
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index d355f67d0cdd..2f876b9ee344 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
| @@ -105,7 +105,7 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, | |||
| 105 | 105 | ||
| 106 | ASSERT_WDEV_LOCK(wdev); | 106 | ASSERT_WDEV_LOCK(wdev); |
| 107 | 107 | ||
| 108 | if (!netif_running(wdev->netdev)) | 108 | if (wdev->netdev && !netif_running(wdev->netdev)) |
| 109 | return; | 109 | return; |
| 110 | 110 | ||
| 111 | switch (wdev->iftype) { | 111 | switch (wdev->iftype) { |
| @@ -143,6 +143,11 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, | |||
| 143 | case NL80211_IFTYPE_WDS: | 143 | case NL80211_IFTYPE_WDS: |
| 144 | /* these interface types don't really have a channel */ | 144 | /* these interface types don't really have a channel */ |
| 145 | return; | 145 | return; |
| 146 | case NL80211_IFTYPE_P2P_DEVICE: | ||
| 147 | if (wdev->wiphy->features & | ||
| 148 | NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL) | ||
| 149 | *chanmode = CHAN_MODE_EXCLUSIVE; | ||
| 150 | return; | ||
| 146 | case NL80211_IFTYPE_UNSPECIFIED: | 151 | case NL80211_IFTYPE_UNSPECIFIED: |
| 147 | case NUM_NL80211_IFTYPES: | 152 | case NUM_NL80211_IFTYPES: |
| 148 | WARN_ON(1); | 153 | WARN_ON(1); |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 31b40cc4a9c3..91b300443f4b 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
| @@ -230,9 +230,24 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked) | |||
| 230 | rtnl_lock(); | 230 | rtnl_lock(); |
| 231 | mutex_lock(&rdev->devlist_mtx); | 231 | mutex_lock(&rdev->devlist_mtx); |
| 232 | 232 | ||
| 233 | list_for_each_entry(wdev, &rdev->wdev_list, list) | 233 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
| 234 | if (wdev->netdev) | 234 | if (wdev->netdev) { |
| 235 | dev_close(wdev->netdev); | 235 | dev_close(wdev->netdev); |
| 236 | continue; | ||
| 237 | } | ||
| 238 | /* otherwise, check iftype */ | ||
| 239 | switch (wdev->iftype) { | ||
| 240 | case NL80211_IFTYPE_P2P_DEVICE: | ||
| 241 | if (!wdev->p2p_started) | ||
| 242 | break; | ||
| 243 | rdev->ops->stop_p2p_device(&rdev->wiphy, wdev); | ||
| 244 | wdev->p2p_started = false; | ||
| 245 | rdev->opencount--; | ||
| 246 | break; | ||
| 247 | default: | ||
| 248 | break; | ||
| 249 | } | ||
| 250 | } | ||
| 236 | 251 | ||
| 237 | mutex_unlock(&rdev->devlist_mtx); | 252 | mutex_unlock(&rdev->devlist_mtx); |
| 238 | rtnl_unlock(); | 253 | rtnl_unlock(); |
| @@ -407,6 +422,11 @@ static int wiphy_verify_combinations(struct wiphy *wiphy) | |||
| 407 | if (WARN_ON(wiphy->software_iftypes & types)) | 422 | if (WARN_ON(wiphy->software_iftypes & types)) |
| 408 | return -EINVAL; | 423 | return -EINVAL; |
| 409 | 424 | ||
| 425 | /* Only a single P2P_DEVICE can be allowed */ | ||
| 426 | if (WARN_ON(types & BIT(NL80211_IFTYPE_P2P_DEVICE) && | ||
| 427 | c->limits[j].max > 1)) | ||
| 428 | return -EINVAL; | ||
| 429 | |||
| 410 | cnt += c->limits[j].max; | 430 | cnt += c->limits[j].max; |
| 411 | /* | 431 | /* |
| 412 | * Don't advertise an unsupported type | 432 | * Don't advertise an unsupported type |
| @@ -734,6 +754,35 @@ static void wdev_cleanup_work(struct work_struct *work) | |||
| 734 | dev_put(wdev->netdev); | 754 | dev_put(wdev->netdev); |
| 735 | } | 755 | } |
| 736 | 756 | ||
| 757 | void cfg80211_unregister_wdev(struct wireless_dev *wdev) | ||
| 758 | { | ||
| 759 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
| 760 | |||
| 761 | ASSERT_RTNL(); | ||
| 762 | |||
| 763 | if (WARN_ON(wdev->netdev)) | ||
| 764 | return; | ||
| 765 | |||
| 766 | mutex_lock(&rdev->devlist_mtx); | ||
| 767 | list_del_rcu(&wdev->list); | ||
| 768 | rdev->devlist_generation++; | ||
| 769 | |||
| 770 | switch (wdev->iftype) { | ||
| 771 | case NL80211_IFTYPE_P2P_DEVICE: | ||
| 772 | if (!wdev->p2p_started) | ||
| 773 | break; | ||
| 774 | rdev->ops->stop_p2p_device(&rdev->wiphy, wdev); | ||
| 775 | wdev->p2p_started = false; | ||
| 776 | rdev->opencount--; | ||
| 777 | break; | ||
| 778 | default: | ||
| 779 | WARN_ON_ONCE(1); | ||
| 780 | break; | ||
| 781 | } | ||
| 782 | mutex_unlock(&rdev->devlist_mtx); | ||
| 783 | } | ||
| 784 | EXPORT_SYMBOL(cfg80211_unregister_wdev); | ||
| 785 | |||
| 737 | static struct device_type wiphy_type = { | 786 | static struct device_type wiphy_type = { |
| 738 | .name = "wlan", | 787 | .name = "wlan", |
| 739 | }; | 788 | }; |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 1cdb1d5e6b0f..8fd0242ee169 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
| @@ -736,7 +736,6 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | |||
| 736 | const u8 *buf, size_t len, bool no_cck, | 736 | const u8 *buf, size_t len, bool no_cck, |
| 737 | bool dont_wait_for_ack, u64 *cookie) | 737 | bool dont_wait_for_ack, u64 *cookie) |
| 738 | { | 738 | { |
| 739 | struct net_device *dev = wdev->netdev; | ||
| 740 | const struct ieee80211_mgmt *mgmt; | 739 | const struct ieee80211_mgmt *mgmt; |
| 741 | u16 stype; | 740 | u16 stype; |
| 742 | 741 | ||
| @@ -796,7 +795,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | |||
| 796 | case NL80211_IFTYPE_AP: | 795 | case NL80211_IFTYPE_AP: |
| 797 | case NL80211_IFTYPE_P2P_GO: | 796 | case NL80211_IFTYPE_P2P_GO: |
| 798 | case NL80211_IFTYPE_AP_VLAN: | 797 | case NL80211_IFTYPE_AP_VLAN: |
| 799 | if (!ether_addr_equal(mgmt->bssid, dev->dev_addr)) | 798 | if (!ether_addr_equal(mgmt->bssid, wdev_address(wdev))) |
| 800 | err = -EINVAL; | 799 | err = -EINVAL; |
| 801 | break; | 800 | break; |
| 802 | case NL80211_IFTYPE_MESH_POINT: | 801 | case NL80211_IFTYPE_MESH_POINT: |
| @@ -809,6 +808,11 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | |||
| 809 | * cfg80211 doesn't track the stations | 808 | * cfg80211 doesn't track the stations |
| 810 | */ | 809 | */ |
| 811 | break; | 810 | break; |
| 811 | case NL80211_IFTYPE_P2P_DEVICE: | ||
| 812 | /* | ||
| 813 | * fall through, P2P device only supports | ||
| 814 | * public action frames | ||
| 815 | */ | ||
| 812 | default: | 816 | default: |
| 813 | err = -EOPNOTSUPP; | 817 | err = -EOPNOTSUPP; |
| 814 | break; | 818 | break; |
| @@ -819,7 +823,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | |||
| 819 | return err; | 823 | return err; |
| 820 | } | 824 | } |
| 821 | 825 | ||
| 822 | if (!ether_addr_equal(mgmt->sa, dev->dev_addr)) | 826 | if (!ether_addr_equal(mgmt->sa, wdev_address(wdev))) |
| 823 | return -EINVAL; | 827 | return -EINVAL; |
| 824 | 828 | ||
| 825 | /* Transmit the Action frame as requested by user space */ | 829 | /* Transmit the Action frame as requested by user space */ |
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 = { |
diff --git a/net/wireless/util.c b/net/wireless/util.c index ce393dd8c928..d7b672262b5f 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
| @@ -800,6 +800,10 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
| 800 | if (otype == NL80211_IFTYPE_AP_VLAN) | 800 | if (otype == NL80211_IFTYPE_AP_VLAN) |
| 801 | return -EOPNOTSUPP; | 801 | return -EOPNOTSUPP; |
| 802 | 802 | ||
| 803 | /* cannot change into P2P device type */ | ||
| 804 | if (ntype == NL80211_IFTYPE_P2P_DEVICE) | ||
| 805 | return -EOPNOTSUPP; | ||
| 806 | |||
| 803 | if (!rdev->ops->change_virtual_intf || | 807 | if (!rdev->ops->change_virtual_intf || |
| 804 | !(rdev->wiphy.interface_modes & (1 << ntype))) | 808 | !(rdev->wiphy.interface_modes & (1 << ntype))) |
| 805 | return -EOPNOTSUPP; | 809 | return -EOPNOTSUPP; |
| @@ -877,6 +881,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
| 877 | case NUM_NL80211_IFTYPES: | 881 | case NUM_NL80211_IFTYPES: |
| 878 | /* not happening */ | 882 | /* not happening */ |
| 879 | break; | 883 | break; |
| 884 | case NL80211_IFTYPE_P2P_DEVICE: | ||
| 885 | WARN_ON(1); | ||
| 886 | break; | ||
| 880 | } | 887 | } |
| 881 | } | 888 | } |
| 882 | 889 | ||
| @@ -1041,8 +1048,15 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, | |||
| 1041 | list_for_each_entry(wdev_iter, &rdev->wdev_list, list) { | 1048 | list_for_each_entry(wdev_iter, &rdev->wdev_list, list) { |
| 1042 | if (wdev_iter == wdev) | 1049 | if (wdev_iter == wdev) |
| 1043 | continue; | 1050 | continue; |
| 1044 | if (!netif_running(wdev_iter->netdev)) | 1051 | if (wdev_iter->netdev) { |
| 1045 | continue; | 1052 | if (!netif_running(wdev_iter->netdev)) |
| 1053 | continue; | ||
| 1054 | } else if (wdev_iter->iftype == NL80211_IFTYPE_P2P_DEVICE) { | ||
| 1055 | if (!wdev_iter->p2p_started) | ||
| 1056 | continue; | ||
| 1057 | } else { | ||
| 1058 | WARN_ON(1); | ||
| 1059 | } | ||
| 1046 | 1060 | ||
| 1047 | if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype)) | 1061 | if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype)) |
| 1048 | continue; | 1062 | continue; |
