mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-18 23:18:20 +00:00
225 lines
5.5 KiB
C
225 lines
5.5 KiB
C
|
/*
|
||
|
* SME code for cfg80211's connect emulation.
|
||
|
*
|
||
|
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
|
||
|
* Copyright (C) 2009 Intel Corporation. All rights reserved.
|
||
|
*/
|
||
|
|
||
|
#include <linux/etherdevice.h>
|
||
|
#include <linux/if_arp.h>
|
||
|
#include <linux/workqueue.h>
|
||
|
#include <net/cfg80211.h>
|
||
|
#include <net/rtnetlink.h>
|
||
|
#include "nl80211.h"
|
||
|
|
||
|
|
||
|
void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||
|
const u8 *req_ie, size_t req_ie_len,
|
||
|
const u8 *resp_ie, size_t resp_ie_len,
|
||
|
u16 status, gfp_t gfp)
|
||
|
{
|
||
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||
|
struct cfg80211_bss *bss;
|
||
|
#ifdef CONFIG_WIRELESS_EXT
|
||
|
union iwreq_data wrqu;
|
||
|
#endif
|
||
|
|
||
|
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
|
||
|
return;
|
||
|
|
||
|
if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING))
|
||
|
return;
|
||
|
|
||
|
if (wdev->current_bss) {
|
||
|
cfg80211_unhold_bss(wdev->current_bss);
|
||
|
cfg80211_put_bss(wdev->current_bss);
|
||
|
wdev->current_bss = NULL;
|
||
|
}
|
||
|
|
||
|
if (status == WLAN_STATUS_SUCCESS) {
|
||
|
bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
|
||
|
wdev->ssid, wdev->ssid_len,
|
||
|
WLAN_CAPABILITY_ESS,
|
||
|
WLAN_CAPABILITY_ESS);
|
||
|
|
||
|
if (WARN_ON(!bss))
|
||
|
return;
|
||
|
|
||
|
cfg80211_hold_bss(bss);
|
||
|
wdev->current_bss = bss;
|
||
|
|
||
|
wdev->sme_state = CFG80211_SME_CONNECTED;
|
||
|
} else {
|
||
|
wdev->sme_state = CFG80211_SME_IDLE;
|
||
|
}
|
||
|
|
||
|
nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, bssid,
|
||
|
req_ie, req_ie_len, resp_ie, resp_ie_len,
|
||
|
status, gfp);
|
||
|
|
||
|
#ifdef CONFIG_WIRELESS_EXT
|
||
|
if (req_ie && status == WLAN_STATUS_SUCCESS) {
|
||
|
memset(&wrqu, 0, sizeof(wrqu));
|
||
|
wrqu.data.length = req_ie_len;
|
||
|
wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie);
|
||
|
}
|
||
|
|
||
|
if (resp_ie && status == WLAN_STATUS_SUCCESS) {
|
||
|
memset(&wrqu, 0, sizeof(wrqu));
|
||
|
wrqu.data.length = resp_ie_len;
|
||
|
wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie);
|
||
|
}
|
||
|
|
||
|
memset(&wrqu, 0, sizeof(wrqu));
|
||
|
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
|
||
|
if (bssid)
|
||
|
memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
|
||
|
wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
|
||
|
#endif
|
||
|
}
|
||
|
EXPORT_SYMBOL(cfg80211_connect_result);
|
||
|
|
||
|
void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
|
||
|
const u8 *req_ie, size_t req_ie_len,
|
||
|
const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
|
||
|
{
|
||
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||
|
struct cfg80211_bss *bss;
|
||
|
#ifdef CONFIG_WIRELESS_EXT
|
||
|
union iwreq_data wrqu;
|
||
|
#endif
|
||
|
|
||
|
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
|
||
|
return;
|
||
|
|
||
|
if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED))
|
||
|
return;
|
||
|
|
||
|
/* internal error -- how did we get to CONNECTED w/o BSS? */
|
||
|
if (WARN_ON(!wdev->current_bss)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
cfg80211_unhold_bss(wdev->current_bss);
|
||
|
cfg80211_put_bss(wdev->current_bss);
|
||
|
wdev->current_bss = NULL;
|
||
|
|
||
|
bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
|
||
|
wdev->ssid, wdev->ssid_len,
|
||
|
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
|
||
|
|
||
|
if (WARN_ON(!bss))
|
||
|
return;
|
||
|
|
||
|
cfg80211_hold_bss(bss);
|
||
|
wdev->current_bss = bss;
|
||
|
|
||
|
nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, bssid,
|
||
|
req_ie, req_ie_len, resp_ie, resp_ie_len, gfp);
|
||
|
|
||
|
#ifdef CONFIG_WIRELESS_EXT
|
||
|
if (req_ie) {
|
||
|
memset(&wrqu, 0, sizeof(wrqu));
|
||
|
wrqu.data.length = req_ie_len;
|
||
|
wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie);
|
||
|
}
|
||
|
|
||
|
if (resp_ie) {
|
||
|
memset(&wrqu, 0, sizeof(wrqu));
|
||
|
wrqu.data.length = resp_ie_len;
|
||
|
wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie);
|
||
|
}
|
||
|
|
||
|
memset(&wrqu, 0, sizeof(wrqu));
|
||
|
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
|
||
|
memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
|
||
|
wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
|
||
|
#endif
|
||
|
}
|
||
|
EXPORT_SYMBOL(cfg80211_roamed);
|
||
|
|
||
|
static void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp,
|
||
|
u8 *ie, size_t ie_len, u16 reason,
|
||
|
bool from_ap)
|
||
|
{
|
||
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||
|
#ifdef CONFIG_WIRELESS_EXT
|
||
|
union iwreq_data wrqu;
|
||
|
#endif
|
||
|
|
||
|
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
|
||
|
return;
|
||
|
|
||
|
if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED))
|
||
|
return;
|
||
|
|
||
|
if (wdev->current_bss) {
|
||
|
cfg80211_unhold_bss(wdev->current_bss);
|
||
|
cfg80211_put_bss(wdev->current_bss);
|
||
|
}
|
||
|
|
||
|
wdev->current_bss = NULL;
|
||
|
wdev->sme_state = CFG80211_SME_IDLE;
|
||
|
|
||
|
nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev,
|
||
|
reason, ie, ie_len, from_ap, gfp);
|
||
|
|
||
|
#ifdef CONFIG_WIRELESS_EXT
|
||
|
memset(&wrqu, 0, sizeof(wrqu));
|
||
|
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
|
||
|
wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void cfg80211_disconnected(struct net_device *dev, u16 reason,
|
||
|
u8 *ie, size_t ie_len, gfp_t gfp)
|
||
|
{
|
||
|
__cfg80211_disconnected(dev, reason, ie, ie_len, true, gfp);
|
||
|
}
|
||
|
EXPORT_SYMBOL(cfg80211_disconnected);
|
||
|
|
||
|
int cfg80211_connect(struct cfg80211_registered_device *rdev,
|
||
|
struct net_device *dev,
|
||
|
struct cfg80211_connect_params *connect)
|
||
|
{
|
||
|
int err;
|
||
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||
|
|
||
|
if (wdev->sme_state != CFG80211_SME_IDLE)
|
||
|
return -EALREADY;
|
||
|
|
||
|
if (!rdev->ops->connect) {
|
||
|
return -EOPNOTSUPP;
|
||
|
} else {
|
||
|
wdev->sme_state = CFG80211_SME_CONNECTING;
|
||
|
err = rdev->ops->connect(&rdev->wiphy, dev, connect);
|
||
|
if (err) {
|
||
|
wdev->sme_state = CFG80211_SME_IDLE;
|
||
|
return err;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
|
||
|
wdev->ssid_len = connect->ssid_len;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
|
||
|
struct net_device *dev, u16 reason)
|
||
|
{
|
||
|
int err;
|
||
|
|
||
|
if (!rdev->ops->disconnect) {
|
||
|
return -EOPNOTSUPP;
|
||
|
} else {
|
||
|
err = rdev->ops->disconnect(&rdev->wiphy, dev, reason);
|
||
|
if (err)
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
__cfg80211_disconnected(dev, 0, NULL, 0, false, GFP_KERNEL);
|
||
|
|
||
|
return 0;
|
||
|
}
|