diff options
Diffstat (limited to 'drivers/net/wireless/libertas/ioctl.c')
-rw-r--r-- | drivers/net/wireless/libertas/ioctl.c | 2500 |
1 files changed, 2500 insertions, 0 deletions
diff --git a/drivers/net/wireless/libertas/ioctl.c b/drivers/net/wireless/libertas/ioctl.c new file mode 100644 index 00000000000..82b39642423 --- /dev/null +++ b/drivers/net/wireless/libertas/ioctl.c @@ -0,0 +1,2500 @@ +/** + * This file contains ioctl functions + */ + +#include <linux/ctype.h> +#include <linux/delay.h> +#include <linux/if.h> +#include <linux/if_arp.h> +#include <linux/wireless.h> + +#include <net/iw_handler.h> +#include <net/ieee80211.h> + +#include "host.h" +#include "radiotap.h" +#include "decl.h" +#include "defs.h" +#include "dev.h" +#include "join.h" +#include "wext.h" + +#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN + \ + IW_ESSID_MAX_SIZE + \ + IW_EV_UINT_LEN + IW_EV_FREQ_LEN + \ + IW_EV_QUAL_LEN + IW_ESSID_MAX_SIZE + \ + IW_EV_PARAM_LEN + 40) /* 40 for WPAIE */ + +#define WAIT_FOR_SCAN_RRESULT_MAX_TIME (10 * HZ) + +static int setrxantenna(wlan_private * priv, int mode) +{ + int ret = 0; + wlan_adapter *adapter = priv->adapter; + + if (mode != RF_ANTENNA_1 && mode != RF_ANTENNA_2 + && mode != RF_ANTENNA_AUTO) { + return -EINVAL; + } + + adapter->rxantennamode = mode; + + lbs_pr_debug(1, "SET RX Antenna mode to 0x%04x\n", adapter->rxantennamode); + + ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna, + cmd_act_set_rx, + cmd_option_waitforrsp, 0, + &adapter->rxantennamode); + return ret; +} + +static int settxantenna(wlan_private * priv, int mode) +{ + int ret = 0; + wlan_adapter *adapter = priv->adapter; + + if ((mode != RF_ANTENNA_1) && (mode != RF_ANTENNA_2) + && (mode != RF_ANTENNA_AUTO)) { + return -EINVAL; + } + + adapter->txantennamode = mode; + + lbs_pr_debug(1, "SET TX Antenna mode to 0x%04x\n", adapter->txantennamode); + + ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna, + cmd_act_set_tx, + cmd_option_waitforrsp, 0, + &adapter->txantennamode); + + return ret; +} + +static int getrxantenna(wlan_private * priv, char *buf) +{ + int ret = 0; + wlan_adapter *adapter = priv->adapter; + + // clear it, so we will know if the value + // returned below is correct or not. + adapter->rxantennamode = 0; + + ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna, + cmd_act_get_rx, + cmd_option_waitforrsp, 0, NULL); + + if (ret) { + LEAVE(); + return ret; + } + + lbs_pr_debug(1, "Get Rx Antenna mode:0x%04x\n", adapter->rxantennamode); + + return sprintf(buf, "0x%04x", adapter->rxantennamode) + 1; +} + +static int gettxantenna(wlan_private * priv, char *buf) +{ + int ret = 0; + wlan_adapter *adapter = priv->adapter; + + // clear it, so we will know if the value + // returned below is correct or not. + adapter->txantennamode = 0; + + ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna, + cmd_act_get_tx, + cmd_option_waitforrsp, 0, NULL); + + if (ret) { + LEAVE(); + return ret; + } + + lbs_pr_debug(1, "Get Tx Antenna mode:0x%04x\n", adapter->txantennamode); + + return sprintf(buf, "0x%04x", adapter->txantennamode) + 1; +} + +static int wlan_set_region(wlan_private * priv, u16 region_code) +{ + int i; + + for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { + // use the region code to search for the index + if (region_code == libertas_region_code_to_index[i]) { + priv->adapter->regiontableindex = (u16) i; + priv->adapter->regioncode = region_code; + break; + } + } + + // if it's unidentified region code + if (i >= MRVDRV_MAX_REGION_CODE) { + lbs_pr_debug(1, "region Code not identified\n"); + LEAVE(); + return -1; + } + + if (libertas_set_regiontable(priv, priv->adapter->regioncode, 0)) { + LEAVE(); + return -EINVAL; + } + + return 0; +} + +/** + * @brief Get/Set Firmware wakeup method + * + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to user data + * @return 0--success, otherwise fail + */ +static int wlan_txcontrol(wlan_private * priv, struct iwreq *wrq) +{ + wlan_adapter *adapter = priv->adapter; + int data; + ENTER(); + + if ((int)wrq->u.data.length == 0) { + if (copy_to_user + (wrq->u.data.pointer, &adapter->pkttxctrl, sizeof(u32))) { + lbs_pr_alert("copy_to_user failed!\n"); + return -EFAULT; + } + } else { + if ((int)wrq->u.data.length > 1) { + lbs_pr_alert("ioctl too many args!\n"); + return -EFAULT; + } + if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { + lbs_pr_alert("Copy from user failed\n"); + return -EFAULT; + } + + adapter->pkttxctrl = (u32) data; + } + + wrq->u.data.length = 1; + + LEAVE(); + return 0; +} + +/** + * @brief Get/Set NULL Package generation interval + * + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to user data + * @return 0--success, otherwise fail + */ +static int wlan_null_pkt_interval(wlan_private * priv, struct iwreq *wrq) +{ + wlan_adapter *adapter = priv->adapter; + int data; + ENTER(); + + if ((int)wrq->u.data.length == 0) { + data = adapter->nullpktinterval; + + if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) { + lbs_pr_alert( "copy_to_user failed!\n"); + return -EFAULT; + } + } else { + if ((int)wrq->u.data.length > 1) { + lbs_pr_alert( "ioctl too many args!\n"); + return -EFAULT; + } + if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { + lbs_pr_debug(1, "Copy from user failed\n"); + return -EFAULT; + } + + adapter->nullpktinterval = data; + } + + wrq->u.data.length = 1; + + LEAVE(); + return 0; +} + +static int wlan_get_rxinfo(wlan_private * priv, struct iwreq *wrq) +{ + wlan_adapter *adapter = priv->adapter; + int data[2]; + ENTER(); + data[0] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG]; + data[1] = adapter->rxpd_rate; + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) { + lbs_pr_debug(1, "Copy to user failed\n"); + return -EFAULT; + } + wrq->u.data.length = 2; + LEAVE(); + return 0; +} + +static int wlan_get_snr(wlan_private * priv, struct iwreq *wrq) +{ + int ret = 0; + wlan_adapter *adapter = priv->adapter; + int data[4]; + + ENTER(); + memset(data, 0, sizeof(data)); + if (wrq->u.data.length) { + if (copy_from_user(data, wrq->u.data.pointer, + min_t(size_t, wrq->u.data.length, 4) * sizeof(int))) + return -EFAULT; + } + if ((wrq->u.data.length == 0) || (data[0] == 0) || (data[0] == 1)) { + if (adapter->connect_status == libertas_connected) { + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_rssi, + 0, + cmd_option_waitforrsp, + 0, NULL); + + if (ret) { + LEAVE(); + return ret; + } + } + } + + if (wrq->u.data.length == 0) { + data[0] = adapter->SNR[TYPE_BEACON][TYPE_NOAVG]; + data[1] = adapter->SNR[TYPE_BEACON][TYPE_AVG]; + data[2] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG]; + data[3] = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 4)) + return -EFAULT; + wrq->u.data.length = 4; + } else if (data[0] == 0) { + data[0] = adapter->SNR[TYPE_BEACON][TYPE_NOAVG]; + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) + return -EFAULT; + wrq->u.data.length = 1; + } else if (data[0] == 1) { + data[0] = adapter->SNR[TYPE_BEACON][TYPE_AVG]; + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) + return -EFAULT; + wrq->u.data.length = 1; + } else if (data[0] == 2) { + data[0] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG]; + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) + return -EFAULT; + wrq->u.data.length = 1; + } else if (data[0] == 3) { + data[0] = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) + return -EFAULT; + wrq->u.data.length = 1; + } else + return -ENOTSUPP; + + LEAVE(); + return 0; +} + +static int wlan_beacon_interval(wlan_private * priv, struct iwreq *wrq) +{ + int data; + wlan_adapter *adapter = priv->adapter; + + if (wrq->u.data.length > 0) { + if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) + return -EFAULT; + + lbs_pr_debug(1, "WLAN SET BEACON INTERVAL: %d\n", data); + if ((data > MRVDRV_MAX_BEACON_INTERVAL) + || (data < MRVDRV_MIN_BEACON_INTERVAL)) + return -ENOTSUPP; + adapter->beaconperiod = data; + } + data = adapter->beaconperiod; + if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) + return -EFAULT; + + wrq->u.data.length = 1; + + return 0; +} + +static int wlan_get_rssi(wlan_private * priv, struct iwreq *wrq) +{ + int ret = 0; + wlan_adapter *adapter = priv->adapter; + int temp; + int data = 0; + int *val; + + ENTER(); + data = SUBCMD_DATA(wrq); + if ((data == 0) || (data == 1)) { + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_rssi, + 0, cmd_option_waitforrsp, + 0, NULL); + if (ret) { + LEAVE(); + return ret; + } + } + + switch (data) { + case 0: + + temp = CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG], + adapter->NF[TYPE_BEACON][TYPE_NOAVG]); + break; + case 1: + temp = CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG], + adapter->NF[TYPE_BEACON][TYPE_AVG]); + break; + case 2: + temp = CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_NOAVG], + adapter->NF[TYPE_RXPD][TYPE_NOAVG]); + break; + case 3: + temp = CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, + adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); + break; + default: + return -ENOTSUPP; + } + val = (int *)wrq->u.name; + *val = temp; + + LEAVE(); + return 0; +} + +static int wlan_get_nf(wlan_private * priv, struct iwreq *wrq) +{ + int ret = 0; + wlan_adapter *adapter = priv->adapter; + int temp; + int data = 0; + int *val; + + data = SUBCMD_DATA(wrq); + if ((data == 0) || (data == 1)) { + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_rssi, + 0, cmd_option_waitforrsp, + 0, NULL); + + if (ret) { + LEAVE(); + return ret; + } + } + + switch (data) { + case 0: + temp = adapter->NF[TYPE_BEACON][TYPE_NOAVG]; + break; + case 1: + temp = adapter->NF[TYPE_BEACON][TYPE_AVG]; + break; + case 2: + temp = adapter->NF[TYPE_RXPD][TYPE_NOAVG]; + break; + case 3: + temp = adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; + break; + default: + return -ENOTSUPP; + } + + temp = CAL_NF(temp); + + lbs_pr_debug(1, "%s: temp = %d\n", __FUNCTION__, temp); + val = (int *)wrq->u.name; + *val = temp; + return 0; +} + +static int wlan_get_txrate_ioctl(wlan_private * priv, struct ifreq *req) +{ + wlan_adapter *adapter = priv->adapter; + int *pdata; + struct iwreq *wrq = (struct iwreq *)req; + int ret = 0; + adapter->txrate = 0; + lbs_pr_debug(1, "wlan_get_txrate_ioctl\n"); + ret = libertas_prepare_and_send_command(priv, cmd_802_11_tx_rate_query, + cmd_act_get, cmd_option_waitforrsp, + 0, NULL); + if (ret) + return ret; + + pdata = (int *)wrq->u.name; + *pdata = (int)adapter->txrate; + return 0; +} + +static int wlan_get_adhoc_status_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + char status[64]; + wlan_adapter *adapter = priv->adapter; + + memset(status, 0, sizeof(status)); + + switch (adapter->inframode) { + case wlan802_11ibss: + if (adapter->connect_status == libertas_connected) { + if (adapter->adhoccreate) + memcpy(&status, "AdhocStarted", sizeof(status)); + else + memcpy(&status, "AdhocJoined", sizeof(status)); + } else { + memcpy(&status, "AdhocIdle", sizeof(status)); + } + break; + case wlan802_11infrastructure: + memcpy(&status, "Inframode", sizeof(status)); + break; + default: + memcpy(&status, "AutoUnknownmode", sizeof(status)); + break; + } + + lbs_pr_debug(1, "status = %s\n", status); + wrq->u.data.length = strlen(status) + 1; + + if (wrq->u.data.pointer) { + if (copy_to_user(wrq->u.data.pointer, + &status, wrq->u.data.length)) + return -EFAULT; + } + + LEAVE(); + return 0; +} + +/** + * @brief Set/Get WPA IE + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_setwpaie_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + wlan_adapter *adapter = priv->adapter; + int ret = 0; + + ENTER(); + + if (wrq->u.data.length) { + if (wrq->u.data.length > sizeof(adapter->wpa_ie)) { + lbs_pr_debug(1, "failed to copy WPA IE, too big \n"); + return -EFAULT; + } + if (copy_from_user(adapter->wpa_ie, wrq->u.data.pointer, + wrq->u.data.length)) { + lbs_pr_debug(1, "failed to copy WPA IE \n"); + return -EFAULT; + } + adapter->wpa_ie_len = wrq->u.data.length; + lbs_pr_debug(1, "Set wpa_ie_len=%d IE=%#x\n", adapter->wpa_ie_len, + adapter->wpa_ie[0]); + lbs_dbg_hex("wpa_ie", adapter->wpa_ie, adapter->wpa_ie_len); + if (adapter->wpa_ie[0] == WPA_IE) + adapter->secinfo.WPAenabled = 1; + else if (adapter->wpa_ie[0] == WPA2_IE) + adapter->secinfo.WPA2enabled = 1; + else { + adapter->secinfo.WPAenabled = 0; + adapter->secinfo.WPA2enabled = 0; + } + } else { + memset(adapter->wpa_ie, 0, sizeof(adapter->wpa_ie)); + adapter->wpa_ie_len = wrq->u.data.length; + lbs_pr_debug(1, "Reset wpa_ie_len=%d IE=%#x\n", + adapter->wpa_ie_len, adapter->wpa_ie[0]); + adapter->secinfo.WPAenabled = 0; + adapter->secinfo.WPA2enabled = 0; + } + + // enable/disable RSN in firmware if WPA is enabled/disabled + // depending on variable adapter->secinfo.WPAenabled is set or not + ret = libertas_prepare_and_send_command(priv, cmd_802_11_enable_rsn, + cmd_act_set, cmd_option_waitforrsp, + 0, NULL); + + LEAVE(); + return ret; +} + +/** + * @brief Set Auto prescan + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to iwreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_subcmd_setprescan_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + int data; + wlan_adapter *adapter = priv->adapter; + int *val; + + data = SUBCMD_DATA(wrq); + lbs_pr_debug(1, "WLAN_SUBCMD_SET_PRESCAN %d\n", data); + adapter->prescan = data; + + val = (int *)wrq->u.name; + *val = data; + return 0; +} + +static int wlan_set_multiple_dtim_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + u32 mdtim; + int idata; + int ret = -EINVAL; + + ENTER(); + + idata = SUBCMD_DATA(wrq); + mdtim = (u32) idata; + if (((mdtim >= MRVDRV_MIN_MULTIPLE_DTIM) + && (mdtim <= MRVDRV_MAX_MULTIPLE_DTIM)) + || (mdtim == MRVDRV_IGNORE_MULTIPLE_DTIM)) { + priv->adapter->multipledtim = mdtim; + ret = 0; + } + if (ret) + lbs_pr_debug(1, "Invalid parameter, multipledtim not changed.\n"); + + LEAVE(); + return ret; +} + +/** + * @brief Set authentication mode + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_setauthalg_ioctl(wlan_private * priv, struct ifreq *req) +{ + int alg; + struct iwreq *wrq = (struct iwreq *)req; + wlan_adapter *adapter = priv->adapter; + + if (wrq->u.data.flags == 0) { + //from iwpriv subcmd + alg = SUBCMD_DATA(wrq); + } else { + //from wpa_supplicant subcmd + if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(alg))) { + lbs_pr_debug(1, "Copy from user failed\n"); + return -EFAULT; + } + } + + lbs_pr_debug(1, "auth alg is %#x\n", alg); + + switch (alg) { + case AUTH_ALG_SHARED_KEY: + adapter->secinfo.authmode = wlan802_11authmodeshared; + break; + case AUTH_ALG_NETWORK_EAP: + adapter->secinfo.authmode = + wlan802_11authmodenetworkEAP; + break; + case AUTH_ALG_OPEN_SYSTEM: + default: + adapter->secinfo.authmode = wlan802_11authmodeopen; + break; + } + return 0; +} + +/** + * @brief Set 802.1x authentication mode + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_set8021xauthalg_ioctl(wlan_private * priv, struct ifreq *req) +{ + int alg; + struct iwreq *wrq = (struct iwreq *)req; + + if (wrq->u.data.flags == 0) { + //from iwpriv subcmd + alg = SUBCMD_DATA(wrq); + } else { + //from wpa_supplicant subcmd + if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(int))) { + lbs_pr_debug(1, "Copy from user failed\n"); + return -EFAULT; + } + } + lbs_pr_debug(1, "802.1x auth alg is %#x\n", alg); + priv->adapter->secinfo.auth1xalg = alg; + return 0; +} + +static int wlan_setencryptionmode_ioctl(wlan_private * priv, struct ifreq *req) +{ + int mode; + struct iwreq *wrq = (struct iwreq *)req; + + ENTER(); + + if (wrq->u.data.flags == 0) { + //from iwpriv subcmd + mode = SUBCMD_DATA(wrq); + } else { + //from wpa_supplicant subcmd + if (copy_from_user(&mode, wrq->u.data.pointer, sizeof(int))) { + lbs_pr_debug(1, "Copy from user failed\n"); + return -EFAULT; + } + } + lbs_pr_debug(1, "encryption mode is %#x\n", mode); + priv->adapter->secinfo.Encryptionmode = mode; + + LEAVE(); + return 0; +} + +static void adjust_mtu(wlan_private * priv) +{ + int mtu_increment = 0; + + if (priv->adapter->linkmode == WLAN_LINKMODE_802_11) + mtu_increment += sizeof(struct ieee80211_hdr_4addr); + + if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) + mtu_increment += max(sizeof(struct tx_radiotap_hdr), + sizeof(struct rx_radiotap_hdr)); + priv->wlan_dev.netdev->mtu = ETH_FRAME_LEN + - sizeof(struct ethhdr) + + mtu_increment; +} + +/** + * @brief Set Link-Layer Layer mode + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_set_linkmode_ioctl(wlan_private * priv, struct ifreq *req) +{ + int mode; + + mode = (int)((struct ifreq *)((u8 *) req + 4))->ifr_data; + + switch (mode) { + case WLAN_LINKMODE_802_3: + priv->adapter->linkmode = mode; + break; + case WLAN_LINKMODE_802_11: + priv->adapter->linkmode = mode; + break; + default: + lbs_pr_info("usb8388-5: invalid link-layer mode (%#x)\n", + mode); + return -EINVAL; + break; + } + lbs_pr_debug(1, "usb8388-5: link-layer mode is %#x\n", mode); + + adjust_mtu(priv); + + return 0; +} + +/** + * @brief Set Radio header mode + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_set_radiomode_ioctl(wlan_private * priv, struct ifreq *req) +{ + int mode; + + mode = (int)((struct ifreq *)((u8 *) req + 4))->ifr_data; + + switch (mode) { + case WLAN_RADIOMODE_NONE: + priv->adapter->radiomode = mode; + break; + case WLAN_RADIOMODE_RADIOTAP: + priv->adapter->radiomode = mode; + break; + default: + lbs_pr_debug(1, "usb8388-5: invalid radio header mode (%#x)\n", + mode); + return -EINVAL; + } + lbs_pr_debug(1, "usb8388-5: radio-header mode is %#x\n", mode); + + adjust_mtu(priv); + return 0; +} + +/** + * @brief Set Debug header mode + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_set_debugmode_ioctl(wlan_private * priv, struct ifreq *req) +{ + priv->adapter->debugmode = (int)((struct ifreq *) + ((u8 *) req + 4))->ifr_data; + return 0; +} + +static int wlan_subcmd_getrxantenna_ioctl(wlan_private * priv, + struct ifreq *req) +{ + int len; + char buf[8]; + struct iwreq *wrq = (struct iwreq *)req; + + lbs_pr_debug(1, "WLAN_SUBCMD_GETRXANTENNA\n"); + len = getrxantenna(priv, buf); + + wrq->u.data.length = len; + if (wrq->u.data.pointer) { + if (copy_to_user(wrq->u.data.pointer, &buf, len)) { + lbs_pr_debug(1, "CopyToUser failed\n"); + return -EFAULT; + } + } + + return 0; +} + +static int wlan_subcmd_gettxantenna_ioctl(wlan_private * priv, + struct ifreq *req) +{ + int len; + char buf[8]; + struct iwreq *wrq = (struct iwreq *)req; + + lbs_pr_debug(1, "WLAN_SUBCMD_GETTXANTENNA\n"); + len = gettxantenna(priv, buf); + + wrq->u.data.length = len; + if (wrq->u.data.pointer) { + if (copy_to_user(wrq->u.data.pointer, &buf, len)) { + lbs_pr_debug(1, "CopyToUser failed\n"); + return -EFAULT; + } + } + return 0; +} + +/** + * @brief Get the MAC TSF value from the firmware + * + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to iwreq structure containing buffer + * space to store a TSF value retrieved from the firmware + * + * @return 0 if successful; IOCTL error code otherwise + */ +static int wlan_get_tsf_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + u64 tsfval; + int ret; + + ret = libertas_prepare_and_send_command(priv, + cmd_get_tsf, + 0, cmd_option_waitforrsp, 0, &tsfval); + + lbs_pr_debug(1, "IOCTL: Get TSF = 0x%016llx\n", tsfval); + + if (ret != 0) { + lbs_pr_debug(1, "IOCTL: Get TSF; command exec failed\n"); + ret = -EFAULT; + } else { + if (copy_to_user(wrq->u.data.pointer, + &tsfval, + min_t(size_t, wrq->u.data.length, + sizeof(tsfval))) != 0) { + + lbs_pr_debug(1, "IOCTL: Get TSF; Copy to user failed\n"); + ret = -EFAULT; + } else { + ret = 0; + } + } + return ret; +} + +/** + * @brief Get/Set adapt rate + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to iwreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_adapt_rateset(wlan_private * priv, struct iwreq *wrq) +{ + int ret; + wlan_adapter *adapter = priv->adapter; + int data[2]; + + memset(data, 0, sizeof(data)); + if (!wrq->u.data.length) { + lbs_pr_debug(1, "Get ADAPT RATE SET\n"); + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_rate_adapt_rateset, + cmd_act_get, + cmd_option_waitforrsp, 0, NULL); + data[0] = adapter->enablehwauto; + data[1] = adapter->ratebitmap; + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) { + lbs_pr_debug(1, "Copy to user failed\n"); + return -EFAULT; + } +#define GET_TWO_INT 2 + wrq->u.data.length = GET_TWO_INT; + } else { + lbs_pr_debug(1, "Set ADAPT RATE SET\n"); + if (wrq->u.data.length > 2) + return -EINVAL; + if (copy_from_user + (data, wrq->u.data.pointer, + sizeof(int) * wrq->u.data.length)) { + lbs_pr_debug(1, "Copy from user failed\n"); + return -EFAULT; + } + + adapter->enablehwauto = data[0]; + adapter->ratebitmap = data[1]; + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_rate_adapt_rateset, + cmd_act_set, + cmd_option_waitforrsp, 0, NULL); + } + return ret; +} + +/** + * @brief Get/Set inactivity timeout + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to iwreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_inactivity_timeout(wlan_private * priv, struct iwreq *wrq) +{ + int ret; + int data = 0; + u16 timeout = 0; + + ENTER(); + if (wrq->u.data.length > 1) + return -ENOTSUPP; + + if (wrq->u.data.length == 0) { + /* Get */ + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_inactivity_timeout, + cmd_act_get, + cmd_option_waitforrsp, 0, + &timeout); + data = timeout; + if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) { + lbs_pr_debug(1, "Copy to user failed\n"); + return -EFAULT; + } + } else { + /* Set */ + if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { + lbs_pr_debug(1, "Copy from user failed\n"); + return -EFAULT; + } + + timeout = data; + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_inactivity_timeout, + cmd_act_set, + cmd_option_waitforrsp, 0, + &timeout); + } + + wrq->u.data.length = 1; + + LEAVE(); + return ret; +} + +static int wlan_do_getlog_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + int ret; + char buf[GETLOG_BUFSIZE - 1]; + wlan_adapter *adapter = priv->adapter; + + lbs_pr_debug(1, " GET STATS\n"); + + ret = libertas_prepare_and_send_command(priv, cmd_802_11_get_log, + 0, cmd_option_waitforrsp, 0, NULL); + + if (ret) { + return ret; + } + + if (wrq->u.data.pointer) { + sprintf(buf, "\n mcasttxframe %u failed %u retry %u " + "multiretry %u framedup %u " + "rtssuccess %u rtsfailure %u ackfailure %u\n" + "rxfrag %u mcastrxframe %u fcserror %u " + "txframe %u wepundecryptable %u ", + adapter->logmsg.mcasttxframe, + adapter->logmsg.failed, + adapter->logmsg.retry, + adapter->logmsg.multiretry, + adapter->logmsg.framedup, + adapter->logmsg.rtssuccess, + adapter->logmsg.rtsfailure, + adapter->logmsg.ackfailure, + adapter->logmsg.rxfrag, + adapter->logmsg.mcastrxframe, + adapter->logmsg.fcserror, + adapter->logmsg.txframe, + adapter->logmsg.wepundecryptable); + wrq->u.data.length = strlen(buf) + 1; + if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) { + lbs_pr_debug(1, "Copy to user failed\n"); + return -EFAULT; + } + } + + return 0; +} + +static int wlan_scan_type_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + u8 buf[12]; + u8 *option[] = { "active", "passive", "get", }; + int i, max_options = (sizeof(option) / sizeof(option[0])); + int ret = 0; + wlan_adapter *adapter = priv->adapter; + + if (priv->adapter->enable11d) { + lbs_pr_debug(1, "11D: Cannot set scantype when 11D enabled\n"); + return -EFAULT; + } + + memset(buf, 0, sizeof(buf)); + + if (copy_from_user(buf, wrq->u.data.pointer, min_t(size_t, sizeof(buf), + wrq->u.data.length))) + return -EFAULT; + + lbs_pr_debug(1, "Scan type Option = %s\n", buf); + + buf[sizeof(buf) - 1] = '\0'; + + for (i = 0; i < max_options; i++) { + if (!strcmp(buf, option[i])) + break; + } + + switch (i) { + case 0: + adapter->scantype = cmd_scan_type_active; + break; + case 1: + adapter->scantype = cmd_scan_type_passive; + break; + case 2: + wrq->u.data.length = strlen(option[adapter->scantype]) + 1; + + if (copy_to_user(wrq->u.data.pointer, + option[adapter->scantype], + wrq->u.data.length)) { + lbs_pr_debug(1, "Copy to user failed\n"); + ret = -EFAULT; + } + + break; + default: + lbs_pr_debug(1, "Invalid Scan type Ioctl Option\n"); + ret = -EINVAL; + break; + } + + return ret; +} + +static int wlan_scan_mode_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + wlan_adapter *adapter = priv->adapter; + u8 buf[12]; + u8 *option[] = { "bss", "ibss", "any", "get" }; + int i, max_options = (sizeof(option) / sizeof(option[0])); + int ret = 0; + + ENTER(); + + memset(buf, 0, sizeof(buf)); + + if (copy_from_user(buf, wrq->u.data.pointer, min_t(size_t, sizeof(buf), + wrq->u.data.length))) { + lbs_pr_debug(1, "Copy from user failed\n"); + return -EFAULT; + } + + lbs_pr_debug(1, "Scan mode Option = %s\n", buf); + + buf[sizeof(buf) - 1] = '\0'; + + for (i = 0; i < max_options; i++) { + if (!strcmp(buf, option[i])) + break; + } + + switch (i) { + + case 0: + adapter->scanmode = cmd_bss_type_bss; + break; + case 1: + adapter->scanmode = cmd_bss_type_ibss; + break; + case 2: + adapter->scanmode = cmd_bss_type_any; + break; + case 3: + + wrq->u.data.length = strlen(option[adapter->scanmode - 1]) + 1; + + lbs_pr_debug(1, "Get Scan mode Option = %s\n", + option[adapter->scanmode - 1]); + + lbs_pr_debug(1, "Scan mode length %d\n", wrq->u.data.length); + + if (copy_to_user(wrq->u.data.pointer, + option[adapter->scanmode - 1], + wrq->u.data.length)) { + lbs_pr_debug(1, "Copy to user failed\n"); + ret = -EFAULT; + } + lbs_pr_debug(1, "GET Scan type Option after copy = %s\n", + (char *)wrq->u.data.pointer); + + break; + + default: + lbs_pr_debug(1, "Invalid Scan mode Ioctl Option\n"); + ret = -EINVAL; + break; + } + + LEAVE(); + return ret; +} + +/** + * @brief Get/Set Adhoc G Rate + * + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to user data + * @return 0--success, otherwise fail + */ +static int wlan_do_set_grate_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + wlan_adapter *adapter = priv->adapter; + int data, data1; + int *val; + + ENTER(); + + data1 = SUBCMD_DATA(wrq); + switch (data1) { + case 0: + adapter->adhoc_grate_enabled = 0; + break; + case 1: + adapter->adhoc_grate_enabled = 1; + break; + case 2: + break; + default: + return -EINVAL; + } + data = adapter->adhoc_grate_enabled; + val = (int *)wrq->u.name; + *val = data; + LEAVE(); + return 0; +} + +static inline int hex2int(char c) +{ + if (c >= '0' && c <= '9') + return (c - '0'); + if (c >= 'a' && c <= 'f') + return (c - 'a' + 10); + if (c >= 'A' && c <= 'F') + return (c - 'A' + 10); + return -1; +} + +/* Convert a string representation of a MAC address ("xx:xx:xx:xx:xx:xx") + into binary format (6 bytes). + + This function expects that each byte is represented with 2 characters + (e.g., 11:2:11:11:11:11 is invalid) + + */ +static char *eth_str2addr(char *ethstr, u8 * addr) +{ + int i, val, val2; + char *pos = ethstr; + + /* get rid of initial blanks */ + while (*pos == ' ' || *pos == '\t') + ++pos; + + for (i = 0; i < 6; i++) { + val = hex2int(*pos++); + if (val < 0) + return NULL; + val2 = hex2int(*pos++); + if (val2 < 0) + return NULL; + addr[i] = (val * 16 + val2) & 0xff; + + if (i < 5 && *pos++ != ':') + return NULL; + } + return pos; +} + +/* this writes xx:xx:xx:xx:xx:xx into ethstr + (ethstr must have space for 18 chars) */ +static int eth_addr2str(u8 * addr, char *ethstr) +{ + int i; + char *pos = ethstr; + + for (i = 0; i < 6; i++) { + sprintf(pos, "%02x", addr[i] & 0xff); + pos += 2; + if (i < 5) + *pos++ = ':'; + } + return 17; +} + +/** + * @brief Add an entry to the BT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_bt_add_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + char ethaddrs_str[18]; + char *pos; + u8 ethaddr[ETH_ALEN]; + + ENTER(); + if (copy_from_user(ethaddrs_str, wrq->u.data.pointer, + sizeof(ethaddrs_str))) + return -EFAULT; + + if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) { + lbs_pr_info("BT_ADD: Invalid MAC address\n"); + return -EINVAL; + } + + lbs_pr_debug(1, "BT: adding %s\n", ethaddrs_str); + LEAVE(); + return (libertas_prepare_and_send_command(priv, cmd_bt_access, + cmd_act_bt_access_add, + cmd_option_waitforrsp, 0, ethaddr)); +} + +/** + * @brief Delete an entry from the BT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_bt_del_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + char ethaddrs_str[18]; + u8 ethaddr[ETH_ALEN]; + char *pos; + + ENTER(); + if (copy_from_user(ethaddrs_str, wrq->u.data.pointer, + sizeof(ethaddrs_str))) + return -EFAULT; + + if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) { + lbs_pr_info("Invalid MAC address\n"); + return -EINVAL; + } + + lbs_pr_debug(1, "BT: deleting %s\n", ethaddrs_str); + + return (libertas_prepare_and_send_command(priv, + cmd_bt_access, + cmd_act_bt_access_del, + cmd_option_waitforrsp, 0, ethaddr)); + LEAVE(); + return 0; +} + +/** + * @brief Reset all entries from the BT table + * @param priv A pointer to wlan_private structure + * @return 0 --success, otherwise fail + */ +static int wlan_bt_reset_ioctl(wlan_private * priv) +{ + ENTER(); + + lbs_pr_alert( "BT: resetting\n"); + + return (libertas_prepare_and_send_command(priv, + cmd_bt_access, + cmd_act_bt_access_reset, + cmd_option_waitforrsp, 0, NULL)); + + LEAVE(); + return 0; +} + +/** + * @brief List an entry from the BT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_bt_list_ioctl(wlan_private * priv, struct ifreq *req) +{ + int pos; + char *addr1; + struct iwreq *wrq = (struct iwreq *)req; + /* used to pass id and store the bt entry returned by the FW */ + union { + int id; + char addr1addr2[2 * ETH_ALEN]; + } param; + static char outstr[64]; + char *pbuf = outstr; + int ret; + + ENTER(); + + if (copy_from_user(outstr, wrq->u.data.pointer, sizeof(outstr))) { + lbs_pr_debug(1, "Copy from user failed\n"); + return -1; + } + param.id = simple_strtoul(outstr, NULL, 10); + pos = sprintf(pbuf, "%d: ", param.id); + pbuf += pos; + + ret = libertas_prepare_and_send_command(priv, cmd_bt_access, + cmd_act_bt_access_list, + cmd_option_waitforrsp, 0, + (char *)¶m); + + if (ret == 0) { + addr1 = param.addr1addr2; + + pos = sprintf(pbuf, "ignoring traffic from "); + pbuf += pos; + pos = eth_addr2str(addr1, pbuf); + pbuf += pos; + } else { + sprintf(pbuf, "(null)"); + pbuf += pos; + } + + wrq->u.data.length = strlen(outstr); + if (copy_to_user(wrq->u.data.pointer, (char *)outstr, + wrq->u.data.length)) { + lbs_pr_debug(1, "BT_LIST: Copy to user failed!\n"); + return -EFAULT; + } + + LEAVE(); + return 0; +} + +/** + * @brief Find the next parameter in an input string + * @param ptr A pointer to the input parameter string + * @return A pointer to the next parameter, or 0 if no parameters left. + */ +static char * next_param(char * ptr) +{ + if (!ptr) return NULL; + while (*ptr == ' ' || *ptr == '\t') ++ptr; + return (*ptr == '\0') ? NULL : ptr; +} + +/** + * @brief Add an entry to the FWT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_fwt_add_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + char in_str[128]; + static struct cmd_ds_fwt_access fwt_access; + char *ptr; + + ENTER(); + if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) + return -EFAULT; + + if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) { + lbs_pr_alert( "FWT_ADD: Invalid MAC address 1\n"); + return -EINVAL; + } + + if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) { + lbs_pr_alert( "FWT_ADD: Invalid MAC address 2\n"); + return -EINVAL; + } + + if ((ptr = next_param(ptr))) + fwt_access.metric = + cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); + else + fwt_access.metric = FWT_DEFAULT_METRIC; + + if ((ptr = next_param(ptr))) + fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10); + else + fwt_access.dir = FWT_DEFAULT_DIR; + + if ((ptr = next_param(ptr))) + fwt_access.ssn = + cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); + else + fwt_access.ssn = FWT_DEFAULT_SSN; + + if ((ptr = next_param(ptr))) + fwt_access.dsn = + cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); + else + fwt_access.dsn = FWT_DEFAULT_DSN; + + if ((ptr = next_param(ptr))) + fwt_access.hopcount = simple_strtoul(ptr, &ptr, 10); + else + fwt_access.hopcount = FWT_DEFAULT_HOPCOUNT; + + if ((ptr = next_param(ptr))) + fwt_access.ttl = simple_strtoul(ptr, &ptr, 10); + else + fwt_access.ttl = FWT_DEFAULT_TTL; + + if ((ptr = next_param(ptr))) + fwt_access.expiration = + cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); + else + fwt_access.expiration = FWT_DEFAULT_EXPIRATION; + + if ((ptr = next_param(ptr))) + fwt_access.sleepmode = (u8)simple_strtoul(ptr, &ptr, 10); + else + fwt_access.sleepmode = FWT_DEFAULT_SLEEPMODE; + + if ((ptr = next_param(ptr))) + fwt_access.snr = + cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); + else + fwt_access.snr = FWT_DEFAULT_SNR; + +#ifdef DEBUG + { + char ethaddr1_str[18], ethaddr2_str[18]; + eth_addr2str(fwt_access.da, ethaddr1_str); + eth_addr2str(fwt_access.ra, ethaddr2_str); + lbs_pr_debug(1, "FWT_ADD: adding (da:%s,%i,ra:%s)\n", ethaddr1_str, + fwt_access.dir, ethaddr2_str); + lbs_pr_debug(1, "FWT_ADD: ssn:%u dsn:%u met:%u hop:%u ttl:%u exp:%u slp:%u snr:%u\n", + fwt_access.ssn, fwt_access.dsn, fwt_access.metric, + fwt_access.hopcount, fwt_access.ttl, fwt_access.expiration, + fwt_access.sleepmode, fwt_access.snr); + } +#endif + + LEAVE(); + return (libertas_prepare_and_send_command(priv, cmd_fwt_access, + cmd_act_fwt_access_add, + cmd_option_waitforrsp, 0, + (void *)&fwt_access)); +} + +/** + * @brief Delete an entry from the FWT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_fwt_del_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + char in_str[64]; + static struct cmd_ds_fwt_access fwt_access; + char *ptr; + + ENTER(); + if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) + return -EFAULT; + + if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) { + lbs_pr_alert( "FWT_DEL: Invalid MAC address 1\n"); + return -EINVAL; + } + + if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) { + lbs_pr_alert( "FWT_DEL: Invalid MAC address 2\n"); + return -EINVAL; + } + + if ((ptr = next_param(ptr))) + fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10); + else + fwt_access.dir = FWT_DEFAULT_DIR; + +#ifdef DEBUG + { + char ethaddr1_str[18], ethaddr2_str[18]; + lbs_pr_debug(1, "FWT_DEL: line is %s\n", in_str); + eth_addr2str(fwt_access.da, ethaddr1_str); + eth_addr2str(fwt_access.ra, ethaddr2_str); + lbs_pr_debug(1, "FWT_DEL: removing (da:%s,ra:%s,dir:%d)\n", ethaddr1_str, + ethaddr2_str, fwt_access.dir); + } +#endif + + LEAVE(); + return (libertas_prepare_and_send_command(priv, + cmd_fwt_access, + cmd_act_fwt_access_del, + cmd_option_waitforrsp, 0, + (void *)&fwt_access)); +} + + +/** + * @brief Print route parameters + * @param fwt_access struct cmd_ds_fwt_access with route info + * @param buf destination buffer for route info + */ +static void print_route(struct cmd_ds_fwt_access fwt_access, char *buf) +{ + buf += sprintf(buf, " "); + buf += eth_addr2str(fwt_access.da, buf); + buf += sprintf(buf, " "); + buf += eth_addr2str(fwt_access.ra, buf); + buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.metric)); + buf += sprintf(buf, " %u", fwt_access.dir); + buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.ssn)); + buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.dsn)); + buf += sprintf(buf, " %u", fwt_access.hopcount); + buf += sprintf(buf, " %u", fwt_access.ttl); + buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.expiration)); + buf += sprintf(buf, " %u", fwt_access.sleepmode); + buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.snr)); +} + +/** + * @brief Lookup an entry in the FWT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_fwt_lookup_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + char in_str[64]; + char *ptr; + static struct cmd_ds_fwt_access fwt_access; + static char out_str[128]; + int ret; + + ENTER(); + if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) + return -EFAULT; + + if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) { + lbs_pr_alert( "FWT_LOOKUP: Invalid MAC address\n"); + return -EINVAL; + } + +#ifdef DEBUG + { + char ethaddr1_str[18]; + lbs_pr_debug(1, "FWT_LOOKUP: line is %s\n", in_str); + eth_addr2str(fwt_access.da, ethaddr1_str); + lbs_pr_debug(1, "FWT_LOOKUP: looking for (da:%s)\n", ethaddr1_str); + } +#endif + + ret = libertas_prepare_and_send_command(priv, + cmd_fwt_access, + cmd_act_fwt_access_lookup, + cmd_option_waitforrsp, 0, + (void *)&fwt_access); + + if (ret == 0) + print_route(fwt_access, out_str); + else + sprintf(out_str, "(null)"); + + wrq->u.data.length = strlen(out_str); + if (copy_to_user(wrq->u.data.pointer, (char *)out_str, + wrq->u.data.length)) { + lbs_pr_debug(1, "FWT_LOOKUP: Copy to user failed!\n"); + return -EFAULT; + } + + LEAVE(); + return 0; +} + +/** + * @brief Reset all entries from the FWT table + * @param priv A pointer to wlan_private structure + * @return 0 --success, otherwise fail + */ +static int wlan_fwt_reset_ioctl(wlan_private * priv) +{ + lbs_pr_debug(1, "FWT: resetting\n"); + + return (libertas_prepare_and_send_command(priv, + cmd_fwt_access, + cmd_act_fwt_access_reset, + cmd_option_waitforrsp, 0, NULL)); +} + +/** + * @brief List an entry from the FWT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_fwt_list_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + char in_str[8]; + static struct cmd_ds_fwt_access fwt_access; + char *ptr = in_str; + static char out_str[128]; + char *pbuf = out_str; + int ret; + + ENTER(); + if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) + return -EFAULT; + + fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); + +#ifdef DEBUG + { + lbs_pr_debug(1, "FWT_LIST: line is %s\n", in_str); + lbs_pr_debug(1, "FWT_LIST: listing id:%i\n", le32_to_cpu(fwt_access.id)); + } +#endif + + ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, + cmd_act_fwt_access_list, + cmd_option_waitforrsp, 0, (void *)&fwt_access); + + if (ret == 0) + print_route(fwt_access, pbuf); + else + pbuf += sprintf(pbuf, " (null)"); + + wrq->u.data.length = strlen(out_str); + if (copy_to_user(wrq->u.data.pointer, (char *)out_str, + wrq->u.data.length)) { + lbs_pr_debug(1, "FWT_LIST: Copy to user failed!\n"); + return -EFAULT; + } + + LEAVE(); + return 0; +} + +/** + * @brief List an entry from the FRT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_fwt_list_route_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + char in_str[64]; + static struct cmd_ds_fwt_access fwt_access; + char *ptr = in_str; + static char out_str[128]; + char *pbuf = out_str; + int ret; + + ENTER(); + if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) + return -EFAULT; + + fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); + +#ifdef DEBUG + { + lbs_pr_debug(1, "FWT_LIST_ROUTE: line is %s\n", in_str); + lbs_pr_debug(1, "FWT_LIST_ROUTE: listing id:%i\n", le32_to_cpu(fwt_access.id)); + } +#endif + + ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, + cmd_act_fwt_access_list_route, + cmd_option_waitforrsp, 0, (void *)&fwt_access); + + if (ret == 0) { + pbuf += sprintf(pbuf, " "); + pbuf += eth_addr2str(fwt_access.da, pbuf); + pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.metric)); + pbuf += sprintf(pbuf, " %u", fwt_access.dir); + /* note that the firmware returns the nid in the id field */ + pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.id)); + pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.ssn)); + pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.dsn)); + pbuf += sprintf(pbuf, " hop %u", fwt_access.hopcount); + pbuf += sprintf(pbuf, " ttl %u", fwt_access.ttl); + pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.expiration)); + } else + pbuf += sprintf(pbuf, " (null)"); + + wrq->u.data.length = strlen(out_str); + if (copy_to_user(wrq->u.data.pointer, (char *)out_str, + wrq->u.data.length)) { + lbs_pr_debug(1, "FWT_LIST_ROUTE: Copy to user failed!\n"); + return -EFAULT; + } + + LEAVE(); + return 0; +} + +/** + * @brief List an entry from the FNT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_fwt_list_neighbor_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + char in_str[8]; + static struct cmd_ds_fwt_access fwt_access; + char *ptr = in_str; + static char out_str[128]; + char *pbuf = out_str; + int ret; + + ENTER(); + if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) + return -EFAULT; + + memset(&fwt_access, 0, sizeof(fwt_access)); + fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); + +#ifdef DEBUG + { + lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: line is %s\n", in_str); + lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: listing id:%i\n", le32_to_cpu(fwt_access.id)); + } +#endif + + ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, + cmd_act_fwt_access_list_neighbor, + cmd_option_waitforrsp, 0, + (void *)&fwt_access); + + if (ret == 0) { + pbuf += sprintf(pbuf, " ra "); + pbuf += eth_addr2str(fwt_access.ra, pbuf); + pbuf += sprintf(pbuf, " slp %u", fwt_access.sleepmode); + pbuf += sprintf(pbuf, " snr %u", le32_to_cpu(fwt_access.snr)); + pbuf += sprintf(pbuf, " ref %u", le32_to_cpu(fwt_access.references)); + } else + pbuf += sprintf(pbuf, " (null)"); + + wrq->u.data.length = strlen(out_str); + if (copy_to_user(wrq->u.data.pointer, (char *)out_str, + wrq->u.data.length)) { + lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: Copy to user failed!\n"); + return -EFAULT; + } + + LEAVE(); + return 0; +} + +/** + * @brief Cleans up the route (FRT) and neighbor (FNT) tables + * (Garbage Collection) + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_fwt_cleanup_ioctl(wlan_private * priv, struct ifreq *req) +{ + static struct cmd_ds_fwt_access fwt_access; + int ret; + + ENTER(); + + lbs_pr_debug(1, "FWT: cleaning up\n"); + + memset(&fwt_access, 0, sizeof(fwt_access)); + + ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, + cmd_act_fwt_access_cleanup, + cmd_option_waitforrsp, 0, + (void *)&fwt_access); + + if (ret == 0) + req->ifr_data = (char *)(le32_to_cpu(fwt_access.references)); + else + return -EFAULT; + + LEAVE(); + return 0; +} + +/** + * @brief Gets firmware internal time (debug purposes) + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_fwt_time_ioctl(wlan_private * priv, struct ifreq *req) +{ + static struct cmd_ds_fwt_access fwt_access; + int ret; + + ENTER(); + + lbs_pr_debug(1, "FWT: getting time\n"); + + memset(&fwt_access, 0, sizeof(fwt_access)); + + ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, + cmd_act_fwt_access_time, + cmd_option_waitforrsp, 0, + (void *)&fwt_access); + + if (ret == 0) + req->ifr_data = (char *)(le32_to_cpu(fwt_access.references)); + else + return -EFAULT; + + LEAVE(); + return 0; +} + +/** + * @brief Gets mesh ttl from firmware + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_mesh_get_ttl_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct cmd_ds_mesh_access mesh_access; + int ret; + + ENTER(); + + memset(&mesh_access, 0, sizeof(mesh_access)); + + ret = libertas_prepare_and_send_command(priv, cmd_mesh_access, + cmd_act_mesh_get_ttl, + cmd_option_waitforrsp, 0, + (void *)&mesh_access); + + if (ret == 0) { + req->ifr_data = (char *)(le32_to_cpu(mesh_access.data[0])); + } + else + return -EFAULT; + + LEAVE(); + return 0; +} + +/** + * @brief Gets mesh ttl from firmware + * @param priv A pointer to wlan_private structure + * @param ttl New ttl value + * @return 0 --success, otherwise fail + */ +static int wlan_mesh_set_ttl_ioctl(wlan_private * priv, int ttl) +{ + struct cmd_ds_mesh_access mesh_access; + int ret; + + ENTER(); + + if( (ttl > 0xff) || (ttl < 0) ) + return -EINVAL; + + memset(&mesh_access, 0, sizeof(mesh_access)); + mesh_access.data[0] = ttl; + + ret = libertas_prepare_and_send_command(priv, cmd_mesh_access, + cmd_act_mesh_set_ttl, + cmd_option_waitforrsp, 0, + (void *)&mesh_access); + + if (ret != 0) + ret = -EFAULT; + + LEAVE(); + return ret; +} + +/** + * @brief ioctl function - entry point + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @param cmd command + * @return 0--success, otherwise fail + */ +int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd) +{ + int subcmd = 0; + int idata = 0; + int *pdata; + int ret = 0; + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + struct iwreq *wrq = (struct iwreq *)req; + + ENTER(); + + lbs_pr_debug(1, "libertas_do_ioctl: ioctl cmd = 0x%x\n", cmd); + switch (cmd) { + case WLANSCAN_TYPE: + lbs_pr_debug(1, "Scan type Ioctl\n"); + ret = wlan_scan_type_ioctl(priv, wrq); + break; + + case WLAN_SETNONE_GETNONE: /* set WPA mode on/off ioctl #20 */ + switch (wrq->u.data.flags) { + case WLANDEAUTH: + lbs_pr_debug(1, "Deauth\n"); + libertas_send_deauth(priv); + break; + + case WLANADHOCSTOP: + lbs_pr_debug(1, "Adhoc stop\n"); + ret = libertas_do_adhocstop_ioctl(priv); + break; + + case WLANRADIOON: + wlan_radio_ioctl(priv, 1); + break; + + case WLANRADIOOFF: + wlan_radio_ioctl(priv, 0); + break; + case WLANWLANIDLEON: + libertas_idle_on(priv); + break; + case WLANWLANIDLEOFF: + libertas_idle_off(priv); + break; + case WLAN_SUBCMD_BT_RESET: /* bt_reset */ + wlan_bt_reset_ioctl(priv); + break; + case WLAN_SUBCMD_FWT_RESET: /* fwt_reset */ + wlan_fwt_reset_ioctl(priv); + break; + } /* End of switch */ + break; + + case WLANSETWPAIE: + ret = wlan_setwpaie_ioctl(priv, req); + break; + case WLAN_SETINT_GETINT: + /* The first 4 bytes of req->ifr_data is sub-ioctl number + * after 4 bytes sits the payload. + */ + subcmd = (int)req->ifr_data; //from iwpriv subcmd + switch (subcmd) { + case WLANNF: + ret = wlan_get_nf(priv, wrq); + break; + case WLANRSSI: + ret = wlan_get_rssi(priv, wrq); + break; + case WLANENABLE11D: + ret = libertas_cmd_enable_11d(priv, wrq); + break; + case WLANADHOCGRATE: + ret = wlan_do_set_grate_ioctl(priv, wrq); + break; + case WLAN_SUBCMD_SET_PRESCAN: + ret = wlan_subcmd_setprescan_ioctl(priv, wrq); + break; + } + break; + + case WLAN_SETONEINT_GETONEINT: + switch (wrq->u.data.flags) { + case WLAN_BEACON_INTERVAL: + ret = wlan_beacon_interval(priv, wrq); + break; + + case WLAN_LISTENINTRVL: + if (!wrq->u.data.length) { + int data; + lbs_pr_debug(1, "Get locallisteninterval value\n"); +#define GET_ONE_INT 1 + data = adapter->locallisteninterval; + if (copy_to_user(wrq->u.data.pointer, + &data, sizeof(int))) { + lbs_pr_debug(1, "Copy to user failed\n"); + return -EFAULT; + } + + wrq->u.data.length = GET_ONE_INT; + } else { + int data; + if (copy_from_user + (&data, wrq->u.data.pointer, sizeof(int))) { + lbs_pr_debug(1, "Copy from user failed\n"); + return -EFAULT; + } + + lbs_pr_debug(1, "Set locallisteninterval = %d\n", + data); +#define MAX_U16_VAL 65535 + if (data > MAX_U16_VAL) { + lbs_pr_debug(1, "Exceeds U16 value\n"); + return -EINVAL; + } + adapter->locallisteninterval = data; + } + break; + case WLAN_TXCONTROL: + ret = wlan_txcontrol(priv, wrq); //adds for txcontrol ioctl + break; + + case WLAN_NULLPKTINTERVAL: + ret = wlan_null_pkt_interval(priv, wrq); + break; + + default: + ret = -EOPNOTSUPP; + break; + } + break; + + case WLAN_SETONEINT_GETNONE: + /* The first 4 bytes of req->ifr_data is sub-ioctl number + * after 4 bytes sits the payload. + */ + subcmd = wrq->u.data.flags; //from wpa_supplicant subcmd + + if (!subcmd) + subcmd = (int)req->ifr_data; //from iwpriv subcmd + + switch (subcmd) { + case WLAN_SUBCMD_SETRXANTENNA: /* SETRXANTENNA */ + idata = SUBCMD_DATA(wrq); + ret = setrxantenna(priv, idata); + break; + case WLAN_SUBCMD_SETTXANTENNA: /* SETTXANTENNA */ + idata = SUBCMD_DATA(wrq); + ret = settxantenna(priv, idata); + break; + case WLAN_SET_ATIM_WINDOW: + adapter->atimwindow = SUBCMD_DATA(wrq); + adapter->atimwindow = min_t(__u16, adapter->atimwindow, 50); + break; + case WLANSETBCNAVG: + adapter->bcn_avg_factor = SUBCMD_DATA(wrq); + if (adapter->bcn_avg_factor == 0) + adapter->bcn_avg_factor = + DEFAULT_BCN_AVG_FACTOR; + if (adapter->bcn_avg_factor > DEFAULT_BCN_AVG_FACTOR) + adapter->bcn_avg_factor = + DEFAULT_BCN_AVG_FACTOR; + break; + case WLANSETDATAAVG: + adapter->data_avg_factor = SUBCMD_DATA(wrq); + if (adapter->data_avg_factor == 0) + adapter->data_avg_factor = + DEFAULT_DATA_AVG_FACTOR; + if (adapter->data_avg_factor > DEFAULT_DATA_AVG_FACTOR) + adapter->data_avg_factor = + DEFAULT_DATA_AVG_FACTOR; + break; + case WLANSETREGION: + idata = SUBCMD_DATA(wrq); + ret = wlan_set_region(priv, (u16) idata); + break; + + case WLAN_SET_LISTEN_INTERVAL: + idata = SUBCMD_DATA(wrq); + adapter->listeninterval = (u16) idata; + break; + + case WLAN_SET_MULTIPLE_DTIM: + ret = wlan_set_multiple_dtim_ioctl(priv, req); + break; + + case WLANSETAUTHALG: + ret = wlan_setauthalg_ioctl(priv, req); + break; + + case WLANSET8021XAUTHALG: + ret = wlan_set8021xauthalg_ioctl(priv, req); + break; + + case WLANSETENCRYPTIONMODE: + ret = wlan_setencryptionmode_ioctl(priv, req); + break; + + case WLAN_SET_LINKMODE: + ret = wlan_set_linkmode_ioctl(priv, req); + break; + + case WLAN_SET_RADIOMODE: + ret = wlan_set_radiomode_ioctl(priv, req); + break; + + case WLAN_SET_DEBUGMODE: + ret = wlan_set_debugmode_ioctl(priv, req); + break; + + case WLAN_SUBCMD_MESH_SET_TTL: + idata = SUBCMD_DATA(wrq); + ret = wlan_mesh_set_ttl_ioctl(priv, idata); + break; + + default: + ret = -EOPNOTSUPP; + break; + } + + break; + + case WLAN_SETNONE_GETTWELVE_CHAR: /* Get Antenna settings */ + /* + * We've not used IW_PRIV_TYPE_FIXED so sub-ioctl number is + * in flags of iwreq structure, otherwise it will be in + * mode member of iwreq structure. + */ + switch ((int)wrq->u.data.flags) { + case WLAN_SUBCMD_GETRXANTENNA: /* Get Rx Antenna */ + ret = wlan_subcmd_getrxantenna_ioctl(priv, req); + break; + + case WLAN_SUBCMD_GETTXANTENNA: /* Get Tx Antenna */ + ret = wlan_subcmd_gettxantenna_ioctl(priv, req); + break; + + case WLAN_GET_TSF: + ret = wlan_get_tsf_ioctl(priv, wrq); + break; + } + break; + + case WLAN_SET128CHAR_GET128CHAR: + switch ((int)wrq->u.data.flags) { + + case WLANSCAN_MODE: + lbs_pr_debug(1, "Scan mode Ioctl\n"); + ret = wlan_scan_mode_ioctl(priv, wrq); + break; + + case WLAN_GET_ADHOC_STATUS: + ret = wlan_get_adhoc_status_ioctl(priv, wrq); + break; + case WLAN_SUBCMD_BT_ADD: + ret = wlan_bt_add_ioctl(priv, req); + break; + case WLAN_SUBCMD_BT_DEL: + ret = wlan_bt_del_ioctl(priv, req); + break; + case WLAN_SUBCMD_BT_LIST: + ret = wlan_bt_list_ioctl(priv, req); + break; + case WLAN_SUBCMD_FWT_ADD: + ret = wlan_fwt_add_ioctl(priv, req); + break; + case WLAN_SUBCMD_FWT_DEL: + ret = wlan_fwt_del_ioctl(priv, req); + break; + case WLAN_SUBCMD_FWT_LOOKUP: + ret = wlan_fwt_lookup_ioctl(priv, req); + break; + case WLAN_SUBCMD_FWT_LIST_NEIGHBOR: + ret = wlan_fwt_list_neighbor_ioctl(priv, req); + break; + case WLAN_SUBCMD_FWT_LIST: + ret = wlan_fwt_list_ioctl(priv, req); + break; + case WLAN_SUBCMD_FWT_LIST_ROUTE: + ret = wlan_fwt_list_route_ioctl(priv, req); + break; + } + break; + + case WLAN_SETNONE_GETONEINT: + switch ((int)req->ifr_data) { + case WLANGETBCNAVG: + pdata = (int *)wrq->u.name; + *pdata = (int)adapter->bcn_avg_factor; + break; + + case WLANGETREGION: + pdata = (int *)wrq->u.name; + *pdata = (int)adapter->regioncode; + break; + + case WLAN_GET_LISTEN_INTERVAL: + pdata = (int *)wrq->u.name; + *pdata = (int)adapter->listeninterval; + break; + + case WLAN_GET_LINKMODE: + req->ifr_data = (char *)((u32) adapter->linkmode); + break; + + case WLAN_GET_RADIOMODE: + req->ifr_data = (char *)((u32) adapter->radiomode); + break; + + case WLAN_GET_DEBUGMODE: + req->ifr_data = (char *)((u32) adapter->debugmode); + break; + + case WLAN_GET_MULTIPLE_DTIM: + pdata = (int *)wrq->u.name; + *pdata = (int)adapter->multipledtim; + break; + case WLAN_GET_TX_RATE: + ret = wlan_get_txrate_ioctl(priv, req); + break; + case WLAN_SUBCMD_FWT_CLEANUP: /* fwt_cleanup */ + ret = wlan_fwt_cleanup_ioctl(priv, req); + break; + + case WLAN_SUBCMD_FWT_TIME: /* fwt_time */ + ret = wlan_fwt_time_ioctl(priv, req); + break; + + case WLAN_SUBCMD_MESH_GET_TTL: + ret = wlan_mesh_get_ttl_ioctl(priv, req); + break; + + default: + ret = -EOPNOTSUPP; + + } + + break; + + case WLANGETLOG: + ret = wlan_do_getlog_ioctl(priv, wrq); + break; + + case WLAN_SET_GET_SIXTEEN_INT: + switch ((int)wrq->u.data.flags) { + case WLAN_TPCCFG: + { + int data[5]; + struct cmd_ds_802_11_tpc_cfg cfg; + memset(&cfg, 0, sizeof(cfg)); + if ((wrq->u.data.length > 1) + && (wrq->u.data.length != 5)) + return -1; + + if (wrq->u.data.length == 0) { + cfg.action = + cpu_to_le16 + (cmd_act_get); + } else { + if (copy_from_user + (data, wrq->u.data.pointer, + sizeof(int) * 5)) { + lbs_pr_debug(1, + "Copy from user failed\n"); + return -EFAULT; + } + + cfg.action = + cpu_to_le16 + (cmd_act_set); + cfg.enable = data[0]; + cfg.usesnr = data[1]; + cfg.P0 = data[2]; + cfg.P1 = data[3]; + cfg.P2 = data[4]; + } + + ret = + libertas_prepare_and_send_command(priv, + cmd_802_11_tpc_cfg, + 0, + cmd_option_waitforrsp, + 0, (void *)&cfg); + + data[0] = cfg.enable; + data[1] = cfg.usesnr; + data[2] = cfg.P0; + data[3] = cfg.P1; + data[4] = cfg.P2; + if (copy_to_user + (wrq->u.data.pointer, data, + sizeof(int) * 5)) { + lbs_pr_debug(1, "Copy to user failed\n"); + return -EFAULT; + } + + wrq->u.data.length = 5; + } + break; + + case WLAN_POWERCFG: + { + int data[4]; + struct cmd_ds_802_11_pwr_cfg cfg; + memset(&cfg, 0, sizeof(cfg)); + if ((wrq->u.data.length > 1) + && (wrq->u.data.length != 4)) + return -1; + if (wrq->u.data.length == 0) { + cfg.action = + cpu_to_le16 + (cmd_act_get); + } else { + if (copy_from_user + (data, wrq->u.data.pointer, + sizeof(int) * 4)) { + lbs_pr_debug(1, + "Copy from user failed\n"); + return -EFAULT; + } + + cfg.action = + cpu_to_le16 + (cmd_act_set); + cfg.enable = data[0]; + cfg.PA_P0 = data[1]; + cfg.PA_P1 = data[2]; + cfg.PA_P2 = data[3]; + } + ret = + libertas_prepare_and_send_command(priv, + cmd_802_11_pwr_cfg, + 0, + cmd_option_waitforrsp, + 0, (void *)&cfg); + data[0] = cfg.enable; + data[1] = cfg.PA_P0; + data[2] = cfg.PA_P1; + data[3] = cfg.PA_P2; + if (copy_to_user + (wrq->u.data.pointer, data, + sizeof(int) * 4)) { + lbs_pr_debug(1, "Copy to user failed\n"); + return -EFAULT; + } + + wrq->u.data.length = 4; + } + break; + case WLAN_AUTO_FREQ_SET: + { + int data[3]; + struct cmd_ds_802_11_afc afc; + memset(&afc, 0, sizeof(afc)); + if (wrq->u.data.length != 3) + return -1; + if (copy_from_user + (data, wrq->u.data.pointer, + sizeof(int) * 3)) { + lbs_pr_debug(1, "Copy from user failed\n"); + return -EFAULT; + } + afc.afc_auto = data[0]; + + if (afc.afc_auto != 0) { + afc.threshold = data[1]; + afc.period = data[2]; + } else { + afc.timing_offset = data[1]; + afc.carrier_offset = data[2]; + } + ret = + libertas_prepare_and_send_command(priv, + cmd_802_11_set_afc, + 0, + cmd_option_waitforrsp, + 0, (void *)&afc); + } + break; + case WLAN_AUTO_FREQ_GET: + { + int data[3]; + struct cmd_ds_802_11_afc afc; + memset(&afc, 0, sizeof(afc)); + ret = + libertas_prepare_and_send_command(priv, + cmd_802_11_get_afc, + 0, + cmd_option_waitforrsp, + 0, (void *)&afc); + data[0] = afc.afc_auto; + data[1] = afc.timing_offset; + data[2] = afc.carrier_offset; + if (copy_to_user + (wrq->u.data.pointer, data, + sizeof(int) * 3)) { + lbs_pr_debug(1, "Copy to user failed\n"); + return -EFAULT; + } + + wrq->u.data.length = 3; + } + break; + case WLAN_SCANPROBES: + { + int data; + if (wrq->u.data.length > 0) { + if (copy_from_user + (&data, wrq->u.data.pointer, + sizeof(int))) { + lbs_pr_debug(1, + "Copy from user failed\n"); + return -EFAULT; + } + + adapter->scanprobes = data; + } else { + data = adapter->scanprobes; + if (copy_to_user + (wrq->u.data.pointer, &data, + sizeof(int))) { + lbs_pr_debug(1, + "Copy to user failed\n"); + return -EFAULT; + } + } + wrq->u.data.length = 1; + } + break; + case WLAN_LED_GPIO_CTRL: + { + int i; + int data[16]; + + struct cmd_ds_802_11_led_ctrl ctrl; + struct mrvlietypes_ledgpio *gpio = + (struct mrvlietypes_ledgpio *) ctrl.data; + + memset(&ctrl, 0, sizeof(ctrl)); + if (wrq->u.data.length > MAX_LEDS * 2) + return -ENOTSUPP; + if ((wrq->u.data.length % 2) != 0) + return -ENOTSUPP; + if (wrq->u.data.length == 0) { + ctrl.action = + cpu_to_le16 + (cmd_act_get); + } else { + if (copy_from_user + (data, wrq->u.data.pointer, + sizeof(int) * + wrq->u.data.length)) { + lbs_pr_debug(1, + "Copy from user failed\n"); + return -EFAULT; + } + + ctrl.action = + cpu_to_le16 + (cmd_act_set); + ctrl.numled = cpu_to_le16(0); + gpio->header.type = + cpu_to_le16(TLV_TYPE_LED_GPIO); + gpio->header.len = wrq->u.data.length; + for (i = 0; i < wrq->u.data.length; + i += 2) { + gpio->ledpin[i / 2].led = + data[i]; + gpio->ledpin[i / 2].pin = + data[i + 1]; + } + } + ret = + libertas_prepare_and_send_command(priv, + cmd_802_11_led_gpio_ctrl, + 0, + cmd_option_waitforrsp, + 0, (void *)&ctrl); + for (i = 0; i < gpio->header.len; i += 2) { + data[i] = gpio->ledpin[i / 2].led; + data[i + 1] = gpio->ledpin[i / 2].pin; + } + if (copy_to_user(wrq->u.data.pointer, data, + sizeof(int) * + gpio->header.len)) { + lbs_pr_debug(1, "Copy to user failed\n"); + return -EFAULT; + } + + wrq->u.data.length = gpio->header.len; + } + break; + case WLAN_ADAPT_RATESET: + ret = wlan_adapt_rateset(priv, wrq); + break; + case WLAN_INACTIVITY_TIMEOUT: + ret = wlan_inactivity_timeout(priv, wrq); + break; + case WLANSNR: + ret = wlan_get_snr(priv, wrq); + break; + case WLAN_GET_RXINFO: + ret = wlan_get_rxinfo(priv, wrq); + } + break; + + default: + ret = -EINVAL; + break; + } + LEAVE(); + return ret; +} + + |