Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mac80211: Implement add_nan_func and rm_nan_func

Implement add/rm_nan_func functions and handle NAN function
termination notifications. Handle instance_id allocation for
NAN functions and implement the reconfig flow.

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Ayala Beker and committed by
Johannes Berg
167e33f4 5953ff6d

+304 -3
+31
include/net/mac80211.h
··· 2177 2177 * @n_cipher_schemes: a size of an array of cipher schemes definitions. 2178 2178 * @cipher_schemes: a pointer to an array of cipher scheme definitions 2179 2179 * supported by HW. 2180 + * @max_nan_de_entries: maximum number of NAN DE functions supported by the 2181 + * device. 2180 2182 */ 2181 2183 struct ieee80211_hw { 2182 2184 struct ieee80211_conf conf; ··· 2213 2211 u8 uapsd_max_sp_len; 2214 2212 u8 n_cipher_schemes; 2215 2213 const struct ieee80211_cipher_scheme *cipher_schemes; 2214 + u8 max_nan_de_entries; 2216 2215 }; 2217 2216 2218 2217 static inline bool _ieee80211_hw_check(struct ieee80211_hw *hw, ··· 3432 3429 * The driver gets both full configuration and the changed parameters since 3433 3430 * some devices may need the full configuration while others need only the 3434 3431 * changed parameters. 3432 + * @add_nan_func: Add a NAN function. Returns 0 on success. The data in 3433 + * cfg80211_nan_func must not be referenced outside the scope of 3434 + * this call. 3435 + * @del_nan_func: Remove a NAN function. The driver must call 3436 + * ieee80211_nan_func_terminated() with 3437 + * NL80211_NAN_FUNC_TERM_REASON_USER_REQUEST reason code upon removal. 3435 3438 */ 3436 3439 struct ieee80211_ops { 3437 3440 void (*tx)(struct ieee80211_hw *hw, ··· 3682 3673 int (*nan_change_conf)(struct ieee80211_hw *hw, 3683 3674 struct ieee80211_vif *vif, 3684 3675 struct cfg80211_nan_conf *conf, u32 changes); 3676 + int (*add_nan_func)(struct ieee80211_hw *hw, 3677 + struct ieee80211_vif *vif, 3678 + const struct cfg80211_nan_func *nan_func); 3679 + void (*del_nan_func)(struct ieee80211_hw *hw, 3680 + struct ieee80211_vif *vif, 3681 + u8 instance_id); 3685 3682 }; 3686 3683 3687 3684 /** ··· 5761 5746 void ieee80211_txq_get_depth(struct ieee80211_txq *txq, 5762 5747 unsigned long *frame_cnt, 5763 5748 unsigned long *byte_cnt); 5749 + 5750 + /** 5751 + * ieee80211_nan_func_terminated - notify about NAN function termination. 5752 + * 5753 + * This function is used to notify mac80211 about NAN function termination. 5754 + * Note that this function can't be called from hard irq. 5755 + * 5756 + * @vif: &struct ieee80211_vif pointer from the add_interface callback. 5757 + * @inst_id: the local instance id 5758 + * @reason: termination reason (one of the NL80211_NAN_FUNC_TERM_REASON_*) 5759 + * @gfp: allocation flags 5760 + */ 5761 + void ieee80211_nan_func_terminated(struct ieee80211_vif *vif, 5762 + u8 inst_id, 5763 + enum nl80211_nan_func_term_reason reason, 5764 + gfp_t gfp); 5764 5765 #endif /* MAC80211_H */
+114
net/mac80211/cfg.c
··· 174 174 if (ret) 175 175 ieee80211_sdata_stop(sdata); 176 176 177 + sdata->u.nan.conf = *conf; 178 + 177 179 return ret; 178 180 } 179 181 ··· 216 214 sdata->u.nan.conf = new_conf; 217 215 218 216 return ret; 217 + } 218 + 219 + static int ieee80211_add_nan_func(struct wiphy *wiphy, 220 + struct wireless_dev *wdev, 221 + struct cfg80211_nan_func *nan_func) 222 + { 223 + struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); 224 + int ret; 225 + 226 + if (sdata->vif.type != NL80211_IFTYPE_NAN) 227 + return -EOPNOTSUPP; 228 + 229 + if (!ieee80211_sdata_running(sdata)) 230 + return -ENETDOWN; 231 + 232 + spin_lock_bh(&sdata->u.nan.func_lock); 233 + 234 + ret = idr_alloc(&sdata->u.nan.function_inst_ids, 235 + nan_func, 1, sdata->local->hw.max_nan_de_entries + 1, 236 + GFP_ATOMIC); 237 + spin_unlock_bh(&sdata->u.nan.func_lock); 238 + 239 + if (ret < 0) 240 + return ret; 241 + 242 + nan_func->instance_id = ret; 243 + 244 + WARN_ON(nan_func->instance_id == 0); 245 + 246 + ret = drv_add_nan_func(sdata->local, sdata, nan_func); 247 + if (ret) { 248 + spin_lock_bh(&sdata->u.nan.func_lock); 249 + idr_remove(&sdata->u.nan.function_inst_ids, 250 + nan_func->instance_id); 251 + spin_unlock_bh(&sdata->u.nan.func_lock); 252 + } 253 + 254 + return ret; 255 + } 256 + 257 + static struct cfg80211_nan_func * 258 + ieee80211_find_nan_func_by_cookie(struct ieee80211_sub_if_data *sdata, 259 + u64 cookie) 260 + { 261 + struct cfg80211_nan_func *func; 262 + int id; 263 + 264 + lockdep_assert_held(&sdata->u.nan.func_lock); 265 + 266 + idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, id) { 267 + if (func->cookie == cookie) 268 + return func; 269 + } 270 + 271 + return NULL; 272 + } 273 + 274 + static void ieee80211_del_nan_func(struct wiphy *wiphy, 275 + struct wireless_dev *wdev, u64 cookie) 276 + { 277 + struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); 278 + struct cfg80211_nan_func *func; 279 + u8 instance_id = 0; 280 + 281 + if (sdata->vif.type != NL80211_IFTYPE_NAN || 282 + !ieee80211_sdata_running(sdata)) 283 + return; 284 + 285 + spin_lock_bh(&sdata->u.nan.func_lock); 286 + 287 + func = ieee80211_find_nan_func_by_cookie(sdata, cookie); 288 + if (func) 289 + instance_id = func->instance_id; 290 + 291 + spin_unlock_bh(&sdata->u.nan.func_lock); 292 + 293 + if (instance_id) 294 + drv_del_nan_func(sdata->local, sdata, instance_id); 219 295 } 220 296 221 297 static int ieee80211_set_noack_map(struct wiphy *wiphy, ··· 3523 3443 return -ENOENT; 3524 3444 } 3525 3445 3446 + void ieee80211_nan_func_terminated(struct ieee80211_vif *vif, 3447 + u8 inst_id, 3448 + enum nl80211_nan_func_term_reason reason, 3449 + gfp_t gfp) 3450 + { 3451 + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); 3452 + struct cfg80211_nan_func *func; 3453 + u64 cookie; 3454 + 3455 + if (WARN_ON(vif->type != NL80211_IFTYPE_NAN)) 3456 + return; 3457 + 3458 + spin_lock_bh(&sdata->u.nan.func_lock); 3459 + 3460 + func = idr_find(&sdata->u.nan.function_inst_ids, inst_id); 3461 + if (WARN_ON(!func)) { 3462 + spin_unlock_bh(&sdata->u.nan.func_lock); 3463 + return; 3464 + } 3465 + 3466 + cookie = func->cookie; 3467 + idr_remove(&sdata->u.nan.function_inst_ids, inst_id); 3468 + 3469 + spin_unlock_bh(&sdata->u.nan.func_lock); 3470 + 3471 + cfg80211_free_nan_func(func); 3472 + 3473 + cfg80211_nan_func_terminated(ieee80211_vif_to_wdev(vif), inst_id, 3474 + reason, cookie, gfp); 3475 + } 3476 + EXPORT_SYMBOL(ieee80211_nan_func_terminated); 3477 + 3526 3478 const struct cfg80211_ops mac80211_config_ops = { 3527 3479 .add_virtual_intf = ieee80211_add_iface, 3528 3480 .del_virtual_intf = ieee80211_del_iface, ··· 3643 3531 .start_nan = ieee80211_start_nan, 3644 3532 .stop_nan = ieee80211_stop_nan, 3645 3533 .nan_change_conf = ieee80211_nan_change_conf, 3534 + .add_nan_func = ieee80211_add_nan_func, 3535 + .del_nan_func = ieee80211_del_nan_func, 3646 3536 };
+32
net/mac80211/driver-ops.h
··· 1213 1213 return ret; 1214 1214 } 1215 1215 1216 + static inline int drv_add_nan_func(struct ieee80211_local *local, 1217 + struct ieee80211_sub_if_data *sdata, 1218 + const struct cfg80211_nan_func *nan_func) 1219 + { 1220 + int ret; 1221 + 1222 + might_sleep(); 1223 + check_sdata_in_driver(sdata); 1224 + 1225 + if (!local->ops->add_nan_func) 1226 + return -EOPNOTSUPP; 1227 + 1228 + trace_drv_add_nan_func(local, sdata, nan_func); 1229 + ret = local->ops->add_nan_func(&local->hw, &sdata->vif, nan_func); 1230 + trace_drv_return_int(local, ret); 1231 + 1232 + return ret; 1233 + } 1234 + 1235 + static inline void drv_del_nan_func(struct ieee80211_local *local, 1236 + struct ieee80211_sub_if_data *sdata, 1237 + u8 instance_id) 1238 + { 1239 + might_sleep(); 1240 + check_sdata_in_driver(sdata); 1241 + 1242 + trace_drv_del_nan_func(local, sdata, instance_id); 1243 + if (local->ops->del_nan_func) 1244 + local->ops->del_nan_func(&local->hw, &sdata->vif, instance_id); 1245 + trace_drv_return_void(local); 1246 + } 1247 + 1216 1248 #endif /* __MAC80211_DRIVER_OPS */
+7
net/mac80211/ieee80211_i.h
··· 86 86 87 87 #define IEEE80211_DEAUTH_FRAME_LEN (24 /* hdr */ + 2 /* reason */) 88 88 89 + #define IEEE80211_MAX_NAN_INSTANCE_ID 255 90 + 89 91 struct ieee80211_fragment_entry { 90 92 struct sk_buff_head skb_list; 91 93 unsigned long first_frag_time; ··· 836 834 * struct ieee80211_if_nan - NAN state 837 835 * 838 836 * @conf: current NAN configuration 837 + * @func_ids: a bitmap of available instance_id's 839 838 */ 840 839 struct ieee80211_if_nan { 841 840 struct cfg80211_nan_conf conf; 841 + 842 + /* protects function_inst_ids */ 843 + spinlock_t func_lock; 844 + struct idr function_inst_ids; 842 845 }; 843 846 844 847 struct ieee80211_sub_if_data {
+18 -2
net/mac80211/iface.c
··· 798 798 struct ps_data *ps; 799 799 struct cfg80211_chan_def chandef; 800 800 bool cancel_scan; 801 + struct cfg80211_nan_func *func; 801 802 802 803 clear_bit(SDATA_STATE_RUNNING, &sdata->state); 803 804 ··· 951 950 952 951 ieee80211_adjust_monitor_flags(sdata, -1); 953 952 break; 953 + case NL80211_IFTYPE_NAN: 954 + /* clean all the functions */ 955 + spin_lock_bh(&sdata->u.nan.func_lock); 956 + 957 + idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, i) { 958 + idr_remove(&sdata->u.nan.function_inst_ids, i); 959 + cfg80211_free_nan_func(func); 960 + } 961 + idr_destroy(&sdata->u.nan.function_inst_ids); 962 + 963 + spin_unlock_bh(&sdata->u.nan.func_lock); 964 + break; 954 965 case NL80211_IFTYPE_P2P_DEVICE: 955 966 /* relies on synchronize_rcu() below */ 956 967 RCU_INIT_POINTER(local->p2p_sdata, NULL); 957 968 /* fall through */ 958 - case NL80211_IFTYPE_NAN: 959 969 default: 960 970 cancel_work_sync(&sdata->work); 961 971 /* ··· 1474 1462 case NL80211_IFTYPE_WDS: 1475 1463 sdata->vif.bss_conf.bssid = NULL; 1476 1464 break; 1465 + case NL80211_IFTYPE_NAN: 1466 + idr_init(&sdata->u.nan.function_inst_ids); 1467 + spin_lock_init(&sdata->u.nan.func_lock); 1468 + sdata->vif.bss_conf.bssid = sdata->vif.addr; 1469 + break; 1477 1470 case NL80211_IFTYPE_AP_VLAN: 1478 1471 case NL80211_IFTYPE_P2P_DEVICE: 1479 - case NL80211_IFTYPE_NAN: 1480 1472 sdata->vif.bss_conf.bssid = sdata->vif.addr; 1481 1473 break; 1482 1474 case NL80211_IFTYPE_UNSPECIFIED:
+3
net/mac80211/main.c
··· 1063 1063 1064 1064 local->dynamic_ps_forced_timeout = -1; 1065 1065 1066 + if (!local->hw.max_nan_de_entries) 1067 + local->hw.max_nan_de_entries = IEEE80211_MAX_NAN_INSTANCE_ID; 1068 + 1066 1069 result = ieee80211_wep_init(local); 1067 1070 if (result < 0) 1068 1071 wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n",
+52
net/mac80211/trace.h
··· 1781 1781 ) 1782 1782 ); 1783 1783 1784 + TRACE_EVENT(drv_add_nan_func, 1785 + TP_PROTO(struct ieee80211_local *local, 1786 + struct ieee80211_sub_if_data *sdata, 1787 + const struct cfg80211_nan_func *func), 1788 + 1789 + TP_ARGS(local, sdata, func), 1790 + TP_STRUCT__entry( 1791 + LOCAL_ENTRY 1792 + VIF_ENTRY 1793 + __field(u8, type) 1794 + __field(u8, inst_id) 1795 + ), 1796 + 1797 + TP_fast_assign( 1798 + LOCAL_ASSIGN; 1799 + VIF_ASSIGN; 1800 + __entry->type = func->type; 1801 + __entry->inst_id = func->instance_id; 1802 + ), 1803 + 1804 + TP_printk( 1805 + LOCAL_PR_FMT VIF_PR_FMT 1806 + ", type: %u, inst_id: %u", 1807 + LOCAL_PR_ARG, VIF_PR_ARG, __entry->type, __entry->inst_id 1808 + ) 1809 + ); 1810 + 1811 + TRACE_EVENT(drv_del_nan_func, 1812 + TP_PROTO(struct ieee80211_local *local, 1813 + struct ieee80211_sub_if_data *sdata, 1814 + u8 instance_id), 1815 + 1816 + TP_ARGS(local, sdata, instance_id), 1817 + TP_STRUCT__entry( 1818 + LOCAL_ENTRY 1819 + VIF_ENTRY 1820 + __field(u8, instance_id) 1821 + ), 1822 + 1823 + TP_fast_assign( 1824 + LOCAL_ASSIGN; 1825 + VIF_ASSIGN; 1826 + __entry->instance_id = instance_id; 1827 + ), 1828 + 1829 + TP_printk( 1830 + LOCAL_PR_FMT VIF_PR_FMT 1831 + ", instance_id: %u", 1832 + LOCAL_PR_ARG, VIF_PR_ARG, __entry->instance_id 1833 + ) 1834 + ); 1835 + 1784 1836 /* 1785 1837 * Tracing for API calls that drivers call. 1786 1838 */
+47 -1
net/mac80211/util.c
··· 1749 1749 mutex_unlock(&local->sta_mtx); 1750 1750 } 1751 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 + 1752 1792 int ieee80211_reconfig(struct ieee80211_local *local) 1753 1793 { 1754 1794 struct ieee80211_hw *hw = &local->hw; ··· 2012 1972 ieee80211_bss_info_change_notify(sdata, changed); 2013 1973 } 2014 1974 break; 1975 + case NL80211_IFTYPE_NAN: 1976 + res = ieee80211_reconfig_nan(sdata); 1977 + if (res < 0) { 1978 + ieee80211_handle_reconfig_failure(local); 1979 + return res; 1980 + } 1981 + break; 2015 1982 case NL80211_IFTYPE_WDS: 2016 1983 case NL80211_IFTYPE_AP_VLAN: 2017 1984 case NL80211_IFTYPE_MONITOR: 2018 1985 case NL80211_IFTYPE_P2P_DEVICE: 2019 - case NL80211_IFTYPE_NAN: 2020 1986 /* nothing to do */ 2021 1987 break; 2022 1988 case NL80211_IFTYPE_UNSPECIFIED: