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 | |
| 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>
| -rw-r--r-- | include/linux/nl80211.h | 30 | ||||
| -rw-r--r-- | include/net/cfg80211.h | 40 | ||||
| -rw-r--r-- | net/mac80211/iface.c | 3 | ||||
| -rw-r--r-- | net/mac80211/util.c | 2 | ||||
| -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 |
9 files changed, 265 insertions, 20 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 2f3878806403..458416279347 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
| @@ -565,6 +565,14 @@ | |||
| 565 | * %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ with | 565 | * %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ with |
| 566 | * %NL80211_ATTR_WIPHY_CHANNEL_TYPE. | 566 | * %NL80211_ATTR_WIPHY_CHANNEL_TYPE. |
| 567 | * | 567 | * |
| 568 | * @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by | ||
| 569 | * its %NL80211_ATTR_WDEV identifier. It must have been created with | ||
| 570 | * %NL80211_CMD_NEW_INTERFACE previously. After it has been started, the | ||
| 571 | * P2P Device can be used for P2P operations, e.g. remain-on-channel and | ||
| 572 | * public action frame TX. | ||
| 573 | * @NL80211_CMD_STOP_P2P_DEVICE: Stop the given P2P Device, identified by | ||
| 574 | * its %NL80211_ATTR_WDEV identifier. | ||
| 575 | * | ||
| 568 | * @NL80211_CMD_MAX: highest used command number | 576 | * @NL80211_CMD_MAX: highest used command number |
| 569 | * @__NL80211_CMD_AFTER_LAST: internal use | 577 | * @__NL80211_CMD_AFTER_LAST: internal use |
| 570 | */ | 578 | */ |
| @@ -708,6 +716,9 @@ enum nl80211_commands { | |||
| 708 | 716 | ||
| 709 | NL80211_CMD_CH_SWITCH_NOTIFY, | 717 | NL80211_CMD_CH_SWITCH_NOTIFY, |
| 710 | 718 | ||
| 719 | NL80211_CMD_START_P2P_DEVICE, | ||
| 720 | NL80211_CMD_STOP_P2P_DEVICE, | ||
| 721 | |||
| 711 | /* add new commands above here */ | 722 | /* add new commands above here */ |
| 712 | 723 | ||
| 713 | /* used to define NL80211_CMD_MAX below */ | 724 | /* used to define NL80211_CMD_MAX below */ |
| @@ -1575,6 +1586,10 @@ enum nl80211_attrs { | |||
| 1575 | * @NL80211_IFTYPE_MESH_POINT: mesh point | 1586 | * @NL80211_IFTYPE_MESH_POINT: mesh point |
| 1576 | * @NL80211_IFTYPE_P2P_CLIENT: P2P client | 1587 | * @NL80211_IFTYPE_P2P_CLIENT: P2P client |
| 1577 | * @NL80211_IFTYPE_P2P_GO: P2P group owner | 1588 | * @NL80211_IFTYPE_P2P_GO: P2P group owner |
| 1589 | * @NL80211_IFTYPE_P2P_DEVICE: P2P device interface type, this is not a netdev | ||
| 1590 | * and therefore can't be created in the normal ways, use the | ||
| 1591 | * %NL80211_CMD_START_P2P_DEVICE and %NL80211_CMD_STOP_P2P_DEVICE | ||
| 1592 | * commands to create and destroy one | ||
| 1578 | * @NL80211_IFTYPE_MAX: highest interface type number currently defined | 1593 | * @NL80211_IFTYPE_MAX: highest interface type number currently defined |
| 1579 | * @NUM_NL80211_IFTYPES: number of defined interface types | 1594 | * @NUM_NL80211_IFTYPES: number of defined interface types |
| 1580 | * | 1595 | * |
| @@ -1593,6 +1608,7 @@ enum nl80211_iftype { | |||
| 1593 | NL80211_IFTYPE_MESH_POINT, | 1608 | NL80211_IFTYPE_MESH_POINT, |
| 1594 | NL80211_IFTYPE_P2P_CLIENT, | 1609 | NL80211_IFTYPE_P2P_CLIENT, |
| 1595 | NL80211_IFTYPE_P2P_GO, | 1610 | NL80211_IFTYPE_P2P_GO, |
| 1611 | NL80211_IFTYPE_P2P_DEVICE, | ||
| 1596 | 1612 | ||
| 1597 | /* keep last */ | 1613 | /* keep last */ |
| 1598 | NUM_NL80211_IFTYPES, | 1614 | NUM_NL80211_IFTYPES, |
| @@ -2994,12 +3010,18 @@ enum nl80211_ap_sme_features { | |||
| 2994 | * @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested | 3010 | * @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested |
| 2995 | * to work properly to suppport receiving regulatory hints from | 3011 | * to work properly to suppport receiving regulatory hints from |
| 2996 | * cellular base stations. | 3012 | * cellular base stations. |
| 3013 | * @NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL: If this is set, an active | ||
| 3014 | * P2P Device (%NL80211_IFTYPE_P2P_DEVICE) requires its own channel | ||
| 3015 | * in the interface combinations, even when it's only used for scan | ||
| 3016 | * and remain-on-channel. This could be due to, for example, the | ||
| 3017 | * remain-on-channel implementation requiring a channel context. | ||
| 2997 | */ | 3018 | */ |
| 2998 | enum nl80211_feature_flags { | 3019 | enum nl80211_feature_flags { |
| 2999 | NL80211_FEATURE_SK_TX_STATUS = 1 << 0, | 3020 | NL80211_FEATURE_SK_TX_STATUS = 1 << 0, |
| 3000 | NL80211_FEATURE_HT_IBSS = 1 << 1, | 3021 | NL80211_FEATURE_HT_IBSS = 1 << 1, |
| 3001 | NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2, | 3022 | NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2, |
| 3002 | NL80211_FEATURE_CELL_BASE_REG_HINTS = 1 << 3, | 3023 | NL80211_FEATURE_CELL_BASE_REG_HINTS = 1 << 3, |
| 3024 | NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL = 1 << 4, | ||
| 3003 | }; | 3025 | }; |
| 3004 | 3026 | ||
| 3005 | /** | 3027 | /** |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 493fa0c79005..4c518f1f1aca 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
| @@ -1437,7 +1437,8 @@ struct cfg80211_gtk_rekey_data { | |||
| 1437 | * @add_virtual_intf: create a new virtual interface with the given name, | 1437 | * @add_virtual_intf: create a new virtual interface with the given name, |
| 1438 | * must set the struct wireless_dev's iftype. Beware: You must create | 1438 | * must set the struct wireless_dev's iftype. Beware: You must create |
| 1439 | * the new netdev in the wiphy's network namespace! Returns the struct | 1439 | * the new netdev in the wiphy's network namespace! Returns the struct |
| 1440 | * wireless_dev, or an ERR_PTR. | 1440 | * wireless_dev, or an ERR_PTR. For P2P device wdevs, the driver must |
| 1441 | * also set the address member in the wdev. | ||
| 1441 | * | 1442 | * |
| 1442 | * @del_virtual_intf: remove the virtual interface | 1443 | * @del_virtual_intf: remove the virtual interface |
| 1443 | * | 1444 | * |
| @@ -1616,6 +1617,9 @@ struct cfg80211_gtk_rekey_data { | |||
| 1616 | * @get_channel: Get the current operating channel for the virtual interface. | 1617 | * @get_channel: Get the current operating channel for the virtual interface. |
| 1617 | * For monitor interfaces, it should return %NULL unless there's a single | 1618 | * For monitor interfaces, it should return %NULL unless there's a single |
| 1618 | * current monitoring channel. | 1619 | * current monitoring channel. |
| 1620 | * | ||
| 1621 | * @start_p2p_device: Start the given P2P device. | ||
| 1622 | * @stop_p2p_device: Stop the given P2P device. | ||
| 1619 | */ | 1623 | */ |
| 1620 | struct cfg80211_ops { | 1624 | struct cfg80211_ops { |
| 1621 | int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); | 1625 | int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); |
| @@ -1832,6 +1836,11 @@ struct cfg80211_ops { | |||
| 1832 | (*get_channel)(struct wiphy *wiphy, | 1836 | (*get_channel)(struct wiphy *wiphy, |
| 1833 | struct wireless_dev *wdev, | 1837 | struct wireless_dev *wdev, |
| 1834 | enum nl80211_channel_type *type); | 1838 | enum nl80211_channel_type *type); |
| 1839 | |||
| 1840 | int (*start_p2p_device)(struct wiphy *wiphy, | ||
| 1841 | struct wireless_dev *wdev); | ||
| 1842 | void (*stop_p2p_device)(struct wiphy *wiphy, | ||
| 1843 | struct wireless_dev *wdev); | ||
| 1835 | }; | 1844 | }; |
| 1836 | 1845 | ||
| 1837 | /* | 1846 | /* |
| @@ -2395,6 +2404,8 @@ struct cfg80211_cached_keys; | |||
| 2395 | * @cleanup_work: work struct used for cleanup that can't be done directly | 2404 | * @cleanup_work: work struct used for cleanup that can't be done directly |
| 2396 | * @beacon_interval: beacon interval used on this device for transmitting | 2405 | * @beacon_interval: beacon interval used on this device for transmitting |
| 2397 | * beacons, 0 when not valid | 2406 | * beacons, 0 when not valid |
| 2407 | * @address: The address for this device, valid only if @netdev is %NULL | ||
| 2408 | * @p2p_started: true if this is a P2P Device that has been started | ||
| 2398 | */ | 2409 | */ |
| 2399 | struct wireless_dev { | 2410 | struct wireless_dev { |
| 2400 | struct wiphy *wiphy; | 2411 | struct wiphy *wiphy; |
| @@ -2413,7 +2424,9 @@ struct wireless_dev { | |||
| 2413 | 2424 | ||
| 2414 | struct work_struct cleanup_work; | 2425 | struct work_struct cleanup_work; |
| 2415 | 2426 | ||
| 2416 | bool use_4addr; | 2427 | bool use_4addr, p2p_started; |
| 2428 | |||
| 2429 | u8 address[ETH_ALEN] __aligned(sizeof(u16)); | ||
| 2417 | 2430 | ||
| 2418 | /* currently used for IBSS and SME - might be rearranged later */ | 2431 | /* currently used for IBSS and SME - might be rearranged later */ |
| 2419 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | 2432 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
| @@ -2461,6 +2474,13 @@ struct wireless_dev { | |||
| 2461 | #endif | 2474 | #endif |
| 2462 | }; | 2475 | }; |
| 2463 | 2476 | ||
| 2477 | static inline u8 *wdev_address(struct wireless_dev *wdev) | ||
| 2478 | { | ||
| 2479 | if (wdev->netdev) | ||
| 2480 | return wdev->netdev->dev_addr; | ||
| 2481 | return wdev->address; | ||
| 2482 | } | ||
| 2483 | |||
| 2464 | /** | 2484 | /** |
| 2465 | * wdev_priv - return wiphy priv from wireless_dev | 2485 | * wdev_priv - return wiphy priv from wireless_dev |
| 2466 | * | 2486 | * |
| @@ -3528,6 +3548,22 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq, | |||
| 3528 | */ | 3548 | */ |
| 3529 | u32 cfg80211_calculate_bitrate(struct rate_info *rate); | 3549 | u32 cfg80211_calculate_bitrate(struct rate_info *rate); |
| 3530 | 3550 | ||
| 3551 | /** | ||
| 3552 | * cfg80211_unregister_wdev - remove the given wdev | ||
| 3553 | * @wdev: struct wireless_dev to remove | ||
| 3554 | * | ||
| 3555 | * Call this function only for wdevs that have no netdev assigned, | ||
| 3556 | * e.g. P2P Devices. It removes the device from the list so that | ||
| 3557 | * it can no longer be used. It is necessary to call this function | ||
| 3558 | * even when cfg80211 requests the removal of the interface by | ||
| 3559 | * calling the del_virtual_intf() callback. The function must also | ||
| 3560 | * be called when the driver wishes to unregister the wdev, e.g. | ||
| 3561 | * when the device is unbound from the driver. | ||
| 3562 | * | ||
| 3563 | * Requires the RTNL to be held. | ||
| 3564 | */ | ||
| 3565 | void cfg80211_unregister_wdev(struct wireless_dev *wdev); | ||
| 3566 | |||
| 3531 | /* Logging, debugging and troubleshooting/diagnostic helpers. */ | 3567 | /* Logging, debugging and troubleshooting/diagnostic helpers. */ |
| 3532 | 3568 | ||
| 3533 | /* wiphy_printk helpers, similar to dev_printk */ | 3569 | /* wiphy_printk helpers, similar to dev_printk */ |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index fbab7a84ca21..366d9d3e84c4 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
| @@ -449,6 +449,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
| 449 | case NUM_NL80211_IFTYPES: | 449 | case NUM_NL80211_IFTYPES: |
| 450 | case NL80211_IFTYPE_P2P_CLIENT: | 450 | case NL80211_IFTYPE_P2P_CLIENT: |
| 451 | case NL80211_IFTYPE_P2P_GO: | 451 | case NL80211_IFTYPE_P2P_GO: |
| 452 | case NL80211_IFTYPE_P2P_DEVICE: | ||
| 452 | /* cannot happen */ | 453 | /* cannot happen */ |
| 453 | WARN_ON(1); | 454 | WARN_ON(1); |
| 454 | break; | 455 | break; |
| @@ -1146,6 +1147,8 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
| 1146 | case NL80211_IFTYPE_WDS: | 1147 | case NL80211_IFTYPE_WDS: |
| 1147 | case NL80211_IFTYPE_AP_VLAN: | 1148 | case NL80211_IFTYPE_AP_VLAN: |
| 1148 | break; | 1149 | break; |
| 1150 | case NL80211_IFTYPE_P2P_DEVICE: | ||
| 1151 | /* not yet supported */ | ||
| 1149 | case NL80211_IFTYPE_UNSPECIFIED: | 1152 | case NL80211_IFTYPE_UNSPECIFIED: |
| 1150 | case NUM_NL80211_IFTYPES: | 1153 | case NUM_NL80211_IFTYPES: |
| 1151 | BUG(); | 1154 | BUG(); |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 7dff94e43a0c..9a4e4e30ea6c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
| @@ -1390,6 +1390,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1390 | case NL80211_IFTYPE_MONITOR: | 1390 | case NL80211_IFTYPE_MONITOR: |
| 1391 | /* ignore virtual */ | 1391 | /* ignore virtual */ |
| 1392 | break; | 1392 | break; |
| 1393 | case NL80211_IFTYPE_P2P_DEVICE: | ||
| 1394 | /* not yet supported */ | ||
| 1393 | case NL80211_IFTYPE_UNSPECIFIED: | 1395 | case NL80211_IFTYPE_UNSPECIFIED: |
| 1394 | case NUM_NL80211_IFTYPES: | 1396 | case NUM_NL80211_IFTYPES: |
| 1395 | case NL80211_IFTYPE_P2P_CLIENT: | 1397 | case NL80211_IFTYPE_P2P_CLIENT: |
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; |
