18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Some IBSS support code for cfg80211. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 98c2ecf20Sopenharmony_ci#include <linux/if_arp.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/export.h> 128c2ecf20Sopenharmony_ci#include <net/cfg80211.h> 138c2ecf20Sopenharmony_ci#include "wext-compat.h" 148c2ecf20Sopenharmony_ci#include "nl80211.h" 158c2ecf20Sopenharmony_ci#include "rdev-ops.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_civoid __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, 198c2ecf20Sopenharmony_ci struct ieee80211_channel *channel) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci struct wireless_dev *wdev = dev->ieee80211_ptr; 228c2ecf20Sopenharmony_ci struct cfg80211_bss *bss; 238c2ecf20Sopenharmony_ci#ifdef CONFIG_CFG80211_WEXT 248c2ecf20Sopenharmony_ci union iwreq_data wrqu; 258c2ecf20Sopenharmony_ci#endif 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) 288c2ecf20Sopenharmony_ci return; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci if (!wdev->ssid_len) 318c2ecf20Sopenharmony_ci return; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, NULL, 0, 348c2ecf20Sopenharmony_ci IEEE80211_BSS_TYPE_IBSS, IEEE80211_PRIVACY_ANY); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci if (WARN_ON(!bss)) 378c2ecf20Sopenharmony_ci return; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci if (wdev->current_bss) { 408c2ecf20Sopenharmony_ci cfg80211_unhold_bss(wdev->current_bss); 418c2ecf20Sopenharmony_ci cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); 428c2ecf20Sopenharmony_ci } 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci cfg80211_hold_bss(bss_from_pub(bss)); 458c2ecf20Sopenharmony_ci wdev->current_bss = bss_from_pub(bss); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (!(wdev->wiphy->flags & WIPHY_FLAG_HAS_STATIC_WEP)) 488c2ecf20Sopenharmony_ci cfg80211_upload_connect_keys(wdev); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci nl80211_send_ibss_bssid(wiphy_to_rdev(wdev->wiphy), dev, bssid, 518c2ecf20Sopenharmony_ci GFP_KERNEL); 528c2ecf20Sopenharmony_ci#ifdef CONFIG_CFG80211_WEXT 538c2ecf20Sopenharmony_ci memset(&wrqu, 0, sizeof(wrqu)); 548c2ecf20Sopenharmony_ci memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); 558c2ecf20Sopenharmony_ci wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); 568c2ecf20Sopenharmony_ci#endif 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_civoid cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, 608c2ecf20Sopenharmony_ci struct ieee80211_channel *channel, gfp_t gfp) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci struct wireless_dev *wdev = dev->ieee80211_ptr; 638c2ecf20Sopenharmony_ci struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); 648c2ecf20Sopenharmony_ci struct cfg80211_event *ev; 658c2ecf20Sopenharmony_ci unsigned long flags; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci trace_cfg80211_ibss_joined(dev, bssid, channel); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (WARN_ON(!channel)) 708c2ecf20Sopenharmony_ci return; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci ev = kzalloc(sizeof(*ev), gfp); 738c2ecf20Sopenharmony_ci if (!ev) 748c2ecf20Sopenharmony_ci return; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci ev->type = EVENT_IBSS_JOINED; 778c2ecf20Sopenharmony_ci memcpy(ev->ij.bssid, bssid, ETH_ALEN); 788c2ecf20Sopenharmony_ci ev->ij.channel = channel; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci spin_lock_irqsave(&wdev->event_lock, flags); 818c2ecf20Sopenharmony_ci list_add_tail(&ev->list, &wdev->event_list); 828c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wdev->event_lock, flags); 838c2ecf20Sopenharmony_ci queue_work(cfg80211_wq, &rdev->event_work); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cfg80211_ibss_joined); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ciint __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, 888c2ecf20Sopenharmony_ci struct net_device *dev, 898c2ecf20Sopenharmony_ci struct cfg80211_ibss_params *params, 908c2ecf20Sopenharmony_ci struct cfg80211_cached_keys *connkeys) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci struct wireless_dev *wdev = dev->ieee80211_ptr; 938c2ecf20Sopenharmony_ci int err; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci ASSERT_RTNL(); 968c2ecf20Sopenharmony_ci ASSERT_WDEV_LOCK(wdev); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (wdev->ssid_len) 998c2ecf20Sopenharmony_ci return -EALREADY; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (!params->basic_rates) { 1028c2ecf20Sopenharmony_ci /* 1038c2ecf20Sopenharmony_ci * If no rates were explicitly configured, 1048c2ecf20Sopenharmony_ci * use the mandatory rate set for 11b or 1058c2ecf20Sopenharmony_ci * 11a for maximum compatibility. 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 1088c2ecf20Sopenharmony_ci enum nl80211_band band; 1098c2ecf20Sopenharmony_ci u32 flag; 1108c2ecf20Sopenharmony_ci int j; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci band = params->chandef.chan->band; 1138c2ecf20Sopenharmony_ci if (band == NL80211_BAND_5GHZ || 1148c2ecf20Sopenharmony_ci band == NL80211_BAND_6GHZ) 1158c2ecf20Sopenharmony_ci flag = IEEE80211_RATE_MANDATORY_A; 1168c2ecf20Sopenharmony_ci else 1178c2ecf20Sopenharmony_ci flag = IEEE80211_RATE_MANDATORY_B; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci sband = rdev->wiphy.bands[band]; 1208c2ecf20Sopenharmony_ci for (j = 0; j < sband->n_bitrates; j++) { 1218c2ecf20Sopenharmony_ci if (sband->bitrates[j].flags & flag) 1228c2ecf20Sopenharmony_ci params->basic_rates |= BIT(j); 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (WARN_ON(connkeys && connkeys->def < 0)) 1278c2ecf20Sopenharmony_ci return -EINVAL; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if (WARN_ON(wdev->connect_keys)) 1308c2ecf20Sopenharmony_ci kfree_sensitive(wdev->connect_keys); 1318c2ecf20Sopenharmony_ci wdev->connect_keys = connkeys; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci wdev->ibss_fixed = params->channel_fixed; 1348c2ecf20Sopenharmony_ci wdev->ibss_dfs_possible = params->userspace_handles_dfs; 1358c2ecf20Sopenharmony_ci wdev->chandef = params->chandef; 1368c2ecf20Sopenharmony_ci if (connkeys) { 1378c2ecf20Sopenharmony_ci params->wep_keys = connkeys->params; 1388c2ecf20Sopenharmony_ci params->wep_tx_key = connkeys->def; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci#ifdef CONFIG_CFG80211_WEXT 1428c2ecf20Sopenharmony_ci wdev->wext.ibss.chandef = params->chandef; 1438c2ecf20Sopenharmony_ci#endif 1448c2ecf20Sopenharmony_ci err = rdev_join_ibss(rdev, dev, params); 1458c2ecf20Sopenharmony_ci if (err) { 1468c2ecf20Sopenharmony_ci wdev->connect_keys = NULL; 1478c2ecf20Sopenharmony_ci return err; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci memcpy(wdev->ssid, params->ssid, params->ssid_len); 1518c2ecf20Sopenharmony_ci wdev->ssid_len = params->ssid_len; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci return 0; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci struct wireless_dev *wdev = dev->ieee80211_ptr; 1598c2ecf20Sopenharmony_ci struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); 1608c2ecf20Sopenharmony_ci int i; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci ASSERT_WDEV_LOCK(wdev); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci kfree_sensitive(wdev->connect_keys); 1658c2ecf20Sopenharmony_ci wdev->connect_keys = NULL; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci rdev_set_qos_map(rdev, dev, NULL); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* 1708c2ecf20Sopenharmony_ci * Delete all the keys ... pairwise keys can't really 1718c2ecf20Sopenharmony_ci * exist any more anyway, but default keys might. 1728c2ecf20Sopenharmony_ci */ 1738c2ecf20Sopenharmony_ci if (rdev->ops->del_key) 1748c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) 1758c2ecf20Sopenharmony_ci rdev_del_key(rdev, dev, i, false, NULL); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (wdev->current_bss) { 1788c2ecf20Sopenharmony_ci cfg80211_unhold_bss(wdev->current_bss); 1798c2ecf20Sopenharmony_ci cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci wdev->current_bss = NULL; 1838c2ecf20Sopenharmony_ci wdev->ssid_len = 0; 1848c2ecf20Sopenharmony_ci memset(&wdev->chandef, 0, sizeof(wdev->chandef)); 1858c2ecf20Sopenharmony_ci#ifdef CONFIG_CFG80211_WEXT 1868c2ecf20Sopenharmony_ci if (!nowext) 1878c2ecf20Sopenharmony_ci wdev->wext.ibss.ssid_len = 0; 1888c2ecf20Sopenharmony_ci#endif 1898c2ecf20Sopenharmony_ci cfg80211_sched_dfs_chan_update(rdev); 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_civoid cfg80211_clear_ibss(struct net_device *dev, bool nowext) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci struct wireless_dev *wdev = dev->ieee80211_ptr; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci wdev_lock(wdev); 1978c2ecf20Sopenharmony_ci __cfg80211_clear_ibss(dev, nowext); 1988c2ecf20Sopenharmony_ci wdev_unlock(wdev); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ciint __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, 2028c2ecf20Sopenharmony_ci struct net_device *dev, bool nowext) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct wireless_dev *wdev = dev->ieee80211_ptr; 2058c2ecf20Sopenharmony_ci int err; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci ASSERT_WDEV_LOCK(wdev); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (!wdev->ssid_len) 2108c2ecf20Sopenharmony_ci return -ENOLINK; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci err = rdev_leave_ibss(rdev, dev); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci if (err) 2158c2ecf20Sopenharmony_ci return err; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci wdev->conn_owner_nlportid = 0; 2188c2ecf20Sopenharmony_ci __cfg80211_clear_ibss(dev, nowext); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci return 0; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ciint cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, 2248c2ecf20Sopenharmony_ci struct net_device *dev, bool nowext) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci struct wireless_dev *wdev = dev->ieee80211_ptr; 2278c2ecf20Sopenharmony_ci int err; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci wdev_lock(wdev); 2308c2ecf20Sopenharmony_ci err = __cfg80211_leave_ibss(rdev, dev, nowext); 2318c2ecf20Sopenharmony_ci wdev_unlock(wdev); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci return err; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci#ifdef CONFIG_CFG80211_WEXT 2378c2ecf20Sopenharmony_ciint cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, 2388c2ecf20Sopenharmony_ci struct wireless_dev *wdev) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci struct cfg80211_cached_keys *ck = NULL; 2418c2ecf20Sopenharmony_ci enum nl80211_band band; 2428c2ecf20Sopenharmony_ci int i, err; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci ASSERT_WDEV_LOCK(wdev); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (!wdev->wext.ibss.beacon_interval) 2478c2ecf20Sopenharmony_ci wdev->wext.ibss.beacon_interval = 100; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci /* try to find an IBSS channel if none requested ... */ 2508c2ecf20Sopenharmony_ci if (!wdev->wext.ibss.chandef.chan) { 2518c2ecf20Sopenharmony_ci struct ieee80211_channel *new_chan = NULL; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci for (band = 0; band < NUM_NL80211_BANDS; band++) { 2548c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 2558c2ecf20Sopenharmony_ci struct ieee80211_channel *chan; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci sband = rdev->wiphy.bands[band]; 2588c2ecf20Sopenharmony_ci if (!sband) 2598c2ecf20Sopenharmony_ci continue; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci for (i = 0; i < sband->n_channels; i++) { 2628c2ecf20Sopenharmony_ci chan = &sband->channels[i]; 2638c2ecf20Sopenharmony_ci if (chan->flags & IEEE80211_CHAN_NO_IR) 2648c2ecf20Sopenharmony_ci continue; 2658c2ecf20Sopenharmony_ci if (chan->flags & IEEE80211_CHAN_DISABLED) 2668c2ecf20Sopenharmony_ci continue; 2678c2ecf20Sopenharmony_ci new_chan = chan; 2688c2ecf20Sopenharmony_ci break; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (new_chan) 2728c2ecf20Sopenharmony_ci break; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (!new_chan) 2768c2ecf20Sopenharmony_ci return -EINVAL; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci cfg80211_chandef_create(&wdev->wext.ibss.chandef, new_chan, 2798c2ecf20Sopenharmony_ci NL80211_CHAN_NO_HT); 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci /* don't join -- SSID is not there */ 2838c2ecf20Sopenharmony_ci if (!wdev->wext.ibss.ssid_len) 2848c2ecf20Sopenharmony_ci return 0; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (!netif_running(wdev->netdev)) 2878c2ecf20Sopenharmony_ci return 0; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (wdev->wext.keys) 2908c2ecf20Sopenharmony_ci wdev->wext.keys->def = wdev->wext.default_key; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci wdev->wext.ibss.privacy = wdev->wext.default_key != -1; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (wdev->wext.keys && wdev->wext.keys->def != -1) { 2958c2ecf20Sopenharmony_ci ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL); 2968c2ecf20Sopenharmony_ci if (!ck) 2978c2ecf20Sopenharmony_ci return -ENOMEM; 2988c2ecf20Sopenharmony_ci for (i = 0; i < CFG80211_MAX_WEP_KEYS; i++) 2998c2ecf20Sopenharmony_ci ck->params[i].key = ck->data[i]; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci err = __cfg80211_join_ibss(rdev, wdev->netdev, 3028c2ecf20Sopenharmony_ci &wdev->wext.ibss, ck); 3038c2ecf20Sopenharmony_ci if (err) 3048c2ecf20Sopenharmony_ci kfree(ck); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci return err; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ciint cfg80211_ibss_wext_siwfreq(struct net_device *dev, 3108c2ecf20Sopenharmony_ci struct iw_request_info *info, 3118c2ecf20Sopenharmony_ci struct iw_freq *wextfreq, char *extra) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci struct wireless_dev *wdev = dev->ieee80211_ptr; 3148c2ecf20Sopenharmony_ci struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); 3158c2ecf20Sopenharmony_ci struct ieee80211_channel *chan = NULL; 3168c2ecf20Sopenharmony_ci int err, freq; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* call only for ibss! */ 3198c2ecf20Sopenharmony_ci if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) 3208c2ecf20Sopenharmony_ci return -EINVAL; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (!rdev->ops->join_ibss) 3238c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci freq = cfg80211_wext_freq(wextfreq); 3268c2ecf20Sopenharmony_ci if (freq < 0) 3278c2ecf20Sopenharmony_ci return freq; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (freq) { 3308c2ecf20Sopenharmony_ci chan = ieee80211_get_channel(wdev->wiphy, freq); 3318c2ecf20Sopenharmony_ci if (!chan) 3328c2ecf20Sopenharmony_ci return -EINVAL; 3338c2ecf20Sopenharmony_ci if (chan->flags & IEEE80211_CHAN_NO_IR || 3348c2ecf20Sopenharmony_ci chan->flags & IEEE80211_CHAN_DISABLED) 3358c2ecf20Sopenharmony_ci return -EINVAL; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (wdev->wext.ibss.chandef.chan == chan) 3398c2ecf20Sopenharmony_ci return 0; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci wdev_lock(wdev); 3428c2ecf20Sopenharmony_ci err = 0; 3438c2ecf20Sopenharmony_ci if (wdev->ssid_len) 3448c2ecf20Sopenharmony_ci err = __cfg80211_leave_ibss(rdev, dev, true); 3458c2ecf20Sopenharmony_ci wdev_unlock(wdev); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (err) 3488c2ecf20Sopenharmony_ci return err; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (chan) { 3518c2ecf20Sopenharmony_ci cfg80211_chandef_create(&wdev->wext.ibss.chandef, chan, 3528c2ecf20Sopenharmony_ci NL80211_CHAN_NO_HT); 3538c2ecf20Sopenharmony_ci wdev->wext.ibss.channel_fixed = true; 3548c2ecf20Sopenharmony_ci } else { 3558c2ecf20Sopenharmony_ci /* cfg80211_ibss_wext_join will pick one if needed */ 3568c2ecf20Sopenharmony_ci wdev->wext.ibss.channel_fixed = false; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci wdev_lock(wdev); 3608c2ecf20Sopenharmony_ci err = cfg80211_ibss_wext_join(rdev, wdev); 3618c2ecf20Sopenharmony_ci wdev_unlock(wdev); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci return err; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ciint cfg80211_ibss_wext_giwfreq(struct net_device *dev, 3678c2ecf20Sopenharmony_ci struct iw_request_info *info, 3688c2ecf20Sopenharmony_ci struct iw_freq *freq, char *extra) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci struct wireless_dev *wdev = dev->ieee80211_ptr; 3718c2ecf20Sopenharmony_ci struct ieee80211_channel *chan = NULL; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci /* call only for ibss! */ 3748c2ecf20Sopenharmony_ci if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) 3758c2ecf20Sopenharmony_ci return -EINVAL; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci wdev_lock(wdev); 3788c2ecf20Sopenharmony_ci if (wdev->current_bss) 3798c2ecf20Sopenharmony_ci chan = wdev->current_bss->pub.channel; 3808c2ecf20Sopenharmony_ci else if (wdev->wext.ibss.chandef.chan) 3818c2ecf20Sopenharmony_ci chan = wdev->wext.ibss.chandef.chan; 3828c2ecf20Sopenharmony_ci wdev_unlock(wdev); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (chan) { 3858c2ecf20Sopenharmony_ci freq->m = chan->center_freq; 3868c2ecf20Sopenharmony_ci freq->e = 6; 3878c2ecf20Sopenharmony_ci return 0; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci /* no channel if not joining */ 3918c2ecf20Sopenharmony_ci return -EINVAL; 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ciint cfg80211_ibss_wext_siwessid(struct net_device *dev, 3958c2ecf20Sopenharmony_ci struct iw_request_info *info, 3968c2ecf20Sopenharmony_ci struct iw_point *data, char *ssid) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci struct wireless_dev *wdev = dev->ieee80211_ptr; 3998c2ecf20Sopenharmony_ci struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); 4008c2ecf20Sopenharmony_ci size_t len = data->length; 4018c2ecf20Sopenharmony_ci int err; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci /* call only for ibss! */ 4048c2ecf20Sopenharmony_ci if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) 4058c2ecf20Sopenharmony_ci return -EINVAL; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (!rdev->ops->join_ibss) 4088c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci wdev_lock(wdev); 4118c2ecf20Sopenharmony_ci err = 0; 4128c2ecf20Sopenharmony_ci if (wdev->ssid_len) 4138c2ecf20Sopenharmony_ci err = __cfg80211_leave_ibss(rdev, dev, true); 4148c2ecf20Sopenharmony_ci wdev_unlock(wdev); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (err) 4178c2ecf20Sopenharmony_ci return err; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci /* iwconfig uses nul termination in SSID.. */ 4208c2ecf20Sopenharmony_ci if (len > 0 && ssid[len - 1] == '\0') 4218c2ecf20Sopenharmony_ci len--; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci memcpy(wdev->ssid, ssid, len); 4248c2ecf20Sopenharmony_ci wdev->wext.ibss.ssid = wdev->ssid; 4258c2ecf20Sopenharmony_ci wdev->wext.ibss.ssid_len = len; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci wdev_lock(wdev); 4288c2ecf20Sopenharmony_ci err = cfg80211_ibss_wext_join(rdev, wdev); 4298c2ecf20Sopenharmony_ci wdev_unlock(wdev); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci return err; 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ciint cfg80211_ibss_wext_giwessid(struct net_device *dev, 4358c2ecf20Sopenharmony_ci struct iw_request_info *info, 4368c2ecf20Sopenharmony_ci struct iw_point *data, char *ssid) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci struct wireless_dev *wdev = dev->ieee80211_ptr; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci /* call only for ibss! */ 4418c2ecf20Sopenharmony_ci if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) 4428c2ecf20Sopenharmony_ci return -EINVAL; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci data->flags = 0; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci wdev_lock(wdev); 4478c2ecf20Sopenharmony_ci if (wdev->ssid_len) { 4488c2ecf20Sopenharmony_ci data->flags = 1; 4498c2ecf20Sopenharmony_ci data->length = wdev->ssid_len; 4508c2ecf20Sopenharmony_ci memcpy(ssid, wdev->ssid, data->length); 4518c2ecf20Sopenharmony_ci } else if (wdev->wext.ibss.ssid && wdev->wext.ibss.ssid_len) { 4528c2ecf20Sopenharmony_ci data->flags = 1; 4538c2ecf20Sopenharmony_ci data->length = wdev->wext.ibss.ssid_len; 4548c2ecf20Sopenharmony_ci memcpy(ssid, wdev->wext.ibss.ssid, data->length); 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci wdev_unlock(wdev); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci return 0; 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ciint cfg80211_ibss_wext_siwap(struct net_device *dev, 4628c2ecf20Sopenharmony_ci struct iw_request_info *info, 4638c2ecf20Sopenharmony_ci struct sockaddr *ap_addr, char *extra) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci struct wireless_dev *wdev = dev->ieee80211_ptr; 4668c2ecf20Sopenharmony_ci struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); 4678c2ecf20Sopenharmony_ci u8 *bssid = ap_addr->sa_data; 4688c2ecf20Sopenharmony_ci int err; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci /* call only for ibss! */ 4718c2ecf20Sopenharmony_ci if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) 4728c2ecf20Sopenharmony_ci return -EINVAL; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci if (!rdev->ops->join_ibss) 4758c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (ap_addr->sa_family != ARPHRD_ETHER) 4788c2ecf20Sopenharmony_ci return -EINVAL; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci /* automatic mode */ 4818c2ecf20Sopenharmony_ci if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) 4828c2ecf20Sopenharmony_ci bssid = NULL; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci if (bssid && !is_valid_ether_addr(bssid)) 4858c2ecf20Sopenharmony_ci return -EINVAL; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* both automatic */ 4888c2ecf20Sopenharmony_ci if (!bssid && !wdev->wext.ibss.bssid) 4898c2ecf20Sopenharmony_ci return 0; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci /* fixed already - and no change */ 4928c2ecf20Sopenharmony_ci if (wdev->wext.ibss.bssid && bssid && 4938c2ecf20Sopenharmony_ci ether_addr_equal(bssid, wdev->wext.ibss.bssid)) 4948c2ecf20Sopenharmony_ci return 0; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci wdev_lock(wdev); 4978c2ecf20Sopenharmony_ci err = 0; 4988c2ecf20Sopenharmony_ci if (wdev->ssid_len) 4998c2ecf20Sopenharmony_ci err = __cfg80211_leave_ibss(rdev, dev, true); 5008c2ecf20Sopenharmony_ci wdev_unlock(wdev); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (err) 5038c2ecf20Sopenharmony_ci return err; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci if (bssid) { 5068c2ecf20Sopenharmony_ci memcpy(wdev->wext.bssid, bssid, ETH_ALEN); 5078c2ecf20Sopenharmony_ci wdev->wext.ibss.bssid = wdev->wext.bssid; 5088c2ecf20Sopenharmony_ci } else 5098c2ecf20Sopenharmony_ci wdev->wext.ibss.bssid = NULL; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci wdev_lock(wdev); 5128c2ecf20Sopenharmony_ci err = cfg80211_ibss_wext_join(rdev, wdev); 5138c2ecf20Sopenharmony_ci wdev_unlock(wdev); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci return err; 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ciint cfg80211_ibss_wext_giwap(struct net_device *dev, 5198c2ecf20Sopenharmony_ci struct iw_request_info *info, 5208c2ecf20Sopenharmony_ci struct sockaddr *ap_addr, char *extra) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci struct wireless_dev *wdev = dev->ieee80211_ptr; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci /* call only for ibss! */ 5258c2ecf20Sopenharmony_ci if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) 5268c2ecf20Sopenharmony_ci return -EINVAL; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci ap_addr->sa_family = ARPHRD_ETHER; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci wdev_lock(wdev); 5318c2ecf20Sopenharmony_ci if (wdev->current_bss) 5328c2ecf20Sopenharmony_ci memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); 5338c2ecf20Sopenharmony_ci else if (wdev->wext.ibss.bssid) 5348c2ecf20Sopenharmony_ci memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN); 5358c2ecf20Sopenharmony_ci else 5368c2ecf20Sopenharmony_ci eth_zero_addr(ap_addr->sa_data); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci wdev_unlock(wdev); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci return 0; 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci#endif 543