/** * 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 wlan_set_region(wlan_private * priv, u16 region_code) { int i; int ret = 0; 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_deb_ioctl("region Code not identified\n"); ret = -1; goto done; } if (libertas_set_regiontable(priv, priv->adapter->regioncode, 0)) { ret = -EINVAL; } done: lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret); return ret; } 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]; int ret; lbs_deb_enter(LBS_DEB_IOCTL); 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_deb_ioctl("BT: adding %s\n", ethaddrs_str); ret = libertas_prepare_and_send_command(priv, cmd_bt_access, cmd_act_bt_access_add, cmd_option_waitforrsp, 0, ethaddr); lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret); return ret; } /** * @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; lbs_deb_enter(LBS_DEB_IOCTL); 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_deb_ioctl("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)); lbs_deb_leave(LBS_DEB_IOCTL); 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) { lbs_deb_enter(LBS_DEB_IOCTL); 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)); lbs_deb_leave(LBS_DEB_IOCTL); 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; lbs_deb_enter(LBS_DEB_IOCTL); if (copy_from_user(outstr, wrq->u.data.pointer, sizeof(outstr))) { lbs_deb_ioctl("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, "BT includes node "); 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_deb_ioctl("BT_LIST: Copy to user failed!\n"); return -EFAULT; } lbs_deb_leave(LBS_DEB_IOCTL); return 0 ; } /** * @brief Sets inverted state of blacklist (non-zero if inverted) * @param priv A pointer to wlan_private structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail */ static int wlan_bt_set_invert_ioctl(wlan_private * priv, struct ifreq *req) { int ret; struct iwreq *wrq = (struct iwreq *)req; union { int id; char addr1addr2[2 * ETH_ALEN]; } param; lbs_deb_enter(LBS_DEB_IOCTL); param.id = SUBCMD_DATA(wrq) ; ret = libertas_prepare_and_send_command(priv, cmd_bt_access, cmd_act_bt_access_set_invert, cmd_option_waitforrsp, 0, (char *)¶m); if (ret != 0) return -EFAULT; lbs_deb_leave(LBS_DEB_IOCTL); return 0; } /** * @brief Gets inverted state of blacklist (non-zero if inverted) * @param priv A pointer to wlan_private structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail */ static int wlan_bt_get_invert_ioctl(wlan_private * priv, struct ifreq *req) { int ret; union { int id; char addr1addr2[2 * ETH_ALEN]; } param; lbs_deb_enter(LBS_DEB_IOCTL); ret = libertas_prepare_and_send_command(priv, cmd_bt_access, cmd_act_bt_access_get_invert, cmd_option_waitforrsp, 0, (char *)¶m); if (ret == 0) req->ifr_data = (char *)(le32_to_cpu(param.id)); else return -EFAULT; lbs_deb_leave(LBS_DEB_IOCTL); 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; int ret; lbs_deb_enter(LBS_DEB_IOCTL); 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.rate = (u8) simple_strtoul(ptr, &ptr, 10); else fwt_access.rate = FWT_DEFAULT_RATE; 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_deb_ioctl("FWT_ADD: adding (da:%s,%i,ra:%s)\n", ethaddr1_str, fwt_access.dir, ethaddr2_str); lbs_deb_ioctl("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 ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, cmd_act_fwt_access_add, cmd_option_waitforrsp, 0, (void *)&fwt_access); lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret); return ret; } /** * @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; int ret; lbs_deb_enter(LBS_DEB_IOCTL); 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_deb_ioctl("FWT_DEL: line is %s\n", in_str); eth_addr2str(fwt_access.da, ethaddr1_str); eth_addr2str(fwt_access.ra, ethaddr2_str); lbs_deb_ioctl("FWT_DEL: removing (da:%s,ra:%s,dir:%d)\n", ethaddr1_str, ethaddr2_str, fwt_access.dir); } #endif ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, cmd_act_fwt_access_del, cmd_option_waitforrsp, 0, (void *)&fwt_access); lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret); return ret; } /** * @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", fwt_access.valid); buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.metric)); buf += sprintf(buf, " %u", fwt_access.dir); buf += sprintf(buf, " %u", fwt_access.rate); 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)); buf += eth_addr2str(fwt_access.prec, buf); } /** * @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; lbs_deb_enter(LBS_DEB_IOCTL); 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_deb_ioctl("FWT_LOOKUP: line is %s\n", in_str); eth_addr2str(fwt_access.da, ethaddr1_str); lbs_deb_ioctl("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_deb_ioctl("FWT_LOOKUP: Copy to user failed!\n"); return -EFAULT; } lbs_deb_leave(LBS_DEB_IOCTL); 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_deb_ioctl("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 = 0; lbs_deb_enter(LBS_DEB_IOCTL); if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) { ret = -EFAULT; goto out; } fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); #ifdef DEBUG { lbs_deb_ioctl("FWT_LIST: line is %s\n", in_str); lbs_deb_ioctl("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_deb_ioctl("FWT_LIST: Copy to user failed!\n"); ret = -EFAULT; goto out; } ret = 0; out: lbs_deb_leave(LBS_DEB_IOCTL); return ret; } /** * @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; lbs_deb_enter(LBS_DEB_IOCTL); 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_deb_ioctl("FWT_LIST_ROUTE: line is %s\n", in_str); lbs_deb_ioctl("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) { 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_deb_ioctl("FWT_LIST_ROUTE: Copy to user failed!\n"); return -EFAULT; } lbs_deb_leave(LBS_DEB_IOCTL); 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; lbs_deb_enter(LBS_DEB_IOCTL); 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_deb_ioctl("FWT_LIST_NEIGHBOR: line is %s\n", in_str); lbs_deb_ioctl("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_deb_ioctl("FWT_LIST_NEIGHBOR: Copy to user failed!\n"); return -EFAULT; } lbs_deb_leave(LBS_DEB_IOCTL); 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) { struct iwreq *wrq = (struct iwreq *)req; static struct cmd_ds_fwt_access fwt_access; int ret; lbs_deb_enter(LBS_DEB_IOCTL); lbs_deb_ioctl("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) wrq->u.param.value = le32_to_cpu(fwt_access.references); else return -EFAULT; lbs_deb_leave(LBS_DEB_IOCTL); 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) { struct iwreq *wrq = (struct iwreq *)req; static struct cmd_ds_fwt_access fwt_access; int ret; lbs_deb_enter(LBS_DEB_IOCTL); lbs_deb_ioctl("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) wrq->u.param.value = le32_to_cpu(fwt_access.references); else return -EFAULT; lbs_deb_leave(LBS_DEB_IOCTL); 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 iwreq *wrq = (struct iwreq *)req; struct cmd_ds_mesh_access mesh_access; int ret; lbs_deb_enter(LBS_DEB_IOCTL); 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) wrq->u.param.value = le32_to_cpu(mesh_access.data[0]); else return -EFAULT; lbs_deb_leave(LBS_DEB_IOCTL); 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; lbs_deb_enter(LBS_DEB_IOCTL); 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; lbs_deb_leave(LBS_DEB_IOCTL); 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; lbs_deb_enter(LBS_DEB_IOCTL); lbs_deb_ioctl("libertas_do_ioctl: ioctl cmd = 0x%x\n", cmd); switch (cmd) { case WLAN_SETNONE_GETNONE: /* set WPA mode on/off ioctl #20 */ switch (wrq->u.data.flags) { 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 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; if (!subcmd) subcmd = (int)wrq->u.param.value; switch (subcmd) { case WLANSETREGION: idata = SUBCMD_DATA(wrq); ret = wlan_set_region(priv, (u16) idata); break; case WLAN_SUBCMD_MESH_SET_TTL: idata = SUBCMD_DATA(wrq); ret = wlan_mesh_set_ttl_ioctl(priv, idata); break; case WLAN_SUBCMD_BT_SET_INVERT: ret = wlan_bt_set_invert_ioctl(priv, req); break ; default: ret = -EOPNOTSUPP; break; } break; case WLAN_SET128CHAR_GET128CHAR: switch ((int)wrq->u.data.flags) { 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 (wrq->u.param.value) { case WLANGETREGION: pdata = (int *)wrq->u.name; *pdata = (int)adapter->regioncode; 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; case WLAN_SUBCMD_BT_GET_INVERT: ret = wlan_bt_get_invert_ioctl(priv, req); break ; default: ret = -EOPNOTSUPP; } break; case WLAN_SET_GET_SIXTEEN_INT: switch ((int)wrq->u.data.flags) { 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_deb_ioctl( "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_deb_ioctl("Copy to user failed\n"); return -EFAULT; } wrq->u.data.length = gpio->header.len; } break; } break; default: ret = -EINVAL; break; } lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret); return ret; }