📄 cmdresp.c
字号:
/** * This file contains the handling of command * responses as well as events generated by firmware. */#include <linux/delay.h>#include <linux/if_arp.h>#include <linux/netdevice.h>#include <net/iw_handler.h>#include "host.h"#include "decl.h"#include "defs.h"#include "dev.h"#include "join.h"#include "wext.h"/** * @brief This function handles disconnect event. it * reports disconnect to upper layer, clean tx/rx packets, * reset link state etc. * * @param priv A pointer to wlan_private structure * @return n/a */void libertas_mac_event_disconnected(wlan_private * priv){ wlan_adapter *adapter = priv->adapter; union iwreq_data wrqu; if (adapter->connect_status != LIBERTAS_CONNECTED) return; lbs_deb_enter(LBS_DEB_CMD); memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN); wrqu.ap_addr.sa_family = ARPHRD_ETHER; /* * Cisco AP sends EAP failure and de-auth in less than 0.5 ms. * It causes problem in the Supplicant */ msleep_interruptible(1000); wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); /* Free Tx and Rx packets */ kfree_skb(priv->adapter->currenttxskb); priv->adapter->currenttxskb = NULL; /* report disconnect to upper layer */ netif_stop_queue(priv->dev); netif_carrier_off(priv->dev); /* reset SNR/NF/RSSI values */ memset(adapter->SNR, 0x00, sizeof(adapter->SNR)); memset(adapter->NF, 0x00, sizeof(adapter->NF)); memset(adapter->RSSI, 0x00, sizeof(adapter->RSSI)); memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR)); memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF)); adapter->nextSNRNF = 0; adapter->numSNRNF = 0; lbs_deb_cmd("current SSID '%s', length %u\n", escape_essid(adapter->curbssparams.ssid, adapter->curbssparams.ssid_len), adapter->curbssparams.ssid_len); adapter->connect_status = LIBERTAS_DISCONNECTED; /* Clear out associated SSID and BSSID since connection is * no longer valid. */ memset(&adapter->curbssparams.bssid, 0, ETH_ALEN); memset(&adapter->curbssparams.ssid, 0, IW_ESSID_MAX_SIZE); adapter->curbssparams.ssid_len = 0; if (adapter->psstate != PS_STATE_FULL_POWER) { /* make firmware to exit PS mode */ lbs_deb_cmd("disconnected, so exit PS mode\n"); libertas_ps_wakeup(priv, 0); } lbs_deb_leave(LBS_DEB_CMD);}/** * @brief This function handles MIC failure event. * * @param priv A pointer to wlan_private structure * @para event the event id * @return n/a */static void handle_mic_failureevent(wlan_private * priv, u32 event){ char buf[50]; lbs_deb_enter(LBS_DEB_CMD); memset(buf, 0, sizeof(buf)); sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication "); if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) { strcat(buf, "unicast "); } else { strcat(buf, "multicast "); } libertas_send_iwevcustom_event(priv, buf); lbs_deb_leave(LBS_DEB_CMD);}static int wlan_ret_reg_access(wlan_private * priv, u16 type, struct cmd_ds_command *resp){ int ret = 0; wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_CMD); switch (type) { case CMD_RET(CMD_MAC_REG_ACCESS): { struct cmd_ds_mac_reg_access *reg = &resp->params.macreg; adapter->offsetvalue.offset = (u32)le16_to_cpu(reg->offset); adapter->offsetvalue.value = le32_to_cpu(reg->value); break; } case CMD_RET(CMD_BBP_REG_ACCESS): { struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg; adapter->offsetvalue.offset = (u32)le16_to_cpu(reg->offset); adapter->offsetvalue.value = reg->value; break; } case CMD_RET(CMD_RF_REG_ACCESS): { struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg; adapter->offsetvalue.offset = (u32)le16_to_cpu(reg->offset); adapter->offsetvalue.value = reg->value; break; } default: ret = -1; } lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret;}static int wlan_ret_get_hw_spec(wlan_private * priv, struct cmd_ds_command *resp){ u32 i; struct cmd_ds_get_hw_spec *hwspec = &resp->params.hwspec; wlan_adapter *adapter = priv->adapter; int ret = 0; DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_CMD); adapter->fwcapinfo = le32_to_cpu(hwspec->fwcapinfo); memcpy(adapter->fwreleasenumber, hwspec->fwreleasenumber, 4); lbs_deb_cmd("GET_HW_SPEC: firmware release %u.%u.%up%u\n", adapter->fwreleasenumber[2], adapter->fwreleasenumber[1], adapter->fwreleasenumber[0], adapter->fwreleasenumber[3]); lbs_deb_cmd("GET_HW_SPEC: MAC addr %s\n", print_mac(mac, hwspec->permanentaddr)); lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n", hwspec->hwifversion, hwspec->version); /* Clamp region code to 8-bit since FW spec indicates that it should * only ever be 8-bit, even though the field size is 16-bit. Some firmware * returns non-zero high 8 bits here. */ adapter->regioncode = le16_to_cpu(hwspec->regioncode) & 0xFF; for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { /* use the region code to search for the index */ if (adapter->regioncode == libertas_region_code_to_index[i]) { break; } } /* if it's unidentified region code, use the default (USA) */ if (i >= MRVDRV_MAX_REGION_CODE) { adapter->regioncode = 0x10; lbs_pr_info("unidentified region code; using the default (USA)\n"); } if (adapter->current_addr[0] == 0xff) memmove(adapter->current_addr, hwspec->permanentaddr, ETH_ALEN); memcpy(priv->dev->dev_addr, adapter->current_addr, ETH_ALEN); if (priv->mesh_dev) memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN); if (libertas_set_regiontable(priv, adapter->regioncode, 0)) { ret = -1; goto done; } if (libertas_set_universaltable(priv, 0)) { ret = -1; goto done; }done: lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret); return ret;}static int wlan_ret_802_11_sleep_params(wlan_private * priv, struct cmd_ds_command *resp){ struct cmd_ds_802_11_sleep_params *sp = &resp->params.sleep_params; wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_CMD); lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, calcontrol 0x%x " "extsleepclk 0x%x\n", le16_to_cpu(sp->error), le16_to_cpu(sp->offset), le16_to_cpu(sp->stabletime), sp->calcontrol, sp->externalsleepclk); adapter->sp.sp_error = le16_to_cpu(sp->error); adapter->sp.sp_offset = le16_to_cpu(sp->offset); adapter->sp.sp_stabletime = le16_to_cpu(sp->stabletime); adapter->sp.sp_calcontrol = sp->calcontrol; adapter->sp.sp_extsleepclk = sp->externalsleepclk; adapter->sp.sp_reserved = le16_to_cpu(sp->reserved); lbs_deb_enter(LBS_DEB_CMD); return 0;}static int wlan_ret_802_11_stat(wlan_private * priv, struct cmd_ds_command *resp){ lbs_deb_enter(LBS_DEB_CMD);/* currently adapter->wlan802_11Stat is unused struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat; wlan_adapter *adapter = priv->adapter; // TODO Convert it to Big endian befor copy memcpy(&adapter->wlan802_11Stat, p11Stat, sizeof(struct cmd_ds_802_11_get_stat));*/ lbs_deb_leave(LBS_DEB_CMD); return 0;}static int wlan_ret_802_11_snmp_mib(wlan_private * priv, struct cmd_ds_command *resp){ struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib; u16 oid = le16_to_cpu(smib->oid); u16 querytype = le16_to_cpu(smib->querytype); lbs_deb_enter(LBS_DEB_CMD); lbs_deb_cmd("SNMP_RESP: oid 0x%x, querytype 0x%x\n", oid, querytype); lbs_deb_cmd("SNMP_RESP: Buf size %d\n", le16_to_cpu(smib->bufsize)); if (querytype == CMD_ACT_GET) { switch (oid) { case FRAGTHRESH_I: priv->adapter->fragthsd = le16_to_cpu(*((__le16 *)(smib->value))); lbs_deb_cmd("SNMP_RESP: frag threshold %u\n", priv->adapter->fragthsd); break; case RTSTHRESH_I: priv->adapter->rtsthsd = le16_to_cpu(*((__le16 *)(smib->value))); lbs_deb_cmd("SNMP_RESP: rts threshold %u\n", priv->adapter->rtsthsd); break; case SHORT_RETRYLIM_I: priv->adapter->txretrycount = le16_to_cpu(*((__le16 *)(smib->value))); lbs_deb_cmd("SNMP_RESP: tx retry count %u\n", priv->adapter->rtsthsd); break; default: break; } } lbs_deb_enter(LBS_DEB_CMD); return 0;}static int wlan_ret_802_11_key_material(wlan_private * priv, struct cmd_ds_command *resp){ struct cmd_ds_802_11_key_material *pkeymaterial = &resp->params.keymaterial; wlan_adapter *adapter = priv->adapter; u16 action = le16_to_cpu(pkeymaterial->action); lbs_deb_enter(LBS_DEB_CMD); /* Copy the returned key to driver private data */ if (action == CMD_ACT_GET) { u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet; u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size)); while (buf_ptr < resp_end) { struct MrvlIEtype_keyParamSet * pkeyparamset = (struct MrvlIEtype_keyParamSet *) buf_ptr; struct enc_key * pkey; u16 param_set_len = le16_to_cpu(pkeyparamset->length); u16 key_len = le16_to_cpu(pkeyparamset->keylen); u16 key_flags = le16_to_cpu(pkeyparamset->keyinfo); u16 key_type = le16_to_cpu(pkeyparamset->keytypeid); u8 * end; end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type) + sizeof (pkeyparamset->length) + param_set_len; /* Make sure we don't access past the end of the IEs */ if (end > resp_end) break; if (key_flags & KEY_INFO_WPA_UNICAST) pkey = &adapter->wpa_unicast_key; else if (key_flags & KEY_INFO_WPA_MCAST) pkey = &adapter->wpa_mcast_key; else break; /* Copy returned key into driver */ memset(pkey, 0, sizeof(struct enc_key)); if (key_len > sizeof(pkey->key)) break; pkey->type = key_type; pkey->flags = key_flags; pkey->len = key_len; memcpy(pkey->key, pkeyparamset->key, pkey->len); buf_ptr = end + 1; } } lbs_deb_enter(LBS_DEB_CMD); return 0;}static int wlan_ret_802_11_mac_address(wlan_private * priv, struct cmd_ds_command *resp){ struct cmd_ds_802_11_mac_address *macadd = &resp->params.macadd; wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_CMD); memcpy(adapter->current_addr, macadd->macadd, ETH_ALEN); lbs_deb_enter(LBS_DEB_CMD); return 0;}static int wlan_ret_802_11_rf_tx_power(wlan_private * priv, struct cmd_ds_command *resp){ struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp; wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_CMD); adapter->txpowerlevel = le16_to_cpu(rtp->currentlevel); lbs_deb_cmd("TX power currently %d\n", adapter->txpowerlevel); lbs_deb_leave(LBS_DEB_CMD); return 0;}static int wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv, struct cmd_ds_command *resp){ struct cmd_ds_802_11_rate_adapt_rateset *rates = &resp->params.rateset; wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_CMD); if (rates->action == CMD_ACT_GET) { adapter->enablehwauto = le16_to_cpu(rates->enablehwauto); adapter->ratebitmap = le16_to_cpu(rates->bitmap); } lbs_deb_leave(LBS_DEB_CMD); return 0;}static int wlan_ret_802_11_data_rate(wlan_private * priv, struct cmd_ds_command *resp){ struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate; wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_CMD); lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate)); /* FIXME: get actual rates FW can do if this command actually returns * all data rates supported. */ adapter->cur_rate = libertas_fw_index_to_data_rate(pdatarate->rates[0]); lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", adapter->cur_rate); lbs_deb_leave(LBS_DEB_CMD); return 0;}static int wlan_ret_802_11_rf_channel(wlan_private * priv, struct cmd_ds_command *resp){ struct cmd_ds_802_11_rf_channel *rfchannel = &resp->params.rfchannel; wlan_adapter *adapter = priv->adapter; u16 action = le16_to_cpu(rfchannel->action); u16 newchannel = le16_to_cpu(rfchannel->currentchannel); lbs_deb_enter(LBS_DEB_CMD); if (action == CMD_OPT_802_11_RF_CHANNEL_GET && adapter->curbssparams.channel != newchannel) { lbs_deb_cmd("channel switch from %d to %d\n", adapter->curbssparams.channel, newchannel); /* Update the channel again */ adapter->curbssparams.channel = newchannel; } lbs_deb_enter(LBS_DEB_CMD); return 0;}static int wlan_ret_802_11_rssi(wlan_private * priv, struct cmd_ds_command *resp){ struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp; wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_CMD); /* store the non average value */ adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR); adapter->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor); adapter->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR); adapter->NF[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgnoisefloor); adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG], adapter->NF[TYPE_BEACON][TYPE_NOAVG]); adapter->RSSI[TYPE_BEACON][TYPE_AVG] = CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE, adapter->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE); lbs_deb_cmd("RSSI: beacon %d, avg %d\n", adapter->RSSI[TYPE_BEACON][TYPE_NOAVG], adapter->RSSI[TYPE_BEACON][TYPE_AVG]); lbs_deb_leave(LBS_DEB_CMD); return 0;}static int wlan_ret_802_11_eeprom_access(wlan_private * priv, struct cmd_ds_command *resp){ wlan_adapter *adapter = priv->adapter; struct wlan_ioctl_regrdwr *pbuf; pbuf = (struct wlan_ioctl_regrdwr *) adapter->prdeeprom; lbs_deb_enter_args(LBS_DEB_CMD, "len %d", le16_to_cpu(resp->params.rdeeprom.bytecount)); if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) { pbuf->NOB = 0; lbs_deb_cmd("EEPROM read length too big\n"); return -1; } pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount); if (pbuf->NOB > 0) { memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value, le16_to_cpu(resp->params.rdeeprom.bytecount)); lbs_deb_hex(LBS_DEB_CMD, "EEPROM", (char *)&pbuf->value, le16_to_cpu(resp->params.rdeeprom.bytecount)); } lbs_deb_leave(LBS_DEB_CMD);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -