// SPDX-License-Identifier: GPL-2.0-only
/*
* This file contains the major functions in WLAN
* driver. It includes init, exit, open, close and main
* thread etc..
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/hardirq.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/kthread.h>
#include <linux/kfifo.h>
#include <linux/slab.h>
#include <net/cfg80211.h>
#include "host.h"
#include "decl.h"
#include "dev.h"
#include "cfg.h"
#include "debugfs.h"
#include "cmd.h"
#include "mesh.h"
#define DRIVER_RELEASE_VERSION "323.p0"
const char lbs_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
#ifdef DEBUG
"-dbg"
#endif
"";
/* Module parameters */
unsigned int lbs_debug;
EXPORT_SYMBOL_GPL(lbs_debug);
module_param_named(libertas_debug, lbs_debug, int, 0644);
static unsigned int lbs_disablemesh;
module_param_named(libertas_disablemesh, lbs_disablemesh, int, 0644);
/*
* This global structure is used to send the confirm_sleep command as
* fast as possible down to the firmware.
*/
struct cmd_confirm_sleep confirm_sleep;
/*
* the table to keep region code
*/
u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
{ 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
/*
* FW rate table. FW refers to rates by their index in this table, not by the
* rate value itself. Values of 0x00 are
* reserved positions.
*/
static u8 fw_data_rates[MAX_RATES] =
{ 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
};
/**
* lbs_fw_index_to_data_rate - use index to get the data rate
*
* @idx: The index of data rate
* returns: data rate or 0
*/
u32 lbs_fw_index_to_data_rate(u8 idx)
{
if (idx >= sizeof(fw_data_rates))
idx = 0;
return fw_data_rates[idx];
}
/**
* lbs_data_rate_to_fw_index - use rate to get the index
*
* @rate: data rate
* returns: index or 0
*/
u8 lbs_data_rate_to_fw_index(u32 rate)
{
u8 i;
if (!rate)
return 0;
for (i = 0; i < sizeof(fw_data_rates); i++) {
if (rate == fw_data_rates[i])
return i;
}
return 0;
}
int lbs_set_iface_type(struct lbs_private *priv, enum nl80211_iftype type)
{
int ret = 0;
switch (type) {
case NL80211_IFTYPE_MONITOR:
ret = lbs_set_monitor_mode(priv, 1);
break;
case NL80211_IFTYPE_STATION:
if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
ret = lbs_set_monitor_mode(priv, 0);
if (!ret)
ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 1);
break;
case NL80211_IFTYPE_ADHOC:
if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
ret = lbs_set_monitor_mode(priv, 0);
if (!ret)
ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 2);
break;
default:
ret = -ENOTSUPP;
}
return ret;
}
int lbs_start_iface(struct lbs_private *priv)
{
struct cmd_ds_802_11_mac_address cmd;
int ret;
if (priv->power_restore) {
ret = priv->power_restore(priv);
if (ret)
return ret;
}
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
cmd.action = cpu_to_le16(CMD_ACT_SET);
memcpy(cmd.macadd, priv->current_addr, ETH_ALEN);
ret = lbs_cmd_with_response(priv, CMD_802_11_MAC_ADDRESS, &cmd);
if (ret) {
lbs_deb_net("set MAC address failed\n");
goto err;
}
ret = lbs_set_iface_type(priv, priv->wdev->iftype);
if (ret) {
lbs_deb_net("set iface type failed\n");
goto err;
}
ret = lbs_set_11d_domain_info(priv);
if (ret) {
lbs_deb_net("set 11d domain info failed\n");
goto err;
}
lbs_update_channel(priv);
priv