cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

wext-sme.c (9026B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * cfg80211 wext compat for managed mode.
      4 *
      5 * Copyright 2009	Johannes Berg <johannes@sipsolutions.net>
      6 * Copyright (C) 2009, 2020-2021 Intel Corporation.
      7 */
      8
      9#include <linux/export.h>
     10#include <linux/etherdevice.h>
     11#include <linux/if_arp.h>
     12#include <linux/slab.h>
     13#include <net/cfg80211.h>
     14#include <net/cfg80211-wext.h>
     15#include "wext-compat.h"
     16#include "nl80211.h"
     17
     18int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
     19			      struct wireless_dev *wdev)
     20{
     21	struct cfg80211_cached_keys *ck = NULL;
     22	const u8 *prev_bssid = NULL;
     23	int err, i;
     24
     25	ASSERT_RTNL();
     26	ASSERT_WDEV_LOCK(wdev);
     27
     28	if (!netif_running(wdev->netdev))
     29		return 0;
     30
     31	wdev->wext.connect.ie = wdev->wext.ie;
     32	wdev->wext.connect.ie_len = wdev->wext.ie_len;
     33
     34	/* Use default background scan period */
     35	wdev->wext.connect.bg_scan_period = -1;
     36
     37	if (wdev->wext.keys) {
     38		wdev->wext.keys->def = wdev->wext.default_key;
     39		if (wdev->wext.default_key != -1)
     40			wdev->wext.connect.privacy = true;
     41	}
     42
     43	if (!wdev->wext.connect.ssid_len)
     44		return 0;
     45
     46	if (wdev->wext.keys && wdev->wext.keys->def != -1) {
     47		ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL);
     48		if (!ck)
     49			return -ENOMEM;
     50		for (i = 0; i < CFG80211_MAX_WEP_KEYS; i++)
     51			ck->params[i].key = ck->data[i];
     52	}
     53
     54	if (wdev->wext.prev_bssid_valid)
     55		prev_bssid = wdev->wext.prev_bssid;
     56
     57	err = cfg80211_connect(rdev, wdev->netdev,
     58			       &wdev->wext.connect, ck, prev_bssid);
     59	if (err)
     60		kfree_sensitive(ck);
     61
     62	return err;
     63}
     64
     65int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
     66			      struct iw_request_info *info,
     67			      struct iw_freq *wextfreq, char *extra)
     68{
     69	struct wireless_dev *wdev = dev->ieee80211_ptr;
     70	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
     71	struct ieee80211_channel *chan = NULL;
     72	int err, freq;
     73
     74	/* call only for station! */
     75	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
     76		return -EINVAL;
     77
     78	freq = cfg80211_wext_freq(wextfreq);
     79	if (freq < 0)
     80		return freq;
     81
     82	if (freq) {
     83		chan = ieee80211_get_channel(wdev->wiphy, freq);
     84		if (!chan)
     85			return -EINVAL;
     86		if (chan->flags & IEEE80211_CHAN_DISABLED)
     87			return -EINVAL;
     88	}
     89
     90	wdev_lock(wdev);
     91
     92	if (wdev->conn) {
     93		bool event = true;
     94
     95		if (wdev->wext.connect.channel == chan) {
     96			err = 0;
     97			goto out;
     98		}
     99
    100		/* if SSID set, we'll try right again, avoid event */
    101		if (wdev->wext.connect.ssid_len)
    102			event = false;
    103		err = cfg80211_disconnect(rdev, dev,
    104					  WLAN_REASON_DEAUTH_LEAVING, event);
    105		if (err)
    106			goto out;
    107	}
    108
    109	wdev->wext.connect.channel = chan;
    110	err = cfg80211_mgd_wext_connect(rdev, wdev);
    111 out:
    112	wdev_unlock(wdev);
    113	return err;
    114}
    115
    116int cfg80211_mgd_wext_giwfreq(struct net_device *dev,
    117			      struct iw_request_info *info,
    118			      struct iw_freq *freq, char *extra)
    119{
    120	struct wireless_dev *wdev = dev->ieee80211_ptr;
    121	struct ieee80211_channel *chan = NULL;
    122
    123	/* call only for station! */
    124	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
    125		return -EINVAL;
    126
    127	wdev_lock(wdev);
    128	if (wdev->current_bss)
    129		chan = wdev->current_bss->pub.channel;
    130	else if (wdev->wext.connect.channel)
    131		chan = wdev->wext.connect.channel;
    132	wdev_unlock(wdev);
    133
    134	if (chan) {
    135		freq->m = chan->center_freq;
    136		freq->e = 6;
    137		return 0;
    138	}
    139
    140	/* no channel if not joining */
    141	return -EINVAL;
    142}
    143
    144int cfg80211_mgd_wext_siwessid(struct net_device *dev,
    145			       struct iw_request_info *info,
    146			       struct iw_point *data, char *ssid)
    147{
    148	struct wireless_dev *wdev = dev->ieee80211_ptr;
    149	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
    150	size_t len = data->length;
    151	int err;
    152
    153	/* call only for station! */
    154	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
    155		return -EINVAL;
    156
    157	if (!data->flags)
    158		len = 0;
    159
    160	/* iwconfig uses nul termination in SSID.. */
    161	if (len > 0 && ssid[len - 1] == '\0')
    162		len--;
    163
    164	wdev_lock(wdev);
    165
    166	err = 0;
    167
    168	if (wdev->conn) {
    169		bool event = true;
    170
    171		if (wdev->wext.connect.ssid && len &&
    172		    len == wdev->wext.connect.ssid_len &&
    173		    memcmp(wdev->wext.connect.ssid, ssid, len) == 0)
    174			goto out;
    175
    176		/* if SSID set now, we'll try to connect, avoid event */
    177		if (len)
    178			event = false;
    179		err = cfg80211_disconnect(rdev, dev,
    180					  WLAN_REASON_DEAUTH_LEAVING, event);
    181		if (err)
    182			goto out;
    183	}
    184
    185	wdev->wext.prev_bssid_valid = false;
    186	wdev->wext.connect.ssid = wdev->wext.ssid;
    187	memcpy(wdev->wext.ssid, ssid, len);
    188	wdev->wext.connect.ssid_len = len;
    189
    190	wdev->wext.connect.crypto.control_port = false;
    191	wdev->wext.connect.crypto.control_port_ethertype =
    192					cpu_to_be16(ETH_P_PAE);
    193
    194	err = cfg80211_mgd_wext_connect(rdev, wdev);
    195 out:
    196	wdev_unlock(wdev);
    197	return err;
    198}
    199
    200int cfg80211_mgd_wext_giwessid(struct net_device *dev,
    201			       struct iw_request_info *info,
    202			       struct iw_point *data, char *ssid)
    203{
    204	struct wireless_dev *wdev = dev->ieee80211_ptr;
    205	int ret = 0;
    206
    207	/* call only for station! */
    208	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
    209		return -EINVAL;
    210
    211	data->flags = 0;
    212
    213	wdev_lock(wdev);
    214	if (wdev->current_bss) {
    215		const struct element *ssid_elem;
    216
    217		rcu_read_lock();
    218		ssid_elem = ieee80211_bss_get_elem(&wdev->current_bss->pub,
    219						   WLAN_EID_SSID);
    220		if (ssid_elem) {
    221			data->flags = 1;
    222			data->length = ssid_elem->datalen;
    223			if (data->length > IW_ESSID_MAX_SIZE)
    224				ret = -EINVAL;
    225			else
    226				memcpy(ssid, ssid_elem->data, data->length);
    227		}
    228		rcu_read_unlock();
    229	} else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) {
    230		data->flags = 1;
    231		data->length = wdev->wext.connect.ssid_len;
    232		memcpy(ssid, wdev->wext.connect.ssid, data->length);
    233	}
    234	wdev_unlock(wdev);
    235
    236	return ret;
    237}
    238
    239int cfg80211_mgd_wext_siwap(struct net_device *dev,
    240			    struct iw_request_info *info,
    241			    struct sockaddr *ap_addr, char *extra)
    242{
    243	struct wireless_dev *wdev = dev->ieee80211_ptr;
    244	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
    245	u8 *bssid = ap_addr->sa_data;
    246	int err;
    247
    248	/* call only for station! */
    249	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
    250		return -EINVAL;
    251
    252	if (ap_addr->sa_family != ARPHRD_ETHER)
    253		return -EINVAL;
    254
    255	/* automatic mode */
    256	if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
    257		bssid = NULL;
    258
    259	wdev_lock(wdev);
    260
    261	if (wdev->conn) {
    262		err = 0;
    263		/* both automatic */
    264		if (!bssid && !wdev->wext.connect.bssid)
    265			goto out;
    266
    267		/* fixed already - and no change */
    268		if (wdev->wext.connect.bssid && bssid &&
    269		    ether_addr_equal(bssid, wdev->wext.connect.bssid))
    270			goto out;
    271
    272		err = cfg80211_disconnect(rdev, dev,
    273					  WLAN_REASON_DEAUTH_LEAVING, false);
    274		if (err)
    275			goto out;
    276	}
    277
    278	if (bssid) {
    279		memcpy(wdev->wext.bssid, bssid, ETH_ALEN);
    280		wdev->wext.connect.bssid = wdev->wext.bssid;
    281	} else
    282		wdev->wext.connect.bssid = NULL;
    283
    284	err = cfg80211_mgd_wext_connect(rdev, wdev);
    285 out:
    286	wdev_unlock(wdev);
    287	return err;
    288}
    289
    290int cfg80211_mgd_wext_giwap(struct net_device *dev,
    291			    struct iw_request_info *info,
    292			    struct sockaddr *ap_addr, char *extra)
    293{
    294	struct wireless_dev *wdev = dev->ieee80211_ptr;
    295
    296	/* call only for station! */
    297	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
    298		return -EINVAL;
    299
    300	ap_addr->sa_family = ARPHRD_ETHER;
    301
    302	wdev_lock(wdev);
    303	if (wdev->current_bss)
    304		memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN);
    305	else
    306		eth_zero_addr(ap_addr->sa_data);
    307	wdev_unlock(wdev);
    308
    309	return 0;
    310}
    311
    312int cfg80211_wext_siwgenie(struct net_device *dev,
    313			   struct iw_request_info *info,
    314			   struct iw_point *data, char *extra)
    315{
    316	struct wireless_dev *wdev = dev->ieee80211_ptr;
    317	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
    318	u8 *ie = extra;
    319	int ie_len = data->length, err;
    320
    321	if (wdev->iftype != NL80211_IFTYPE_STATION)
    322		return -EOPNOTSUPP;
    323
    324	if (!ie_len)
    325		ie = NULL;
    326
    327	wdev_lock(wdev);
    328
    329	/* no change */
    330	err = 0;
    331	if (wdev->wext.ie_len == ie_len &&
    332	    memcmp(wdev->wext.ie, ie, ie_len) == 0)
    333		goto out;
    334
    335	if (ie_len) {
    336		ie = kmemdup(extra, ie_len, GFP_KERNEL);
    337		if (!ie) {
    338			err = -ENOMEM;
    339			goto out;
    340		}
    341	} else
    342		ie = NULL;
    343
    344	kfree(wdev->wext.ie);
    345	wdev->wext.ie = ie;
    346	wdev->wext.ie_len = ie_len;
    347
    348	if (wdev->conn) {
    349		err = cfg80211_disconnect(rdev, dev,
    350					  WLAN_REASON_DEAUTH_LEAVING, false);
    351		if (err)
    352			goto out;
    353	}
    354
    355	/* userspace better not think we'll reconnect */
    356	err = 0;
    357 out:
    358	wdev_unlock(wdev);
    359	return err;
    360}
    361
    362int cfg80211_wext_siwmlme(struct net_device *dev,
    363			  struct iw_request_info *info,
    364			  struct iw_point *data, char *extra)
    365{
    366	struct wireless_dev *wdev = dev->ieee80211_ptr;
    367	struct iw_mlme *mlme = (struct iw_mlme *)extra;
    368	struct cfg80211_registered_device *rdev;
    369	int err;
    370
    371	if (!wdev)
    372		return -EOPNOTSUPP;
    373
    374	rdev = wiphy_to_rdev(wdev->wiphy);
    375
    376	if (wdev->iftype != NL80211_IFTYPE_STATION)
    377		return -EINVAL;
    378
    379	if (mlme->addr.sa_family != ARPHRD_ETHER)
    380		return -EINVAL;
    381
    382	wiphy_lock(&rdev->wiphy);
    383	wdev_lock(wdev);
    384	switch (mlme->cmd) {
    385	case IW_MLME_DEAUTH:
    386	case IW_MLME_DISASSOC:
    387		err = cfg80211_disconnect(rdev, dev, mlme->reason_code, true);
    388		break;
    389	default:
    390		err = -EOPNOTSUPP;
    391		break;
    392	}
    393	wdev_unlock(wdev);
    394	wiphy_unlock(&rdev->wiphy);
    395
    396	return err;
    397}