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; |