diff options
author | David S. Miller <davem@davemloft.net> | 2016-10-04 20:14:07 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-10-04 20:14:07 -0400 |
commit | 1ebf8b42b1f6da380f70990234c119f4d63905c9 (patch) | |
tree | 81c8883606ed2dd821f4509581888505d48631dd | |
parent | 9a8dd213d2a38349e5ea2ca8888400952112b45c (diff) | |
parent | 1e1430d5282bc3a572465ef3261eea793d98a653 (diff) |
Merge tag 'mac80211-next-for-davem-2016-10-04' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Johannes Berg says:
====================
This time around, we have
* Neighbor Awareness Networking (NAN) APIs
* a fix for a previous patch that caused memory corruption
in wireless extensions key settings
* beacon rate configuration for AP and mesh
* memory limits for mac80211's internal TXQs
* a (fairly involved) fix for the TXQ vs. crypto problems
* direct cfg80211 driver API for WEP keys
This also pulls in net-next to fix the merge conflicts, see
the merge commit for more details.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
33 files changed, 2660 insertions, 411 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index bd26cc6e2d79..fe78f02a242e 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> | 6 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> |
7 | * Copyright 2013-2014 Intel Mobile Communications GmbH | 7 | * Copyright 2013-2014 Intel Mobile Communications GmbH |
8 | * Copyright 2015 Intel Deutschland GmbH | 8 | * Copyright 2015-2016 Intel Deutschland GmbH |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
@@ -593,6 +593,8 @@ struct survey_info { | |||
593 | s8 noise; | 593 | s8 noise; |
594 | }; | 594 | }; |
595 | 595 | ||
596 | #define CFG80211_MAX_WEP_KEYS 4 | ||
597 | |||
596 | /** | 598 | /** |
597 | * struct cfg80211_crypto_settings - Crypto settings | 599 | * struct cfg80211_crypto_settings - Crypto settings |
598 | * @wpa_versions: indicates which, if any, WPA versions are enabled | 600 | * @wpa_versions: indicates which, if any, WPA versions are enabled |
@@ -610,6 +612,9 @@ struct survey_info { | |||
610 | * allowed through even on unauthorized ports | 612 | * allowed through even on unauthorized ports |
611 | * @control_port_no_encrypt: TRUE to prevent encryption of control port | 613 | * @control_port_no_encrypt: TRUE to prevent encryption of control port |
612 | * protocol frames. | 614 | * protocol frames. |
615 | * @wep_keys: static WEP keys, if not NULL points to an array of | ||
616 | * CFG80211_MAX_WEP_KEYS WEP keys | ||
617 | * @wep_tx_key: key index (0..3) of the default TX static WEP key | ||
613 | */ | 618 | */ |
614 | struct cfg80211_crypto_settings { | 619 | struct cfg80211_crypto_settings { |
615 | u32 wpa_versions; | 620 | u32 wpa_versions; |
@@ -621,6 +626,8 @@ struct cfg80211_crypto_settings { | |||
621 | bool control_port; | 626 | bool control_port; |
622 | __be16 control_port_ethertype; | 627 | __be16 control_port_ethertype; |
623 | bool control_port_no_encrypt; | 628 | bool control_port_no_encrypt; |
629 | struct key_params *wep_keys; | ||
630 | int wep_tx_key; | ||
624 | }; | 631 | }; |
625 | 632 | ||
626 | /** | 633 | /** |
@@ -676,6 +683,18 @@ struct cfg80211_acl_data { | |||
676 | struct mac_address mac_addrs[]; | 683 | struct mac_address mac_addrs[]; |
677 | }; | 684 | }; |
678 | 685 | ||
686 | /* | ||
687 | * cfg80211_bitrate_mask - masks for bitrate control | ||
688 | */ | ||
689 | struct cfg80211_bitrate_mask { | ||
690 | struct { | ||
691 | u32 legacy; | ||
692 | u8 ht_mcs[IEEE80211_HT_MCS_MASK_LEN]; | ||
693 | u16 vht_mcs[NL80211_VHT_NSS_MAX]; | ||
694 | enum nl80211_txrate_gi gi; | ||
695 | } control[NUM_NL80211_BANDS]; | ||
696 | }; | ||
697 | |||
679 | /** | 698 | /** |
680 | * struct cfg80211_ap_settings - AP configuration | 699 | * struct cfg80211_ap_settings - AP configuration |
681 | * | 700 | * |
@@ -700,6 +719,7 @@ struct cfg80211_acl_data { | |||
700 | * MAC address based access control | 719 | * MAC address based access control |
701 | * @pbss: If set, start as a PCP instead of AP. Relevant for DMG | 720 | * @pbss: If set, start as a PCP instead of AP. Relevant for DMG |
702 | * networks. | 721 | * networks. |
722 | * @beacon_rate: bitrate to be used for beacons | ||
703 | */ | 723 | */ |
704 | struct cfg80211_ap_settings { | 724 | struct cfg80211_ap_settings { |
705 | struct cfg80211_chan_def chandef; | 725 | struct cfg80211_chan_def chandef; |
@@ -719,6 +739,7 @@ struct cfg80211_ap_settings { | |||
719 | bool p2p_opp_ps; | 739 | bool p2p_opp_ps; |
720 | const struct cfg80211_acl_data *acl; | 740 | const struct cfg80211_acl_data *acl; |
721 | bool pbss; | 741 | bool pbss; |
742 | struct cfg80211_bitrate_mask beacon_rate; | ||
722 | }; | 743 | }; |
723 | 744 | ||
724 | /** | 745 | /** |
@@ -1351,6 +1372,7 @@ struct mesh_config { | |||
1351 | * @beacon_interval: beacon interval to use | 1372 | * @beacon_interval: beacon interval to use |
1352 | * @mcast_rate: multicat rate for Mesh Node [6Mbps is the default for 802.11a] | 1373 | * @mcast_rate: multicat rate for Mesh Node [6Mbps is the default for 802.11a] |
1353 | * @basic_rates: basic rates to use when creating the mesh | 1374 | * @basic_rates: basic rates to use when creating the mesh |
1375 | * @beacon_rate: bitrate to be used for beacons | ||
1354 | * | 1376 | * |
1355 | * These parameters are fixed when the mesh is created. | 1377 | * These parameters are fixed when the mesh is created. |
1356 | */ | 1378 | */ |
@@ -1371,6 +1393,7 @@ struct mesh_setup { | |||
1371 | u16 beacon_interval; | 1393 | u16 beacon_interval; |
1372 | int mcast_rate[NUM_NL80211_BANDS]; | 1394 | int mcast_rate[NUM_NL80211_BANDS]; |
1373 | u32 basic_rates; | 1395 | u32 basic_rates; |
1396 | struct cfg80211_bitrate_mask beacon_rate; | ||
1374 | }; | 1397 | }; |
1375 | 1398 | ||
1376 | /** | 1399 | /** |
@@ -2010,17 +2033,6 @@ enum wiphy_params_flags { | |||
2010 | WIPHY_PARAM_DYN_ACK = 1 << 5, | 2033 | WIPHY_PARAM_DYN_ACK = 1 << 5, |
2011 | }; | 2034 | }; |
2012 | 2035 | ||
2013 | /* | ||
2014 | * cfg80211_bitrate_mask - masks for bitrate control | ||
2015 | */ | ||
2016 | struct cfg80211_bitrate_mask { | ||
2017 | struct { | ||
2018 | u32 legacy; | ||
2019 | u8 ht_mcs[IEEE80211_HT_MCS_MASK_LEN]; | ||
2020 | u16 vht_mcs[NL80211_VHT_NSS_MAX]; | ||
2021 | enum nl80211_txrate_gi gi; | ||
2022 | } control[NUM_NL80211_BANDS]; | ||
2023 | }; | ||
2024 | /** | 2036 | /** |
2025 | * struct cfg80211_pmksa - PMK Security Association | 2037 | * struct cfg80211_pmksa - PMK Security Association |
2026 | * | 2038 | * |
@@ -2302,6 +2314,98 @@ struct cfg80211_qos_map { | |||
2302 | }; | 2314 | }; |
2303 | 2315 | ||
2304 | /** | 2316 | /** |
2317 | * struct cfg80211_nan_conf - NAN configuration | ||
2318 | * | ||
2319 | * This struct defines NAN configuration parameters | ||
2320 | * | ||
2321 | * @master_pref: master preference (1 - 255) | ||
2322 | * @dual: dual band operation mode, see &enum nl80211_nan_dual_band_conf | ||
2323 | */ | ||
2324 | struct cfg80211_nan_conf { | ||
2325 | u8 master_pref; | ||
2326 | u8 dual; | ||
2327 | }; | ||
2328 | |||
2329 | /** | ||
2330 | * enum cfg80211_nan_conf_changes - indicates changed fields in NAN | ||
2331 | * configuration | ||
2332 | * | ||
2333 | * @CFG80211_NAN_CONF_CHANGED_PREF: master preference | ||
2334 | * @CFG80211_NAN_CONF_CHANGED_DUAL: dual band operation | ||
2335 | */ | ||
2336 | enum cfg80211_nan_conf_changes { | ||
2337 | CFG80211_NAN_CONF_CHANGED_PREF = BIT(0), | ||
2338 | CFG80211_NAN_CONF_CHANGED_DUAL = BIT(1), | ||
2339 | }; | ||
2340 | |||
2341 | /** | ||
2342 | * struct cfg80211_nan_func_filter - a NAN function Rx / Tx filter | ||
2343 | * | ||
2344 | * @filter: the content of the filter | ||
2345 | * @len: the length of the filter | ||
2346 | */ | ||
2347 | struct cfg80211_nan_func_filter { | ||
2348 | const u8 *filter; | ||
2349 | u8 len; | ||
2350 | }; | ||
2351 | |||
2352 | /** | ||
2353 | * struct cfg80211_nan_func - a NAN function | ||
2354 | * | ||
2355 | * @type: &enum nl80211_nan_function_type | ||
2356 | * @service_id: the service ID of the function | ||
2357 | * @publish_type: &nl80211_nan_publish_type | ||
2358 | * @close_range: if true, the range should be limited. Threshold is | ||
2359 | * implementation specific. | ||
2360 | * @publish_bcast: if true, the solicited publish should be broadcasted | ||
2361 | * @subscribe_active: if true, the subscribe is active | ||
2362 | * @followup_id: the instance ID for follow up | ||
2363 | * @followup_reqid: the requestor instance ID for follow up | ||
2364 | * @followup_dest: MAC address of the recipient of the follow up | ||
2365 | * @ttl: time to live counter in DW. | ||
2366 | * @serv_spec_info: Service Specific Info | ||
2367 | * @serv_spec_info_len: Service Specific Info length | ||
2368 | * @srf_include: if true, SRF is inclusive | ||
2369 | * @srf_bf: Bloom Filter | ||
2370 | * @srf_bf_len: Bloom Filter length | ||
2371 | * @srf_bf_idx: Bloom Filter index | ||
2372 | * @srf_macs: SRF MAC addresses | ||
2373 | * @srf_num_macs: number of MAC addresses in SRF | ||
2374 | * @rx_filters: rx filters that are matched with corresponding peer's tx_filter | ||
2375 | * @tx_filters: filters that should be transmitted in the SDF. | ||
2376 | * @num_rx_filters: length of &rx_filters. | ||
2377 | * @num_tx_filters: length of &tx_filters. | ||
2378 | * @instance_id: driver allocated id of the function. | ||
2379 | * @cookie: unique NAN function identifier. | ||
2380 | */ | ||
2381 | struct cfg80211_nan_func { | ||
2382 | enum nl80211_nan_function_type type; | ||
2383 | u8 service_id[NL80211_NAN_FUNC_SERVICE_ID_LEN]; | ||
2384 | u8 publish_type; | ||
2385 | bool close_range; | ||
2386 | bool publish_bcast; | ||
2387 | bool subscribe_active; | ||
2388 | u8 followup_id; | ||
2389 | u8 followup_reqid; | ||
2390 | struct mac_address followup_dest; | ||
2391 | u32 ttl; | ||
2392 | const u8 *serv_spec_info; | ||
2393 | u8 serv_spec_info_len; | ||
2394 | bool srf_include; | ||
2395 | const u8 *srf_bf; | ||
2396 | u8 srf_bf_len; | ||
2397 | u8 srf_bf_idx; | ||
2398 | struct mac_address *srf_macs; | ||
2399 | int srf_num_macs; | ||
2400 | struct cfg80211_nan_func_filter *rx_filters; | ||
2401 | struct cfg80211_nan_func_filter *tx_filters; | ||
2402 | u8 num_tx_filters; | ||
2403 | u8 num_rx_filters; | ||
2404 | u8 instance_id; | ||
2405 | u64 cookie; | ||
2406 | }; | ||
2407 | |||
2408 | /** | ||
2305 | * struct cfg80211_ops - backend description for wireless configuration | 2409 | * struct cfg80211_ops - backend description for wireless configuration |
2306 | * | 2410 | * |
2307 | * This struct is registered by fullmac card drivers and/or wireless stacks | 2411 | * This struct is registered by fullmac card drivers and/or wireless stacks |
@@ -2589,6 +2693,19 @@ struct cfg80211_qos_map { | |||
2589 | * and returning to the base channel for communication with the AP. | 2693 | * and returning to the base channel for communication with the AP. |
2590 | * @tdls_cancel_channel_switch: Stop channel-switching with a TDLS peer. Both | 2694 | * @tdls_cancel_channel_switch: Stop channel-switching with a TDLS peer. Both |
2591 | * peers must be on the base channel when the call completes. | 2695 | * peers must be on the base channel when the call completes. |
2696 | * @start_nan: Start the NAN interface. | ||
2697 | * @stop_nan: Stop the NAN interface. | ||
2698 | * @add_nan_func: Add a NAN function. Returns negative value on failure. | ||
2699 | * On success @nan_func ownership is transferred to the driver and | ||
2700 | * it may access it outside of the scope of this function. The driver | ||
2701 | * should free the @nan_func when no longer needed by calling | ||
2702 | * cfg80211_free_nan_func(). | ||
2703 | * On success the driver should assign an instance_id in the | ||
2704 | * provided @nan_func. | ||
2705 | * @del_nan_func: Delete a NAN function. | ||
2706 | * @nan_change_conf: changes NAN configuration. The changed parameters must | ||
2707 | * be specified in @changes (using &enum cfg80211_nan_conf_changes); | ||
2708 | * All other parameters must be ignored. | ||
2592 | */ | 2709 | */ |
2593 | struct cfg80211_ops { | 2710 | struct cfg80211_ops { |
2594 | int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); | 2711 | int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); |
@@ -2854,6 +2971,17 @@ struct cfg80211_ops { | |||
2854 | void (*tdls_cancel_channel_switch)(struct wiphy *wiphy, | 2971 | void (*tdls_cancel_channel_switch)(struct wiphy *wiphy, |
2855 | struct net_device *dev, | 2972 | struct net_device *dev, |
2856 | const u8 *addr); | 2973 | const u8 *addr); |
2974 | int (*start_nan)(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
2975 | struct cfg80211_nan_conf *conf); | ||
2976 | void (*stop_nan)(struct wiphy *wiphy, struct wireless_dev *wdev); | ||
2977 | int (*add_nan_func)(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
2978 | struct cfg80211_nan_func *nan_func); | ||
2979 | void (*del_nan_func)(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
2980 | u64 cookie); | ||
2981 | int (*nan_change_conf)(struct wiphy *wiphy, | ||
2982 | struct wireless_dev *wdev, | ||
2983 | struct cfg80211_nan_conf *conf, | ||
2984 | u32 changes); | ||
2857 | }; | 2985 | }; |
2858 | 2986 | ||
2859 | /* | 2987 | /* |
@@ -2900,6 +3028,8 @@ struct cfg80211_ops { | |||
2900 | * @WIPHY_FLAG_SUPPORTS_5_10_MHZ: Device supports 5 MHz and 10 MHz channels. | 3028 | * @WIPHY_FLAG_SUPPORTS_5_10_MHZ: Device supports 5 MHz and 10 MHz channels. |
2901 | * @WIPHY_FLAG_HAS_CHANNEL_SWITCH: Device supports channel switch in | 3029 | * @WIPHY_FLAG_HAS_CHANNEL_SWITCH: Device supports channel switch in |
2902 | * beaconing mode (AP, IBSS, Mesh, ...). | 3030 | * beaconing mode (AP, IBSS, Mesh, ...). |
3031 | * @WIPHY_FLAG_HAS_STATIC_WEP: The device supports static WEP key installation | ||
3032 | * before connection. | ||
2903 | */ | 3033 | */ |
2904 | enum wiphy_flags { | 3034 | enum wiphy_flags { |
2905 | /* use hole at 0 */ | 3035 | /* use hole at 0 */ |
@@ -2925,6 +3055,7 @@ enum wiphy_flags { | |||
2925 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL = BIT(21), | 3055 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL = BIT(21), |
2926 | WIPHY_FLAG_SUPPORTS_5_10_MHZ = BIT(22), | 3056 | WIPHY_FLAG_SUPPORTS_5_10_MHZ = BIT(22), |
2927 | WIPHY_FLAG_HAS_CHANNEL_SWITCH = BIT(23), | 3057 | WIPHY_FLAG_HAS_CHANNEL_SWITCH = BIT(23), |
3058 | WIPHY_FLAG_HAS_STATIC_WEP = BIT(24), | ||
2928 | }; | 3059 | }; |
2929 | 3060 | ||
2930 | /** | 3061 | /** |
@@ -3302,6 +3433,8 @@ struct wiphy_iftype_ext_capab { | |||
3302 | * @bss_select_support: bitmask indicating the BSS selection criteria supported | 3433 | * @bss_select_support: bitmask indicating the BSS selection criteria supported |
3303 | * by the driver in the .connect() callback. The bit position maps to the | 3434 | * by the driver in the .connect() callback. The bit position maps to the |
3304 | * attribute indices defined in &enum nl80211_bss_select_attr. | 3435 | * attribute indices defined in &enum nl80211_bss_select_attr. |
3436 | * | ||
3437 | * @cookie_counter: unique generic cookie counter, used to identify objects. | ||
3305 | */ | 3438 | */ |
3306 | struct wiphy { | 3439 | struct wiphy { |
3307 | /* assign these fields before you register the wiphy */ | 3440 | /* assign these fields before you register the wiphy */ |
@@ -3431,6 +3564,8 @@ struct wiphy { | |||
3431 | 3564 | ||
3432 | u32 bss_select_support; | 3565 | u32 bss_select_support; |
3433 | 3566 | ||
3567 | u64 cookie_counter; | ||
3568 | |||
3434 | char priv[0] __aligned(NETDEV_ALIGN); | 3569 | char priv[0] __aligned(NETDEV_ALIGN); |
3435 | }; | 3570 | }; |
3436 | 3571 | ||
@@ -3611,6 +3746,7 @@ struct cfg80211_cached_keys; | |||
3611 | * beacons, 0 when not valid | 3746 | * beacons, 0 when not valid |
3612 | * @address: The address for this device, valid only if @netdev is %NULL | 3747 | * @address: The address for this device, valid only if @netdev is %NULL |
3613 | * @p2p_started: true if this is a P2P Device that has been started | 3748 | * @p2p_started: true if this is a P2P Device that has been started |
3749 | * @nan_started: true if this is a NAN interface that has been started | ||
3614 | * @cac_started: true if DFS channel availability check has been started | 3750 | * @cac_started: true if DFS channel availability check has been started |
3615 | * @cac_start_time: timestamp (jiffies) when the dfs state was entered. | 3751 | * @cac_start_time: timestamp (jiffies) when the dfs state was entered. |
3616 | * @cac_time_ms: CAC time in ms | 3752 | * @cac_time_ms: CAC time in ms |
@@ -3642,7 +3778,7 @@ struct wireless_dev { | |||
3642 | 3778 | ||
3643 | struct mutex mtx; | 3779 | struct mutex mtx; |
3644 | 3780 | ||
3645 | bool use_4addr, p2p_started; | 3781 | bool use_4addr, p2p_started, nan_started; |
3646 | 3782 | ||
3647 | u8 address[ETH_ALEN] __aligned(sizeof(u16)); | 3783 | u8 address[ETH_ALEN] __aligned(sizeof(u16)); |
3648 | 3784 | ||
@@ -5550,6 +5686,67 @@ wiphy_ext_feature_isset(struct wiphy *wiphy, | |||
5550 | return (ft_byte & BIT(ftidx % 8)) != 0; | 5686 | return (ft_byte & BIT(ftidx % 8)) != 0; |
5551 | } | 5687 | } |
5552 | 5688 | ||
5689 | /** | ||
5690 | * cfg80211_free_nan_func - free NAN function | ||
5691 | * @f: NAN function that should be freed | ||
5692 | * | ||
5693 | * Frees all the NAN function and all it's allocated members. | ||
5694 | */ | ||
5695 | void cfg80211_free_nan_func(struct cfg80211_nan_func *f); | ||
5696 | |||
5697 | /** | ||
5698 | * struct cfg80211_nan_match_params - NAN match parameters | ||
5699 | * @type: the type of the function that triggered a match. If it is | ||
5700 | * %NL80211_NAN_FUNC_SUBSCRIBE it means that we replied to a subscriber. | ||
5701 | * If it is %NL80211_NAN_FUNC_PUBLISH, it means that we got a discovery | ||
5702 | * result. | ||
5703 | * If it is %NL80211_NAN_FUNC_FOLLOW_UP, we received a follow up. | ||
5704 | * @inst_id: the local instance id | ||
5705 | * @peer_inst_id: the instance id of the peer's function | ||
5706 | * @addr: the MAC address of the peer | ||
5707 | * @info_len: the length of the &info | ||
5708 | * @info: the Service Specific Info from the peer (if any) | ||
5709 | * @cookie: unique identifier of the corresponding function | ||
5710 | */ | ||
5711 | struct cfg80211_nan_match_params { | ||
5712 | enum nl80211_nan_function_type type; | ||
5713 | u8 inst_id; | ||
5714 | u8 peer_inst_id; | ||
5715 | const u8 *addr; | ||
5716 | u8 info_len; | ||
5717 | const u8 *info; | ||
5718 | u64 cookie; | ||
5719 | }; | ||
5720 | |||
5721 | /** | ||
5722 | * cfg80211_nan_match - report a match for a NAN function. | ||
5723 | * @wdev: the wireless device reporting the match | ||
5724 | * @match: match notification parameters | ||
5725 | * @gfp: allocation flags | ||
5726 | * | ||
5727 | * This function reports that the a NAN function had a match. This | ||
5728 | * can be a subscribe that had a match or a solicited publish that | ||
5729 | * was sent. It can also be a follow up that was received. | ||
5730 | */ | ||
5731 | void cfg80211_nan_match(struct wireless_dev *wdev, | ||
5732 | struct cfg80211_nan_match_params *match, gfp_t gfp); | ||
5733 | |||
5734 | /** | ||
5735 | * cfg80211_nan_func_terminated - notify about NAN function termination. | ||
5736 | * | ||
5737 | * @wdev: the wireless device reporting the match | ||
5738 | * @inst_id: the local instance id | ||
5739 | * @reason: termination reason (one of the NL80211_NAN_FUNC_TERM_REASON_*) | ||
5740 | * @cookie: unique NAN function identifier | ||
5741 | * @gfp: allocation flags | ||
5742 | * | ||
5743 | * This function reports that the a NAN function is terminated. | ||
5744 | */ | ||
5745 | void cfg80211_nan_func_terminated(struct wireless_dev *wdev, | ||
5746 | u8 inst_id, | ||
5747 | enum nl80211_nan_func_term_reason reason, | ||
5748 | u64 cookie, gfp_t gfp); | ||
5749 | |||
5553 | /* ethtool helper */ | 5750 | /* ethtool helper */ |
5554 | void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info); | 5751 | void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info); |
5555 | 5752 | ||
diff --git a/include/net/fq.h b/include/net/fq.h index 268b49049c37..6d8521a30c5c 100644 --- a/include/net/fq.h +++ b/include/net/fq.h | |||
@@ -72,9 +72,12 @@ struct fq { | |||
72 | u32 flows_cnt; | 72 | u32 flows_cnt; |
73 | u32 perturbation; | 73 | u32 perturbation; |
74 | u32 limit; | 74 | u32 limit; |
75 | u32 memory_limit; | ||
76 | u32 memory_usage; | ||
75 | u32 quantum; | 77 | u32 quantum; |
76 | u32 backlog; | 78 | u32 backlog; |
77 | u32 overlimit; | 79 | u32 overlimit; |
80 | u32 overmemory; | ||
78 | u32 collisions; | 81 | u32 collisions; |
79 | }; | 82 | }; |
80 | 83 | ||
diff --git a/include/net/fq_impl.h b/include/net/fq_impl.h index 163f3ed0f05a..4e6131cd3f43 100644 --- a/include/net/fq_impl.h +++ b/include/net/fq_impl.h | |||
@@ -29,6 +29,7 @@ static struct sk_buff *fq_flow_dequeue(struct fq *fq, | |||
29 | tin->backlog_packets--; | 29 | tin->backlog_packets--; |
30 | flow->backlog -= skb->len; | 30 | flow->backlog -= skb->len; |
31 | fq->backlog--; | 31 | fq->backlog--; |
32 | fq->memory_usage -= skb->truesize; | ||
32 | 33 | ||
33 | if (flow->backlog == 0) { | 34 | if (flow->backlog == 0) { |
34 | list_del_init(&flow->backlogchain); | 35 | list_del_init(&flow->backlogchain); |
@@ -154,6 +155,7 @@ static void fq_tin_enqueue(struct fq *fq, | |||
154 | flow->backlog += skb->len; | 155 | flow->backlog += skb->len; |
155 | tin->backlog_bytes += skb->len; | 156 | tin->backlog_bytes += skb->len; |
156 | tin->backlog_packets++; | 157 | tin->backlog_packets++; |
158 | fq->memory_usage += skb->truesize; | ||
157 | fq->backlog++; | 159 | fq->backlog++; |
158 | 160 | ||
159 | fq_recalc_backlog(fq, tin, flow); | 161 | fq_recalc_backlog(fq, tin, flow); |
@@ -166,7 +168,7 @@ static void fq_tin_enqueue(struct fq *fq, | |||
166 | 168 | ||
167 | __skb_queue_tail(&flow->queue, skb); | 169 | __skb_queue_tail(&flow->queue, skb); |
168 | 170 | ||
169 | if (fq->backlog > fq->limit) { | 171 | if (fq->backlog > fq->limit || fq->memory_usage > fq->memory_limit) { |
170 | flow = list_first_entry_or_null(&fq->backlogs, | 172 | flow = list_first_entry_or_null(&fq->backlogs, |
171 | struct fq_flow, | 173 | struct fq_flow, |
172 | backlogchain); | 174 | backlogchain); |
@@ -181,6 +183,8 @@ static void fq_tin_enqueue(struct fq *fq, | |||
181 | 183 | ||
182 | flow->tin->overlimit++; | 184 | flow->tin->overlimit++; |
183 | fq->overlimit++; | 185 | fq->overlimit++; |
186 | if (fq->memory_usage > fq->memory_limit) | ||
187 | fq->overmemory++; | ||
184 | } | 188 | } |
185 | } | 189 | } |
186 | 190 | ||
@@ -251,6 +255,7 @@ static int fq_init(struct fq *fq, int flows_cnt) | |||
251 | fq->perturbation = prandom_u32(); | 255 | fq->perturbation = prandom_u32(); |
252 | fq->quantum = 300; | 256 | fq->quantum = 300; |
253 | fq->limit = 8192; | 257 | fq->limit = 8192; |
258 | fq->memory_limit = 16 << 20; /* 16 MBytes */ | ||
254 | 259 | ||
255 | fq->flows = kcalloc(fq->flows_cnt, sizeof(fq->flows[0]), GFP_KERNEL); | 260 | fq->flows = kcalloc(fq->flows_cnt, sizeof(fq->flows[0]), GFP_KERNEL); |
256 | if (!fq->flows) | 261 | if (!fq->flows) |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 5296100f3889..a810dfcb83c2 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -715,6 +715,7 @@ enum mac80211_tx_info_flags { | |||
715 | * frame (PS-Poll or uAPSD). | 715 | * frame (PS-Poll or uAPSD). |
716 | * @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information | 716 | * @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information |
717 | * @IEEE80211_TX_CTRL_AMSDU: This frame is an A-MSDU frame | 717 | * @IEEE80211_TX_CTRL_AMSDU: This frame is an A-MSDU frame |
718 | * @IEEE80211_TX_CTRL_FAST_XMIT: This frame is going through the fast_xmit path | ||
718 | * | 719 | * |
719 | * These flags are used in tx_info->control.flags. | 720 | * These flags are used in tx_info->control.flags. |
720 | */ | 721 | */ |
@@ -723,6 +724,7 @@ enum mac80211_tx_control_flags { | |||
723 | IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1), | 724 | IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1), |
724 | IEEE80211_TX_CTRL_RATE_INJECT = BIT(2), | 725 | IEEE80211_TX_CTRL_RATE_INJECT = BIT(2), |
725 | IEEE80211_TX_CTRL_AMSDU = BIT(3), | 726 | IEEE80211_TX_CTRL_AMSDU = BIT(3), |
727 | IEEE80211_TX_CTRL_FAST_XMIT = BIT(4), | ||
726 | }; | 728 | }; |
727 | 729 | ||
728 | /* | 730 | /* |
@@ -2177,6 +2179,8 @@ enum ieee80211_hw_flags { | |||
2177 | * @n_cipher_schemes: a size of an array of cipher schemes definitions. | 2179 | * @n_cipher_schemes: a size of an array of cipher schemes definitions. |
2178 | * @cipher_schemes: a pointer to an array of cipher scheme definitions | 2180 | * @cipher_schemes: a pointer to an array of cipher scheme definitions |
2179 | * supported by HW. | 2181 | * supported by HW. |
2182 | * @max_nan_de_entries: maximum number of NAN DE functions supported by the | ||
2183 | * device. | ||
2180 | */ | 2184 | */ |
2181 | struct ieee80211_hw { | 2185 | struct ieee80211_hw { |
2182 | struct ieee80211_conf conf; | 2186 | struct ieee80211_conf conf; |
@@ -2211,6 +2215,7 @@ struct ieee80211_hw { | |||
2211 | u8 uapsd_max_sp_len; | 2215 | u8 uapsd_max_sp_len; |
2212 | u8 n_cipher_schemes; | 2216 | u8 n_cipher_schemes; |
2213 | const struct ieee80211_cipher_scheme *cipher_schemes; | 2217 | const struct ieee80211_cipher_scheme *cipher_schemes; |
2218 | u8 max_nan_de_entries; | ||
2214 | }; | 2219 | }; |
2215 | 2220 | ||
2216 | static inline bool _ieee80211_hw_check(struct ieee80211_hw *hw, | 2221 | static inline bool _ieee80211_hw_check(struct ieee80211_hw *hw, |
@@ -3166,6 +3171,12 @@ enum ieee80211_reconfig_type { | |||
3166 | * required function. | 3171 | * required function. |
3167 | * The callback can sleep. | 3172 | * The callback can sleep. |
3168 | * | 3173 | * |
3174 | * @offset_tsf: Offset the TSF timer by the specified value in the | ||
3175 | * firmware/hardware. Preferred to set_tsf as it avoids delay between | ||
3176 | * calling set_tsf() and hardware getting programmed, which will show up | ||
3177 | * as TSF delay. Is not a required function. | ||
3178 | * The callback can sleep. | ||
3179 | * | ||
3169 | * @reset_tsf: Reset the TSF timer and allow firmware/hardware to synchronize | 3180 | * @reset_tsf: Reset the TSF timer and allow firmware/hardware to synchronize |
3170 | * with other STAs in the IBSS. This is only used in IBSS mode. This | 3181 | * with other STAs in the IBSS. This is only used in IBSS mode. This |
3171 | * function is optional if the firmware/hardware takes full care of | 3182 | * function is optional if the firmware/hardware takes full care of |
@@ -3420,6 +3431,21 @@ enum ieee80211_reconfig_type { | |||
3420 | * synchronization which is needed in case driver has in its RSS queues | 3431 | * synchronization which is needed in case driver has in its RSS queues |
3421 | * pending frames that were received prior to the control path action | 3432 | * pending frames that were received prior to the control path action |
3422 | * currently taken (e.g. disassociation) but are not processed yet. | 3433 | * currently taken (e.g. disassociation) but are not processed yet. |
3434 | * | ||
3435 | * @start_nan: join an existing NAN cluster, or create a new one. | ||
3436 | * @stop_nan: leave the NAN cluster. | ||
3437 | * @nan_change_conf: change NAN configuration. The data in cfg80211_nan_conf | ||
3438 | * contains full new configuration and changes specify which parameters | ||
3439 | * are changed with respect to the last NAN config. | ||
3440 | * The driver gets both full configuration and the changed parameters since | ||
3441 | * some devices may need the full configuration while others need only the | ||
3442 | * changed parameters. | ||
3443 | * @add_nan_func: Add a NAN function. Returns 0 on success. The data in | ||
3444 | * cfg80211_nan_func must not be referenced outside the scope of | ||
3445 | * this call. | ||
3446 | * @del_nan_func: Remove a NAN function. The driver must call | ||
3447 | * ieee80211_nan_func_terminated() with | ||
3448 | * NL80211_NAN_FUNC_TERM_REASON_USER_REQUEST reason code upon removal. | ||
3423 | */ | 3449 | */ |
3424 | struct ieee80211_ops { | 3450 | struct ieee80211_ops { |
3425 | void (*tx)(struct ieee80211_hw *hw, | 3451 | void (*tx)(struct ieee80211_hw *hw, |
@@ -3531,6 +3557,8 @@ struct ieee80211_ops { | |||
3531 | u64 (*get_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); | 3557 | u64 (*get_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); |
3532 | void (*set_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 3558 | void (*set_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
3533 | u64 tsf); | 3559 | u64 tsf); |
3560 | void (*offset_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
3561 | s64 offset); | ||
3534 | void (*reset_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); | 3562 | void (*reset_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); |
3535 | int (*tx_last_beacon)(struct ieee80211_hw *hw); | 3563 | int (*tx_last_beacon)(struct ieee80211_hw *hw); |
3536 | int (*ampdu_action)(struct ieee80211_hw *hw, | 3564 | int (*ampdu_action)(struct ieee80211_hw *hw, |
@@ -3655,6 +3683,21 @@ struct ieee80211_ops { | |||
3655 | void (*wake_tx_queue)(struct ieee80211_hw *hw, | 3683 | void (*wake_tx_queue)(struct ieee80211_hw *hw, |
3656 | struct ieee80211_txq *txq); | 3684 | struct ieee80211_txq *txq); |
3657 | void (*sync_rx_queues)(struct ieee80211_hw *hw); | 3685 | void (*sync_rx_queues)(struct ieee80211_hw *hw); |
3686 | |||
3687 | int (*start_nan)(struct ieee80211_hw *hw, | ||
3688 | struct ieee80211_vif *vif, | ||
3689 | struct cfg80211_nan_conf *conf); | ||
3690 | int (*stop_nan)(struct ieee80211_hw *hw, | ||
3691 | struct ieee80211_vif *vif); | ||
3692 | int (*nan_change_conf)(struct ieee80211_hw *hw, | ||
3693 | struct ieee80211_vif *vif, | ||
3694 | struct cfg80211_nan_conf *conf, u32 changes); | ||
3695 | int (*add_nan_func)(struct ieee80211_hw *hw, | ||
3696 | struct ieee80211_vif *vif, | ||
3697 | const struct cfg80211_nan_func *nan_func); | ||
3698 | void (*del_nan_func)(struct ieee80211_hw *hw, | ||
3699 | struct ieee80211_vif *vif, | ||
3700 | u8 instance_id); | ||
3658 | }; | 3701 | }; |
3659 | 3702 | ||
3660 | /** | 3703 | /** |
@@ -5728,4 +5771,36 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, | |||
5728 | void ieee80211_txq_get_depth(struct ieee80211_txq *txq, | 5771 | void ieee80211_txq_get_depth(struct ieee80211_txq *txq, |
5729 | unsigned long *frame_cnt, | 5772 | unsigned long *frame_cnt, |
5730 | unsigned long *byte_cnt); | 5773 | unsigned long *byte_cnt); |
5774 | |||
5775 | /** | ||
5776 | * ieee80211_nan_func_terminated - notify about NAN function termination. | ||
5777 | * | ||
5778 | * This function is used to notify mac80211 about NAN function termination. | ||
5779 | * Note that this function can't be called from hard irq. | ||
5780 | * | ||
5781 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. | ||
5782 | * @inst_id: the local instance id | ||
5783 | * @reason: termination reason (one of the NL80211_NAN_FUNC_TERM_REASON_*) | ||
5784 | * @gfp: allocation flags | ||
5785 | */ | ||
5786 | void ieee80211_nan_func_terminated(struct ieee80211_vif *vif, | ||
5787 | u8 inst_id, | ||
5788 | enum nl80211_nan_func_term_reason reason, | ||
5789 | gfp_t gfp); | ||
5790 | |||
5791 | /** | ||
5792 | * ieee80211_nan_func_match - notify about NAN function match event. | ||
5793 | * | ||
5794 | * This function is used to notify mac80211 about NAN function match. The | ||
5795 | * cookie inside the match struct will be assigned by mac80211. | ||
5796 | * Note that this function can't be called from hard irq. | ||
5797 | * | ||
5798 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. | ||
5799 | * @match: match event information | ||
5800 | * @gfp: allocation flags | ||
5801 | */ | ||
5802 | void ieee80211_nan_func_match(struct ieee80211_vif *vif, | ||
5803 | struct cfg80211_nan_match_params *match, | ||
5804 | gfp_t gfp); | ||
5805 | |||
5731 | #endif /* MAC80211_H */ | 5806 | #endif /* MAC80211_H */ |
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 220694151434..56368e9b4622 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h | |||
@@ -48,6 +48,7 @@ | |||
48 | #define NL80211_MULTICAST_GROUP_REG "regulatory" | 48 | #define NL80211_MULTICAST_GROUP_REG "regulatory" |
49 | #define NL80211_MULTICAST_GROUP_MLME "mlme" | 49 | #define NL80211_MULTICAST_GROUP_MLME "mlme" |
50 | #define NL80211_MULTICAST_GROUP_VENDOR "vendor" | 50 | #define NL80211_MULTICAST_GROUP_VENDOR "vendor" |
51 | #define NL80211_MULTICAST_GROUP_NAN "nan" | ||
51 | #define NL80211_MULTICAST_GROUP_TESTMODE "testmode" | 52 | #define NL80211_MULTICAST_GROUP_TESTMODE "testmode" |
52 | 53 | ||
53 | /** | 54 | /** |
@@ -838,6 +839,41 @@ | |||
838 | * not running. The driver indicates the status of the scan through | 839 | * not running. The driver indicates the status of the scan through |
839 | * cfg80211_scan_done(). | 840 | * cfg80211_scan_done(). |
840 | * | 841 | * |
842 | * @NL80211_CMD_START_NAN: Start NAN operation, identified by its | ||
843 | * %NL80211_ATTR_WDEV interface. This interface must have been previously | ||
844 | * created with %NL80211_CMD_NEW_INTERFACE. After it has been started, the | ||
845 | * NAN interface will create or join a cluster. This command must have a | ||
846 | * valid %NL80211_ATTR_NAN_MASTER_PREF attribute and optional | ||
847 | * %NL80211_ATTR_NAN_DUAL attributes. | ||
848 | * After this command NAN functions can be added. | ||
849 | * @NL80211_CMD_STOP_NAN: Stop the NAN operation, identified by | ||
850 | * its %NL80211_ATTR_WDEV interface. | ||
851 | * @NL80211_CMD_ADD_NAN_FUNCTION: Add a NAN function. The function is defined | ||
852 | * with %NL80211_ATTR_NAN_FUNC nested attribute. When called, this | ||
853 | * operation returns the strictly positive and unique instance id | ||
854 | * (%NL80211_ATTR_NAN_FUNC_INST_ID) and a cookie (%NL80211_ATTR_COOKIE) | ||
855 | * of the function upon success. | ||
856 | * Since instance ID's can be re-used, this cookie is the right | ||
857 | * way to identify the function. This will avoid races when a termination | ||
858 | * event is handled by the user space after it has already added a new | ||
859 | * function that got the same instance id from the kernel as the one | ||
860 | * which just terminated. | ||
861 | * This cookie may be used in NAN events even before the command | ||
862 | * returns, so userspace shouldn't process NAN events until it processes | ||
863 | * the response to this command. | ||
864 | * Look at %NL80211_ATTR_SOCKET_OWNER as well. | ||
865 | * @NL80211_CMD_DEL_NAN_FUNCTION: Delete a NAN function by cookie. | ||
866 | * This command is also used as a notification sent when a NAN function is | ||
867 | * terminated. This will contain a %NL80211_ATTR_NAN_FUNC_INST_ID | ||
868 | * and %NL80211_ATTR_COOKIE attributes. | ||
869 | * @NL80211_CMD_CHANGE_NAN_CONFIG: Change current NAN configuration. NAN | ||
870 | * must be operational (%NL80211_CMD_START_NAN was executed). | ||
871 | * It must contain at least one of the following attributes: | ||
872 | * %NL80211_ATTR_NAN_MASTER_PREF, %NL80211_ATTR_NAN_DUAL. | ||
873 | * @NL80211_CMD_NAN_FUNC_MATCH: Notification sent when a match is reported. | ||
874 | * This will contain a %NL80211_ATTR_NAN_MATCH nested attribute and | ||
875 | * %NL80211_ATTR_COOKIE. | ||
876 | * | ||
841 | * @NL80211_CMD_MAX: highest used command number | 877 | * @NL80211_CMD_MAX: highest used command number |
842 | * @__NL80211_CMD_AFTER_LAST: internal use | 878 | * @__NL80211_CMD_AFTER_LAST: internal use |
843 | */ | 879 | */ |
@@ -1026,6 +1062,13 @@ enum nl80211_commands { | |||
1026 | 1062 | ||
1027 | NL80211_CMD_ABORT_SCAN, | 1063 | NL80211_CMD_ABORT_SCAN, |
1028 | 1064 | ||
1065 | NL80211_CMD_START_NAN, | ||
1066 | NL80211_CMD_STOP_NAN, | ||
1067 | NL80211_CMD_ADD_NAN_FUNCTION, | ||
1068 | NL80211_CMD_DEL_NAN_FUNCTION, | ||
1069 | NL80211_CMD_CHANGE_NAN_CONFIG, | ||
1070 | NL80211_CMD_NAN_MATCH, | ||
1071 | |||
1029 | /* add new commands above here */ | 1072 | /* add new commands above here */ |
1030 | 1073 | ||
1031 | /* used to define NL80211_CMD_MAX below */ | 1074 | /* used to define NL80211_CMD_MAX below */ |
@@ -1343,7 +1386,13 @@ enum nl80211_commands { | |||
1343 | * enum nl80211_band value is used as the index (nla_type() of the nested | 1386 | * enum nl80211_band value is used as the index (nla_type() of the nested |
1344 | * data. If a band is not included, it will be configured to allow all | 1387 | * data. If a band is not included, it will be configured to allow all |
1345 | * rates based on negotiated supported rates information. This attribute | 1388 | * rates based on negotiated supported rates information. This attribute |
1346 | * is used with %NL80211_CMD_SET_TX_BITRATE_MASK. | 1389 | * is used with %NL80211_CMD_SET_TX_BITRATE_MASK and with starting AP, |
1390 | * and joining mesh networks (not IBSS yet). In the later case, it must | ||
1391 | * specify just a single bitrate, which is to be used for the beacon. | ||
1392 | * The driver must also specify support for this with the extended | ||
1393 | * features NL80211_EXT_FEATURE_BEACON_RATE_LEGACY, | ||
1394 | * NL80211_EXT_FEATURE_BEACON_RATE_HT and | ||
1395 | * NL80211_EXT_FEATURE_BEACON_RATE_VHT. | ||
1347 | * | 1396 | * |
1348 | * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain | 1397 | * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain |
1349 | * at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME. | 1398 | * at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME. |
@@ -1733,6 +1782,12 @@ enum nl80211_commands { | |||
1733 | * regulatory indoor configuration would be owned by the netlink socket | 1782 | * regulatory indoor configuration would be owned by the netlink socket |
1734 | * that configured the indoor setting, and the indoor operation would be | 1783 | * that configured the indoor setting, and the indoor operation would be |
1735 | * cleared when the socket is closed. | 1784 | * cleared when the socket is closed. |
1785 | * If set during NAN interface creation, the interface will be destroyed | ||
1786 | * if the socket is closed just like any other interface. Moreover, only | ||
1787 | * the netlink socket that created the interface will be allowed to add | ||
1788 | * and remove functions. NAN notifications will be sent in unicast to that | ||
1789 | * socket. Without this attribute, any socket can add functions and the | ||
1790 | * notifications will be sent to the %NL80211_MCGRP_NAN multicast group. | ||
1736 | * | 1791 | * |
1737 | * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is | 1792 | * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is |
1738 | * the TDLS link initiator. | 1793 | * the TDLS link initiator. |
@@ -1867,6 +1922,21 @@ enum nl80211_commands { | |||
1867 | * @NL80211_ATTR_MESH_PEER_AID: Association ID for the mesh peer (u16). This is | 1922 | * @NL80211_ATTR_MESH_PEER_AID: Association ID for the mesh peer (u16). This is |
1868 | * used to pull the stored data for mesh peer in power save state. | 1923 | * used to pull the stored data for mesh peer in power save state. |
1869 | * | 1924 | * |
1925 | * @NL80211_ATTR_NAN_MASTER_PREF: the master preference to be used by | ||
1926 | * %NL80211_CMD_START_NAN and optionally with | ||
1927 | * %NL80211_CMD_CHANGE_NAN_CONFIG. Its type is u8 and it can't be 0. | ||
1928 | * Also, values 1 and 255 are reserved for certification purposes and | ||
1929 | * should not be used during a normal device operation. | ||
1930 | * @NL80211_ATTR_NAN_DUAL: NAN dual band operation config (see | ||
1931 | * &enum nl80211_nan_dual_band_conf). This attribute is used with | ||
1932 | * %NL80211_CMD_START_NAN and optionally with | ||
1933 | * %NL80211_CMD_CHANGE_NAN_CONFIG. | ||
1934 | * @NL80211_ATTR_NAN_FUNC: a function that can be added to NAN. See | ||
1935 | * &enum nl80211_nan_func_attributes for description of this nested | ||
1936 | * attribute. | ||
1937 | * @NL80211_ATTR_NAN_MATCH: used to report a match. This is a nested attribute. | ||
1938 | * See &enum nl80211_nan_match_attributes. | ||
1939 | * | ||
1870 | * @NUM_NL80211_ATTR: total number of nl80211_attrs available | 1940 | * @NUM_NL80211_ATTR: total number of nl80211_attrs available |
1871 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 1941 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
1872 | * @__NL80211_ATTR_AFTER_LAST: internal use | 1942 | * @__NL80211_ATTR_AFTER_LAST: internal use |
@@ -2261,6 +2331,11 @@ enum nl80211_attrs { | |||
2261 | 2331 | ||
2262 | NL80211_ATTR_MESH_PEER_AID, | 2332 | NL80211_ATTR_MESH_PEER_AID, |
2263 | 2333 | ||
2334 | NL80211_ATTR_NAN_MASTER_PREF, | ||
2335 | NL80211_ATTR_NAN_DUAL, | ||
2336 | NL80211_ATTR_NAN_FUNC, | ||
2337 | NL80211_ATTR_NAN_MATCH, | ||
2338 | |||
2264 | /* add attributes here, update the policy in nl80211.c */ | 2339 | /* add attributes here, update the policy in nl80211.c */ |
2265 | 2340 | ||
2266 | __NL80211_ATTR_AFTER_LAST, | 2341 | __NL80211_ATTR_AFTER_LAST, |
@@ -2339,6 +2414,7 @@ enum nl80211_attrs { | |||
2339 | * commands to create and destroy one | 2414 | * commands to create and destroy one |
2340 | * @NL80211_IF_TYPE_OCB: Outside Context of a BSS | 2415 | * @NL80211_IF_TYPE_OCB: Outside Context of a BSS |
2341 | * This mode corresponds to the MIB variable dot11OCBActivated=true | 2416 | * This mode corresponds to the MIB variable dot11OCBActivated=true |
2417 | * @NL80211_IFTYPE_NAN: NAN device interface type (not a netdev) | ||
2342 | * @NL80211_IFTYPE_MAX: highest interface type number currently defined | 2418 | * @NL80211_IFTYPE_MAX: highest interface type number currently defined |
2343 | * @NUM_NL80211_IFTYPES: number of defined interface types | 2419 | * @NUM_NL80211_IFTYPES: number of defined interface types |
2344 | * | 2420 | * |
@@ -2359,6 +2435,7 @@ enum nl80211_iftype { | |||
2359 | NL80211_IFTYPE_P2P_GO, | 2435 | NL80211_IFTYPE_P2P_GO, |
2360 | NL80211_IFTYPE_P2P_DEVICE, | 2436 | NL80211_IFTYPE_P2P_DEVICE, |
2361 | NL80211_IFTYPE_OCB, | 2437 | NL80211_IFTYPE_OCB, |
2438 | NL80211_IFTYPE_NAN, | ||
2362 | 2439 | ||
2363 | /* keep last */ | 2440 | /* keep last */ |
2364 | NUM_NL80211_IFTYPES, | 2441 | NUM_NL80211_IFTYPES, |
@@ -4551,6 +4628,12 @@ enum nl80211_feature_flags { | |||
4551 | * (if available). | 4628 | * (if available). |
4552 | * @NL80211_EXT_FEATURE_SET_SCAN_DWELL: This driver supports configuration of | 4629 | * @NL80211_EXT_FEATURE_SET_SCAN_DWELL: This driver supports configuration of |
4553 | * channel dwell time. | 4630 | * channel dwell time. |
4631 | * @NL80211_EXT_FEATURE_BEACON_RATE_LEGACY: Driver supports beacon rate | ||
4632 | * configuration (AP/mesh), supporting a legacy (non HT/VHT) rate. | ||
4633 | * @NL80211_EXT_FEATURE_BEACON_RATE_HT: Driver supports beacon rate | ||
4634 | * configuration (AP/mesh) with HT rates. | ||
4635 | * @NL80211_EXT_FEATURE_BEACON_RATE_VHT: Driver supports beacon rate | ||
4636 | * configuration (AP/mesh) with VHT rates. | ||
4554 | * | 4637 | * |
4555 | * @NUM_NL80211_EXT_FEATURES: number of extended features. | 4638 | * @NUM_NL80211_EXT_FEATURES: number of extended features. |
4556 | * @MAX_NL80211_EXT_FEATURES: highest extended feature index. | 4639 | * @MAX_NL80211_EXT_FEATURES: highest extended feature index. |
@@ -4562,6 +4645,9 @@ enum nl80211_ext_feature_index { | |||
4562 | NL80211_EXT_FEATURE_SCAN_START_TIME, | 4645 | NL80211_EXT_FEATURE_SCAN_START_TIME, |
4563 | NL80211_EXT_FEATURE_BSS_PARENT_TSF, | 4646 | NL80211_EXT_FEATURE_BSS_PARENT_TSF, |
4564 | NL80211_EXT_FEATURE_SET_SCAN_DWELL, | 4647 | NL80211_EXT_FEATURE_SET_SCAN_DWELL, |
4648 | NL80211_EXT_FEATURE_BEACON_RATE_LEGACY, | ||
4649 | NL80211_EXT_FEATURE_BEACON_RATE_HT, | ||
4650 | NL80211_EXT_FEATURE_BEACON_RATE_VHT, | ||
4565 | 4651 | ||
4566 | /* add new features before the definition below */ | 4652 | /* add new features before the definition below */ |
4567 | NUM_NL80211_EXT_FEATURES, | 4653 | NUM_NL80211_EXT_FEATURES, |
@@ -4855,4 +4941,186 @@ enum nl80211_bss_select_attr { | |||
4855 | NL80211_BSS_SELECT_ATTR_MAX = __NL80211_BSS_SELECT_ATTR_AFTER_LAST - 1 | 4941 | NL80211_BSS_SELECT_ATTR_MAX = __NL80211_BSS_SELECT_ATTR_AFTER_LAST - 1 |
4856 | }; | 4942 | }; |
4857 | 4943 | ||
4944 | /** | ||
4945 | * enum nl80211_nan_dual_band_conf - NAN dual band configuration | ||
4946 | * | ||
4947 | * Defines the NAN dual band mode of operation | ||
4948 | * | ||
4949 | * @NL80211_NAN_BAND_DEFAULT: device default mode | ||
4950 | * @NL80211_NAN_BAND_2GHZ: 2.4GHz mode | ||
4951 | * @NL80211_NAN_BAND_5GHZ: 5GHz mode | ||
4952 | */ | ||
4953 | enum nl80211_nan_dual_band_conf { | ||
4954 | NL80211_NAN_BAND_DEFAULT = 1 << 0, | ||
4955 | NL80211_NAN_BAND_2GHZ = 1 << 1, | ||
4956 | NL80211_NAN_BAND_5GHZ = 1 << 2, | ||
4957 | }; | ||
4958 | |||
4959 | /** | ||
4960 | * enum nl80211_nan_function_type - NAN function type | ||
4961 | * | ||
4962 | * Defines the function type of a NAN function | ||
4963 | * | ||
4964 | * @NL80211_NAN_FUNC_PUBLISH: function is publish | ||
4965 | * @NL80211_NAN_FUNC_SUBSCRIBE: function is subscribe | ||
4966 | * @NL80211_NAN_FUNC_FOLLOW_UP: function is follow-up | ||
4967 | */ | ||
4968 | enum nl80211_nan_function_type { | ||
4969 | NL80211_NAN_FUNC_PUBLISH, | ||
4970 | NL80211_NAN_FUNC_SUBSCRIBE, | ||
4971 | NL80211_NAN_FUNC_FOLLOW_UP, | ||
4972 | |||
4973 | /* keep last */ | ||
4974 | __NL80211_NAN_FUNC_TYPE_AFTER_LAST, | ||
4975 | NL80211_NAN_FUNC_MAX_TYPE = __NL80211_NAN_FUNC_TYPE_AFTER_LAST - 1, | ||
4976 | }; | ||
4977 | |||
4978 | /** | ||
4979 | * enum nl80211_nan_publish_type - NAN publish tx type | ||
4980 | * | ||
4981 | * Defines how to send publish Service Discovery Frames | ||
4982 | * | ||
4983 | * @NL80211_NAN_SOLICITED_PUBLISH: publish function is solicited | ||
4984 | * @NL80211_NAN_UNSOLICITED_PUBLISH: publish function is unsolicited | ||
4985 | */ | ||
4986 | enum nl80211_nan_publish_type { | ||
4987 | NL80211_NAN_SOLICITED_PUBLISH = 1 << 0, | ||
4988 | NL80211_NAN_UNSOLICITED_PUBLISH = 1 << 1, | ||
4989 | }; | ||
4990 | |||
4991 | /** | ||
4992 | * enum nl80211_nan_func_term_reason - NAN functions termination reason | ||
4993 | * | ||
4994 | * Defines termination reasons of a NAN function | ||
4995 | * | ||
4996 | * @NL80211_NAN_FUNC_TERM_REASON_USER_REQUEST: requested by user | ||
4997 | * @NL80211_NAN_FUNC_TERM_REASON_TTL_EXPIRED: timeout | ||
4998 | * @NL80211_NAN_FUNC_TERM_REASON_ERROR: errored | ||
4999 | */ | ||
5000 | enum nl80211_nan_func_term_reason { | ||
5001 | NL80211_NAN_FUNC_TERM_REASON_USER_REQUEST, | ||
5002 | NL80211_NAN_FUNC_TERM_REASON_TTL_EXPIRED, | ||
5003 | NL80211_NAN_FUNC_TERM_REASON_ERROR, | ||
5004 | }; | ||
5005 | |||
5006 | #define NL80211_NAN_FUNC_SERVICE_ID_LEN 6 | ||
5007 | #define NL80211_NAN_FUNC_SERVICE_SPEC_INFO_MAX_LEN 0xff | ||
5008 | #define NL80211_NAN_FUNC_SRF_MAX_LEN 0xff | ||
5009 | |||
5010 | /** | ||
5011 | * enum nl80211_nan_func_attributes - NAN function attributes | ||
5012 | * @__NL80211_NAN_FUNC_INVALID: invalid | ||
5013 | * @NL80211_NAN_FUNC_TYPE: &enum nl80211_nan_function_type (u8). | ||
5014 | * @NL80211_NAN_FUNC_SERVICE_ID: 6 bytes of the service ID hash as | ||
5015 | * specified in NAN spec. This is a binary attribute. | ||
5016 | * @NL80211_NAN_FUNC_PUBLISH_TYPE: relevant if the function's type is | ||
5017 | * publish. Defines the transmission type for the publish Service Discovery | ||
5018 | * Frame, see &enum nl80211_nan_publish_type. Its type is u8. | ||
5019 | * @NL80211_NAN_FUNC_PUBLISH_BCAST: relevant if the function is a solicited | ||
5020 | * publish. Should the solicited publish Service Discovery Frame be sent to | ||
5021 | * the NAN Broadcast address. This is a flag. | ||
5022 | * @NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE: relevant if the function's type is | ||
5023 | * subscribe. Is the subscribe active. This is a flag. | ||
5024 | * @NL80211_NAN_FUNC_FOLLOW_UP_ID: relevant if the function's type is follow up. | ||
5025 | * The instance ID for the follow up Service Discovery Frame. This is u8. | ||
5026 | * @NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID: relevant if the function's type | ||
5027 | * is follow up. This is a u8. | ||
5028 | * The requestor instance ID for the follow up Service Discovery Frame. | ||
5029 | * @NL80211_NAN_FUNC_FOLLOW_UP_DEST: the MAC address of the recipient of the | ||
5030 | * follow up Service Discovery Frame. This is a binary attribute. | ||
5031 | * @NL80211_NAN_FUNC_CLOSE_RANGE: is this function limited for devices in a | ||
5032 | * close range. The range itself (RSSI) is defined by the device. | ||
5033 | * This is a flag. | ||
5034 | * @NL80211_NAN_FUNC_TTL: strictly positive number of DWs this function should | ||
5035 | * stay active. If not present infinite TTL is assumed. This is a u32. | ||
5036 | * @NL80211_NAN_FUNC_SERVICE_INFO: array of bytes describing the service | ||
5037 | * specific info. This is a binary attribute. | ||
5038 | * @NL80211_NAN_FUNC_SRF: Service Receive Filter. This is a nested attribute. | ||
5039 | * See &enum nl80211_nan_srf_attributes. | ||
5040 | * @NL80211_NAN_FUNC_RX_MATCH_FILTER: Receive Matching filter. This is a nested | ||
5041 | * attribute. It is a list of binary values. | ||
5042 | * @NL80211_NAN_FUNC_TX_MATCH_FILTER: Transmit Matching filter. This is a | ||
5043 | * nested attribute. It is a list of binary values. | ||
5044 | * @NL80211_NAN_FUNC_INSTANCE_ID: The instance ID of the function. | ||
5045 | * Its type is u8 and it cannot be 0. | ||
5046 | * @NL80211_NAN_FUNC_TERM_REASON: NAN function termination reason. | ||
5047 | * See &enum nl80211_nan_func_term_reason. | ||
5048 | * | ||
5049 | * @NUM_NL80211_NAN_FUNC_ATTR: internal | ||
5050 | * @NL80211_NAN_FUNC_ATTR_MAX: highest NAN function attribute | ||
5051 | */ | ||
5052 | enum nl80211_nan_func_attributes { | ||
5053 | __NL80211_NAN_FUNC_INVALID, | ||
5054 | NL80211_NAN_FUNC_TYPE, | ||
5055 | NL80211_NAN_FUNC_SERVICE_ID, | ||
5056 | NL80211_NAN_FUNC_PUBLISH_TYPE, | ||
5057 | NL80211_NAN_FUNC_PUBLISH_BCAST, | ||
5058 | NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE, | ||
5059 | NL80211_NAN_FUNC_FOLLOW_UP_ID, | ||
5060 | NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID, | ||
5061 | NL80211_NAN_FUNC_FOLLOW_UP_DEST, | ||
5062 | NL80211_NAN_FUNC_CLOSE_RANGE, | ||
5063 | NL80211_NAN_FUNC_TTL, | ||
5064 | NL80211_NAN_FUNC_SERVICE_INFO, | ||
5065 | NL80211_NAN_FUNC_SRF, | ||
5066 | NL80211_NAN_FUNC_RX_MATCH_FILTER, | ||
5067 | NL80211_NAN_FUNC_TX_MATCH_FILTER, | ||
5068 | NL80211_NAN_FUNC_INSTANCE_ID, | ||
5069 | NL80211_NAN_FUNC_TERM_REASON, | ||
5070 | |||
5071 | /* keep last */ | ||
5072 | NUM_NL80211_NAN_FUNC_ATTR, | ||
5073 | NL80211_NAN_FUNC_ATTR_MAX = NUM_NL80211_NAN_FUNC_ATTR - 1 | ||
5074 | }; | ||
5075 | |||
5076 | /** | ||
5077 | * enum nl80211_nan_srf_attributes - NAN Service Response filter attributes | ||
5078 | * @__NL80211_NAN_SRF_INVALID: invalid | ||
5079 | * @NL80211_NAN_SRF_INCLUDE: present if the include bit of the SRF set. | ||
5080 | * This is a flag. | ||
5081 | * @NL80211_NAN_SRF_BF: Bloom Filter. Present if and only if | ||
5082 | * &NL80211_NAN_SRF_MAC_ADDRS isn't present. This attribute is binary. | ||
5083 | * @NL80211_NAN_SRF_BF_IDX: index of the Bloom Filter. Mandatory if | ||
5084 | * &NL80211_NAN_SRF_BF is present. This is a u8. | ||
5085 | * @NL80211_NAN_SRF_MAC_ADDRS: list of MAC addresses for the SRF. Present if | ||
5086 | * and only if &NL80211_NAN_SRF_BF isn't present. This is a nested | ||
5087 | * attribute. Each nested attribute is a MAC address. | ||
5088 | * @NUM_NL80211_NAN_SRF_ATTR: internal | ||
5089 | * @NL80211_NAN_SRF_ATTR_MAX: highest NAN SRF attribute | ||
5090 | */ | ||
5091 | enum nl80211_nan_srf_attributes { | ||
5092 | __NL80211_NAN_SRF_INVALID, | ||
5093 | NL80211_NAN_SRF_INCLUDE, | ||
5094 | NL80211_NAN_SRF_BF, | ||
5095 | NL80211_NAN_SRF_BF_IDX, | ||
5096 | NL80211_NAN_SRF_MAC_ADDRS, | ||
5097 | |||
5098 | /* keep last */ | ||
5099 | NUM_NL80211_NAN_SRF_ATTR, | ||
5100 | NL80211_NAN_SRF_ATTR_MAX = NUM_NL80211_NAN_SRF_ATTR - 1, | ||
5101 | }; | ||
5102 | |||
5103 | /** | ||
5104 | * enum nl80211_nan_match_attributes - NAN match attributes | ||
5105 | * @__NL80211_NAN_MATCH_INVALID: invalid | ||
5106 | * @NL80211_NAN_MATCH_FUNC_LOCAL: the local function that had the | ||
5107 | * match. This is a nested attribute. | ||
5108 | * See &enum nl80211_nan_func_attributes. | ||
5109 | * @NL80211_NAN_MATCH_FUNC_PEER: the peer function | ||
5110 | * that caused the match. This is a nested attribute. | ||
5111 | * See &enum nl80211_nan_func_attributes. | ||
5112 | * | ||
5113 | * @NUM_NL80211_NAN_MATCH_ATTR: internal | ||
5114 | * @NL80211_NAN_MATCH_ATTR_MAX: highest NAN match attribute | ||
5115 | */ | ||
5116 | enum nl80211_nan_match_attributes { | ||
5117 | __NL80211_NAN_MATCH_INVALID, | ||
5118 | NL80211_NAN_MATCH_FUNC_LOCAL, | ||
5119 | NL80211_NAN_MATCH_FUNC_PEER, | ||
5120 | |||
5121 | /* keep last */ | ||
5122 | NUM_NL80211_NAN_MATCH_ATTR, | ||
5123 | NL80211_NAN_MATCH_ATTR_MAX = NUM_NL80211_NAN_MATCH_ATTR - 1 | ||
5124 | }; | ||
5125 | |||
4858 | #endif /* __LINUX_NL80211_H */ | 5126 | #endif /* __LINUX_NL80211_H */ |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index e29ff5749944..fd6541f3ade3 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -3,6 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> |
5 | * Copyright 2013-2015 Intel Mobile Communications GmbH | 5 | * Copyright 2013-2015 Intel Mobile Communications GmbH |
6 | * Copyright (C) 2015-2016 Intel Deutschland GmbH | ||
6 | * | 7 | * |
7 | * This file is GPLv2 as found in COPYING. | 8 | * This file is GPLv2 as found in COPYING. |
8 | */ | 9 | */ |
@@ -152,6 +153,149 @@ static void ieee80211_stop_p2p_device(struct wiphy *wiphy, | |||
152 | ieee80211_sdata_stop(IEEE80211_WDEV_TO_SUB_IF(wdev)); | 153 | ieee80211_sdata_stop(IEEE80211_WDEV_TO_SUB_IF(wdev)); |
153 | } | 154 | } |
154 | 155 | ||
156 | static int ieee80211_start_nan(struct wiphy *wiphy, | ||
157 | struct wireless_dev *wdev, | ||
158 | struct cfg80211_nan_conf *conf) | ||
159 | { | ||
160 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | ||
161 | int ret; | ||
162 | |||
163 | mutex_lock(&sdata->local->chanctx_mtx); | ||
164 | ret = ieee80211_check_combinations(sdata, NULL, 0, 0); | ||
165 | mutex_unlock(&sdata->local->chanctx_mtx); | ||
166 | if (ret < 0) | ||
167 | return ret; | ||
168 | |||
169 | ret = ieee80211_do_open(wdev, true); | ||
170 | if (ret) | ||
171 | return ret; | ||
172 | |||
173 | ret = drv_start_nan(sdata->local, sdata, conf); | ||
174 | if (ret) | ||
175 | ieee80211_sdata_stop(sdata); | ||
176 | |||
177 | sdata->u.nan.conf = *conf; | ||
178 | |||
179 | return ret; | ||
180 | } | ||
181 | |||
182 | static void ieee80211_stop_nan(struct wiphy *wiphy, | ||
183 | struct wireless_dev *wdev) | ||
184 | { | ||
185 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | ||
186 | |||
187 | drv_stop_nan(sdata->local, sdata); | ||
188 | ieee80211_sdata_stop(sdata); | ||
189 | } | ||
190 | |||
191 | static int ieee80211_nan_change_conf(struct wiphy *wiphy, | ||
192 | struct wireless_dev *wdev, | ||
193 | struct cfg80211_nan_conf *conf, | ||
194 | u32 changes) | ||
195 | { | ||
196 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | ||
197 | struct cfg80211_nan_conf new_conf; | ||
198 | int ret = 0; | ||
199 | |||
200 | if (sdata->vif.type != NL80211_IFTYPE_NAN) | ||
201 | return -EOPNOTSUPP; | ||
202 | |||
203 | if (!ieee80211_sdata_running(sdata)) | ||
204 | return -ENETDOWN; | ||
205 | |||
206 | new_conf = sdata->u.nan.conf; | ||
207 | |||
208 | if (changes & CFG80211_NAN_CONF_CHANGED_PREF) | ||
209 | new_conf.master_pref = conf->master_pref; | ||
210 | |||
211 | if (changes & CFG80211_NAN_CONF_CHANGED_DUAL) | ||
212 | new_conf.dual = conf->dual; | ||
213 | |||
214 | ret = drv_nan_change_conf(sdata->local, sdata, &new_conf, changes); | ||
215 | if (!ret) | ||
216 | sdata->u.nan.conf = new_conf; | ||
217 | |||
218 | return ret; | ||
219 | } | ||
220 | |||
221 | static int ieee80211_add_nan_func(struct wiphy *wiphy, | ||
222 | struct wireless_dev *wdev, | ||
223 | struct cfg80211_nan_func *nan_func) | ||
224 | { | ||
225 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | ||
226 | int ret; | ||
227 | |||
228 | if (sdata->vif.type != NL80211_IFTYPE_NAN) | ||
229 | return -EOPNOTSUPP; | ||
230 | |||
231 | if (!ieee80211_sdata_running(sdata)) | ||
232 | return -ENETDOWN; | ||
233 | |||
234 | spin_lock_bh(&sdata->u.nan.func_lock); | ||
235 | |||
236 | ret = idr_alloc(&sdata->u.nan.function_inst_ids, | ||
237 | nan_func, 1, sdata->local->hw.max_nan_de_entries + 1, | ||
238 | GFP_ATOMIC); | ||
239 | spin_unlock_bh(&sdata->u.nan.func_lock); | ||
240 | |||
241 | if (ret < 0) | ||
242 | return ret; | ||
243 | |||
244 | nan_func->instance_id = ret; | ||
245 | |||
246 | WARN_ON(nan_func->instance_id == 0); | ||
247 | |||
248 | ret = drv_add_nan_func(sdata->local, sdata, nan_func); | ||
249 | if (ret) { | ||
250 | spin_lock_bh(&sdata->u.nan.func_lock); | ||
251 | idr_remove(&sdata->u.nan.function_inst_ids, | ||
252 | nan_func->instance_id); | ||
253 | spin_unlock_bh(&sdata->u.nan.func_lock); | ||
254 | } | ||
255 | |||
256 | return ret; | ||
257 | } | ||
258 | |||
259 | static struct cfg80211_nan_func * | ||
260 | ieee80211_find_nan_func_by_cookie(struct ieee80211_sub_if_data *sdata, | ||
261 | u64 cookie) | ||
262 | { | ||
263 | struct cfg80211_nan_func *func; | ||
264 | int id; | ||
265 | |||
266 | lockdep_assert_held(&sdata->u.nan.func_lock); | ||
267 | |||
268 | idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, id) { | ||
269 | if (func->cookie == cookie) | ||
270 | return func; | ||
271 | } | ||
272 | |||
273 | return NULL; | ||
274 | } | ||
275 | |||
276 | static void ieee80211_del_nan_func(struct wiphy *wiphy, | ||
277 | struct wireless_dev *wdev, u64 cookie) | ||
278 | { | ||
279 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | ||
280 | struct cfg80211_nan_func *func; | ||
281 | u8 instance_id = 0; | ||
282 | |||
283 | if (sdata->vif.type != NL80211_IFTYPE_NAN || | ||
284 | !ieee80211_sdata_running(sdata)) | ||
285 | return; | ||
286 | |||
287 | spin_lock_bh(&sdata->u.nan.func_lock); | ||
288 | |||
289 | func = ieee80211_find_nan_func_by_cookie(sdata, cookie); | ||
290 | if (func) | ||
291 | instance_id = func->instance_id; | ||
292 | |||
293 | spin_unlock_bh(&sdata->u.nan.func_lock); | ||
294 | |||
295 | if (instance_id) | ||
296 | drv_del_nan_func(sdata->local, sdata, instance_id); | ||
297 | } | ||
298 | |||
155 | static int ieee80211_set_noack_map(struct wiphy *wiphy, | 299 | static int ieee80211_set_noack_map(struct wiphy *wiphy, |
156 | struct net_device *dev, | 300 | struct net_device *dev, |
157 | u16 noack_map) | 301 | u16 noack_map) |
@@ -257,6 +401,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
257 | case NL80211_IFTYPE_WDS: | 401 | case NL80211_IFTYPE_WDS: |
258 | case NL80211_IFTYPE_MONITOR: | 402 | case NL80211_IFTYPE_MONITOR: |
259 | case NL80211_IFTYPE_P2P_DEVICE: | 403 | case NL80211_IFTYPE_P2P_DEVICE: |
404 | case NL80211_IFTYPE_NAN: | ||
260 | case NL80211_IFTYPE_UNSPECIFIED: | 405 | case NL80211_IFTYPE_UNSPECIFIED: |
261 | case NUM_NL80211_IFTYPES: | 406 | case NUM_NL80211_IFTYPES: |
262 | case NL80211_IFTYPE_P2P_CLIENT: | 407 | case NL80211_IFTYPE_P2P_CLIENT: |
@@ -2036,6 +2181,7 @@ static int ieee80211_scan(struct wiphy *wiphy, | |||
2036 | !(req->flags & NL80211_SCAN_FLAG_AP))) | 2181 | !(req->flags & NL80211_SCAN_FLAG_AP))) |
2037 | return -EOPNOTSUPP; | 2182 | return -EOPNOTSUPP; |
2038 | break; | 2183 | break; |
2184 | case NL80211_IFTYPE_NAN: | ||
2039 | default: | 2185 | default: |
2040 | return -EOPNOTSUPP; | 2186 | return -EOPNOTSUPP; |
2041 | } | 2187 | } |
@@ -3377,6 +3523,63 @@ static int ieee80211_del_tx_ts(struct wiphy *wiphy, struct net_device *dev, | |||
3377 | return -ENOENT; | 3523 | return -ENOENT; |
3378 | } | 3524 | } |
3379 | 3525 | ||
3526 | void ieee80211_nan_func_terminated(struct ieee80211_vif *vif, | ||
3527 | u8 inst_id, | ||
3528 | enum nl80211_nan_func_term_reason reason, | ||
3529 | gfp_t gfp) | ||
3530 | { | ||
3531 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
3532 | struct cfg80211_nan_func *func; | ||
3533 | u64 cookie; | ||
3534 | |||
3535 | if (WARN_ON(vif->type != NL80211_IFTYPE_NAN)) | ||
3536 | return; | ||
3537 | |||
3538 | spin_lock_bh(&sdata->u.nan.func_lock); | ||
3539 | |||
3540 | func = idr_find(&sdata->u.nan.function_inst_ids, inst_id); | ||
3541 | if (WARN_ON(!func)) { | ||
3542 | spin_unlock_bh(&sdata->u.nan.func_lock); | ||
3543 | return; | ||
3544 | } | ||
3545 | |||
3546 | cookie = func->cookie; | ||
3547 | idr_remove(&sdata->u.nan.function_inst_ids, inst_id); | ||
3548 | |||
3549 | spin_unlock_bh(&sdata->u.nan.func_lock); | ||
3550 | |||
3551 | cfg80211_free_nan_func(func); | ||
3552 | |||
3553 | cfg80211_nan_func_terminated(ieee80211_vif_to_wdev(vif), inst_id, | ||
3554 | reason, cookie, gfp); | ||
3555 | } | ||
3556 | EXPORT_SYMBOL(ieee80211_nan_func_terminated); | ||
3557 | |||
3558 | void ieee80211_nan_func_match(struct ieee80211_vif *vif, | ||
3559 | struct cfg80211_nan_match_params *match, | ||
3560 | gfp_t gfp) | ||
3561 | { | ||
3562 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
3563 | struct cfg80211_nan_func *func; | ||
3564 | |||
3565 | if (WARN_ON(vif->type != NL80211_IFTYPE_NAN)) | ||
3566 | return; | ||
3567 | |||
3568 | spin_lock_bh(&sdata->u.nan.func_lock); | ||
3569 | |||
3570 | func = idr_find(&sdata->u.nan.function_inst_ids, match->inst_id); | ||
3571 | if (WARN_ON(!func)) { | ||
3572 | spin_unlock_bh(&sdata->u.nan.func_lock); | ||
3573 | return; | ||
3574 | } | ||
3575 | match->cookie = func->cookie; | ||
3576 | |||
3577 | spin_unlock_bh(&sdata->u.nan.func_lock); | ||
3578 | |||
3579 | cfg80211_nan_match(ieee80211_vif_to_wdev(vif), match, gfp); | ||
3580 | } | ||
3581 | EXPORT_SYMBOL(ieee80211_nan_func_match); | ||
3582 | |||
3380 | const struct cfg80211_ops mac80211_config_ops = { | 3583 | const struct cfg80211_ops mac80211_config_ops = { |
3381 | .add_virtual_intf = ieee80211_add_iface, | 3584 | .add_virtual_intf = ieee80211_add_iface, |
3382 | .del_virtual_intf = ieee80211_del_iface, | 3585 | .del_virtual_intf = ieee80211_del_iface, |
@@ -3462,4 +3665,9 @@ const struct cfg80211_ops mac80211_config_ops = { | |||
3462 | .set_ap_chanwidth = ieee80211_set_ap_chanwidth, | 3665 | .set_ap_chanwidth = ieee80211_set_ap_chanwidth, |
3463 | .add_tx_ts = ieee80211_add_tx_ts, | 3666 | .add_tx_ts = ieee80211_add_tx_ts, |
3464 | .del_tx_ts = ieee80211_del_tx_ts, | 3667 | .del_tx_ts = ieee80211_del_tx_ts, |
3668 | .start_nan = ieee80211_start_nan, | ||
3669 | .stop_nan = ieee80211_stop_nan, | ||
3670 | .nan_change_conf = ieee80211_nan_change_conf, | ||
3671 | .add_nan_func = ieee80211_add_nan_func, | ||
3672 | .del_nan_func = ieee80211_del_nan_func, | ||
3465 | }; | 3673 | }; |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 74142d07ad31..e75cbf6ecc26 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -274,6 +274,7 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, | |||
274 | ieee80211_get_max_required_bw(sdata)); | 274 | ieee80211_get_max_required_bw(sdata)); |
275 | break; | 275 | break; |
276 | case NL80211_IFTYPE_P2P_DEVICE: | 276 | case NL80211_IFTYPE_P2P_DEVICE: |
277 | case NL80211_IFTYPE_NAN: | ||
277 | continue; | 278 | continue; |
278 | case NL80211_IFTYPE_ADHOC: | 279 | case NL80211_IFTYPE_ADHOC: |
279 | case NL80211_IFTYPE_WDS: | 280 | case NL80211_IFTYPE_WDS: |
@@ -646,6 +647,9 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | |||
646 | struct ieee80211_chanctx *curr_ctx = NULL; | 647 | struct ieee80211_chanctx *curr_ctx = NULL; |
647 | int ret = 0; | 648 | int ret = 0; |
648 | 649 | ||
650 | if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_NAN)) | ||
651 | return -ENOTSUPP; | ||
652 | |||
649 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | 653 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, |
650 | lockdep_is_held(&local->chanctx_mtx)); | 654 | lockdep_is_held(&local->chanctx_mtx)); |
651 | 655 | ||
@@ -718,6 +722,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, | |||
718 | 722 | ||
719 | switch (sdata->vif.type) { | 723 | switch (sdata->vif.type) { |
720 | case NL80211_IFTYPE_P2P_DEVICE: | 724 | case NL80211_IFTYPE_P2P_DEVICE: |
725 | case NL80211_IFTYPE_NAN: | ||
721 | continue; | 726 | continue; |
722 | case NL80211_IFTYPE_STATION: | 727 | case NL80211_IFTYPE_STATION: |
723 | if (!sdata->u.mgd.associated) | 728 | if (!sdata->u.mgd.associated) |
@@ -980,6 +985,7 @@ ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata) | |||
980 | case NL80211_IFTYPE_P2P_CLIENT: | 985 | case NL80211_IFTYPE_P2P_CLIENT: |
981 | case NL80211_IFTYPE_P2P_GO: | 986 | case NL80211_IFTYPE_P2P_GO: |
982 | case NL80211_IFTYPE_P2P_DEVICE: | 987 | case NL80211_IFTYPE_P2P_DEVICE: |
988 | case NL80211_IFTYPE_NAN: | ||
983 | case NUM_NL80211_IFTYPES: | 989 | case NUM_NL80211_IFTYPES: |
984 | WARN_ON(1); | 990 | WARN_ON(1); |
985 | break; | 991 | break; |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 8ca62b6bb02a..f56e2f487d09 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -89,13 +89,19 @@ static ssize_t aqm_read(struct file *file, | |||
89 | "R fq_flows_cnt %u\n" | 89 | "R fq_flows_cnt %u\n" |
90 | "R fq_backlog %u\n" | 90 | "R fq_backlog %u\n" |
91 | "R fq_overlimit %u\n" | 91 | "R fq_overlimit %u\n" |
92 | "R fq_overmemory %u\n" | ||
92 | "R fq_collisions %u\n" | 93 | "R fq_collisions %u\n" |
94 | "R fq_memory_usage %u\n" | ||
95 | "RW fq_memory_limit %u\n" | ||
93 | "RW fq_limit %u\n" | 96 | "RW fq_limit %u\n" |
94 | "RW fq_quantum %u\n", | 97 | "RW fq_quantum %u\n", |
95 | fq->flows_cnt, | 98 | fq->flows_cnt, |
96 | fq->backlog, | 99 | fq->backlog, |
100 | fq->overmemory, | ||
97 | fq->overlimit, | 101 | fq->overlimit, |
98 | fq->collisions, | 102 | fq->collisions, |
103 | fq->memory_usage, | ||
104 | fq->memory_limit, | ||
99 | fq->limit, | 105 | fq->limit, |
100 | fq->quantum); | 106 | fq->quantum); |
101 | 107 | ||
@@ -128,6 +134,8 @@ static ssize_t aqm_write(struct file *file, | |||
128 | 134 | ||
129 | if (sscanf(buf, "fq_limit %u", &local->fq.limit) == 1) | 135 | if (sscanf(buf, "fq_limit %u", &local->fq.limit) == 1) |
130 | return count; | 136 | return count; |
137 | else if (sscanf(buf, "fq_memory_limit %u", &local->fq.memory_limit) == 1) | ||
138 | return count; | ||
131 | else if (sscanf(buf, "fq_quantum %u", &local->fq.quantum) == 1) | 139 | else if (sscanf(buf, "fq_quantum %u", &local->fq.quantum) == 1) |
132 | return count; | 140 | return count; |
133 | 141 | ||
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 5d35c0f37bb7..bcec1240f41d 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -556,9 +556,15 @@ static ssize_t ieee80211_if_parse_tsf( | |||
556 | ret = kstrtoull(buf, 10, &tsf); | 556 | ret = kstrtoull(buf, 10, &tsf); |
557 | if (ret < 0) | 557 | if (ret < 0) |
558 | return ret; | 558 | return ret; |
559 | if (tsf_is_delta) | 559 | if (tsf_is_delta && local->ops->offset_tsf) { |
560 | tsf = drv_get_tsf(local, sdata) + tsf_is_delta * tsf; | 560 | drv_offset_tsf(local, sdata, tsf_is_delta * tsf); |
561 | if (local->ops->set_tsf) { | 561 | wiphy_info(local->hw.wiphy, |
562 | "debugfs offset TSF by %018lld\n", | ||
563 | tsf_is_delta * tsf); | ||
564 | } else if (local->ops->set_tsf) { | ||
565 | if (tsf_is_delta) | ||
566 | tsf = drv_get_tsf(local, sdata) + | ||
567 | tsf_is_delta * tsf; | ||
562 | drv_set_tsf(local, sdata, tsf); | 568 | drv_set_tsf(local, sdata, tsf); |
563 | wiphy_info(local->hw.wiphy, | 569 | wiphy_info(local->hw.wiphy, |
564 | "debugfs set TSF to %#018llx\n", tsf); | 570 | "debugfs set TSF to %#018llx\n", tsf); |
diff --git a/net/mac80211/driver-ops.c b/net/mac80211/driver-ops.c index c701b6438bd9..bb886e7db47f 100644 --- a/net/mac80211/driver-ops.c +++ b/net/mac80211/driver-ops.c | |||
@@ -215,6 +215,21 @@ void drv_set_tsf(struct ieee80211_local *local, | |||
215 | trace_drv_return_void(local); | 215 | trace_drv_return_void(local); |
216 | } | 216 | } |
217 | 217 | ||
218 | void drv_offset_tsf(struct ieee80211_local *local, | ||
219 | struct ieee80211_sub_if_data *sdata, | ||
220 | s64 offset) | ||
221 | { | ||
222 | might_sleep(); | ||
223 | |||
224 | if (!check_sdata_in_driver(sdata)) | ||
225 | return; | ||
226 | |||
227 | trace_drv_offset_tsf(local, sdata, offset); | ||
228 | if (local->ops->offset_tsf) | ||
229 | local->ops->offset_tsf(&local->hw, &sdata->vif, offset); | ||
230 | trace_drv_return_void(local); | ||
231 | } | ||
232 | |||
218 | void drv_reset_tsf(struct ieee80211_local *local, | 233 | void drv_reset_tsf(struct ieee80211_local *local, |
219 | struct ieee80211_sub_if_data *sdata) | 234 | struct ieee80211_sub_if_data *sdata) |
220 | { | 235 | { |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index fe35a1c0dc86..09f77e4a8a79 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -162,6 +162,7 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, | |||
162 | return; | 162 | return; |
163 | 163 | ||
164 | if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || | 164 | if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || |
165 | sdata->vif.type == NL80211_IFTYPE_NAN || | ||
165 | (sdata->vif.type == NL80211_IFTYPE_MONITOR && | 166 | (sdata->vif.type == NL80211_IFTYPE_MONITOR && |
166 | !sdata->vif.mu_mimo_owner))) | 167 | !sdata->vif.mu_mimo_owner))) |
167 | return; | 168 | return; |
@@ -568,6 +569,9 @@ u64 drv_get_tsf(struct ieee80211_local *local, | |||
568 | void drv_set_tsf(struct ieee80211_local *local, | 569 | void drv_set_tsf(struct ieee80211_local *local, |
569 | struct ieee80211_sub_if_data *sdata, | 570 | struct ieee80211_sub_if_data *sdata, |
570 | u64 tsf); | 571 | u64 tsf); |
572 | void drv_offset_tsf(struct ieee80211_local *local, | ||
573 | struct ieee80211_sub_if_data *sdata, | ||
574 | s64 offset); | ||
571 | void drv_reset_tsf(struct ieee80211_local *local, | 575 | void drv_reset_tsf(struct ieee80211_local *local, |
572 | struct ieee80211_sub_if_data *sdata); | 576 | struct ieee80211_sub_if_data *sdata); |
573 | 577 | ||
@@ -1165,4 +1169,83 @@ static inline void drv_wake_tx_queue(struct ieee80211_local *local, | |||
1165 | local->ops->wake_tx_queue(&local->hw, &txq->txq); | 1169 | local->ops->wake_tx_queue(&local->hw, &txq->txq); |
1166 | } | 1170 | } |
1167 | 1171 | ||
1172 | static inline int drv_start_nan(struct ieee80211_local *local, | ||
1173 | struct ieee80211_sub_if_data *sdata, | ||
1174 | struct cfg80211_nan_conf *conf) | ||
1175 | { | ||
1176 | int ret; | ||
1177 | |||
1178 | might_sleep(); | ||
1179 | check_sdata_in_driver(sdata); | ||
1180 | |||
1181 | trace_drv_start_nan(local, sdata, conf); | ||
1182 | ret = local->ops->start_nan(&local->hw, &sdata->vif, conf); | ||
1183 | trace_drv_return_int(local, ret); | ||
1184 | return ret; | ||
1185 | } | ||
1186 | |||
1187 | static inline void drv_stop_nan(struct ieee80211_local *local, | ||
1188 | struct ieee80211_sub_if_data *sdata) | ||
1189 | { | ||
1190 | might_sleep(); | ||
1191 | check_sdata_in_driver(sdata); | ||
1192 | |||
1193 | trace_drv_stop_nan(local, sdata); | ||
1194 | local->ops->stop_nan(&local->hw, &sdata->vif); | ||
1195 | trace_drv_return_void(local); | ||
1196 | } | ||
1197 | |||
1198 | static inline int drv_nan_change_conf(struct ieee80211_local *local, | ||
1199 | struct ieee80211_sub_if_data *sdata, | ||
1200 | struct cfg80211_nan_conf *conf, | ||
1201 | u32 changes) | ||
1202 | { | ||
1203 | int ret; | ||
1204 | |||
1205 | might_sleep(); | ||
1206 | check_sdata_in_driver(sdata); | ||
1207 | |||
1208 | if (!local->ops->nan_change_conf) | ||
1209 | return -EOPNOTSUPP; | ||
1210 | |||
1211 | trace_drv_nan_change_conf(local, sdata, conf, changes); | ||
1212 | ret = local->ops->nan_change_conf(&local->hw, &sdata->vif, conf, | ||
1213 | changes); | ||
1214 | trace_drv_return_int(local, ret); | ||
1215 | |||
1216 | return ret; | ||
1217 | } | ||
1218 | |||
1219 | static inline int drv_add_nan_func(struct ieee80211_local *local, | ||
1220 | struct ieee80211_sub_if_data *sdata, | ||
1221 | const struct cfg80211_nan_func *nan_func) | ||
1222 | { | ||
1223 | int ret; | ||
1224 | |||
1225 | might_sleep(); | ||
1226 | check_sdata_in_driver(sdata); | ||
1227 | |||
1228 | if (!local->ops->add_nan_func) | ||
1229 | return -EOPNOTSUPP; | ||
1230 | |||
1231 | trace_drv_add_nan_func(local, sdata, nan_func); | ||
1232 | ret = local->ops->add_nan_func(&local->hw, &sdata->vif, nan_func); | ||
1233 | trace_drv_return_int(local, ret); | ||
1234 | |||
1235 | return ret; | ||
1236 | } | ||
1237 | |||
1238 | static inline void drv_del_nan_func(struct ieee80211_local *local, | ||
1239 | struct ieee80211_sub_if_data *sdata, | ||
1240 | u8 instance_id) | ||
1241 | { | ||
1242 | might_sleep(); | ||
1243 | check_sdata_in_driver(sdata); | ||
1244 | |||
1245 | trace_drv_del_nan_func(local, sdata, instance_id); | ||
1246 | if (local->ops->del_nan_func) | ||
1247 | local->ops->del_nan_func(&local->hw, &sdata->vif, instance_id); | ||
1248 | trace_drv_return_void(local); | ||
1249 | } | ||
1250 | |||
1168 | #endif /* __MAC80211_DRIVER_OPS */ | 1251 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e496dee5af08..34c2add2c455 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -86,6 +86,8 @@ struct ieee80211_local; | |||
86 | 86 | ||
87 | #define IEEE80211_DEAUTH_FRAME_LEN (24 /* hdr */ + 2 /* reason */) | 87 | #define IEEE80211_DEAUTH_FRAME_LEN (24 /* hdr */ + 2 /* reason */) |
88 | 88 | ||
89 | #define IEEE80211_MAX_NAN_INSTANCE_ID 255 | ||
90 | |||
89 | struct ieee80211_fragment_entry { | 91 | struct ieee80211_fragment_entry { |
90 | struct sk_buff_head skb_list; | 92 | struct sk_buff_head skb_list; |
91 | unsigned long first_frag_time; | 93 | unsigned long first_frag_time; |
@@ -813,12 +815,14 @@ enum txq_info_flags { | |||
813 | * @def_flow: used as a fallback flow when a packet destined to @tin hashes to | 815 | * @def_flow: used as a fallback flow when a packet destined to @tin hashes to |
814 | * a fq_flow which is already owned by a different tin | 816 | * a fq_flow which is already owned by a different tin |
815 | * @def_cvars: codel vars for @def_flow | 817 | * @def_cvars: codel vars for @def_flow |
818 | * @frags: used to keep fragments created after dequeue | ||
816 | */ | 819 | */ |
817 | struct txq_info { | 820 | struct txq_info { |
818 | struct fq_tin tin; | 821 | struct fq_tin tin; |
819 | struct fq_flow def_flow; | 822 | struct fq_flow def_flow; |
820 | struct codel_vars def_cvars; | 823 | struct codel_vars def_cvars; |
821 | struct codel_stats cstats; | 824 | struct codel_stats cstats; |
825 | struct sk_buff_head frags; | ||
822 | unsigned long flags; | 826 | unsigned long flags; |
823 | 827 | ||
824 | /* keep last! */ | 828 | /* keep last! */ |
@@ -830,6 +834,20 @@ struct ieee80211_if_mntr { | |||
830 | u8 mu_follow_addr[ETH_ALEN] __aligned(2); | 834 | u8 mu_follow_addr[ETH_ALEN] __aligned(2); |
831 | }; | 835 | }; |
832 | 836 | ||
837 | /** | ||
838 | * struct ieee80211_if_nan - NAN state | ||
839 | * | ||
840 | * @conf: current NAN configuration | ||
841 | * @func_ids: a bitmap of available instance_id's | ||
842 | */ | ||
843 | struct ieee80211_if_nan { | ||
844 | struct cfg80211_nan_conf conf; | ||
845 | |||
846 | /* protects function_inst_ids */ | ||
847 | spinlock_t func_lock; | ||
848 | struct idr function_inst_ids; | ||
849 | }; | ||
850 | |||
833 | struct ieee80211_sub_if_data { | 851 | struct ieee80211_sub_if_data { |
834 | struct list_head list; | 852 | struct list_head list; |
835 | 853 | ||
@@ -929,6 +947,7 @@ struct ieee80211_sub_if_data { | |||
929 | struct ieee80211_if_mesh mesh; | 947 | struct ieee80211_if_mesh mesh; |
930 | struct ieee80211_if_ocb ocb; | 948 | struct ieee80211_if_ocb ocb; |
931 | struct ieee80211_if_mntr mntr; | 949 | struct ieee80211_if_mntr mntr; |
950 | struct ieee80211_if_nan nan; | ||
932 | } u; | 951 | } u; |
933 | 952 | ||
934 | #ifdef CONFIG_MAC80211_DEBUGFS | 953 | #ifdef CONFIG_MAC80211_DEBUGFS |
@@ -1481,6 +1500,13 @@ static inline struct txq_info *to_txq_info(struct ieee80211_txq *txq) | |||
1481 | return container_of(txq, struct txq_info, txq); | 1500 | return container_of(txq, struct txq_info, txq); |
1482 | } | 1501 | } |
1483 | 1502 | ||
1503 | static inline bool txq_has_queue(struct ieee80211_txq *txq) | ||
1504 | { | ||
1505 | struct txq_info *txqi = to_txq_info(txq); | ||
1506 | |||
1507 | return !(skb_queue_empty(&txqi->frags) && !txqi->tin.backlog_packets); | ||
1508 | } | ||
1509 | |||
1484 | static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) | 1510 | static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) |
1485 | { | 1511 | { |
1486 | return ether_addr_equal(raddr, addr) || | 1512 | return ether_addr_equal(raddr, addr) || |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index b0abddc714ef..638ec0759078 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -327,6 +327,9 @@ static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata, | |||
327 | int n_queues = sdata->local->hw.queues; | 327 | int n_queues = sdata->local->hw.queues; |
328 | int i; | 328 | int i; |
329 | 329 | ||
330 | if (iftype == NL80211_IFTYPE_NAN) | ||
331 | return 0; | ||
332 | |||
330 | if (iftype != NL80211_IFTYPE_P2P_DEVICE) { | 333 | if (iftype != NL80211_IFTYPE_P2P_DEVICE) { |
331 | for (i = 0; i < IEEE80211_NUM_ACS; i++) { | 334 | for (i = 0; i < IEEE80211_NUM_ACS; i++) { |
332 | if (WARN_ON_ONCE(sdata->vif.hw_queue[i] == | 335 | if (WARN_ON_ONCE(sdata->vif.hw_queue[i] == |
@@ -545,6 +548,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
545 | case NL80211_IFTYPE_ADHOC: | 548 | case NL80211_IFTYPE_ADHOC: |
546 | case NL80211_IFTYPE_P2P_DEVICE: | 549 | case NL80211_IFTYPE_P2P_DEVICE: |
547 | case NL80211_IFTYPE_OCB: | 550 | case NL80211_IFTYPE_OCB: |
551 | case NL80211_IFTYPE_NAN: | ||
548 | /* no special treatment */ | 552 | /* no special treatment */ |
549 | break; | 553 | break; |
550 | case NL80211_IFTYPE_UNSPECIFIED: | 554 | case NL80211_IFTYPE_UNSPECIFIED: |
@@ -646,7 +650,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
646 | local->fif_probe_req++; | 650 | local->fif_probe_req++; |
647 | } | 651 | } |
648 | 652 | ||
649 | if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE) | 653 | if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && |
654 | sdata->vif.type != NL80211_IFTYPE_NAN) | ||
650 | changed |= ieee80211_reset_erp_info(sdata); | 655 | changed |= ieee80211_reset_erp_info(sdata); |
651 | ieee80211_bss_info_change_notify(sdata, changed); | 656 | ieee80211_bss_info_change_notify(sdata, changed); |
652 | 657 | ||
@@ -660,6 +665,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
660 | break; | 665 | break; |
661 | case NL80211_IFTYPE_WDS: | 666 | case NL80211_IFTYPE_WDS: |
662 | case NL80211_IFTYPE_P2P_DEVICE: | 667 | case NL80211_IFTYPE_P2P_DEVICE: |
668 | case NL80211_IFTYPE_NAN: | ||
663 | break; | 669 | break; |
664 | default: | 670 | default: |
665 | /* not reached */ | 671 | /* not reached */ |
@@ -792,6 +798,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
792 | struct ps_data *ps; | 798 | struct ps_data *ps; |
793 | struct cfg80211_chan_def chandef; | 799 | struct cfg80211_chan_def chandef; |
794 | bool cancel_scan; | 800 | bool cancel_scan; |
801 | struct cfg80211_nan_func *func; | ||
795 | 802 | ||
796 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | 803 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); |
797 | 804 | ||
@@ -944,6 +951,18 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
944 | 951 | ||
945 | ieee80211_adjust_monitor_flags(sdata, -1); | 952 | ieee80211_adjust_monitor_flags(sdata, -1); |
946 | break; | 953 | break; |
954 | case NL80211_IFTYPE_NAN: | ||
955 | /* clean all the functions */ | ||
956 | spin_lock_bh(&sdata->u.nan.func_lock); | ||
957 | |||
958 | idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, i) { | ||
959 | idr_remove(&sdata->u.nan.function_inst_ids, i); | ||
960 | cfg80211_free_nan_func(func); | ||
961 | } | ||
962 | idr_destroy(&sdata->u.nan.function_inst_ids); | ||
963 | |||
964 | spin_unlock_bh(&sdata->u.nan.func_lock); | ||
965 | break; | ||
947 | case NL80211_IFTYPE_P2P_DEVICE: | 966 | case NL80211_IFTYPE_P2P_DEVICE: |
948 | /* relies on synchronize_rcu() below */ | 967 | /* relies on synchronize_rcu() below */ |
949 | RCU_INIT_POINTER(local->p2p_sdata, NULL); | 968 | RCU_INIT_POINTER(local->p2p_sdata, NULL); |
@@ -1455,6 +1474,11 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
1455 | case NL80211_IFTYPE_WDS: | 1474 | case NL80211_IFTYPE_WDS: |
1456 | sdata->vif.bss_conf.bssid = NULL; | 1475 | sdata->vif.bss_conf.bssid = NULL; |
1457 | break; | 1476 | break; |
1477 | case NL80211_IFTYPE_NAN: | ||
1478 | idr_init(&sdata->u.nan.function_inst_ids); | ||
1479 | spin_lock_init(&sdata->u.nan.func_lock); | ||
1480 | sdata->vif.bss_conf.bssid = sdata->vif.addr; | ||
1481 | break; | ||
1458 | case NL80211_IFTYPE_AP_VLAN: | 1482 | case NL80211_IFTYPE_AP_VLAN: |
1459 | case NL80211_IFTYPE_P2P_DEVICE: | 1483 | case NL80211_IFTYPE_P2P_DEVICE: |
1460 | sdata->vif.bss_conf.bssid = sdata->vif.addr; | 1484 | sdata->vif.bss_conf.bssid = sdata->vif.addr; |
@@ -1722,7 +1746,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1722 | 1746 | ||
1723 | ASSERT_RTNL(); | 1747 | ASSERT_RTNL(); |
1724 | 1748 | ||
1725 | if (type == NL80211_IFTYPE_P2P_DEVICE) { | 1749 | if (type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN) { |
1726 | struct wireless_dev *wdev; | 1750 | struct wireless_dev *wdev; |
1727 | 1751 | ||
1728 | sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, | 1752 | sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index ac053a9df36d..1075ac24c8c5 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -821,6 +821,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
821 | !local->ops->tdls_recv_channel_switch)) | 821 | !local->ops->tdls_recv_channel_switch)) |
822 | return -EOPNOTSUPP; | 822 | return -EOPNOTSUPP; |
823 | 823 | ||
824 | if (WARN_ON(local->hw.wiphy->interface_modes & | ||
825 | BIT(NL80211_IFTYPE_NAN) && | ||
826 | (!local->ops->start_nan || !local->ops->stop_nan))) | ||
827 | return -EINVAL; | ||
828 | |||
824 | #ifdef CONFIG_PM | 829 | #ifdef CONFIG_PM |
825 | if (hw->wiphy->wowlan && (!local->ops->suspend || !local->ops->resume)) | 830 | if (hw->wiphy->wowlan && (!local->ops->suspend || !local->ops->resume)) |
826 | return -EINVAL; | 831 | return -EINVAL; |
@@ -1058,6 +1063,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
1058 | 1063 | ||
1059 | local->dynamic_ps_forced_timeout = -1; | 1064 | local->dynamic_ps_forced_timeout = -1; |
1060 | 1065 | ||
1066 | if (!local->hw.max_nan_de_entries) | ||
1067 | local->hw.max_nan_de_entries = IEEE80211_MAX_NAN_INSTANCE_ID; | ||
1068 | |||
1061 | result = ieee80211_wep_init(local); | 1069 | result = ieee80211_wep_init(local); |
1062 | if (result < 0) | 1070 | if (result < 0) |
1063 | wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n", | 1071 | wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n", |
diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c index 64bc22ad9496..faca22cd02b5 100644 --- a/net/mac80211/mesh_sync.c +++ b/net/mac80211/mesh_sync.c | |||
@@ -28,7 +28,7 @@ | |||
28 | * could be, for instance, in case a neighbor is restarted and its TSF counter | 28 | * could be, for instance, in case a neighbor is restarted and its TSF counter |
29 | * reset. | 29 | * reset. |
30 | */ | 30 | */ |
31 | #define TOFFSET_MAXIMUM_ADJUSTMENT 30000 /* 30 ms */ | 31 | #define TOFFSET_MAXIMUM_ADJUSTMENT 800 /* 0.8 ms */ |
32 | 32 | ||
33 | struct sync_method { | 33 | struct sync_method { |
34 | u8 method; | 34 | u8 method; |
@@ -70,9 +70,13 @@ void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata) | |||
70 | } | 70 | } |
71 | spin_unlock_bh(&ifmsh->sync_offset_lock); | 71 | spin_unlock_bh(&ifmsh->sync_offset_lock); |
72 | 72 | ||
73 | tsf = drv_get_tsf(local, sdata); | 73 | if (local->ops->offset_tsf) { |
74 | if (tsf != -1ULL) | 74 | drv_offset_tsf(local, sdata, tsfdelta); |
75 | drv_set_tsf(local, sdata, tsf + tsfdelta); | 75 | } else { |
76 | tsf = drv_get_tsf(local, sdata); | ||
77 | if (tsf != -1ULL) | ||
78 | drv_set_tsf(local, sdata, tsf + tsfdelta); | ||
79 | } | ||
76 | } | 80 | } |
77 | 81 | ||
78 | static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | 82 | static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 55a9c5b94ce1..c3f610bba3fe 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c | |||
@@ -128,7 +128,8 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local) | |||
128 | if (!ieee80211_sdata_running(sdata)) | 128 | if (!ieee80211_sdata_running(sdata)) |
129 | continue; | 129 | continue; |
130 | 130 | ||
131 | if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) | 131 | if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || |
132 | sdata->vif.type == NL80211_IFTYPE_NAN) | ||
132 | continue; | 133 | continue; |
133 | 134 | ||
134 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR) | 135 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR) |
@@ -838,6 +839,7 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
838 | case NL80211_IFTYPE_P2P_DEVICE: | 839 | case NL80211_IFTYPE_P2P_DEVICE: |
839 | need_offchan = true; | 840 | need_offchan = true; |
840 | break; | 841 | break; |
842 | case NL80211_IFTYPE_NAN: | ||
841 | default: | 843 | default: |
842 | return -EOPNOTSUPP; | 844 | return -EOPNOTSUPP; |
843 | } | 845 | } |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index f7cf342bab52..6175db385ba7 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1323,9 +1323,7 @@ static void sta_ps_start(struct sta_info *sta) | |||
1323 | return; | 1323 | return; |
1324 | 1324 | ||
1325 | for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) { | 1325 | for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) { |
1326 | struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]); | 1326 | if (txq_has_queue(sta->sta.txq[tid])) |
1327 | |||
1328 | if (txqi->tin.backlog_packets) | ||
1329 | set_bit(tid, &sta->txq_buffered_tids); | 1327 | set_bit(tid, &sta->txq_buffered_tids); |
1330 | else | 1328 | else |
1331 | clear_bit(tid, &sta->txq_buffered_tids); | 1329 | clear_bit(tid, &sta->txq_buffered_tids); |
@@ -3586,6 +3584,9 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx) | |||
3586 | ieee80211_is_probe_req(hdr->frame_control) || | 3584 | ieee80211_is_probe_req(hdr->frame_control) || |
3587 | ieee80211_is_probe_resp(hdr->frame_control) || | 3585 | ieee80211_is_probe_resp(hdr->frame_control) || |
3588 | ieee80211_is_beacon(hdr->frame_control); | 3586 | ieee80211_is_beacon(hdr->frame_control); |
3587 | case NL80211_IFTYPE_NAN: | ||
3588 | /* Currently no frames on NAN interface are allowed */ | ||
3589 | return false; | ||
3589 | default: | 3590 | default: |
3590 | break; | 3591 | break; |
3591 | } | 3592 | } |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 011880d633b4..78e9ecbc96e6 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -1202,12 +1202,10 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
1202 | 1202 | ||
1203 | if (sta->sta.txq[0]) { | 1203 | if (sta->sta.txq[0]) { |
1204 | for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { | 1204 | for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { |
1205 | struct txq_info *txqi = to_txq_info(sta->sta.txq[i]); | 1205 | if (!txq_has_queue(sta->sta.txq[i])) |
1206 | |||
1207 | if (!txqi->tin.backlog_packets) | ||
1208 | continue; | 1206 | continue; |
1209 | 1207 | ||
1210 | drv_wake_tx_queue(local, txqi); | 1208 | drv_wake_tx_queue(local, to_txq_info(sta->sta.txq[i])); |
1211 | } | 1209 | } |
1212 | } | 1210 | } |
1213 | 1211 | ||
@@ -1638,10 +1636,8 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta, | |||
1638 | return; | 1636 | return; |
1639 | 1637 | ||
1640 | for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) { | 1638 | for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) { |
1641 | struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]); | ||
1642 | |||
1643 | if (!(driver_release_tids & BIT(tid)) || | 1639 | if (!(driver_release_tids & BIT(tid)) || |
1644 | txqi->tin.backlog_packets) | 1640 | txq_has_queue(sta->sta.txq[tid])) |
1645 | continue; | 1641 | continue; |
1646 | 1642 | ||
1647 | sta_info_recalc_tim(sta); | 1643 | sta_info_recalc_tim(sta); |
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 77e4c53baefb..92a47afaa989 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -984,6 +984,32 @@ TRACE_EVENT(drv_set_tsf, | |||
984 | ) | 984 | ) |
985 | ); | 985 | ); |
986 | 986 | ||
987 | TRACE_EVENT(drv_offset_tsf, | ||
988 | TP_PROTO(struct ieee80211_local *local, | ||
989 | struct ieee80211_sub_if_data *sdata, | ||
990 | s64 offset), | ||
991 | |||
992 | TP_ARGS(local, sdata, offset), | ||
993 | |||
994 | TP_STRUCT__entry( | ||
995 | LOCAL_ENTRY | ||
996 | VIF_ENTRY | ||
997 | __field(s64, tsf_offset) | ||
998 | ), | ||
999 | |||
1000 | TP_fast_assign( | ||
1001 | LOCAL_ASSIGN; | ||
1002 | VIF_ASSIGN; | ||
1003 | __entry->tsf_offset = offset; | ||
1004 | ), | ||
1005 | |||
1006 | TP_printk( | ||
1007 | LOCAL_PR_FMT VIF_PR_FMT " tsf offset:%lld", | ||
1008 | LOCAL_PR_ARG, VIF_PR_ARG, | ||
1009 | (unsigned long long)__entry->tsf_offset | ||
1010 | ) | ||
1011 | ); | ||
1012 | |||
987 | DEFINE_EVENT(local_sdata_evt, drv_reset_tsf, | 1013 | DEFINE_EVENT(local_sdata_evt, drv_reset_tsf, |
988 | TP_PROTO(struct ieee80211_local *local, | 1014 | TP_PROTO(struct ieee80211_local *local, |
989 | struct ieee80211_sub_if_data *sdata), | 1015 | struct ieee80211_sub_if_data *sdata), |
@@ -1700,6 +1726,139 @@ TRACE_EVENT(drv_get_expected_throughput, | |||
1700 | ) | 1726 | ) |
1701 | ); | 1727 | ); |
1702 | 1728 | ||
1729 | TRACE_EVENT(drv_start_nan, | ||
1730 | TP_PROTO(struct ieee80211_local *local, | ||
1731 | struct ieee80211_sub_if_data *sdata, | ||
1732 | struct cfg80211_nan_conf *conf), | ||
1733 | |||
1734 | TP_ARGS(local, sdata, conf), | ||
1735 | TP_STRUCT__entry( | ||
1736 | LOCAL_ENTRY | ||
1737 | VIF_ENTRY | ||
1738 | __field(u8, master_pref) | ||
1739 | __field(u8, dual) | ||
1740 | ), | ||
1741 | |||
1742 | TP_fast_assign( | ||
1743 | LOCAL_ASSIGN; | ||
1744 | VIF_ASSIGN; | ||
1745 | __entry->master_pref = conf->master_pref; | ||
1746 | __entry->dual = conf->dual; | ||
1747 | ), | ||
1748 | |||
1749 | TP_printk( | ||
1750 | LOCAL_PR_FMT VIF_PR_FMT | ||
1751 | ", master preference: %u, dual: %d", | ||
1752 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->master_pref, | ||
1753 | __entry->dual | ||
1754 | ) | ||
1755 | ); | ||
1756 | |||
1757 | TRACE_EVENT(drv_stop_nan, | ||
1758 | TP_PROTO(struct ieee80211_local *local, | ||
1759 | struct ieee80211_sub_if_data *sdata), | ||
1760 | |||
1761 | TP_ARGS(local, sdata), | ||
1762 | |||
1763 | TP_STRUCT__entry( | ||
1764 | LOCAL_ENTRY | ||
1765 | VIF_ENTRY | ||
1766 | ), | ||
1767 | |||
1768 | TP_fast_assign( | ||
1769 | LOCAL_ASSIGN; | ||
1770 | VIF_ASSIGN; | ||
1771 | ), | ||
1772 | |||
1773 | TP_printk( | ||
1774 | LOCAL_PR_FMT VIF_PR_FMT, | ||
1775 | LOCAL_PR_ARG, VIF_PR_ARG | ||
1776 | ) | ||
1777 | ); | ||
1778 | |||
1779 | TRACE_EVENT(drv_nan_change_conf, | ||
1780 | TP_PROTO(struct ieee80211_local *local, | ||
1781 | struct ieee80211_sub_if_data *sdata, | ||
1782 | struct cfg80211_nan_conf *conf, | ||
1783 | u32 changes), | ||
1784 | |||
1785 | TP_ARGS(local, sdata, conf, changes), | ||
1786 | TP_STRUCT__entry( | ||
1787 | LOCAL_ENTRY | ||
1788 | VIF_ENTRY | ||
1789 | __field(u8, master_pref) | ||
1790 | __field(u8, dual) | ||
1791 | __field(u32, changes) | ||
1792 | ), | ||
1793 | |||
1794 | TP_fast_assign( | ||
1795 | LOCAL_ASSIGN; | ||
1796 | VIF_ASSIGN; | ||
1797 | __entry->master_pref = conf->master_pref; | ||
1798 | __entry->dual = conf->dual; | ||
1799 | __entry->changes = changes; | ||
1800 | ), | ||
1801 | |||
1802 | TP_printk( | ||
1803 | LOCAL_PR_FMT VIF_PR_FMT | ||
1804 | ", master preference: %u, dual: %d, changes: 0x%x", | ||
1805 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->master_pref, | ||
1806 | __entry->dual, __entry->changes | ||
1807 | ) | ||
1808 | ); | ||
1809 | |||
1810 | TRACE_EVENT(drv_add_nan_func, | ||
1811 | TP_PROTO(struct ieee80211_local *local, | ||
1812 | struct ieee80211_sub_if_data *sdata, | ||
1813 | const struct cfg80211_nan_func *func), | ||
1814 | |||
1815 | TP_ARGS(local, sdata, func), | ||
1816 | TP_STRUCT__entry( | ||
1817 | LOCAL_ENTRY | ||
1818 | VIF_ENTRY | ||
1819 | __field(u8, type) | ||
1820 | __field(u8, inst_id) | ||
1821 | ), | ||
1822 | |||
1823 | TP_fast_assign( | ||
1824 | LOCAL_ASSIGN; | ||
1825 | VIF_ASSIGN; | ||
1826 | __entry->type = func->type; | ||
1827 | __entry->inst_id = func->instance_id; | ||
1828 | ), | ||
1829 | |||
1830 | TP_printk( | ||
1831 | LOCAL_PR_FMT VIF_PR_FMT | ||
1832 | ", type: %u, inst_id: %u", | ||
1833 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->type, __entry->inst_id | ||
1834 | ) | ||
1835 | ); | ||
1836 | |||
1837 | TRACE_EVENT(drv_del_nan_func, | ||
1838 | TP_PROTO(struct ieee80211_local *local, | ||
1839 | struct ieee80211_sub_if_data *sdata, | ||
1840 | u8 instance_id), | ||
1841 | |||
1842 | TP_ARGS(local, sdata, instance_id), | ||
1843 | TP_STRUCT__entry( | ||
1844 | LOCAL_ENTRY | ||
1845 | VIF_ENTRY | ||
1846 | __field(u8, instance_id) | ||
1847 | ), | ||
1848 | |||
1849 | TP_fast_assign( | ||
1850 | LOCAL_ASSIGN; | ||
1851 | VIF_ASSIGN; | ||
1852 | __entry->instance_id = instance_id; | ||
1853 | ), | ||
1854 | |||
1855 | TP_printk( | ||
1856 | LOCAL_PR_FMT VIF_PR_FMT | ||
1857 | ", instance_id: %u", | ||
1858 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->instance_id | ||
1859 | ) | ||
1860 | ); | ||
1861 | |||
1703 | /* | 1862 | /* |
1704 | * Tracing for API calls that drivers call. | 1863 | * Tracing for API calls that drivers call. |
1705 | */ | 1864 | */ |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 1ff08be90a98..1c56abc49627 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -796,36 +796,6 @@ static __le16 ieee80211_tx_next_seq(struct sta_info *sta, int tid) | |||
796 | return ret; | 796 | return ret; |
797 | } | 797 | } |
798 | 798 | ||
799 | static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local, | ||
800 | struct ieee80211_vif *vif, | ||
801 | struct ieee80211_sta *pubsta, | ||
802 | struct sk_buff *skb) | ||
803 | { | ||
804 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
805 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
806 | struct ieee80211_txq *txq = NULL; | ||
807 | |||
808 | if ((info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) || | ||
809 | (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE)) | ||
810 | return NULL; | ||
811 | |||
812 | if (!ieee80211_is_data(hdr->frame_control)) | ||
813 | return NULL; | ||
814 | |||
815 | if (pubsta) { | ||
816 | u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; | ||
817 | |||
818 | txq = pubsta->txq[tid]; | ||
819 | } else if (vif) { | ||
820 | txq = vif->txq; | ||
821 | } | ||
822 | |||
823 | if (!txq) | ||
824 | return NULL; | ||
825 | |||
826 | return to_txq_info(txq); | ||
827 | } | ||
828 | |||
829 | static ieee80211_tx_result debug_noinline | 799 | static ieee80211_tx_result debug_noinline |
830 | ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) | 800 | ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) |
831 | { | 801 | { |
@@ -883,9 +853,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) | |||
883 | tid = *qc & IEEE80211_QOS_CTL_TID_MASK; | 853 | tid = *qc & IEEE80211_QOS_CTL_TID_MASK; |
884 | tx->sta->tx_stats.msdu[tid]++; | 854 | tx->sta->tx_stats.msdu[tid]++; |
885 | 855 | ||
886 | if (!ieee80211_get_txq(tx->local, info->control.vif, &tx->sta->sta, | 856 | hdr->seq_ctrl = ieee80211_tx_next_seq(tx->sta, tid); |
887 | tx->skb)) | ||
888 | hdr->seq_ctrl = ieee80211_tx_next_seq(tx->sta, tid); | ||
889 | 857 | ||
890 | return TX_CONTINUE; | 858 | return TX_CONTINUE; |
891 | } | 859 | } |
@@ -1274,6 +1242,36 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
1274 | return TX_CONTINUE; | 1242 | return TX_CONTINUE; |
1275 | } | 1243 | } |
1276 | 1244 | ||
1245 | static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local, | ||
1246 | struct ieee80211_vif *vif, | ||
1247 | struct ieee80211_sta *pubsta, | ||
1248 | struct sk_buff *skb) | ||
1249 | { | ||
1250 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
1251 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
1252 | struct ieee80211_txq *txq = NULL; | ||
1253 | |||
1254 | if ((info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) || | ||
1255 | (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE)) | ||
1256 | return NULL; | ||
1257 | |||
1258 | if (!ieee80211_is_data(hdr->frame_control)) | ||
1259 | return NULL; | ||
1260 | |||
1261 | if (pubsta) { | ||
1262 | u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; | ||
1263 | |||
1264 | txq = pubsta->txq[tid]; | ||
1265 | } else if (vif) { | ||
1266 | txq = vif->txq; | ||
1267 | } | ||
1268 | |||
1269 | if (!txq) | ||
1270 | return NULL; | ||
1271 | |||
1272 | return to_txq_info(txq); | ||
1273 | } | ||
1274 | |||
1277 | static void ieee80211_set_skb_enqueue_time(struct sk_buff *skb) | 1275 | static void ieee80211_set_skb_enqueue_time(struct sk_buff *skb) |
1278 | { | 1276 | { |
1279 | IEEE80211_SKB_CB(skb)->control.enqueue_time = codel_get_time(); | 1277 | IEEE80211_SKB_CB(skb)->control.enqueue_time = codel_get_time(); |
@@ -1405,6 +1403,7 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata, | |||
1405 | fq_flow_init(&txqi->def_flow); | 1403 | fq_flow_init(&txqi->def_flow); |
1406 | codel_vars_init(&txqi->def_cvars); | 1404 | codel_vars_init(&txqi->def_cvars); |
1407 | codel_stats_init(&txqi->cstats); | 1405 | codel_stats_init(&txqi->cstats); |
1406 | __skb_queue_head_init(&txqi->frags); | ||
1408 | 1407 | ||
1409 | txqi->txq.vif = &sdata->vif; | 1408 | txqi->txq.vif = &sdata->vif; |
1410 | 1409 | ||
@@ -1427,6 +1426,7 @@ void ieee80211_txq_purge(struct ieee80211_local *local, | |||
1427 | struct fq_tin *tin = &txqi->tin; | 1426 | struct fq_tin *tin = &txqi->tin; |
1428 | 1427 | ||
1429 | fq_tin_reset(fq, tin, fq_skb_free_func); | 1428 | fq_tin_reset(fq, tin, fq_skb_free_func); |
1429 | ieee80211_purge_tx_queue(&local->hw, &txqi->frags); | ||
1430 | } | 1430 | } |
1431 | 1431 | ||
1432 | int ieee80211_txq_setup_flows(struct ieee80211_local *local) | 1432 | int ieee80211_txq_setup_flows(struct ieee80211_local *local) |
@@ -1434,6 +1434,8 @@ int ieee80211_txq_setup_flows(struct ieee80211_local *local) | |||
1434 | struct fq *fq = &local->fq; | 1434 | struct fq *fq = &local->fq; |
1435 | int ret; | 1435 | int ret; |
1436 | int i; | 1436 | int i; |
1437 | bool supp_vht = false; | ||
1438 | enum nl80211_band band; | ||
1437 | 1439 | ||
1438 | if (!local->ops->wake_tx_queue) | 1440 | if (!local->ops->wake_tx_queue) |
1439 | return 0; | 1441 | return 0; |
@@ -1442,6 +1444,23 @@ int ieee80211_txq_setup_flows(struct ieee80211_local *local) | |||
1442 | if (ret) | 1444 | if (ret) |
1443 | return ret; | 1445 | return ret; |
1444 | 1446 | ||
1447 | /* | ||
1448 | * If the hardware doesn't support VHT, it is safe to limit the maximum | ||
1449 | * queue size. 4 Mbytes is 64 max-size aggregates in 802.11n. | ||
1450 | */ | ||
1451 | for (band = 0; band < NUM_NL80211_BANDS; band++) { | ||
1452 | struct ieee80211_supported_band *sband; | ||
1453 | |||
1454 | sband = local->hw.wiphy->bands[band]; | ||
1455 | if (!sband) | ||
1456 | continue; | ||
1457 | |||
1458 | supp_vht = supp_vht || sband->vht_cap.vht_supported; | ||
1459 | } | ||
1460 | |||
1461 | if (!supp_vht) | ||
1462 | fq->memory_limit = 4 << 20; /* 4 Mbytes */ | ||
1463 | |||
1445 | codel_params_init(&local->cparams); | 1464 | codel_params_init(&local->cparams); |
1446 | local->cparams.interval = MS2TIME(100); | 1465 | local->cparams.interval = MS2TIME(100); |
1447 | local->cparams.target = MS2TIME(20); | 1466 | local->cparams.target = MS2TIME(20); |
@@ -1477,54 +1496,46 @@ void ieee80211_txq_teardown_flows(struct ieee80211_local *local) | |||
1477 | spin_unlock_bh(&fq->lock); | 1496 | spin_unlock_bh(&fq->lock); |
1478 | } | 1497 | } |
1479 | 1498 | ||
1480 | struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, | 1499 | static bool ieee80211_queue_skb(struct ieee80211_local *local, |
1481 | struct ieee80211_txq *txq) | 1500 | struct ieee80211_sub_if_data *sdata, |
1501 | struct sta_info *sta, | ||
1502 | struct sk_buff *skb) | ||
1482 | { | 1503 | { |
1483 | struct ieee80211_local *local = hw_to_local(hw); | 1504 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1484 | struct txq_info *txqi = container_of(txq, struct txq_info, txq); | ||
1485 | struct ieee80211_hdr *hdr; | ||
1486 | struct sk_buff *skb = NULL; | ||
1487 | struct fq *fq = &local->fq; | 1505 | struct fq *fq = &local->fq; |
1488 | struct fq_tin *tin = &txqi->tin; | 1506 | struct ieee80211_vif *vif; |
1507 | struct txq_info *txqi; | ||
1508 | struct ieee80211_sta *pubsta; | ||
1489 | 1509 | ||
1490 | spin_lock_bh(&fq->lock); | 1510 | if (!local->ops->wake_tx_queue || |
1511 | sdata->vif.type == NL80211_IFTYPE_MONITOR) | ||
1512 | return false; | ||
1491 | 1513 | ||
1492 | if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags)) | 1514 | if (sta && sta->uploaded) |
1493 | goto out; | 1515 | pubsta = &sta->sta; |
1516 | else | ||
1517 | pubsta = NULL; | ||
1494 | 1518 | ||
1495 | skb = fq_tin_dequeue(fq, tin, fq_tin_dequeue_func); | 1519 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
1496 | if (!skb) | 1520 | sdata = container_of(sdata->bss, |
1497 | goto out; | 1521 | struct ieee80211_sub_if_data, u.ap); |
1498 | 1522 | ||
1499 | ieee80211_set_skb_vif(skb, txqi); | 1523 | vif = &sdata->vif; |
1524 | txqi = ieee80211_get_txq(local, vif, pubsta, skb); | ||
1500 | 1525 | ||
1501 | hdr = (struct ieee80211_hdr *)skb->data; | 1526 | if (!txqi) |
1502 | if (txq->sta && ieee80211_is_data_qos(hdr->frame_control)) { | 1527 | return false; |
1503 | struct sta_info *sta = container_of(txq->sta, struct sta_info, | ||
1504 | sta); | ||
1505 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
1506 | 1528 | ||
1507 | hdr->seq_ctrl = ieee80211_tx_next_seq(sta, txq->tid); | 1529 | info->control.vif = vif; |
1508 | if (test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags)) | ||
1509 | info->flags |= IEEE80211_TX_CTL_AMPDU; | ||
1510 | else | ||
1511 | info->flags &= ~IEEE80211_TX_CTL_AMPDU; | ||
1512 | } | ||
1513 | 1530 | ||
1514 | out: | 1531 | spin_lock_bh(&fq->lock); |
1532 | ieee80211_txq_enqueue(local, txqi, skb); | ||
1515 | spin_unlock_bh(&fq->lock); | 1533 | spin_unlock_bh(&fq->lock); |
1516 | 1534 | ||
1517 | if (skb && skb_has_frag_list(skb) && | 1535 | drv_wake_tx_queue(local, txqi); |
1518 | !ieee80211_hw_check(&local->hw, TX_FRAG_LIST)) { | ||
1519 | if (skb_linearize(skb)) { | ||
1520 | ieee80211_free_txskb(&local->hw, skb); | ||
1521 | return NULL; | ||
1522 | } | ||
1523 | } | ||
1524 | 1536 | ||
1525 | return skb; | 1537 | return true; |
1526 | } | 1538 | } |
1527 | EXPORT_SYMBOL(ieee80211_tx_dequeue); | ||
1528 | 1539 | ||
1529 | static bool ieee80211_tx_frags(struct ieee80211_local *local, | 1540 | static bool ieee80211_tx_frags(struct ieee80211_local *local, |
1530 | struct ieee80211_vif *vif, | 1541 | struct ieee80211_vif *vif, |
@@ -1533,9 +1544,7 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local, | |||
1533 | bool txpending) | 1544 | bool txpending) |
1534 | { | 1545 | { |
1535 | struct ieee80211_tx_control control = {}; | 1546 | struct ieee80211_tx_control control = {}; |
1536 | struct fq *fq = &local->fq; | ||
1537 | struct sk_buff *skb, *tmp; | 1547 | struct sk_buff *skb, *tmp; |
1538 | struct txq_info *txqi; | ||
1539 | unsigned long flags; | 1548 | unsigned long flags; |
1540 | 1549 | ||
1541 | skb_queue_walk_safe(skbs, skb, tmp) { | 1550 | skb_queue_walk_safe(skbs, skb, tmp) { |
@@ -1550,21 +1559,6 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local, | |||
1550 | } | 1559 | } |
1551 | #endif | 1560 | #endif |
1552 | 1561 | ||
1553 | txqi = ieee80211_get_txq(local, vif, sta, skb); | ||
1554 | if (txqi) { | ||
1555 | info->control.vif = vif; | ||
1556 | |||
1557 | __skb_unlink(skb, skbs); | ||
1558 | |||
1559 | spin_lock_bh(&fq->lock); | ||
1560 | ieee80211_txq_enqueue(local, txqi, skb); | ||
1561 | spin_unlock_bh(&fq->lock); | ||
1562 | |||
1563 | drv_wake_tx_queue(local, txqi); | ||
1564 | |||
1565 | continue; | ||
1566 | } | ||
1567 | |||
1568 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 1562 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
1569 | if (local->queue_stop_reasons[q] || | 1563 | if (local->queue_stop_reasons[q] || |
1570 | (!txpending && !skb_queue_empty(&local->pending[q]))) { | 1564 | (!txpending && !skb_queue_empty(&local->pending[q]))) { |
@@ -1685,10 +1679,13 @@ static bool __ieee80211_tx(struct ieee80211_local *local, | |||
1685 | /* | 1679 | /* |
1686 | * Invoke TX handlers, return 0 on success and non-zero if the | 1680 | * Invoke TX handlers, return 0 on success and non-zero if the |
1687 | * frame was dropped or queued. | 1681 | * frame was dropped or queued. |
1682 | * | ||
1683 | * The handlers are split into an early and late part. The latter is everything | ||
1684 | * that can be sensitive to reordering, and will be deferred to after packets | ||
1685 | * are dequeued from the intermediate queues (when they are enabled). | ||
1688 | */ | 1686 | */ |
1689 | static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | 1687 | static int invoke_tx_handlers_early(struct ieee80211_tx_data *tx) |
1690 | { | 1688 | { |
1691 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | ||
1692 | ieee80211_tx_result res = TX_DROP; | 1689 | ieee80211_tx_result res = TX_DROP; |
1693 | 1690 | ||
1694 | #define CALL_TXH(txh) \ | 1691 | #define CALL_TXH(txh) \ |
@@ -1706,6 +1703,31 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | |||
1706 | if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL)) | 1703 | if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL)) |
1707 | CALL_TXH(ieee80211_tx_h_rate_ctrl); | 1704 | CALL_TXH(ieee80211_tx_h_rate_ctrl); |
1708 | 1705 | ||
1706 | txh_done: | ||
1707 | if (unlikely(res == TX_DROP)) { | ||
1708 | I802_DEBUG_INC(tx->local->tx_handlers_drop); | ||
1709 | if (tx->skb) | ||
1710 | ieee80211_free_txskb(&tx->local->hw, tx->skb); | ||
1711 | else | ||
1712 | ieee80211_purge_tx_queue(&tx->local->hw, &tx->skbs); | ||
1713 | return -1; | ||
1714 | } else if (unlikely(res == TX_QUEUED)) { | ||
1715 | I802_DEBUG_INC(tx->local->tx_handlers_queued); | ||
1716 | return -1; | ||
1717 | } | ||
1718 | |||
1719 | return 0; | ||
1720 | } | ||
1721 | |||
1722 | /* | ||
1723 | * Late handlers can be called while the sta lock is held. Handlers that can | ||
1724 | * cause packets to be generated will cause deadlock! | ||
1725 | */ | ||
1726 | static int invoke_tx_handlers_late(struct ieee80211_tx_data *tx) | ||
1727 | { | ||
1728 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | ||
1729 | ieee80211_tx_result res = TX_CONTINUE; | ||
1730 | |||
1709 | if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION)) { | 1731 | if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION)) { |
1710 | __skb_queue_tail(&tx->skbs, tx->skb); | 1732 | __skb_queue_tail(&tx->skbs, tx->skb); |
1711 | tx->skb = NULL; | 1733 | tx->skb = NULL; |
@@ -1738,6 +1760,15 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | |||
1738 | return 0; | 1760 | return 0; |
1739 | } | 1761 | } |
1740 | 1762 | ||
1763 | static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | ||
1764 | { | ||
1765 | int r = invoke_tx_handlers_early(tx); | ||
1766 | |||
1767 | if (r) | ||
1768 | return r; | ||
1769 | return invoke_tx_handlers_late(tx); | ||
1770 | } | ||
1771 | |||
1741 | bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw, | 1772 | bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw, |
1742 | struct ieee80211_vif *vif, struct sk_buff *skb, | 1773 | struct ieee80211_vif *vif, struct sk_buff *skb, |
1743 | int band, struct ieee80211_sta **sta) | 1774 | int band, struct ieee80211_sta **sta) |
@@ -1812,7 +1843,13 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, | |||
1812 | info->hw_queue = | 1843 | info->hw_queue = |
1813 | sdata->vif.hw_queue[skb_get_queue_mapping(skb)]; | 1844 | sdata->vif.hw_queue[skb_get_queue_mapping(skb)]; |
1814 | 1845 | ||
1815 | if (!invoke_tx_handlers(&tx)) | 1846 | if (invoke_tx_handlers_early(&tx)) |
1847 | return false; | ||
1848 | |||
1849 | if (ieee80211_queue_skb(local, sdata, tx.sta, tx.skb)) | ||
1850 | return true; | ||
1851 | |||
1852 | if (!invoke_tx_handlers_late(&tx)) | ||
1816 | result = __ieee80211_tx(local, &tx.skbs, led_len, | 1853 | result = __ieee80211_tx(local, &tx.skbs, led_len, |
1817 | tx.sta, txpending); | 1854 | tx.sta, txpending); |
1818 | 1855 | ||
@@ -3156,8 +3193,71 @@ out: | |||
3156 | return ret; | 3193 | return ret; |
3157 | } | 3194 | } |
3158 | 3195 | ||
3196 | /* | ||
3197 | * Can be called while the sta lock is held. Anything that can cause packets to | ||
3198 | * be generated will cause deadlock! | ||
3199 | */ | ||
3200 | static void ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata, | ||
3201 | struct sta_info *sta, u8 pn_offs, | ||
3202 | struct ieee80211_key *key, | ||
3203 | struct sk_buff *skb) | ||
3204 | { | ||
3205 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
3206 | struct ieee80211_hdr *hdr = (void *)skb->data; | ||
3207 | u8 tid = IEEE80211_NUM_TIDS; | ||
3208 | |||
3209 | if (key) | ||
3210 | info->control.hw_key = &key->conf; | ||
3211 | |||
3212 | ieee80211_tx_stats(skb->dev, skb->len); | ||
3213 | |||
3214 | if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) { | ||
3215 | tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; | ||
3216 | *ieee80211_get_qos_ctl(hdr) = tid; | ||
3217 | hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid); | ||
3218 | } else { | ||
3219 | info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; | ||
3220 | hdr->seq_ctrl = cpu_to_le16(sdata->sequence_number); | ||
3221 | sdata->sequence_number += 0x10; | ||
3222 | } | ||
3223 | |||
3224 | if (skb_shinfo(skb)->gso_size) | ||
3225 | sta->tx_stats.msdu[tid] += | ||
3226 | DIV_ROUND_UP(skb->len, skb_shinfo(skb)->gso_size); | ||
3227 | else | ||
3228 | sta->tx_stats.msdu[tid]++; | ||
3229 | |||
3230 | info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)]; | ||
3231 | |||
3232 | /* statistics normally done by ieee80211_tx_h_stats (but that | ||
3233 | * has to consider fragmentation, so is more complex) | ||
3234 | */ | ||
3235 | sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len; | ||
3236 | sta->tx_stats.packets[skb_get_queue_mapping(skb)]++; | ||
3237 | |||
3238 | if (pn_offs) { | ||
3239 | u64 pn; | ||
3240 | u8 *crypto_hdr = skb->data + pn_offs; | ||
3241 | |||
3242 | switch (key->conf.cipher) { | ||
3243 | case WLAN_CIPHER_SUITE_CCMP: | ||
3244 | case WLAN_CIPHER_SUITE_CCMP_256: | ||
3245 | case WLAN_CIPHER_SUITE_GCMP: | ||
3246 | case WLAN_CIPHER_SUITE_GCMP_256: | ||
3247 | pn = atomic64_inc_return(&key->conf.tx_pn); | ||
3248 | crypto_hdr[0] = pn; | ||
3249 | crypto_hdr[1] = pn >> 8; | ||
3250 | crypto_hdr[4] = pn >> 16; | ||
3251 | crypto_hdr[5] = pn >> 24; | ||
3252 | crypto_hdr[6] = pn >> 32; | ||
3253 | crypto_hdr[7] = pn >> 40; | ||
3254 | break; | ||
3255 | } | ||
3256 | } | ||
3257 | } | ||
3258 | |||
3159 | static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, | 3259 | static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, |
3160 | struct net_device *dev, struct sta_info *sta, | 3260 | struct sta_info *sta, |
3161 | struct ieee80211_fast_tx *fast_tx, | 3261 | struct ieee80211_fast_tx *fast_tx, |
3162 | struct sk_buff *skb) | 3262 | struct sk_buff *skb) |
3163 | { | 3263 | { |
@@ -3208,8 +3308,6 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, | |||
3208 | return true; | 3308 | return true; |
3209 | } | 3309 | } |
3210 | 3310 | ||
3211 | ieee80211_tx_stats(dev, skb->len + extra_head); | ||
3212 | |||
3213 | if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) && | 3311 | if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) && |
3214 | ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb)) | 3312 | ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb)) |
3215 | return true; | 3313 | return true; |
@@ -3238,24 +3336,7 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, | |||
3238 | info->flags = IEEE80211_TX_CTL_FIRST_FRAGMENT | | 3336 | info->flags = IEEE80211_TX_CTL_FIRST_FRAGMENT | |
3239 | IEEE80211_TX_CTL_DONTFRAG | | 3337 | IEEE80211_TX_CTL_DONTFRAG | |
3240 | (tid_tx ? IEEE80211_TX_CTL_AMPDU : 0); | 3338 | (tid_tx ? IEEE80211_TX_CTL_AMPDU : 0); |
3241 | 3339 | info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT; | |
3242 | if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) { | ||
3243 | *ieee80211_get_qos_ctl(hdr) = tid; | ||
3244 | if (!ieee80211_get_txq(local, &sdata->vif, &sta->sta, skb)) | ||
3245 | hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid); | ||
3246 | } else { | ||
3247 | info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; | ||
3248 | hdr->seq_ctrl = cpu_to_le16(sdata->sequence_number); | ||
3249 | sdata->sequence_number += 0x10; | ||
3250 | } | ||
3251 | |||
3252 | if (skb_shinfo(skb)->gso_size) | ||
3253 | sta->tx_stats.msdu[tid] += | ||
3254 | DIV_ROUND_UP(skb->len, skb_shinfo(skb)->gso_size); | ||
3255 | else | ||
3256 | sta->tx_stats.msdu[tid]++; | ||
3257 | |||
3258 | info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)]; | ||
3259 | 3340 | ||
3260 | __skb_queue_head_init(&tx.skbs); | 3341 | __skb_queue_head_init(&tx.skbs); |
3261 | 3342 | ||
@@ -3265,9 +3346,6 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, | |||
3265 | tx.sta = sta; | 3346 | tx.sta = sta; |
3266 | tx.key = fast_tx->key; | 3347 | tx.key = fast_tx->key; |
3267 | 3348 | ||
3268 | if (fast_tx->key) | ||
3269 | info->control.hw_key = &fast_tx->key->conf; | ||
3270 | |||
3271 | if (!ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) { | 3349 | if (!ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) { |
3272 | tx.skb = skb; | 3350 | tx.skb = skb; |
3273 | r = ieee80211_tx_h_rate_ctrl(&tx); | 3351 | r = ieee80211_tx_h_rate_ctrl(&tx); |
@@ -3281,31 +3359,11 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, | |||
3281 | } | 3359 | } |
3282 | } | 3360 | } |
3283 | 3361 | ||
3284 | /* statistics normally done by ieee80211_tx_h_stats (but that | 3362 | if (ieee80211_queue_skb(local, sdata, sta, skb)) |
3285 | * has to consider fragmentation, so is more complex) | 3363 | return true; |
3286 | */ | ||
3287 | sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len; | ||
3288 | sta->tx_stats.packets[skb_get_queue_mapping(skb)]++; | ||
3289 | |||
3290 | if (fast_tx->pn_offs) { | ||
3291 | u64 pn; | ||
3292 | u8 *crypto_hdr = skb->data + fast_tx->pn_offs; | ||
3293 | 3364 | ||
3294 | switch (fast_tx->key->conf.cipher) { | 3365 | ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs, |
3295 | case WLAN_CIPHER_SUITE_CCMP: | 3366 | fast_tx->key, skb); |
3296 | case WLAN_CIPHER_SUITE_CCMP_256: | ||
3297 | case WLAN_CIPHER_SUITE_GCMP: | ||
3298 | case WLAN_CIPHER_SUITE_GCMP_256: | ||
3299 | pn = atomic64_inc_return(&fast_tx->key->conf.tx_pn); | ||
3300 | crypto_hdr[0] = pn; | ||
3301 | crypto_hdr[1] = pn >> 8; | ||
3302 | crypto_hdr[4] = pn >> 16; | ||
3303 | crypto_hdr[5] = pn >> 24; | ||
3304 | crypto_hdr[6] = pn >> 32; | ||
3305 | crypto_hdr[7] = pn >> 40; | ||
3306 | break; | ||
3307 | } | ||
3308 | } | ||
3309 | 3367 | ||
3310 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 3368 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
3311 | sdata = container_of(sdata->bss, | 3369 | sdata = container_of(sdata->bss, |
@@ -3316,6 +3374,94 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, | |||
3316 | return true; | 3374 | return true; |
3317 | } | 3375 | } |
3318 | 3376 | ||
3377 | struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, | ||
3378 | struct ieee80211_txq *txq) | ||
3379 | { | ||
3380 | struct ieee80211_local *local = hw_to_local(hw); | ||
3381 | struct txq_info *txqi = container_of(txq, struct txq_info, txq); | ||
3382 | struct ieee80211_hdr *hdr; | ||
3383 | struct sk_buff *skb = NULL; | ||
3384 | struct fq *fq = &local->fq; | ||
3385 | struct fq_tin *tin = &txqi->tin; | ||
3386 | struct ieee80211_tx_info *info; | ||
3387 | struct ieee80211_tx_data tx; | ||
3388 | ieee80211_tx_result r; | ||
3389 | |||
3390 | spin_lock_bh(&fq->lock); | ||
3391 | |||
3392 | if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags)) | ||
3393 | goto out; | ||
3394 | |||
3395 | /* Make sure fragments stay together. */ | ||
3396 | skb = __skb_dequeue(&txqi->frags); | ||
3397 | if (skb) | ||
3398 | goto out; | ||
3399 | |||
3400 | begin: | ||
3401 | skb = fq_tin_dequeue(fq, tin, fq_tin_dequeue_func); | ||
3402 | if (!skb) | ||
3403 | goto out; | ||
3404 | |||
3405 | ieee80211_set_skb_vif(skb, txqi); | ||
3406 | |||
3407 | hdr = (struct ieee80211_hdr *)skb->data; | ||
3408 | info = IEEE80211_SKB_CB(skb); | ||
3409 | |||
3410 | memset(&tx, 0, sizeof(tx)); | ||
3411 | __skb_queue_head_init(&tx.skbs); | ||
3412 | tx.local = local; | ||
3413 | tx.skb = skb; | ||
3414 | tx.sdata = vif_to_sdata(info->control.vif); | ||
3415 | |||
3416 | if (txq->sta) | ||
3417 | tx.sta = container_of(txq->sta, struct sta_info, sta); | ||
3418 | |||
3419 | /* | ||
3420 | * The key can be removed while the packet was queued, so need to call | ||
3421 | * this here to get the current key. | ||
3422 | */ | ||
3423 | r = ieee80211_tx_h_select_key(&tx); | ||
3424 | if (r != TX_CONTINUE) { | ||
3425 | ieee80211_free_txskb(&local->hw, skb); | ||
3426 | goto begin; | ||
3427 | } | ||
3428 | |||
3429 | if (info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) { | ||
3430 | struct sta_info *sta = container_of(txq->sta, struct sta_info, | ||
3431 | sta); | ||
3432 | u8 pn_offs = 0; | ||
3433 | |||
3434 | if (tx.key && | ||
3435 | (tx.key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) | ||
3436 | pn_offs = ieee80211_hdrlen(hdr->frame_control); | ||
3437 | |||
3438 | ieee80211_xmit_fast_finish(sta->sdata, sta, pn_offs, | ||
3439 | tx.key, skb); | ||
3440 | } else { | ||
3441 | if (invoke_tx_handlers_late(&tx)) | ||
3442 | goto begin; | ||
3443 | |||
3444 | skb = __skb_dequeue(&tx.skbs); | ||
3445 | |||
3446 | if (!skb_queue_empty(&tx.skbs)) | ||
3447 | skb_queue_splice_tail(&tx.skbs, &txqi->frags); | ||
3448 | } | ||
3449 | |||
3450 | if (skb && skb_has_frag_list(skb) && | ||
3451 | !ieee80211_hw_check(&local->hw, TX_FRAG_LIST)) { | ||
3452 | if (skb_linearize(skb)) { | ||
3453 | ieee80211_free_txskb(&local->hw, skb); | ||
3454 | goto begin; | ||
3455 | } | ||
3456 | } | ||
3457 | |||
3458 | out: | ||
3459 | spin_unlock_bh(&fq->lock); | ||
3460 | |||
3461 | return skb; | ||
3462 | } | ||
3463 | EXPORT_SYMBOL(ieee80211_tx_dequeue); | ||
3464 | |||
3319 | void __ieee80211_subif_start_xmit(struct sk_buff *skb, | 3465 | void __ieee80211_subif_start_xmit(struct sk_buff *skb, |
3320 | struct net_device *dev, | 3466 | struct net_device *dev, |
3321 | u32 info_flags) | 3467 | u32 info_flags) |
@@ -3340,7 +3486,7 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
3340 | fast_tx = rcu_dereference(sta->fast_tx); | 3486 | fast_tx = rcu_dereference(sta->fast_tx); |
3341 | 3487 | ||
3342 | if (fast_tx && | 3488 | if (fast_tx && |
3343 | ieee80211_xmit_fast(sdata, dev, sta, fast_tx, skb)) | 3489 | ieee80211_xmit_fast(sdata, sta, fast_tx, skb)) |
3344 | goto out; | 3490 | goto out; |
3345 | } | 3491 | } |
3346 | 3492 | ||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index b6865d884487..545c79a42a77 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1209,7 +1209,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
1209 | } | 1209 | } |
1210 | 1210 | ||
1211 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR && | 1211 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR && |
1212 | sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE) { | 1212 | sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && |
1213 | sdata->vif.type != NL80211_IFTYPE_NAN) { | ||
1213 | sdata->vif.bss_conf.qos = enable_qos; | 1214 | sdata->vif.bss_conf.qos = enable_qos; |
1214 | if (bss_notify) | 1215 | if (bss_notify) |
1215 | ieee80211_bss_info_change_notify(sdata, | 1216 | ieee80211_bss_info_change_notify(sdata, |
@@ -1748,6 +1749,46 @@ static void ieee80211_reconfig_stations(struct ieee80211_sub_if_data *sdata) | |||
1748 | mutex_unlock(&local->sta_mtx); | 1749 | mutex_unlock(&local->sta_mtx); |
1749 | } | 1750 | } |
1750 | 1751 | ||
1752 | static int ieee80211_reconfig_nan(struct ieee80211_sub_if_data *sdata) | ||
1753 | { | ||
1754 | struct cfg80211_nan_func *func, **funcs; | ||
1755 | int res, id, i = 0; | ||
1756 | |||
1757 | res = drv_start_nan(sdata->local, sdata, | ||
1758 | &sdata->u.nan.conf); | ||
1759 | if (WARN_ON(res)) | ||
1760 | return res; | ||
1761 | |||
1762 | funcs = kzalloc((sdata->local->hw.max_nan_de_entries + 1) * | ||
1763 | sizeof(*funcs), GFP_KERNEL); | ||
1764 | if (!funcs) | ||
1765 | return -ENOMEM; | ||
1766 | |||
1767 | /* Add all the functions: | ||
1768 | * This is a little bit ugly. We need to call a potentially sleeping | ||
1769 | * callback for each NAN function, so we can't hold the spinlock. | ||
1770 | */ | ||
1771 | spin_lock_bh(&sdata->u.nan.func_lock); | ||
1772 | |||
1773 | idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, id) | ||
1774 | funcs[i++] = func; | ||
1775 | |||
1776 | spin_unlock_bh(&sdata->u.nan.func_lock); | ||
1777 | |||
1778 | for (i = 0; funcs[i]; i++) { | ||
1779 | res = drv_add_nan_func(sdata->local, sdata, funcs[i]); | ||
1780 | if (WARN_ON(res)) | ||
1781 | ieee80211_nan_func_terminated(&sdata->vif, | ||
1782 | funcs[i]->instance_id, | ||
1783 | NL80211_NAN_FUNC_TERM_REASON_ERROR, | ||
1784 | GFP_KERNEL); | ||
1785 | } | ||
1786 | |||
1787 | kfree(funcs); | ||
1788 | |||
1789 | return 0; | ||
1790 | } | ||
1791 | |||
1751 | int ieee80211_reconfig(struct ieee80211_local *local) | 1792 | int ieee80211_reconfig(struct ieee80211_local *local) |
1752 | { | 1793 | { |
1753 | struct ieee80211_hw *hw = &local->hw; | 1794 | struct ieee80211_hw *hw = &local->hw; |
@@ -1971,6 +2012,13 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1971 | ieee80211_bss_info_change_notify(sdata, changed); | 2012 | ieee80211_bss_info_change_notify(sdata, changed); |
1972 | } | 2013 | } |
1973 | break; | 2014 | break; |
2015 | case NL80211_IFTYPE_NAN: | ||
2016 | res = ieee80211_reconfig_nan(sdata); | ||
2017 | if (res < 0) { | ||
2018 | ieee80211_handle_reconfig_failure(local); | ||
2019 | return res; | ||
2020 | } | ||
2021 | break; | ||
1974 | case NL80211_IFTYPE_WDS: | 2022 | case NL80211_IFTYPE_WDS: |
1975 | case NL80211_IFTYPE_AP_VLAN: | 2023 | case NL80211_IFTYPE_AP_VLAN: |
1976 | case NL80211_IFTYPE_MONITOR: | 2024 | case NL80211_IFTYPE_MONITOR: |
@@ -3393,11 +3441,18 @@ void ieee80211_txq_get_depth(struct ieee80211_txq *txq, | |||
3393 | unsigned long *byte_cnt) | 3441 | unsigned long *byte_cnt) |
3394 | { | 3442 | { |
3395 | struct txq_info *txqi = to_txq_info(txq); | 3443 | struct txq_info *txqi = to_txq_info(txq); |
3444 | u32 frag_cnt = 0, frag_bytes = 0; | ||
3445 | struct sk_buff *skb; | ||
3446 | |||
3447 | skb_queue_walk(&txqi->frags, skb) { | ||
3448 | frag_cnt++; | ||
3449 | frag_bytes += skb->len; | ||
3450 | } | ||
3396 | 3451 | ||
3397 | if (frame_cnt) | 3452 | if (frame_cnt) |
3398 | *frame_cnt = txqi->tin.backlog_packets; | 3453 | *frame_cnt = txqi->tin.backlog_packets + frag_cnt; |
3399 | 3454 | ||
3400 | if (byte_cnt) | 3455 | if (byte_cnt) |
3401 | *byte_cnt = txqi->tin.backlog_bytes; | 3456 | *byte_cnt = txqi->tin.backlog_bytes + frag_bytes; |
3402 | } | 3457 | } |
3403 | EXPORT_SYMBOL(ieee80211_txq_get_depth); | 3458 | EXPORT_SYMBOL(ieee80211_txq_get_depth); |
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 0f506220a3bd..5497d022fada 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
@@ -372,6 +372,7 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy, | |||
372 | case NL80211_IFTYPE_AP_VLAN: | 372 | case NL80211_IFTYPE_AP_VLAN: |
373 | case NL80211_IFTYPE_WDS: | 373 | case NL80211_IFTYPE_WDS: |
374 | case NL80211_IFTYPE_P2P_DEVICE: | 374 | case NL80211_IFTYPE_P2P_DEVICE: |
375 | case NL80211_IFTYPE_NAN: | ||
375 | break; | 376 | break; |
376 | case NL80211_IFTYPE_UNSPECIFIED: | 377 | case NL80211_IFTYPE_UNSPECIFIED: |
377 | case NUM_NL80211_IFTYPES: | 378 | case NUM_NL80211_IFTYPES: |
@@ -946,6 +947,7 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, | |||
946 | case NL80211_IFTYPE_AP_VLAN: | 947 | case NL80211_IFTYPE_AP_VLAN: |
947 | case NL80211_IFTYPE_WDS: | 948 | case NL80211_IFTYPE_WDS: |
948 | case NL80211_IFTYPE_P2P_DEVICE: | 949 | case NL80211_IFTYPE_P2P_DEVICE: |
950 | case NL80211_IFTYPE_NAN: | ||
949 | /* these interface types don't really have a channel */ | 951 | /* these interface types don't really have a channel */ |
950 | return; | 952 | return; |
951 | case NL80211_IFTYPE_UNSPECIFIED: | 953 | case NL80211_IFTYPE_UNSPECIFIED: |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 4911cd997b9a..8201e6d7449e 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -225,6 +225,23 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, | |||
225 | } | 225 | } |
226 | } | 226 | } |
227 | 227 | ||
228 | void cfg80211_stop_nan(struct cfg80211_registered_device *rdev, | ||
229 | struct wireless_dev *wdev) | ||
230 | { | ||
231 | ASSERT_RTNL(); | ||
232 | |||
233 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_NAN)) | ||
234 | return; | ||
235 | |||
236 | if (!wdev->nan_started) | ||
237 | return; | ||
238 | |||
239 | rdev_stop_nan(rdev, wdev); | ||
240 | wdev->nan_started = false; | ||
241 | |||
242 | rdev->opencount--; | ||
243 | } | ||
244 | |||
228 | void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy) | 245 | void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy) |
229 | { | 246 | { |
230 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | 247 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); |
@@ -242,6 +259,9 @@ void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy) | |||
242 | case NL80211_IFTYPE_P2P_DEVICE: | 259 | case NL80211_IFTYPE_P2P_DEVICE: |
243 | cfg80211_stop_p2p_device(rdev, wdev); | 260 | cfg80211_stop_p2p_device(rdev, wdev); |
244 | break; | 261 | break; |
262 | case NL80211_IFTYPE_NAN: | ||
263 | cfg80211_stop_nan(rdev, wdev); | ||
264 | break; | ||
245 | default: | 265 | default: |
246 | break; | 266 | break; |
247 | } | 267 | } |
@@ -537,6 +557,11 @@ static int wiphy_verify_combinations(struct wiphy *wiphy) | |||
537 | c->limits[j].max > 1)) | 557 | c->limits[j].max > 1)) |
538 | return -EINVAL; | 558 | return -EINVAL; |
539 | 559 | ||
560 | /* Only a single NAN can be allowed */ | ||
561 | if (WARN_ON(types & BIT(NL80211_IFTYPE_NAN) && | ||
562 | c->limits[j].max > 1)) | ||
563 | return -EINVAL; | ||
564 | |||
540 | cnt += c->limits[j].max; | 565 | cnt += c->limits[j].max; |
541 | /* | 566 | /* |
542 | * Don't advertise an unsupported type | 567 | * Don't advertise an unsupported type |
@@ -579,6 +604,11 @@ int wiphy_register(struct wiphy *wiphy) | |||
579 | !rdev->ops->tdls_cancel_channel_switch))) | 604 | !rdev->ops->tdls_cancel_channel_switch))) |
580 | return -EINVAL; | 605 | return -EINVAL; |
581 | 606 | ||
607 | if (WARN_ON((wiphy->interface_modes & BIT(NL80211_IFTYPE_NAN)) && | ||
608 | (!rdev->ops->start_nan || !rdev->ops->stop_nan || | ||
609 | !rdev->ops->add_nan_func || !rdev->ops->del_nan_func))) | ||
610 | return -EINVAL; | ||
611 | |||
582 | /* | 612 | /* |
583 | * if a wiphy has unsupported modes for regulatory channel enforcement, | 613 | * if a wiphy has unsupported modes for regulatory channel enforcement, |
584 | * opt-out of enforcement checking | 614 | * opt-out of enforcement checking |
@@ -589,6 +619,7 @@ int wiphy_register(struct wiphy *wiphy) | |||
589 | BIT(NL80211_IFTYPE_P2P_GO) | | 619 | BIT(NL80211_IFTYPE_P2P_GO) | |
590 | BIT(NL80211_IFTYPE_ADHOC) | | 620 | BIT(NL80211_IFTYPE_ADHOC) | |
591 | BIT(NL80211_IFTYPE_P2P_DEVICE) | | 621 | BIT(NL80211_IFTYPE_P2P_DEVICE) | |
622 | BIT(NL80211_IFTYPE_NAN) | | ||
592 | BIT(NL80211_IFTYPE_AP_VLAN) | | 623 | BIT(NL80211_IFTYPE_AP_VLAN) | |
593 | BIT(NL80211_IFTYPE_MONITOR))) | 624 | BIT(NL80211_IFTYPE_MONITOR))) |
594 | wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF; | 625 | wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF; |
@@ -916,6 +947,9 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev) | |||
916 | cfg80211_mlme_purge_registrations(wdev); | 947 | cfg80211_mlme_purge_registrations(wdev); |
917 | cfg80211_stop_p2p_device(rdev, wdev); | 948 | cfg80211_stop_p2p_device(rdev, wdev); |
918 | break; | 949 | break; |
950 | case NL80211_IFTYPE_NAN: | ||
951 | cfg80211_stop_nan(rdev, wdev); | ||
952 | break; | ||
919 | default: | 953 | default: |
920 | WARN_ON_ONCE(1); | 954 | WARN_ON_ONCE(1); |
921 | break; | 955 | break; |
@@ -979,6 +1013,7 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev, | |||
979 | /* must be handled by mac80211/driver, has no APIs */ | 1013 | /* must be handled by mac80211/driver, has no APIs */ |
980 | break; | 1014 | break; |
981 | case NL80211_IFTYPE_P2P_DEVICE: | 1015 | case NL80211_IFTYPE_P2P_DEVICE: |
1016 | case NL80211_IFTYPE_NAN: | ||
982 | /* cannot happen, has no netdev */ | 1017 | /* cannot happen, has no netdev */ |
983 | break; | 1018 | break; |
984 | case NL80211_IFTYPE_AP_VLAN: | 1019 | case NL80211_IFTYPE_AP_VLAN: |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 5555e3c13ae9..08d2e948c9ad 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -249,8 +249,8 @@ struct cfg80211_event { | |||
249 | }; | 249 | }; |
250 | 250 | ||
251 | struct cfg80211_cached_keys { | 251 | struct cfg80211_cached_keys { |
252 | struct key_params params[4]; | 252 | struct key_params params[CFG80211_MAX_WEP_KEYS]; |
253 | u8 data[4][WLAN_KEY_LEN_WEP104]; | 253 | u8 data[CFG80211_MAX_WEP_KEYS][WLAN_KEY_LEN_WEP104]; |
254 | int def; | 254 | int def; |
255 | }; | 255 | }; |
256 | 256 | ||
@@ -488,6 +488,9 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, | |||
488 | void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, | 488 | void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, |
489 | struct wireless_dev *wdev); | 489 | struct wireless_dev *wdev); |
490 | 490 | ||
491 | void cfg80211_stop_nan(struct cfg80211_registered_device *rdev, | ||
492 | struct wireless_dev *wdev); | ||
493 | |||
491 | #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 | 494 | #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 |
492 | 495 | ||
493 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS | 496 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index eafdfa5798ae..364f900a3dc4 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
@@ -43,7 +43,8 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, | |||
43 | cfg80211_hold_bss(bss_from_pub(bss)); | 43 | cfg80211_hold_bss(bss_from_pub(bss)); |
44 | wdev->current_bss = bss_from_pub(bss); | 44 | wdev->current_bss = bss_from_pub(bss); |
45 | 45 | ||
46 | cfg80211_upload_connect_keys(wdev); | 46 | if (!(wdev->wiphy->flags & WIPHY_FLAG_HAS_STATIC_WEP)) |
47 | cfg80211_upload_connect_keys(wdev); | ||
47 | 48 | ||
48 | nl80211_send_ibss_bssid(wiphy_to_rdev(wdev->wiphy), dev, bssid, | 49 | nl80211_send_ibss_bssid(wiphy_to_rdev(wdev->wiphy), dev, bssid, |
49 | GFP_KERNEL); | 50 | GFP_KERNEL); |
@@ -296,7 +297,7 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, | |||
296 | ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL); | 297 | ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL); |
297 | if (!ck) | 298 | if (!ck) |
298 | return -ENOMEM; | 299 | return -ENOMEM; |
299 | for (i = 0; i < 4; i++) | 300 | for (i = 0; i < CFG80211_MAX_WEP_KEYS; i++) |
300 | ck->params[i].key = ck->data[i]; | 301 | ck->params[i].key = ck->data[i]; |
301 | } | 302 | } |
302 | err = __cfg80211_join_ibss(rdev, wdev->netdev, | 303 | err = __cfg80211_join_ibss(rdev, wdev->netdev, |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index d6abb0704db5..cbb48e26a871 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -634,6 +634,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | |||
634 | * fall through, P2P device only supports | 634 | * fall through, P2P device only supports |
635 | * public action frames | 635 | * public action frames |
636 | */ | 636 | */ |
637 | case NL80211_IFTYPE_NAN: | ||
637 | default: | 638 | default: |
638 | err = -EOPNOTSUPP; | 639 | err = -EOPNOTSUPP; |
639 | break; | 640 | break; |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index fd111e2b559d..c510810f0b7c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -56,6 +56,7 @@ enum nl80211_multicast_groups { | |||
56 | NL80211_MCGRP_REGULATORY, | 56 | NL80211_MCGRP_REGULATORY, |
57 | NL80211_MCGRP_MLME, | 57 | NL80211_MCGRP_MLME, |
58 | NL80211_MCGRP_VENDOR, | 58 | NL80211_MCGRP_VENDOR, |
59 | NL80211_MCGRP_NAN, | ||
59 | NL80211_MCGRP_TESTMODE /* keep last - ifdef! */ | 60 | NL80211_MCGRP_TESTMODE /* keep last - ifdef! */ |
60 | }; | 61 | }; |
61 | 62 | ||
@@ -65,6 +66,7 @@ static const struct genl_multicast_group nl80211_mcgrps[] = { | |||
65 | [NL80211_MCGRP_REGULATORY] = { .name = NL80211_MULTICAST_GROUP_REG }, | 66 | [NL80211_MCGRP_REGULATORY] = { .name = NL80211_MULTICAST_GROUP_REG }, |
66 | [NL80211_MCGRP_MLME] = { .name = NL80211_MULTICAST_GROUP_MLME }, | 67 | [NL80211_MCGRP_MLME] = { .name = NL80211_MULTICAST_GROUP_MLME }, |
67 | [NL80211_MCGRP_VENDOR] = { .name = NL80211_MULTICAST_GROUP_VENDOR }, | 68 | [NL80211_MCGRP_VENDOR] = { .name = NL80211_MULTICAST_GROUP_VENDOR }, |
69 | [NL80211_MCGRP_NAN] = { .name = NL80211_MULTICAST_GROUP_NAN }, | ||
68 | #ifdef CONFIG_NL80211_TESTMODE | 70 | #ifdef CONFIG_NL80211_TESTMODE |
69 | [NL80211_MCGRP_TESTMODE] = { .name = NL80211_MULTICAST_GROUP_TESTMODE } | 71 | [NL80211_MCGRP_TESTMODE] = { .name = NL80211_MULTICAST_GROUP_TESTMODE } |
70 | #endif | 72 | #endif |
@@ -409,6 +411,9 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { | |||
409 | .len = VHT_MUMIMO_GROUPS_DATA_LEN | 411 | .len = VHT_MUMIMO_GROUPS_DATA_LEN |
410 | }, | 412 | }, |
411 | [NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR] = { .len = ETH_ALEN }, | 413 | [NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR] = { .len = ETH_ALEN }, |
414 | [NL80211_ATTR_NAN_MASTER_PREF] = { .type = NLA_U8 }, | ||
415 | [NL80211_ATTR_NAN_DUAL] = { .type = NLA_U8 }, | ||
416 | [NL80211_ATTR_NAN_FUNC] = { .type = NLA_NESTED }, | ||
412 | }; | 417 | }; |
413 | 418 | ||
414 | /* policy for the key attributes */ | 419 | /* policy for the key attributes */ |
@@ -502,6 +507,39 @@ nl80211_bss_select_policy[NL80211_BSS_SELECT_ATTR_MAX + 1] = { | |||
502 | }, | 507 | }, |
503 | }; | 508 | }; |
504 | 509 | ||
510 | /* policy for NAN function attributes */ | ||
511 | static const struct nla_policy | ||
512 | nl80211_nan_func_policy[NL80211_NAN_FUNC_ATTR_MAX + 1] = { | ||
513 | [NL80211_NAN_FUNC_TYPE] = { .type = NLA_U8 }, | ||
514 | [NL80211_NAN_FUNC_SERVICE_ID] = { .type = NLA_BINARY, | ||
515 | .len = NL80211_NAN_FUNC_SERVICE_ID_LEN }, | ||
516 | [NL80211_NAN_FUNC_PUBLISH_TYPE] = { .type = NLA_U8 }, | ||
517 | [NL80211_NAN_FUNC_PUBLISH_BCAST] = { .type = NLA_FLAG }, | ||
518 | [NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE] = { .type = NLA_FLAG }, | ||
519 | [NL80211_NAN_FUNC_FOLLOW_UP_ID] = { .type = NLA_U8 }, | ||
520 | [NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] = { .type = NLA_U8 }, | ||
521 | [NL80211_NAN_FUNC_FOLLOW_UP_DEST] = { .len = ETH_ALEN }, | ||
522 | [NL80211_NAN_FUNC_CLOSE_RANGE] = { .type = NLA_FLAG }, | ||
523 | [NL80211_NAN_FUNC_TTL] = { .type = NLA_U32 }, | ||
524 | [NL80211_NAN_FUNC_SERVICE_INFO] = { .type = NLA_BINARY, | ||
525 | .len = NL80211_NAN_FUNC_SERVICE_SPEC_INFO_MAX_LEN }, | ||
526 | [NL80211_NAN_FUNC_SRF] = { .type = NLA_NESTED }, | ||
527 | [NL80211_NAN_FUNC_RX_MATCH_FILTER] = { .type = NLA_NESTED }, | ||
528 | [NL80211_NAN_FUNC_TX_MATCH_FILTER] = { .type = NLA_NESTED }, | ||
529 | [NL80211_NAN_FUNC_INSTANCE_ID] = { .type = NLA_U8 }, | ||
530 | [NL80211_NAN_FUNC_TERM_REASON] = { .type = NLA_U8 }, | ||
531 | }; | ||
532 | |||
533 | /* policy for Service Response Filter attributes */ | ||
534 | static const struct nla_policy | ||
535 | nl80211_nan_srf_policy[NL80211_NAN_SRF_ATTR_MAX + 1] = { | ||
536 | [NL80211_NAN_SRF_INCLUDE] = { .type = NLA_FLAG }, | ||
537 | [NL80211_NAN_SRF_BF] = { .type = NLA_BINARY, | ||
538 | .len = NL80211_NAN_FUNC_SRF_MAX_LEN }, | ||
539 | [NL80211_NAN_SRF_BF_IDX] = { .type = NLA_U8 }, | ||
540 | [NL80211_NAN_SRF_MAC_ADDRS] = { .type = NLA_NESTED }, | ||
541 | }; | ||
542 | |||
505 | static int nl80211_prepare_wdev_dump(struct sk_buff *skb, | 543 | static int nl80211_prepare_wdev_dump(struct sk_buff *skb, |
506 | struct netlink_callback *cb, | 544 | struct netlink_callback *cb, |
507 | struct cfg80211_registered_device **rdev, | 545 | struct cfg80211_registered_device **rdev, |
@@ -934,6 +972,7 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) | |||
934 | case NL80211_IFTYPE_UNSPECIFIED: | 972 | case NL80211_IFTYPE_UNSPECIFIED: |
935 | case NL80211_IFTYPE_OCB: | 973 | case NL80211_IFTYPE_OCB: |
936 | case NL80211_IFTYPE_MONITOR: | 974 | case NL80211_IFTYPE_MONITOR: |
975 | case NL80211_IFTYPE_NAN: | ||
937 | case NL80211_IFTYPE_P2P_DEVICE: | 976 | case NL80211_IFTYPE_P2P_DEVICE: |
938 | case NL80211_IFTYPE_WDS: | 977 | case NL80211_IFTYPE_WDS: |
939 | case NUM_NL80211_IFTYPES: | 978 | case NUM_NL80211_IFTYPES: |
@@ -2819,7 +2858,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
2819 | !(rdev->wiphy.interface_modes & (1 << type))) | 2858 | !(rdev->wiphy.interface_modes & (1 << type))) |
2820 | return -EOPNOTSUPP; | 2859 | return -EOPNOTSUPP; |
2821 | 2860 | ||
2822 | if ((type == NL80211_IFTYPE_P2P_DEVICE || | 2861 | if ((type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN || |
2823 | rdev->wiphy.features & NL80211_FEATURE_MAC_ON_CREATE) && | 2862 | rdev->wiphy.features & NL80211_FEATURE_MAC_ON_CREATE) && |
2824 | info->attrs[NL80211_ATTR_MAC]) { | 2863 | info->attrs[NL80211_ATTR_MAC]) { |
2825 | nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC], | 2864 | nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC], |
@@ -2875,9 +2914,10 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
2875 | wdev->mesh_id_up_len); | 2914 | wdev->mesh_id_up_len); |
2876 | wdev_unlock(wdev); | 2915 | wdev_unlock(wdev); |
2877 | break; | 2916 | break; |
2917 | case NL80211_IFTYPE_NAN: | ||
2878 | case NL80211_IFTYPE_P2P_DEVICE: | 2918 | case NL80211_IFTYPE_P2P_DEVICE: |
2879 | /* | 2919 | /* |
2880 | * P2P Device doesn't have a netdev, so doesn't go | 2920 | * P2P Device and NAN do not have a netdev, so don't go |
2881 | * through the netdev notifier and must be added here | 2921 | * through the netdev notifier and must be added here |
2882 | */ | 2922 | */ |
2883 | mutex_init(&wdev->mtx); | 2923 | mutex_init(&wdev->mtx); |
@@ -3340,6 +3380,291 @@ static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info) | |||
3340 | return err; | 3380 | return err; |
3341 | } | 3381 | } |
3342 | 3382 | ||
3383 | static u32 rateset_to_mask(struct ieee80211_supported_band *sband, | ||
3384 | u8 *rates, u8 rates_len) | ||
3385 | { | ||
3386 | u8 i; | ||
3387 | u32 mask = 0; | ||
3388 | |||
3389 | for (i = 0; i < rates_len; i++) { | ||
3390 | int rate = (rates[i] & 0x7f) * 5; | ||
3391 | int ridx; | ||
3392 | |||
3393 | for (ridx = 0; ridx < sband->n_bitrates; ridx++) { | ||
3394 | struct ieee80211_rate *srate = | ||
3395 | &sband->bitrates[ridx]; | ||
3396 | if (rate == srate->bitrate) { | ||
3397 | mask |= 1 << ridx; | ||
3398 | break; | ||
3399 | } | ||
3400 | } | ||
3401 | if (ridx == sband->n_bitrates) | ||
3402 | return 0; /* rate not found */ | ||
3403 | } | ||
3404 | |||
3405 | return mask; | ||
3406 | } | ||
3407 | |||
3408 | static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband, | ||
3409 | u8 *rates, u8 rates_len, | ||
3410 | u8 mcs[IEEE80211_HT_MCS_MASK_LEN]) | ||
3411 | { | ||
3412 | u8 i; | ||
3413 | |||
3414 | memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN); | ||
3415 | |||
3416 | for (i = 0; i < rates_len; i++) { | ||
3417 | int ridx, rbit; | ||
3418 | |||
3419 | ridx = rates[i] / 8; | ||
3420 | rbit = BIT(rates[i] % 8); | ||
3421 | |||
3422 | /* check validity */ | ||
3423 | if ((ridx < 0) || (ridx >= IEEE80211_HT_MCS_MASK_LEN)) | ||
3424 | return false; | ||
3425 | |||
3426 | /* check availability */ | ||
3427 | if (sband->ht_cap.mcs.rx_mask[ridx] & rbit) | ||
3428 | mcs[ridx] |= rbit; | ||
3429 | else | ||
3430 | return false; | ||
3431 | } | ||
3432 | |||
3433 | return true; | ||
3434 | } | ||
3435 | |||
3436 | static u16 vht_mcs_map_to_mcs_mask(u8 vht_mcs_map) | ||
3437 | { | ||
3438 | u16 mcs_mask = 0; | ||
3439 | |||
3440 | switch (vht_mcs_map) { | ||
3441 | case IEEE80211_VHT_MCS_NOT_SUPPORTED: | ||
3442 | break; | ||
3443 | case IEEE80211_VHT_MCS_SUPPORT_0_7: | ||
3444 | mcs_mask = 0x00FF; | ||
3445 | break; | ||
3446 | case IEEE80211_VHT_MCS_SUPPORT_0_8: | ||
3447 | mcs_mask = 0x01FF; | ||
3448 | break; | ||
3449 | case IEEE80211_VHT_MCS_SUPPORT_0_9: | ||
3450 | mcs_mask = 0x03FF; | ||
3451 | break; | ||
3452 | default: | ||
3453 | break; | ||
3454 | } | ||
3455 | |||
3456 | return mcs_mask; | ||
3457 | } | ||
3458 | |||
3459 | static void vht_build_mcs_mask(u16 vht_mcs_map, | ||
3460 | u16 vht_mcs_mask[NL80211_VHT_NSS_MAX]) | ||
3461 | { | ||
3462 | u8 nss; | ||
3463 | |||
3464 | for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) { | ||
3465 | vht_mcs_mask[nss] = vht_mcs_map_to_mcs_mask(vht_mcs_map & 0x03); | ||
3466 | vht_mcs_map >>= 2; | ||
3467 | } | ||
3468 | } | ||
3469 | |||
3470 | static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband, | ||
3471 | struct nl80211_txrate_vht *txrate, | ||
3472 | u16 mcs[NL80211_VHT_NSS_MAX]) | ||
3473 | { | ||
3474 | u16 tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map); | ||
3475 | u16 tx_mcs_mask[NL80211_VHT_NSS_MAX] = {}; | ||
3476 | u8 i; | ||
3477 | |||
3478 | if (!sband->vht_cap.vht_supported) | ||
3479 | return false; | ||
3480 | |||
3481 | memset(mcs, 0, sizeof(u16) * NL80211_VHT_NSS_MAX); | ||
3482 | |||
3483 | /* Build vht_mcs_mask from VHT capabilities */ | ||
3484 | vht_build_mcs_mask(tx_mcs_map, tx_mcs_mask); | ||
3485 | |||
3486 | for (i = 0; i < NL80211_VHT_NSS_MAX; i++) { | ||
3487 | if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i]) | ||
3488 | mcs[i] = txrate->mcs[i]; | ||
3489 | else | ||
3490 | return false; | ||
3491 | } | ||
3492 | |||
3493 | return true; | ||
3494 | } | ||
3495 | |||
3496 | static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = { | ||
3497 | [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY, | ||
3498 | .len = NL80211_MAX_SUPP_RATES }, | ||
3499 | [NL80211_TXRATE_HT] = { .type = NLA_BINARY, | ||
3500 | .len = NL80211_MAX_SUPP_HT_RATES }, | ||
3501 | [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)}, | ||
3502 | [NL80211_TXRATE_GI] = { .type = NLA_U8 }, | ||
3503 | }; | ||
3504 | |||
3505 | static int nl80211_parse_tx_bitrate_mask(struct genl_info *info, | ||
3506 | struct cfg80211_bitrate_mask *mask) | ||
3507 | { | ||
3508 | struct nlattr *tb[NL80211_TXRATE_MAX + 1]; | ||
3509 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
3510 | int rem, i; | ||
3511 | struct nlattr *tx_rates; | ||
3512 | struct ieee80211_supported_band *sband; | ||
3513 | u16 vht_tx_mcs_map; | ||
3514 | |||
3515 | memset(mask, 0, sizeof(*mask)); | ||
3516 | /* Default to all rates enabled */ | ||
3517 | for (i = 0; i < NUM_NL80211_BANDS; i++) { | ||
3518 | sband = rdev->wiphy.bands[i]; | ||
3519 | |||
3520 | if (!sband) | ||
3521 | continue; | ||
3522 | |||
3523 | mask->control[i].legacy = (1 << sband->n_bitrates) - 1; | ||
3524 | memcpy(mask->control[i].ht_mcs, | ||
3525 | sband->ht_cap.mcs.rx_mask, | ||
3526 | sizeof(mask->control[i].ht_mcs)); | ||
3527 | |||
3528 | if (!sband->vht_cap.vht_supported) | ||
3529 | continue; | ||
3530 | |||
3531 | vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map); | ||
3532 | vht_build_mcs_mask(vht_tx_mcs_map, mask->control[i].vht_mcs); | ||
3533 | } | ||
3534 | |||
3535 | /* if no rates are given set it back to the defaults */ | ||
3536 | if (!info->attrs[NL80211_ATTR_TX_RATES]) | ||
3537 | goto out; | ||
3538 | |||
3539 | /* The nested attribute uses enum nl80211_band as the index. This maps | ||
3540 | * directly to the enum nl80211_band values used in cfg80211. | ||
3541 | */ | ||
3542 | BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8); | ||
3543 | nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) { | ||
3544 | enum nl80211_band band = nla_type(tx_rates); | ||
3545 | int err; | ||
3546 | |||
3547 | if (band < 0 || band >= NUM_NL80211_BANDS) | ||
3548 | return -EINVAL; | ||
3549 | sband = rdev->wiphy.bands[band]; | ||
3550 | if (sband == NULL) | ||
3551 | return -EINVAL; | ||
3552 | err = nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), | ||
3553 | nla_len(tx_rates), nl80211_txattr_policy); | ||
3554 | if (err) | ||
3555 | return err; | ||
3556 | if (tb[NL80211_TXRATE_LEGACY]) { | ||
3557 | mask->control[band].legacy = rateset_to_mask( | ||
3558 | sband, | ||
3559 | nla_data(tb[NL80211_TXRATE_LEGACY]), | ||
3560 | nla_len(tb[NL80211_TXRATE_LEGACY])); | ||
3561 | if ((mask->control[band].legacy == 0) && | ||
3562 | nla_len(tb[NL80211_TXRATE_LEGACY])) | ||
3563 | return -EINVAL; | ||
3564 | } | ||
3565 | if (tb[NL80211_TXRATE_HT]) { | ||
3566 | if (!ht_rateset_to_mask( | ||
3567 | sband, | ||
3568 | nla_data(tb[NL80211_TXRATE_HT]), | ||
3569 | nla_len(tb[NL80211_TXRATE_HT]), | ||
3570 | mask->control[band].ht_mcs)) | ||
3571 | return -EINVAL; | ||
3572 | } | ||
3573 | if (tb[NL80211_TXRATE_VHT]) { | ||
3574 | if (!vht_set_mcs_mask( | ||
3575 | sband, | ||
3576 | nla_data(tb[NL80211_TXRATE_VHT]), | ||
3577 | mask->control[band].vht_mcs)) | ||
3578 | return -EINVAL; | ||
3579 | } | ||
3580 | if (tb[NL80211_TXRATE_GI]) { | ||
3581 | mask->control[band].gi = | ||
3582 | nla_get_u8(tb[NL80211_TXRATE_GI]); | ||
3583 | if (mask->control[band].gi > NL80211_TXRATE_FORCE_LGI) | ||
3584 | return -EINVAL; | ||
3585 | } | ||
3586 | |||
3587 | if (mask->control[band].legacy == 0) { | ||
3588 | /* don't allow empty legacy rates if HT or VHT | ||
3589 | * are not even supported. | ||
3590 | */ | ||
3591 | if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported || | ||
3592 | rdev->wiphy.bands[band]->vht_cap.vht_supported)) | ||
3593 | return -EINVAL; | ||
3594 | |||
3595 | for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) | ||
3596 | if (mask->control[band].ht_mcs[i]) | ||
3597 | goto out; | ||
3598 | |||
3599 | for (i = 0; i < NL80211_VHT_NSS_MAX; i++) | ||
3600 | if (mask->control[band].vht_mcs[i]) | ||
3601 | goto out; | ||
3602 | |||
3603 | /* legacy and mcs rates may not be both empty */ | ||
3604 | return -EINVAL; | ||
3605 | } | ||
3606 | } | ||
3607 | |||
3608 | out: | ||
3609 | return 0; | ||
3610 | } | ||
3611 | |||
3612 | static int validate_beacon_tx_rate(struct cfg80211_registered_device *rdev, | ||
3613 | enum nl80211_band band, | ||
3614 | struct cfg80211_bitrate_mask *beacon_rate) | ||
3615 | { | ||
3616 | u32 count_ht, count_vht, i; | ||
3617 | u32 rate = beacon_rate->control[band].legacy; | ||
3618 | |||
3619 | /* Allow only one rate */ | ||
3620 | if (hweight32(rate) > 1) | ||
3621 | return -EINVAL; | ||
3622 | |||
3623 | count_ht = 0; | ||
3624 | for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) { | ||
3625 | if (hweight8(beacon_rate->control[band].ht_mcs[i]) > 1) { | ||
3626 | return -EINVAL; | ||
3627 | } else if (beacon_rate->control[band].ht_mcs[i]) { | ||
3628 | count_ht++; | ||
3629 | if (count_ht > 1) | ||
3630 | return -EINVAL; | ||
3631 | } | ||
3632 | if (count_ht && rate) | ||
3633 | return -EINVAL; | ||
3634 | } | ||
3635 | |||
3636 | count_vht = 0; | ||
3637 | for (i = 0; i < NL80211_VHT_NSS_MAX; i++) { | ||
3638 | if (hweight16(beacon_rate->control[band].vht_mcs[i]) > 1) { | ||
3639 | return -EINVAL; | ||
3640 | } else if (beacon_rate->control[band].vht_mcs[i]) { | ||
3641 | count_vht++; | ||
3642 | if (count_vht > 1) | ||
3643 | return -EINVAL; | ||
3644 | } | ||
3645 | if (count_vht && rate) | ||
3646 | return -EINVAL; | ||
3647 | } | ||
3648 | |||
3649 | if ((count_ht && count_vht) || (!rate && !count_ht && !count_vht)) | ||
3650 | return -EINVAL; | ||
3651 | |||
3652 | if (rate && | ||
3653 | !wiphy_ext_feature_isset(&rdev->wiphy, | ||
3654 | NL80211_EXT_FEATURE_BEACON_RATE_LEGACY)) | ||
3655 | return -EINVAL; | ||
3656 | if (count_ht && | ||
3657 | !wiphy_ext_feature_isset(&rdev->wiphy, | ||
3658 | NL80211_EXT_FEATURE_BEACON_RATE_HT)) | ||
3659 | return -EINVAL; | ||
3660 | if (count_vht && | ||
3661 | !wiphy_ext_feature_isset(&rdev->wiphy, | ||
3662 | NL80211_EXT_FEATURE_BEACON_RATE_VHT)) | ||
3663 | return -EINVAL; | ||
3664 | |||
3665 | return 0; | ||
3666 | } | ||
3667 | |||
3343 | static int nl80211_parse_beacon(struct nlattr *attrs[], | 3668 | static int nl80211_parse_beacon(struct nlattr *attrs[], |
3344 | struct cfg80211_beacon_data *bcn) | 3669 | struct cfg80211_beacon_data *bcn) |
3345 | { | 3670 | { |
@@ -3569,6 +3894,17 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
3569 | wdev->iftype)) | 3894 | wdev->iftype)) |
3570 | return -EINVAL; | 3895 | return -EINVAL; |
3571 | 3896 | ||
3897 | if (info->attrs[NL80211_ATTR_TX_RATES]) { | ||
3898 | err = nl80211_parse_tx_bitrate_mask(info, ¶ms.beacon_rate); | ||
3899 | if (err) | ||
3900 | return err; | ||
3901 | |||
3902 | err = validate_beacon_tx_rate(rdev, params.chandef.chan->band, | ||
3903 | ¶ms.beacon_rate); | ||
3904 | if (err) | ||
3905 | return err; | ||
3906 | } | ||
3907 | |||
3572 | if (info->attrs[NL80211_ATTR_SMPS_MODE]) { | 3908 | if (info->attrs[NL80211_ATTR_SMPS_MODE]) { |
3573 | params.smps_mode = | 3909 | params.smps_mode = |
3574 | nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]); | 3910 | nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]); |
@@ -6138,6 +6474,9 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
6138 | 6474 | ||
6139 | wiphy = &rdev->wiphy; | 6475 | wiphy = &rdev->wiphy; |
6140 | 6476 | ||
6477 | if (wdev->iftype == NL80211_IFTYPE_NAN) | ||
6478 | return -EOPNOTSUPP; | ||
6479 | |||
6141 | if (!rdev->ops->scan) | 6480 | if (!rdev->ops->scan) |
6142 | return -EOPNOTSUPP; | 6481 | return -EOPNOTSUPP; |
6143 | 6482 | ||
@@ -8641,238 +8980,21 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, | |||
8641 | return rdev_cancel_remain_on_channel(rdev, wdev, cookie); | 8980 | return rdev_cancel_remain_on_channel(rdev, wdev, cookie); |
8642 | } | 8981 | } |
8643 | 8982 | ||
8644 | static u32 rateset_to_mask(struct ieee80211_supported_band *sband, | ||
8645 | u8 *rates, u8 rates_len) | ||
8646 | { | ||
8647 | u8 i; | ||
8648 | u32 mask = 0; | ||
8649 | |||
8650 | for (i = 0; i < rates_len; i++) { | ||
8651 | int rate = (rates[i] & 0x7f) * 5; | ||
8652 | int ridx; | ||
8653 | |||
8654 | for (ridx = 0; ridx < sband->n_bitrates; ridx++) { | ||
8655 | struct ieee80211_rate *srate = | ||
8656 | &sband->bitrates[ridx]; | ||
8657 | if (rate == srate->bitrate) { | ||
8658 | mask |= 1 << ridx; | ||
8659 | break; | ||
8660 | } | ||
8661 | } | ||
8662 | if (ridx == sband->n_bitrates) | ||
8663 | return 0; /* rate not found */ | ||
8664 | } | ||
8665 | |||
8666 | return mask; | ||
8667 | } | ||
8668 | |||
8669 | static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband, | ||
8670 | u8 *rates, u8 rates_len, | ||
8671 | u8 mcs[IEEE80211_HT_MCS_MASK_LEN]) | ||
8672 | { | ||
8673 | u8 i; | ||
8674 | |||
8675 | memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN); | ||
8676 | |||
8677 | for (i = 0; i < rates_len; i++) { | ||
8678 | int ridx, rbit; | ||
8679 | |||
8680 | ridx = rates[i] / 8; | ||
8681 | rbit = BIT(rates[i] % 8); | ||
8682 | |||
8683 | /* check validity */ | ||
8684 | if ((ridx < 0) || (ridx >= IEEE80211_HT_MCS_MASK_LEN)) | ||
8685 | return false; | ||
8686 | |||
8687 | /* check availability */ | ||
8688 | if (sband->ht_cap.mcs.rx_mask[ridx] & rbit) | ||
8689 | mcs[ridx] |= rbit; | ||
8690 | else | ||
8691 | return false; | ||
8692 | } | ||
8693 | |||
8694 | return true; | ||
8695 | } | ||
8696 | |||
8697 | static u16 vht_mcs_map_to_mcs_mask(u8 vht_mcs_map) | ||
8698 | { | ||
8699 | u16 mcs_mask = 0; | ||
8700 | |||
8701 | switch (vht_mcs_map) { | ||
8702 | case IEEE80211_VHT_MCS_NOT_SUPPORTED: | ||
8703 | break; | ||
8704 | case IEEE80211_VHT_MCS_SUPPORT_0_7: | ||
8705 | mcs_mask = 0x00FF; | ||
8706 | break; | ||
8707 | case IEEE80211_VHT_MCS_SUPPORT_0_8: | ||
8708 | mcs_mask = 0x01FF; | ||
8709 | break; | ||
8710 | case IEEE80211_VHT_MCS_SUPPORT_0_9: | ||
8711 | mcs_mask = 0x03FF; | ||
8712 | break; | ||
8713 | default: | ||
8714 | break; | ||
8715 | } | ||
8716 | |||
8717 | return mcs_mask; | ||
8718 | } | ||
8719 | |||
8720 | static void vht_build_mcs_mask(u16 vht_mcs_map, | ||
8721 | u16 vht_mcs_mask[NL80211_VHT_NSS_MAX]) | ||
8722 | { | ||
8723 | u8 nss; | ||
8724 | |||
8725 | for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) { | ||
8726 | vht_mcs_mask[nss] = vht_mcs_map_to_mcs_mask(vht_mcs_map & 0x03); | ||
8727 | vht_mcs_map >>= 2; | ||
8728 | } | ||
8729 | } | ||
8730 | |||
8731 | static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband, | ||
8732 | struct nl80211_txrate_vht *txrate, | ||
8733 | u16 mcs[NL80211_VHT_NSS_MAX]) | ||
8734 | { | ||
8735 | u16 tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map); | ||
8736 | u16 tx_mcs_mask[NL80211_VHT_NSS_MAX] = {}; | ||
8737 | u8 i; | ||
8738 | |||
8739 | if (!sband->vht_cap.vht_supported) | ||
8740 | return false; | ||
8741 | |||
8742 | memset(mcs, 0, sizeof(u16) * NL80211_VHT_NSS_MAX); | ||
8743 | |||
8744 | /* Build vht_mcs_mask from VHT capabilities */ | ||
8745 | vht_build_mcs_mask(tx_mcs_map, tx_mcs_mask); | ||
8746 | |||
8747 | for (i = 0; i < NL80211_VHT_NSS_MAX; i++) { | ||
8748 | if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i]) | ||
8749 | mcs[i] = txrate->mcs[i]; | ||
8750 | else | ||
8751 | return false; | ||
8752 | } | ||
8753 | |||
8754 | return true; | ||
8755 | } | ||
8756 | |||
8757 | static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = { | ||
8758 | [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY, | ||
8759 | .len = NL80211_MAX_SUPP_RATES }, | ||
8760 | [NL80211_TXRATE_HT] = { .type = NLA_BINARY, | ||
8761 | .len = NL80211_MAX_SUPP_HT_RATES }, | ||
8762 | [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)}, | ||
8763 | [NL80211_TXRATE_GI] = { .type = NLA_U8 }, | ||
8764 | }; | ||
8765 | |||
8766 | static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | 8983 | static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, |
8767 | struct genl_info *info) | 8984 | struct genl_info *info) |
8768 | { | 8985 | { |
8769 | struct nlattr *tb[NL80211_TXRATE_MAX + 1]; | ||
8770 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
8771 | struct cfg80211_bitrate_mask mask; | 8986 | struct cfg80211_bitrate_mask mask; |
8772 | int rem, i; | 8987 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
8773 | struct net_device *dev = info->user_ptr[1]; | 8988 | struct net_device *dev = info->user_ptr[1]; |
8774 | struct nlattr *tx_rates; | 8989 | int err; |
8775 | struct ieee80211_supported_band *sband; | ||
8776 | u16 vht_tx_mcs_map; | ||
8777 | 8990 | ||
8778 | if (!rdev->ops->set_bitrate_mask) | 8991 | if (!rdev->ops->set_bitrate_mask) |
8779 | return -EOPNOTSUPP; | 8992 | return -EOPNOTSUPP; |
8780 | 8993 | ||
8781 | memset(&mask, 0, sizeof(mask)); | 8994 | err = nl80211_parse_tx_bitrate_mask(info, &mask); |
8782 | /* Default to all rates enabled */ | 8995 | if (err) |
8783 | for (i = 0; i < NUM_NL80211_BANDS; i++) { | 8996 | return err; |
8784 | sband = rdev->wiphy.bands[i]; | ||
8785 | |||
8786 | if (!sband) | ||
8787 | continue; | ||
8788 | |||
8789 | mask.control[i].legacy = (1 << sband->n_bitrates) - 1; | ||
8790 | memcpy(mask.control[i].ht_mcs, | ||
8791 | sband->ht_cap.mcs.rx_mask, | ||
8792 | sizeof(mask.control[i].ht_mcs)); | ||
8793 | |||
8794 | if (!sband->vht_cap.vht_supported) | ||
8795 | continue; | ||
8796 | |||
8797 | vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map); | ||
8798 | vht_build_mcs_mask(vht_tx_mcs_map, mask.control[i].vht_mcs); | ||
8799 | } | ||
8800 | |||
8801 | /* if no rates are given set it back to the defaults */ | ||
8802 | if (!info->attrs[NL80211_ATTR_TX_RATES]) | ||
8803 | goto out; | ||
8804 | |||
8805 | /* | ||
8806 | * The nested attribute uses enum nl80211_band as the index. This maps | ||
8807 | * directly to the enum nl80211_band values used in cfg80211. | ||
8808 | */ | ||
8809 | BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8); | ||
8810 | nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) { | ||
8811 | enum nl80211_band band = nla_type(tx_rates); | ||
8812 | int err; | ||
8813 | |||
8814 | if (band < 0 || band >= NUM_NL80211_BANDS) | ||
8815 | return -EINVAL; | ||
8816 | sband = rdev->wiphy.bands[band]; | ||
8817 | if (sband == NULL) | ||
8818 | return -EINVAL; | ||
8819 | err = nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), | ||
8820 | nla_len(tx_rates), nl80211_txattr_policy); | ||
8821 | if (err) | ||
8822 | return err; | ||
8823 | if (tb[NL80211_TXRATE_LEGACY]) { | ||
8824 | mask.control[band].legacy = rateset_to_mask( | ||
8825 | sband, | ||
8826 | nla_data(tb[NL80211_TXRATE_LEGACY]), | ||
8827 | nla_len(tb[NL80211_TXRATE_LEGACY])); | ||
8828 | if ((mask.control[band].legacy == 0) && | ||
8829 | nla_len(tb[NL80211_TXRATE_LEGACY])) | ||
8830 | return -EINVAL; | ||
8831 | } | ||
8832 | if (tb[NL80211_TXRATE_HT]) { | ||
8833 | if (!ht_rateset_to_mask( | ||
8834 | sband, | ||
8835 | nla_data(tb[NL80211_TXRATE_HT]), | ||
8836 | nla_len(tb[NL80211_TXRATE_HT]), | ||
8837 | mask.control[band].ht_mcs)) | ||
8838 | return -EINVAL; | ||
8839 | } | ||
8840 | if (tb[NL80211_TXRATE_VHT]) { | ||
8841 | if (!vht_set_mcs_mask( | ||
8842 | sband, | ||
8843 | nla_data(tb[NL80211_TXRATE_VHT]), | ||
8844 | mask.control[band].vht_mcs)) | ||
8845 | return -EINVAL; | ||
8846 | } | ||
8847 | if (tb[NL80211_TXRATE_GI]) { | ||
8848 | mask.control[band].gi = | ||
8849 | nla_get_u8(tb[NL80211_TXRATE_GI]); | ||
8850 | if (mask.control[band].gi > NL80211_TXRATE_FORCE_LGI) | ||
8851 | return -EINVAL; | ||
8852 | } | ||
8853 | |||
8854 | if (mask.control[band].legacy == 0) { | ||
8855 | /* don't allow empty legacy rates if HT or VHT | ||
8856 | * are not even supported. | ||
8857 | */ | ||
8858 | if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported || | ||
8859 | rdev->wiphy.bands[band]->vht_cap.vht_supported)) | ||
8860 | return -EINVAL; | ||
8861 | |||
8862 | for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) | ||
8863 | if (mask.control[band].ht_mcs[i]) | ||
8864 | goto out; | ||
8865 | |||
8866 | for (i = 0; i < NL80211_VHT_NSS_MAX; i++) | ||
8867 | if (mask.control[band].vht_mcs[i]) | ||
8868 | goto out; | ||
8869 | |||
8870 | /* legacy and mcs rates may not be both empty */ | ||
8871 | return -EINVAL; | ||
8872 | } | ||
8873 | } | ||
8874 | 8997 | ||
8875 | out: | ||
8876 | return rdev_set_bitrate_mask(rdev, dev, NULL, &mask); | 8998 | return rdev_set_bitrate_mask(rdev, dev, NULL, &mask); |
8877 | } | 8999 | } |
8878 | 9000 | ||
@@ -8898,6 +9020,7 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
8898 | case NL80211_IFTYPE_P2P_GO: | 9020 | case NL80211_IFTYPE_P2P_GO: |
8899 | case NL80211_IFTYPE_P2P_DEVICE: | 9021 | case NL80211_IFTYPE_P2P_DEVICE: |
8900 | break; | 9022 | break; |
9023 | case NL80211_IFTYPE_NAN: | ||
8901 | default: | 9024 | default: |
8902 | return -EOPNOTSUPP; | 9025 | return -EOPNOTSUPP; |
8903 | } | 9026 | } |
@@ -8943,6 +9066,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
8943 | case NL80211_IFTYPE_MESH_POINT: | 9066 | case NL80211_IFTYPE_MESH_POINT: |
8944 | case NL80211_IFTYPE_P2P_GO: | 9067 | case NL80211_IFTYPE_P2P_GO: |
8945 | break; | 9068 | break; |
9069 | case NL80211_IFTYPE_NAN: | ||
8946 | default: | 9070 | default: |
8947 | return -EOPNOTSUPP; | 9071 | return -EOPNOTSUPP; |
8948 | } | 9072 | } |
@@ -9059,6 +9183,7 @@ static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *in | |||
9059 | case NL80211_IFTYPE_P2P_GO: | 9183 | case NL80211_IFTYPE_P2P_GO: |
9060 | case NL80211_IFTYPE_P2P_DEVICE: | 9184 | case NL80211_IFTYPE_P2P_DEVICE: |
9061 | break; | 9185 | break; |
9186 | case NL80211_IFTYPE_NAN: | ||
9062 | default: | 9187 | default: |
9063 | return -EOPNOTSUPP; | 9188 | return -EOPNOTSUPP; |
9064 | } | 9189 | } |
@@ -9340,6 +9465,17 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) | |||
9340 | return err; | 9465 | return err; |
9341 | } | 9466 | } |
9342 | 9467 | ||
9468 | if (info->attrs[NL80211_ATTR_TX_RATES]) { | ||
9469 | err = nl80211_parse_tx_bitrate_mask(info, &setup.beacon_rate); | ||
9470 | if (err) | ||
9471 | return err; | ||
9472 | |||
9473 | err = validate_beacon_tx_rate(rdev, setup.chandef.chan->band, | ||
9474 | &setup.beacon_rate); | ||
9475 | if (err) | ||
9476 | return err; | ||
9477 | } | ||
9478 | |||
9343 | return cfg80211_join_mesh(rdev, dev, &setup, &cfg); | 9479 | return cfg80211_join_mesh(rdev, dev, &setup, &cfg); |
9344 | } | 9480 | } |
9345 | 9481 | ||
@@ -10414,6 +10550,549 @@ static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info) | |||
10414 | return 0; | 10550 | return 0; |
10415 | } | 10551 | } |
10416 | 10552 | ||
10553 | static int nl80211_start_nan(struct sk_buff *skb, struct genl_info *info) | ||
10554 | { | ||
10555 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
10556 | struct wireless_dev *wdev = info->user_ptr[1]; | ||
10557 | struct cfg80211_nan_conf conf = {}; | ||
10558 | int err; | ||
10559 | |||
10560 | if (wdev->iftype != NL80211_IFTYPE_NAN) | ||
10561 | return -EOPNOTSUPP; | ||
10562 | |||
10563 | if (wdev->nan_started) | ||
10564 | return -EEXIST; | ||
10565 | |||
10566 | if (rfkill_blocked(rdev->rfkill)) | ||
10567 | return -ERFKILL; | ||
10568 | |||
10569 | if (!info->attrs[NL80211_ATTR_NAN_MASTER_PREF]) | ||
10570 | return -EINVAL; | ||
10571 | |||
10572 | if (!info->attrs[NL80211_ATTR_NAN_DUAL]) | ||
10573 | return -EINVAL; | ||
10574 | |||
10575 | conf.master_pref = | ||
10576 | nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]); | ||
10577 | if (!conf.master_pref) | ||
10578 | return -EINVAL; | ||
10579 | |||
10580 | conf.dual = nla_get_u8(info->attrs[NL80211_ATTR_NAN_DUAL]); | ||
10581 | |||
10582 | err = rdev_start_nan(rdev, wdev, &conf); | ||
10583 | if (err) | ||
10584 | return err; | ||
10585 | |||
10586 | wdev->nan_started = true; | ||
10587 | rdev->opencount++; | ||
10588 | |||
10589 | return 0; | ||
10590 | } | ||
10591 | |||
10592 | static int nl80211_stop_nan(struct sk_buff *skb, struct genl_info *info) | ||
10593 | { | ||
10594 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
10595 | struct wireless_dev *wdev = info->user_ptr[1]; | ||
10596 | |||
10597 | if (wdev->iftype != NL80211_IFTYPE_NAN) | ||
10598 | return -EOPNOTSUPP; | ||
10599 | |||
10600 | cfg80211_stop_nan(rdev, wdev); | ||
10601 | |||
10602 | return 0; | ||
10603 | } | ||
10604 | |||
10605 | static int validate_nan_filter(struct nlattr *filter_attr) | ||
10606 | { | ||
10607 | struct nlattr *attr; | ||
10608 | int len = 0, n_entries = 0, rem; | ||
10609 | |||
10610 | nla_for_each_nested(attr, filter_attr, rem) { | ||
10611 | len += nla_len(attr); | ||
10612 | n_entries++; | ||
10613 | } | ||
10614 | |||
10615 | if (len >= U8_MAX) | ||
10616 | return -EINVAL; | ||
10617 | |||
10618 | return n_entries; | ||
10619 | } | ||
10620 | |||
10621 | static int handle_nan_filter(struct nlattr *attr_filter, | ||
10622 | struct cfg80211_nan_func *func, | ||
10623 | bool tx) | ||
10624 | { | ||
10625 | struct nlattr *attr; | ||
10626 | int n_entries, rem, i; | ||
10627 | struct cfg80211_nan_func_filter *filter; | ||
10628 | |||
10629 | n_entries = validate_nan_filter(attr_filter); | ||
10630 | if (n_entries < 0) | ||
10631 | return n_entries; | ||
10632 | |||
10633 | BUILD_BUG_ON(sizeof(*func->rx_filters) != sizeof(*func->tx_filters)); | ||
10634 | |||
10635 | filter = kcalloc(n_entries, sizeof(*func->rx_filters), GFP_KERNEL); | ||
10636 | if (!filter) | ||
10637 | return -ENOMEM; | ||
10638 | |||
10639 | i = 0; | ||
10640 | nla_for_each_nested(attr, attr_filter, rem) { | ||
10641 | filter[i].filter = kmemdup(nla_data(attr), nla_len(attr), | ||
10642 | GFP_KERNEL); | ||
10643 | filter[i].len = nla_len(attr); | ||
10644 | i++; | ||
10645 | } | ||
10646 | if (tx) { | ||
10647 | func->num_tx_filters = n_entries; | ||
10648 | func->tx_filters = filter; | ||
10649 | } else { | ||
10650 | func->num_rx_filters = n_entries; | ||
10651 | func->rx_filters = filter; | ||
10652 | } | ||
10653 | |||
10654 | return 0; | ||
10655 | } | ||
10656 | |||
10657 | static int nl80211_nan_add_func(struct sk_buff *skb, | ||
10658 | struct genl_info *info) | ||
10659 | { | ||
10660 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
10661 | struct wireless_dev *wdev = info->user_ptr[1]; | ||
10662 | struct nlattr *tb[NUM_NL80211_NAN_FUNC_ATTR], *func_attr; | ||
10663 | struct cfg80211_nan_func *func; | ||
10664 | struct sk_buff *msg = NULL; | ||
10665 | void *hdr = NULL; | ||
10666 | int err = 0; | ||
10667 | |||
10668 | if (wdev->iftype != NL80211_IFTYPE_NAN) | ||
10669 | return -EOPNOTSUPP; | ||
10670 | |||
10671 | if (!wdev->nan_started) | ||
10672 | return -ENOTCONN; | ||
10673 | |||
10674 | if (!info->attrs[NL80211_ATTR_NAN_FUNC]) | ||
10675 | return -EINVAL; | ||
10676 | |||
10677 | if (wdev->owner_nlportid && | ||
10678 | wdev->owner_nlportid != info->snd_portid) | ||
10679 | return -ENOTCONN; | ||
10680 | |||
10681 | err = nla_parse(tb, NL80211_NAN_FUNC_ATTR_MAX, | ||
10682 | nla_data(info->attrs[NL80211_ATTR_NAN_FUNC]), | ||
10683 | nla_len(info->attrs[NL80211_ATTR_NAN_FUNC]), | ||
10684 | nl80211_nan_func_policy); | ||
10685 | if (err) | ||
10686 | return err; | ||
10687 | |||
10688 | func = kzalloc(sizeof(*func), GFP_KERNEL); | ||
10689 | if (!func) | ||
10690 | return -ENOMEM; | ||
10691 | |||
10692 | func->cookie = wdev->wiphy->cookie_counter++; | ||
10693 | |||
10694 | if (!tb[NL80211_NAN_FUNC_TYPE] || | ||
10695 | nla_get_u8(tb[NL80211_NAN_FUNC_TYPE]) > NL80211_NAN_FUNC_MAX_TYPE) { | ||
10696 | err = -EINVAL; | ||
10697 | goto out; | ||
10698 | } | ||
10699 | |||
10700 | |||
10701 | func->type = nla_get_u8(tb[NL80211_NAN_FUNC_TYPE]); | ||
10702 | |||
10703 | if (!tb[NL80211_NAN_FUNC_SERVICE_ID]) { | ||
10704 | err = -EINVAL; | ||
10705 | goto out; | ||
10706 | } | ||
10707 | |||
10708 | memcpy(func->service_id, nla_data(tb[NL80211_NAN_FUNC_SERVICE_ID]), | ||
10709 | sizeof(func->service_id)); | ||
10710 | |||
10711 | func->close_range = | ||
10712 | nla_get_flag(tb[NL80211_NAN_FUNC_CLOSE_RANGE]); | ||
10713 | |||
10714 | if (tb[NL80211_NAN_FUNC_SERVICE_INFO]) { | ||
10715 | func->serv_spec_info_len = | ||
10716 | nla_len(tb[NL80211_NAN_FUNC_SERVICE_INFO]); | ||
10717 | func->serv_spec_info = | ||
10718 | kmemdup(nla_data(tb[NL80211_NAN_FUNC_SERVICE_INFO]), | ||
10719 | func->serv_spec_info_len, | ||
10720 | GFP_KERNEL); | ||
10721 | if (!func->serv_spec_info) { | ||
10722 | err = -ENOMEM; | ||
10723 | goto out; | ||
10724 | } | ||
10725 | } | ||
10726 | |||
10727 | if (tb[NL80211_NAN_FUNC_TTL]) | ||
10728 | func->ttl = nla_get_u32(tb[NL80211_NAN_FUNC_TTL]); | ||
10729 | |||
10730 | switch (func->type) { | ||
10731 | case NL80211_NAN_FUNC_PUBLISH: | ||
10732 | if (!tb[NL80211_NAN_FUNC_PUBLISH_TYPE]) { | ||
10733 | err = -EINVAL; | ||
10734 | goto out; | ||
10735 | } | ||
10736 | |||
10737 | func->publish_type = | ||
10738 | nla_get_u8(tb[NL80211_NAN_FUNC_PUBLISH_TYPE]); | ||
10739 | func->publish_bcast = | ||
10740 | nla_get_flag(tb[NL80211_NAN_FUNC_PUBLISH_BCAST]); | ||
10741 | |||
10742 | if ((!(func->publish_type & NL80211_NAN_SOLICITED_PUBLISH)) && | ||
10743 | func->publish_bcast) { | ||
10744 | err = -EINVAL; | ||
10745 | goto out; | ||
10746 | } | ||
10747 | break; | ||
10748 | case NL80211_NAN_FUNC_SUBSCRIBE: | ||
10749 | func->subscribe_active = | ||
10750 | nla_get_flag(tb[NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE]); | ||
10751 | break; | ||
10752 | case NL80211_NAN_FUNC_FOLLOW_UP: | ||
10753 | if (!tb[NL80211_NAN_FUNC_FOLLOW_UP_ID] || | ||
10754 | !tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID]) { | ||
10755 | err = -EINVAL; | ||
10756 | goto out; | ||
10757 | } | ||
10758 | |||
10759 | func->followup_id = | ||
10760 | nla_get_u8(tb[NL80211_NAN_FUNC_FOLLOW_UP_ID]); | ||
10761 | func->followup_reqid = | ||
10762 | nla_get_u8(tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID]); | ||
10763 | memcpy(func->followup_dest.addr, | ||
10764 | nla_data(tb[NL80211_NAN_FUNC_FOLLOW_UP_DEST]), | ||
10765 | sizeof(func->followup_dest.addr)); | ||
10766 | if (func->ttl) { | ||
10767 | err = -EINVAL; | ||
10768 | goto out; | ||
10769 | } | ||
10770 | break; | ||
10771 | default: | ||
10772 | err = -EINVAL; | ||
10773 | goto out; | ||
10774 | } | ||
10775 | |||
10776 | if (tb[NL80211_NAN_FUNC_SRF]) { | ||
10777 | struct nlattr *srf_tb[NUM_NL80211_NAN_SRF_ATTR]; | ||
10778 | |||
10779 | err = nla_parse(srf_tb, NL80211_NAN_SRF_ATTR_MAX, | ||
10780 | nla_data(tb[NL80211_NAN_FUNC_SRF]), | ||
10781 | nla_len(tb[NL80211_NAN_FUNC_SRF]), NULL); | ||
10782 | if (err) | ||
10783 | goto out; | ||
10784 | |||
10785 | func->srf_include = | ||
10786 | nla_get_flag(srf_tb[NL80211_NAN_SRF_INCLUDE]); | ||
10787 | |||
10788 | if (srf_tb[NL80211_NAN_SRF_BF]) { | ||
10789 | if (srf_tb[NL80211_NAN_SRF_MAC_ADDRS] || | ||
10790 | !srf_tb[NL80211_NAN_SRF_BF_IDX]) { | ||
10791 | err = -EINVAL; | ||
10792 | goto out; | ||
10793 | } | ||
10794 | |||
10795 | func->srf_bf_len = | ||
10796 | nla_len(srf_tb[NL80211_NAN_SRF_BF]); | ||
10797 | func->srf_bf = | ||
10798 | kmemdup(nla_data(srf_tb[NL80211_NAN_SRF_BF]), | ||
10799 | func->srf_bf_len, GFP_KERNEL); | ||
10800 | if (!func->srf_bf) { | ||
10801 | err = -ENOMEM; | ||
10802 | goto out; | ||
10803 | } | ||
10804 | |||
10805 | func->srf_bf_idx = | ||
10806 | nla_get_u8(srf_tb[NL80211_NAN_SRF_BF_IDX]); | ||
10807 | } else { | ||
10808 | struct nlattr *attr, *mac_attr = | ||
10809 | srf_tb[NL80211_NAN_SRF_MAC_ADDRS]; | ||
10810 | int n_entries, rem, i = 0; | ||
10811 | |||
10812 | if (!mac_attr) { | ||
10813 | err = -EINVAL; | ||
10814 | goto out; | ||
10815 | } | ||
10816 | |||
10817 | n_entries = validate_acl_mac_addrs(mac_attr); | ||
10818 | if (n_entries <= 0) { | ||
10819 | err = -EINVAL; | ||
10820 | goto out; | ||
10821 | } | ||
10822 | |||
10823 | func->srf_num_macs = n_entries; | ||
10824 | func->srf_macs = | ||
10825 | kzalloc(sizeof(*func->srf_macs) * n_entries, | ||
10826 | GFP_KERNEL); | ||
10827 | if (!func->srf_macs) { | ||
10828 | err = -ENOMEM; | ||
10829 | goto out; | ||
10830 | } | ||
10831 | |||
10832 | nla_for_each_nested(attr, mac_attr, rem) | ||
10833 | memcpy(func->srf_macs[i++].addr, nla_data(attr), | ||
10834 | sizeof(*func->srf_macs)); | ||
10835 | } | ||
10836 | } | ||
10837 | |||
10838 | if (tb[NL80211_NAN_FUNC_TX_MATCH_FILTER]) { | ||
10839 | err = handle_nan_filter(tb[NL80211_NAN_FUNC_TX_MATCH_FILTER], | ||
10840 | func, true); | ||
10841 | if (err) | ||
10842 | goto out; | ||
10843 | } | ||
10844 | |||
10845 | if (tb[NL80211_NAN_FUNC_RX_MATCH_FILTER]) { | ||
10846 | err = handle_nan_filter(tb[NL80211_NAN_FUNC_RX_MATCH_FILTER], | ||
10847 | func, false); | ||
10848 | if (err) | ||
10849 | goto out; | ||
10850 | } | ||
10851 | |||
10852 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
10853 | if (!msg) { | ||
10854 | err = -ENOMEM; | ||
10855 | goto out; | ||
10856 | } | ||
10857 | |||
10858 | hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0, | ||
10859 | NL80211_CMD_ADD_NAN_FUNCTION); | ||
10860 | /* This can't really happen - we just allocated 4KB */ | ||
10861 | if (WARN_ON(!hdr)) { | ||
10862 | err = -ENOMEM; | ||
10863 | goto out; | ||
10864 | } | ||
10865 | |||
10866 | err = rdev_add_nan_func(rdev, wdev, func); | ||
10867 | out: | ||
10868 | if (err < 0) { | ||
10869 | cfg80211_free_nan_func(func); | ||
10870 | nlmsg_free(msg); | ||
10871 | return err; | ||
10872 | } | ||
10873 | |||
10874 | /* propagate the instance id and cookie to userspace */ | ||
10875 | if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, func->cookie, | ||
10876 | NL80211_ATTR_PAD)) | ||
10877 | goto nla_put_failure; | ||
10878 | |||
10879 | func_attr = nla_nest_start(msg, NL80211_ATTR_NAN_FUNC); | ||
10880 | if (!func_attr) | ||
10881 | goto nla_put_failure; | ||
10882 | |||
10883 | if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, | ||
10884 | func->instance_id)) | ||
10885 | goto nla_put_failure; | ||
10886 | |||
10887 | nla_nest_end(msg, func_attr); | ||
10888 | |||
10889 | genlmsg_end(msg, hdr); | ||
10890 | return genlmsg_reply(msg, info); | ||
10891 | |||
10892 | nla_put_failure: | ||
10893 | nlmsg_free(msg); | ||
10894 | return -ENOBUFS; | ||
10895 | } | ||
10896 | |||
10897 | static int nl80211_nan_del_func(struct sk_buff *skb, | ||
10898 | struct genl_info *info) | ||
10899 | { | ||
10900 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
10901 | struct wireless_dev *wdev = info->user_ptr[1]; | ||
10902 | u64 cookie; | ||
10903 | |||
10904 | if (wdev->iftype != NL80211_IFTYPE_NAN) | ||
10905 | return -EOPNOTSUPP; | ||
10906 | |||
10907 | if (!wdev->nan_started) | ||
10908 | return -ENOTCONN; | ||
10909 | |||
10910 | if (!info->attrs[NL80211_ATTR_COOKIE]) | ||
10911 | return -EINVAL; | ||
10912 | |||
10913 | if (wdev->owner_nlportid && | ||
10914 | wdev->owner_nlportid != info->snd_portid) | ||
10915 | return -ENOTCONN; | ||
10916 | |||
10917 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); | ||
10918 | |||
10919 | rdev_del_nan_func(rdev, wdev, cookie); | ||
10920 | |||
10921 | return 0; | ||
10922 | } | ||
10923 | |||
10924 | static int nl80211_nan_change_config(struct sk_buff *skb, | ||
10925 | struct genl_info *info) | ||
10926 | { | ||
10927 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
10928 | struct wireless_dev *wdev = info->user_ptr[1]; | ||
10929 | struct cfg80211_nan_conf conf = {}; | ||
10930 | u32 changed = 0; | ||
10931 | |||
10932 | if (wdev->iftype != NL80211_IFTYPE_NAN) | ||
10933 | return -EOPNOTSUPP; | ||
10934 | |||
10935 | if (!wdev->nan_started) | ||
10936 | return -ENOTCONN; | ||
10937 | |||
10938 | if (info->attrs[NL80211_ATTR_NAN_MASTER_PREF]) { | ||
10939 | conf.master_pref = | ||
10940 | nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]); | ||
10941 | if (conf.master_pref <= 1 || conf.master_pref == 255) | ||
10942 | return -EINVAL; | ||
10943 | |||
10944 | changed |= CFG80211_NAN_CONF_CHANGED_PREF; | ||
10945 | } | ||
10946 | |||
10947 | if (info->attrs[NL80211_ATTR_NAN_DUAL]) { | ||
10948 | conf.dual = nla_get_u8(info->attrs[NL80211_ATTR_NAN_DUAL]); | ||
10949 | changed |= CFG80211_NAN_CONF_CHANGED_DUAL; | ||
10950 | } | ||
10951 | |||
10952 | if (!changed) | ||
10953 | return -EINVAL; | ||
10954 | |||
10955 | return rdev_nan_change_conf(rdev, wdev, &conf, changed); | ||
10956 | } | ||
10957 | |||
10958 | void cfg80211_nan_match(struct wireless_dev *wdev, | ||
10959 | struct cfg80211_nan_match_params *match, gfp_t gfp) | ||
10960 | { | ||
10961 | struct wiphy *wiphy = wdev->wiphy; | ||
10962 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | ||
10963 | struct nlattr *match_attr, *local_func_attr, *peer_func_attr; | ||
10964 | struct sk_buff *msg; | ||
10965 | void *hdr; | ||
10966 | |||
10967 | if (WARN_ON(!match->inst_id || !match->peer_inst_id || !match->addr)) | ||
10968 | return; | ||
10969 | |||
10970 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | ||
10971 | if (!msg) | ||
10972 | return; | ||
10973 | |||
10974 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NAN_MATCH); | ||
10975 | if (!hdr) { | ||
10976 | nlmsg_free(msg); | ||
10977 | return; | ||
10978 | } | ||
10979 | |||
10980 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
10981 | (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, | ||
10982 | wdev->netdev->ifindex)) || | ||
10983 | nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev), | ||
10984 | NL80211_ATTR_PAD)) | ||
10985 | goto nla_put_failure; | ||
10986 | |||
10987 | if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, match->cookie, | ||
10988 | NL80211_ATTR_PAD) || | ||
10989 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, match->addr)) | ||
10990 | goto nla_put_failure; | ||
10991 | |||
10992 | match_attr = nla_nest_start(msg, NL80211_ATTR_NAN_MATCH); | ||
10993 | if (!match_attr) | ||
10994 | goto nla_put_failure; | ||
10995 | |||
10996 | local_func_attr = nla_nest_start(msg, NL80211_NAN_MATCH_FUNC_LOCAL); | ||
10997 | if (!local_func_attr) | ||
10998 | goto nla_put_failure; | ||
10999 | |||
11000 | if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, match->inst_id)) | ||
11001 | goto nla_put_failure; | ||
11002 | |||
11003 | nla_nest_end(msg, local_func_attr); | ||
11004 | |||
11005 | peer_func_attr = nla_nest_start(msg, NL80211_NAN_MATCH_FUNC_PEER); | ||
11006 | if (!peer_func_attr) | ||
11007 | goto nla_put_failure; | ||
11008 | |||
11009 | if (nla_put_u8(msg, NL80211_NAN_FUNC_TYPE, match->type) || | ||
11010 | nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, match->peer_inst_id)) | ||
11011 | goto nla_put_failure; | ||
11012 | |||
11013 | if (match->info && match->info_len && | ||
11014 | nla_put(msg, NL80211_NAN_FUNC_SERVICE_INFO, match->info_len, | ||
11015 | match->info)) | ||
11016 | goto nla_put_failure; | ||
11017 | |||
11018 | nla_nest_end(msg, peer_func_attr); | ||
11019 | nla_nest_end(msg, match_attr); | ||
11020 | genlmsg_end(msg, hdr); | ||
11021 | |||
11022 | if (!wdev->owner_nlportid) | ||
11023 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), | ||
11024 | msg, 0, NL80211_MCGRP_NAN, gfp); | ||
11025 | else | ||
11026 | genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, | ||
11027 | wdev->owner_nlportid); | ||
11028 | |||
11029 | return; | ||
11030 | |||
11031 | nla_put_failure: | ||
11032 | nlmsg_free(msg); | ||
11033 | } | ||
11034 | EXPORT_SYMBOL(cfg80211_nan_match); | ||
11035 | |||
11036 | void cfg80211_nan_func_terminated(struct wireless_dev *wdev, | ||
11037 | u8 inst_id, | ||
11038 | enum nl80211_nan_func_term_reason reason, | ||
11039 | u64 cookie, gfp_t gfp) | ||
11040 | { | ||
11041 | struct wiphy *wiphy = wdev->wiphy; | ||
11042 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | ||
11043 | struct sk_buff *msg; | ||
11044 | struct nlattr *func_attr; | ||
11045 | void *hdr; | ||
11046 | |||
11047 | if (WARN_ON(!inst_id)) | ||
11048 | return; | ||
11049 | |||
11050 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | ||
11051 | if (!msg) | ||
11052 | return; | ||
11053 | |||
11054 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DEL_NAN_FUNCTION); | ||
11055 | if (!hdr) { | ||
11056 | nlmsg_free(msg); | ||
11057 | return; | ||
11058 | } | ||
11059 | |||
11060 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
11061 | (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, | ||
11062 | wdev->netdev->ifindex)) || | ||
11063 | nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev), | ||
11064 | NL80211_ATTR_PAD)) | ||
11065 | goto nla_put_failure; | ||
11066 | |||
11067 | if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, cookie, | ||
11068 | NL80211_ATTR_PAD)) | ||
11069 | goto nla_put_failure; | ||
11070 | |||
11071 | func_attr = nla_nest_start(msg, NL80211_ATTR_NAN_FUNC); | ||
11072 | if (!func_attr) | ||
11073 | goto nla_put_failure; | ||
11074 | |||
11075 | if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, inst_id) || | ||
11076 | nla_put_u8(msg, NL80211_NAN_FUNC_TERM_REASON, reason)) | ||
11077 | goto nla_put_failure; | ||
11078 | |||
11079 | nla_nest_end(msg, func_attr); | ||
11080 | genlmsg_end(msg, hdr); | ||
11081 | |||
11082 | if (!wdev->owner_nlportid) | ||
11083 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), | ||
11084 | msg, 0, NL80211_MCGRP_NAN, gfp); | ||
11085 | else | ||
11086 | genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, | ||
11087 | wdev->owner_nlportid); | ||
11088 | |||
11089 | return; | ||
11090 | |||
11091 | nla_put_failure: | ||
11092 | nlmsg_free(msg); | ||
11093 | } | ||
11094 | EXPORT_SYMBOL(cfg80211_nan_func_terminated); | ||
11095 | |||
10417 | static int nl80211_get_protocol_features(struct sk_buff *skb, | 11096 | static int nl80211_get_protocol_features(struct sk_buff *skb, |
10418 | struct genl_info *info) | 11097 | struct genl_info *info) |
10419 | { | 11098 | { |
@@ -11115,7 +11794,14 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, | |||
11115 | 11794 | ||
11116 | dev_hold(dev); | 11795 | dev_hold(dev); |
11117 | } else if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP) { | 11796 | } else if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP) { |
11118 | if (!wdev->p2p_started) { | 11797 | if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE && |
11798 | !wdev->p2p_started) { | ||
11799 | if (rtnl) | ||
11800 | rtnl_unlock(); | ||
11801 | return -ENETDOWN; | ||
11802 | } | ||
11803 | if (wdev->iftype == NL80211_IFTYPE_NAN && | ||
11804 | !wdev->nan_started) { | ||
11119 | if (rtnl) | 11805 | if (rtnl) |
11120 | rtnl_unlock(); | 11806 | rtnl_unlock(); |
11121 | return -ENETDOWN; | 11807 | return -ENETDOWN; |
@@ -11749,6 +12435,46 @@ static const struct genl_ops nl80211_ops[] = { | |||
11749 | NL80211_FLAG_NEED_RTNL, | 12435 | NL80211_FLAG_NEED_RTNL, |
11750 | }, | 12436 | }, |
11751 | { | 12437 | { |
12438 | .cmd = NL80211_CMD_START_NAN, | ||
12439 | .doit = nl80211_start_nan, | ||
12440 | .policy = nl80211_policy, | ||
12441 | .flags = GENL_ADMIN_PERM, | ||
12442 | .internal_flags = NL80211_FLAG_NEED_WDEV | | ||
12443 | NL80211_FLAG_NEED_RTNL, | ||
12444 | }, | ||
12445 | { | ||
12446 | .cmd = NL80211_CMD_STOP_NAN, | ||
12447 | .doit = nl80211_stop_nan, | ||
12448 | .policy = nl80211_policy, | ||
12449 | .flags = GENL_ADMIN_PERM, | ||
12450 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | | ||
12451 | NL80211_FLAG_NEED_RTNL, | ||
12452 | }, | ||
12453 | { | ||
12454 | .cmd = NL80211_CMD_ADD_NAN_FUNCTION, | ||
12455 | .doit = nl80211_nan_add_func, | ||
12456 | .policy = nl80211_policy, | ||
12457 | .flags = GENL_ADMIN_PERM, | ||
12458 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | | ||
12459 | NL80211_FLAG_NEED_RTNL, | ||
12460 | }, | ||
12461 | { | ||
12462 | .cmd = NL80211_CMD_DEL_NAN_FUNCTION, | ||
12463 | .doit = nl80211_nan_del_func, | ||
12464 | .policy = nl80211_policy, | ||
12465 | .flags = GENL_ADMIN_PERM, | ||
12466 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | | ||
12467 | NL80211_FLAG_NEED_RTNL, | ||
12468 | }, | ||
12469 | { | ||
12470 | .cmd = NL80211_CMD_CHANGE_NAN_CONFIG, | ||
12471 | .doit = nl80211_nan_change_config, | ||
12472 | .policy = nl80211_policy, | ||
12473 | .flags = GENL_ADMIN_PERM, | ||
12474 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | | ||
12475 | NL80211_FLAG_NEED_RTNL, | ||
12476 | }, | ||
12477 | { | ||
11752 | .cmd = NL80211_CMD_SET_MCAST_RATE, | 12478 | .cmd = NL80211_CMD_SET_MCAST_RATE, |
11753 | .doit = nl80211_set_mcast_rate, | 12479 | .doit = nl80211_set_mcast_rate, |
11754 | .policy = nl80211_policy, | 12480 | .policy = nl80211_policy, |
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 85ff30bee2b9..11cf83c8ad4f 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h | |||
@@ -887,6 +887,64 @@ static inline void rdev_stop_p2p_device(struct cfg80211_registered_device *rdev, | |||
887 | trace_rdev_return_void(&rdev->wiphy); | 887 | trace_rdev_return_void(&rdev->wiphy); |
888 | } | 888 | } |
889 | 889 | ||
890 | static inline int rdev_start_nan(struct cfg80211_registered_device *rdev, | ||
891 | struct wireless_dev *wdev, | ||
892 | struct cfg80211_nan_conf *conf) | ||
893 | { | ||
894 | int ret; | ||
895 | |||
896 | trace_rdev_start_nan(&rdev->wiphy, wdev, conf); | ||
897 | ret = rdev->ops->start_nan(&rdev->wiphy, wdev, conf); | ||
898 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
899 | return ret; | ||
900 | } | ||
901 | |||
902 | static inline void rdev_stop_nan(struct cfg80211_registered_device *rdev, | ||
903 | struct wireless_dev *wdev) | ||
904 | { | ||
905 | trace_rdev_stop_nan(&rdev->wiphy, wdev); | ||
906 | rdev->ops->stop_nan(&rdev->wiphy, wdev); | ||
907 | trace_rdev_return_void(&rdev->wiphy); | ||
908 | } | ||
909 | |||
910 | static inline int | ||
911 | rdev_add_nan_func(struct cfg80211_registered_device *rdev, | ||
912 | struct wireless_dev *wdev, | ||
913 | struct cfg80211_nan_func *nan_func) | ||
914 | { | ||
915 | int ret; | ||
916 | |||
917 | trace_rdev_add_nan_func(&rdev->wiphy, wdev, nan_func); | ||
918 | ret = rdev->ops->add_nan_func(&rdev->wiphy, wdev, nan_func); | ||
919 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
920 | return ret; | ||
921 | } | ||
922 | |||
923 | static inline void rdev_del_nan_func(struct cfg80211_registered_device *rdev, | ||
924 | struct wireless_dev *wdev, u64 cookie) | ||
925 | { | ||
926 | trace_rdev_del_nan_func(&rdev->wiphy, wdev, cookie); | ||
927 | rdev->ops->del_nan_func(&rdev->wiphy, wdev, cookie); | ||
928 | trace_rdev_return_void(&rdev->wiphy); | ||
929 | } | ||
930 | |||
931 | static inline int | ||
932 | rdev_nan_change_conf(struct cfg80211_registered_device *rdev, | ||
933 | struct wireless_dev *wdev, | ||
934 | struct cfg80211_nan_conf *conf, u32 changes) | ||
935 | { | ||
936 | int ret; | ||
937 | |||
938 | trace_rdev_nan_change_conf(&rdev->wiphy, wdev, conf, changes); | ||
939 | if (rdev->ops->nan_change_conf) | ||
940 | ret = rdev->ops->nan_change_conf(&rdev->wiphy, wdev, conf, | ||
941 | changes); | ||
942 | else | ||
943 | ret = -ENOTSUPP; | ||
944 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
945 | return ret; | ||
946 | } | ||
947 | |||
890 | static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev, | 948 | static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev, |
891 | struct net_device *dev, | 949 | struct net_device *dev, |
892 | struct cfg80211_acl_data *params) | 950 | struct cfg80211_acl_data *params) |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index c08a3b57dca1..a77db333927e 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -726,7 +726,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
726 | 726 | ||
727 | wdev->current_bss = bss_from_pub(bss); | 727 | wdev->current_bss = bss_from_pub(bss); |
728 | 728 | ||
729 | cfg80211_upload_connect_keys(wdev); | 729 | if (!(wdev->wiphy->flags & WIPHY_FLAG_HAS_STATIC_WEP)) |
730 | cfg80211_upload_connect_keys(wdev); | ||
730 | 731 | ||
731 | rcu_read_lock(); | 732 | rcu_read_lock(); |
732 | country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY); | 733 | country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY); |
@@ -1043,6 +1044,9 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
1043 | connect->crypto.ciphers_pairwise[0] = cipher; | 1044 | connect->crypto.ciphers_pairwise[0] = cipher; |
1044 | } | 1045 | } |
1045 | } | 1046 | } |
1047 | |||
1048 | connect->crypto.wep_keys = connkeys->params; | ||
1049 | connect->crypto.wep_tx_key = connkeys->def; | ||
1046 | } else { | 1050 | } else { |
1047 | if (WARN_ON(connkeys)) | 1051 | if (WARN_ON(connkeys)) |
1048 | return -EINVAL; | 1052 | return -EINVAL; |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 72b5255cefe2..a3d0a91b1e09 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -1889,6 +1889,96 @@ DEFINE_EVENT(wiphy_wdev_evt, rdev_stop_p2p_device, | |||
1889 | TP_ARGS(wiphy, wdev) | 1889 | TP_ARGS(wiphy, wdev) |
1890 | ); | 1890 | ); |
1891 | 1891 | ||
1892 | TRACE_EVENT(rdev_start_nan, | ||
1893 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
1894 | struct cfg80211_nan_conf *conf), | ||
1895 | TP_ARGS(wiphy, wdev, conf), | ||
1896 | TP_STRUCT__entry( | ||
1897 | WIPHY_ENTRY | ||
1898 | WDEV_ENTRY | ||
1899 | __field(u8, master_pref) | ||
1900 | __field(u8, dual); | ||
1901 | ), | ||
1902 | TP_fast_assign( | ||
1903 | WIPHY_ASSIGN; | ||
1904 | WDEV_ASSIGN; | ||
1905 | __entry->master_pref = conf->master_pref; | ||
1906 | __entry->dual = conf->dual; | ||
1907 | ), | ||
1908 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT | ||
1909 | ", master preference: %u, dual: %d", | ||
1910 | WIPHY_PR_ARG, WDEV_PR_ARG, __entry->master_pref, | ||
1911 | __entry->dual) | ||
1912 | ); | ||
1913 | |||
1914 | TRACE_EVENT(rdev_nan_change_conf, | ||
1915 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
1916 | struct cfg80211_nan_conf *conf, u32 changes), | ||
1917 | TP_ARGS(wiphy, wdev, conf, changes), | ||
1918 | TP_STRUCT__entry( | ||
1919 | WIPHY_ENTRY | ||
1920 | WDEV_ENTRY | ||
1921 | __field(u8, master_pref) | ||
1922 | __field(u8, dual); | ||
1923 | __field(u32, changes); | ||
1924 | ), | ||
1925 | TP_fast_assign( | ||
1926 | WIPHY_ASSIGN; | ||
1927 | WDEV_ASSIGN; | ||
1928 | __entry->master_pref = conf->master_pref; | ||
1929 | __entry->dual = conf->dual; | ||
1930 | __entry->changes = changes; | ||
1931 | ), | ||
1932 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT | ||
1933 | ", master preference: %u, dual: %d, changes: %x", | ||
1934 | WIPHY_PR_ARG, WDEV_PR_ARG, __entry->master_pref, | ||
1935 | __entry->dual, __entry->changes) | ||
1936 | ); | ||
1937 | |||
1938 | DEFINE_EVENT(wiphy_wdev_evt, rdev_stop_nan, | ||
1939 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), | ||
1940 | TP_ARGS(wiphy, wdev) | ||
1941 | ); | ||
1942 | |||
1943 | TRACE_EVENT(rdev_add_nan_func, | ||
1944 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
1945 | const struct cfg80211_nan_func *func), | ||
1946 | TP_ARGS(wiphy, wdev, func), | ||
1947 | TP_STRUCT__entry( | ||
1948 | WIPHY_ENTRY | ||
1949 | WDEV_ENTRY | ||
1950 | __field(u8, func_type) | ||
1951 | __field(u64, cookie) | ||
1952 | ), | ||
1953 | TP_fast_assign( | ||
1954 | WIPHY_ASSIGN; | ||
1955 | WDEV_ASSIGN; | ||
1956 | __entry->func_type = func->type; | ||
1957 | __entry->cookie = func->cookie | ||
1958 | ), | ||
1959 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", type=%u, cookie=%llu", | ||
1960 | WIPHY_PR_ARG, WDEV_PR_ARG, __entry->func_type, | ||
1961 | __entry->cookie) | ||
1962 | ); | ||
1963 | |||
1964 | TRACE_EVENT(rdev_del_nan_func, | ||
1965 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
1966 | u64 cookie), | ||
1967 | TP_ARGS(wiphy, wdev, cookie), | ||
1968 | TP_STRUCT__entry( | ||
1969 | WIPHY_ENTRY | ||
1970 | WDEV_ENTRY | ||
1971 | __field(u64, cookie) | ||
1972 | ), | ||
1973 | TP_fast_assign( | ||
1974 | WIPHY_ASSIGN; | ||
1975 | WDEV_ASSIGN; | ||
1976 | __entry->cookie = cookie; | ||
1977 | ), | ||
1978 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", cookie=%llu", | ||
1979 | WIPHY_PR_ARG, WDEV_PR_ARG, __entry->cookie) | ||
1980 | ); | ||
1981 | |||
1892 | TRACE_EVENT(rdev_set_mac_acl, | 1982 | TRACE_EVENT(rdev_set_mac_acl, |
1893 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | 1983 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, |
1894 | struct cfg80211_acl_data *params), | 1984 | struct cfg80211_acl_data *params), |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 9e6e2aaa7766..8edce22d1b93 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -912,7 +912,7 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev) | |||
912 | if (!wdev->connect_keys) | 912 | if (!wdev->connect_keys) |
913 | return; | 913 | return; |
914 | 914 | ||
915 | for (i = 0; i < 4; i++) { | 915 | for (i = 0; i < CFG80211_MAX_WEP_KEYS; i++) { |
916 | if (!wdev->connect_keys->params[i].cipher) | 916 | if (!wdev->connect_keys->params[i].cipher) |
917 | continue; | 917 | continue; |
918 | if (rdev_add_key(rdev, dev, i, false, NULL, | 918 | if (rdev_add_key(rdev, dev, i, false, NULL, |
@@ -1008,8 +1008,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
1008 | if (otype == NL80211_IFTYPE_AP_VLAN) | 1008 | if (otype == NL80211_IFTYPE_AP_VLAN) |
1009 | return -EOPNOTSUPP; | 1009 | return -EOPNOTSUPP; |
1010 | 1010 | ||
1011 | /* cannot change into P2P device type */ | 1011 | /* cannot change into P2P device or NAN */ |
1012 | if (ntype == NL80211_IFTYPE_P2P_DEVICE) | 1012 | if (ntype == NL80211_IFTYPE_P2P_DEVICE || |
1013 | ntype == NL80211_IFTYPE_NAN) | ||
1013 | return -EOPNOTSUPP; | 1014 | return -EOPNOTSUPP; |
1014 | 1015 | ||
1015 | if (!rdev->ops->change_virtual_intf || | 1016 | if (!rdev->ops->change_virtual_intf || |
@@ -1088,6 +1089,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
1088 | /* not happening */ | 1089 | /* not happening */ |
1089 | break; | 1090 | break; |
1090 | case NL80211_IFTYPE_P2P_DEVICE: | 1091 | case NL80211_IFTYPE_P2P_DEVICE: |
1092 | case NL80211_IFTYPE_NAN: | ||
1091 | WARN_ON(1); | 1093 | WARN_ON(1); |
1092 | break; | 1094 | break; |
1093 | } | 1095 | } |
@@ -1760,6 +1762,28 @@ int cfg80211_get_station(struct net_device *dev, const u8 *mac_addr, | |||
1760 | } | 1762 | } |
1761 | EXPORT_SYMBOL(cfg80211_get_station); | 1763 | EXPORT_SYMBOL(cfg80211_get_station); |
1762 | 1764 | ||
1765 | void cfg80211_free_nan_func(struct cfg80211_nan_func *f) | ||
1766 | { | ||
1767 | int i; | ||
1768 | |||
1769 | if (!f) | ||
1770 | return; | ||
1771 | |||
1772 | kfree(f->serv_spec_info); | ||
1773 | kfree(f->srf_bf); | ||
1774 | kfree(f->srf_macs); | ||
1775 | for (i = 0; i < f->num_rx_filters; i++) | ||
1776 | kfree(f->rx_filters[i].filter); | ||
1777 | |||
1778 | for (i = 0; i < f->num_tx_filters; i++) | ||
1779 | kfree(f->tx_filters[i].filter); | ||
1780 | |||
1781 | kfree(f->rx_filters); | ||
1782 | kfree(f->tx_filters); | ||
1783 | kfree(f); | ||
1784 | } | ||
1785 | EXPORT_SYMBOL(cfg80211_free_nan_func); | ||
1786 | |||
1763 | /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ | 1787 | /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ |
1764 | /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ | 1788 | /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ |
1765 | const unsigned char rfc1042_header[] __aligned(2) = | 1789 | const unsigned char rfc1042_header[] __aligned(2) = |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 7b97d43b27e1..a220156cf217 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -406,12 +406,16 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
406 | if (pairwise && !addr) | 406 | if (pairwise && !addr) |
407 | return -EINVAL; | 407 | return -EINVAL; |
408 | 408 | ||
409 | /* | ||
410 | * In many cases we won't actually need this, but it's better | ||
411 | * to do it first in case the allocation fails. Don't use wext. | ||
412 | */ | ||
409 | if (!wdev->wext.keys) { | 413 | if (!wdev->wext.keys) { |
410 | wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), | 414 | wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys), |
411 | GFP_KERNEL); | 415 | GFP_KERNEL); |
412 | if (!wdev->wext.keys) | 416 | if (!wdev->wext.keys) |
413 | return -ENOMEM; | 417 | return -ENOMEM; |
414 | for (i = 0; i < 4; i++) | 418 | for (i = 0; i < CFG80211_MAX_WEP_KEYS; i++) |
415 | wdev->wext.keys->params[i].key = | 419 | wdev->wext.keys->params[i].key = |
416 | wdev->wext.keys->data[i]; | 420 | wdev->wext.keys->data[i]; |
417 | } | 421 | } |
@@ -493,7 +497,13 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
493 | if (err) | 497 | if (err) |
494 | return err; | 498 | return err; |
495 | 499 | ||
496 | if (!addr) { | 500 | /* |
501 | * We only need to store WEP keys, since they're the only keys that | ||
502 | * can be be set before a connection is established and persist after | ||
503 | * disconnecting. | ||
504 | */ | ||
505 | if (!addr && (params->cipher == WLAN_CIPHER_SUITE_WEP40 || | ||
506 | params->cipher == WLAN_CIPHER_SUITE_WEP104)) { | ||
497 | wdev->wext.keys->params[idx] = *params; | 507 | wdev->wext.keys->params[idx] = *params; |
498 | memcpy(wdev->wext.keys->data[idx], | 508 | memcpy(wdev->wext.keys->data[idx], |
499 | params->key, params->key_len); | 509 | params->key, params->key_len); |
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 88f1f6931ab8..995163830a61 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c | |||
@@ -46,7 +46,7 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | |||
46 | ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL); | 46 | ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL); |
47 | if (!ck) | 47 | if (!ck) |
48 | return -ENOMEM; | 48 | return -ENOMEM; |
49 | for (i = 0; i < 4; i++) | 49 | for (i = 0; i < CFG80211_MAX_WEP_KEYS; i++) |
50 | ck->params[i].key = ck->data[i]; | 50 | ck->params[i].key = ck->data[i]; |
51 | } | 51 | } |
52 | 52 | ||