// SPDX-License-Identifier: GPL-2.0
/*
* SME code for cfg80211
* both driver SME event handling and the SME implementation
* (for nl80211's connect() and wext)
*
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
* Copyright (C) 2009 Intel Corporation. All rights reserved.
* Copyright 2017 Intel Deutschland GmbH
*/
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/wireless.h>
#include <linux/export.h>
#include <net/iw_handler.h>
#include <net/cfg80211.h>
#include <net/rtnetlink.h>
#include "nl80211.h"
#include "reg.h"
#include "rdev-ops.h"
/*
* Software SME in cfg80211, using auth/assoc/deauth calls to the
* driver. This is is for implementing nl80211's connect/disconnect
* and wireless extensions (if configured.)
*/
struct cfg80211_conn {
struct cfg80211_connect_params params;
/* these are sub-states of the _CONNECTING sme_state */
enum {
CFG80211_CONN_SCANNING,
CFG80211_CONN_SCAN_AGAIN,
CFG80211_CONN_AUTHENTICATE_NEXT,
CFG80211_CONN_AUTHENTICATING,
CFG80211_CONN_AUTH_FAILED_TIMEOUT,
CFG80211_CONN_ASSOCIATE_NEXT,
CFG80211_CONN_ASSOCIATING,
CFG80211_CONN_ASSOC_FAILED,
CFG80211_CONN_ASSOC_FAILED_TIMEOUT,
CFG80211_CONN_DEAUTH,
CFG80211_CONN_ABANDON,
CFG80211_CONN_CONNECTED,
} state;
u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
const u8 *ie;
size_t ie_len;
bool auto_auth, prev_bssid_valid;
};
static void cfg80211_sme_free(struct wireless_dev *wdev)
{
if (!wdev->conn)
return;
kfree(wdev->conn->ie);
kfree(wdev->conn);
wdev->conn = NULL;
}
static int cfg80211_conn_scan(struct wireless_dev *wdev)
{
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct cfg80211_scan_request *request;
int n_channels, err;
ASSERT_RTNL();
ASSERT_WDEV_LOCK(wdev);
if (rdev->scan_req || rdev->scan_msg)
return -EBUSY;
if (wdev->conn->params.channel)
n_channels = 1;
else
n_channels = ieee80211_get_num_supported_channels(wdev->wiphy);
request = kzalloc(sizeof(*request) + sizeof(request->ssids[0]) +
sizeof(request->channels[0]) * n_channels,
GFP_KERNEL);
if (!request)
return -ENOMEM;
if (wdev->conn->params.channel) {
enum nl80211_band band = wdev->conn->params.channel->band;
struct ieee80211_supported_band *sband =
wdev->wiphy->bands[band];
if (!sband) {
kfree(request);
return -EINVAL;
}
request