/** * This file contains ioctl functions */ #include #include #include #include #include #include #include #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; }