📄 hostap_ioctl.c
字号:
rrq->value = local->manual_retry_count; } else if ((rrq->flags & IW_RETRY_MAX)) { rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; rrq->value = longretry; } else { rrq->flags = IW_RETRY_LIMIT; rrq->value = shortretry; if (shortretry != longretry) rrq->flags |= IW_RETRY_MIN; } } return 0;}/* Note! This TX power controlling is experimental and should not be used in * production use. It just sets raw power register and does not use any kind of * feedback information from the measured TX power (CR58). This is now * commented out to make sure that it is not used by accident. TX power * configuration will be enabled again after proper algorithm using feedback * has been implemented. */#ifdef RAW_TXPOWER_SETTING/* Map HFA386x's CR31 to and from dBm with some sort of ad hoc mapping.. * This version assumes following mapping: * CR31 is 7-bit value with -64 to +63 range. * -64 is mapped into +20dBm and +63 into -43dBm. * This is certainly not an exact mapping for every card, but at least * increasing dBm value should correspond to increasing TX power. */static int prism2_txpower_hfa386x_to_dBm(u16 val){ signed char tmp; if (val > 255) val = 255; tmp = val; tmp >>= 2; return -12 - tmp;}static u16 prism2_txpower_dBm_to_hfa386x(int val){ signed char tmp; if (val > 20) return 128; else if (val < -43) return 127; tmp = val; tmp = -12 - tmp; tmp <<= 2; return (unsigned char) tmp;}#endif /* RAW_TXPOWER_SETTING */static int prism2_ioctl_siwtxpow(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra){ struct hostap_interface *iface; local_info_t *local;#ifdef RAW_TXPOWER_SETTING char *tmp;#endif u16 val; int ret = 0; iface = netdev_priv(dev); local = iface->local; if (rrq->disabled) { if (local->txpower_type != PRISM2_TXPOWER_OFF) { val = 0xff; /* use all standby and sleep modes */ ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, HFA386X_CR_A_D_TEST_MODES2, &val, NULL); printk(KERN_DEBUG "%s: Turning radio off: %s\n", dev->name, ret ? "failed" : "OK"); local->txpower_type = PRISM2_TXPOWER_OFF; } return (ret ? -EOPNOTSUPP : 0); } if (local->txpower_type == PRISM2_TXPOWER_OFF) { val = 0; /* disable all standby and sleep modes */ ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, HFA386X_CR_A_D_TEST_MODES2, &val, NULL); printk(KERN_DEBUG "%s: Turning radio on: %s\n", dev->name, ret ? "failed" : "OK"); local->txpower_type = PRISM2_TXPOWER_UNKNOWN; }#ifdef RAW_TXPOWER_SETTING if (!rrq->fixed && local->txpower_type != PRISM2_TXPOWER_AUTO) { printk(KERN_DEBUG "Setting ALC on\n"); val = HFA384X_TEST_CFG_BIT_ALC; local->func->cmd(dev, HFA384X_CMDCODE_TEST | (HFA384X_TEST_CFG_BITS << 8), 1, &val, NULL); local->txpower_type = PRISM2_TXPOWER_AUTO; return 0; } if (local->txpower_type != PRISM2_TXPOWER_FIXED) { printk(KERN_DEBUG "Setting ALC off\n"); val = HFA384X_TEST_CFG_BIT_ALC; local->func->cmd(dev, HFA384X_CMDCODE_TEST | (HFA384X_TEST_CFG_BITS << 8), 0, &val, NULL); local->txpower_type = PRISM2_TXPOWER_FIXED; } if (rrq->flags == IW_TXPOW_DBM) tmp = "dBm"; else if (rrq->flags == IW_TXPOW_MWATT) tmp = "mW"; else tmp = "UNKNOWN"; printk(KERN_DEBUG "Setting TX power to %d %s\n", rrq->value, tmp); if (rrq->flags != IW_TXPOW_DBM) { printk("SIOCSIWTXPOW with mW is not supported; use dBm\n"); return -EOPNOTSUPP; } local->txpower = rrq->value; val = prism2_txpower_dBm_to_hfa386x(local->txpower); if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, HFA386X_CR_MANUAL_TX_POWER, &val, NULL)) ret = -EOPNOTSUPP;#else /* RAW_TXPOWER_SETTING */ if (rrq->fixed) ret = -EOPNOTSUPP;#endif /* RAW_TXPOWER_SETTING */ return ret;}static int prism2_ioctl_giwtxpow(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra){#ifdef RAW_TXPOWER_SETTING struct hostap_interface *iface; local_info_t *local; u16 resp0; iface = netdev_priv(dev); local = iface->local; rrq->flags = IW_TXPOW_DBM; rrq->disabled = 0; rrq->fixed = 0; if (local->txpower_type == PRISM2_TXPOWER_AUTO) { if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF, HFA386X_CR_MANUAL_TX_POWER, NULL, &resp0) == 0) { rrq->value = prism2_txpower_hfa386x_to_dBm(resp0); } else { /* Could not get real txpower; guess 15 dBm */ rrq->value = 15; } } else if (local->txpower_type == PRISM2_TXPOWER_OFF) { rrq->value = 0; rrq->disabled = 1; } else if (local->txpower_type == PRISM2_TXPOWER_FIXED) { rrq->value = local->txpower; rrq->fixed = 1; } else { printk("SIOCGIWTXPOW - unknown txpower_type=%d\n", local->txpower_type); } return 0;#else /* RAW_TXPOWER_SETTING */ return -EOPNOTSUPP;#endif /* RAW_TXPOWER_SETTING */}#ifndef PRISM2_NO_STATION_MODES/* HostScan request works with and without host_roaming mode. In addition, it * does not break current association. However, it requires newer station * firmware version (>= 1.3.1) than scan request. */static int prism2_request_hostscan(struct net_device *dev, u8 *ssid, u8 ssid_len){ struct hostap_interface *iface; local_info_t *local; struct hfa384x_hostscan_request scan_req; iface = netdev_priv(dev); local = iface->local; memset(&scan_req, 0, sizeof(scan_req)); scan_req.channel_list = cpu_to_le16(local->channel_mask & local->scan_channel_mask); scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS); if (ssid) { if (ssid_len > 32) return -EINVAL; scan_req.target_ssid_len = cpu_to_le16(ssid_len); memcpy(scan_req.target_ssid, ssid, ssid_len); } if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req, sizeof(scan_req))) { printk(KERN_DEBUG "%s: HOSTSCAN failed\n", dev->name); return -EINVAL; } return 0;}static int prism2_request_scan(struct net_device *dev){ struct hostap_interface *iface; local_info_t *local; struct hfa384x_scan_request scan_req; int ret = 0; iface = netdev_priv(dev); local = iface->local; memset(&scan_req, 0, sizeof(scan_req)); scan_req.channel_list = cpu_to_le16(local->channel_mask & local->scan_channel_mask); scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS); /* FIX: * It seems to be enough to set roaming mode for a short moment to * host-based and then setup scanrequest data and return the mode to * firmware-based. * * Master mode would need to drop to Managed mode for a short while * to make scanning work.. Or sweep through the different channels and * use passive scan based on beacons. */ if (!local->host_roaming) hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE, HFA384X_ROAMING_HOST); if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST, &scan_req, sizeof(scan_req))) { printk(KERN_DEBUG "SCANREQUEST failed\n"); ret = -EINVAL; } if (!local->host_roaming) hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE, HFA384X_ROAMING_FIRMWARE); return 0;}#else /* !PRISM2_NO_STATION_MODES */static inline int prism2_request_hostscan(struct net_device *dev, u8 *ssid, u8 ssid_len){ return -EOPNOTSUPP;}static inline int prism2_request_scan(struct net_device *dev){ return -EOPNOTSUPP;}#endif /* !PRISM2_NO_STATION_MODES */static int prism2_ioctl_siwscan(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra){ struct hostap_interface *iface; local_info_t *local; int ret; u8 *ssid = NULL, ssid_len = 0; struct iw_scan_req *req = (struct iw_scan_req *) extra; iface = netdev_priv(dev); local = iface->local; if (data->length < sizeof(struct iw_scan_req)) req = NULL; if (local->iw_mode == IW_MODE_MASTER) { /* In master mode, we just return the results of our local * tables, so we don't need to start anything... * Jean II */ data->length = 0; return 0; } if (!local->dev_enabled) return -ENETDOWN; if (req && data->flags & IW_SCAN_THIS_ESSID) { ssid = req->essid; ssid_len = req->essid_len; if (ssid_len && ((local->iw_mode != IW_MODE_INFRA && local->iw_mode != IW_MODE_ADHOC) || (local->sta_fw_ver < PRISM2_FW_VER(1,3,1)))) return -EOPNOTSUPP; } if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) ret = prism2_request_hostscan(dev, ssid, ssid_len); else ret = prism2_request_scan(dev); if (ret == 0) local->scan_timestamp = jiffies; /* Could inquire F101, F103 or wait for SIOCGIWSCAN and read RID */ return ret;}#ifndef PRISM2_NO_STATION_MODESstatic char * __prism2_translate_scan(local_info_t *local, struct hfa384x_hostscan_result *scan, struct hostap_bss_info *bss, char *current_ev, char *end_buf){ int i, chan; struct iw_event iwe; char *current_val; u16 capabilities; u8 *pos; u8 *ssid, *bssid; size_t ssid_len; char *buf; if (bss) { ssid = bss->ssid; ssid_len = bss->ssid_len; bssid = bss->bssid; } else { ssid = scan->ssid; ssid_len = le16_to_cpu(scan->ssid_len); bssid = scan->bssid; } if (ssid_len > 32) ssid_len = 32; /* First entry *MUST* be the AP MAC address */ memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, bssid, ETH_ALEN); current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); /* Other entries will be displayed in the order we give them */ memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWESSID; iwe.u.data.length = ssid_len; iwe.u.data.flags = 1; current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ssid); memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWMODE; if (bss) { capabilities = bss->capab_info; } else { capabilities = le16_to_cpu(scan->capability); } if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { if (capabilities & WLAN_CAPABILITY_ESS) iwe.u.mode = IW_MODE_MASTER; else iwe.u.mode = IW_MODE_ADHOC; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN); } memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWFREQ; if (scan) { chan = scan->chid; } else if (bss) { chan = bss->chan; } else { chan = 0; } if (chan > 0) { iwe.u.freq.m = freq_list[le16_to_cpu(chan - 1)] * 100000; iwe.u.freq.e = 1; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); } if (scan) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVQUAL; if (local->last_scan_type == PRISM2_HOSTSCAN) { iwe.u.qual.level = le16_to_cpu(scan->sl); iwe.u.qual.noise = le16_to_cpu(scan->anl); } else { iwe.u.qual.level = HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->sl)); iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->anl)); } iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_UPDATED | IW_QUAL_QUAL_INVALID | IW_QUAL_DBM; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); } memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWENCODE; if (capabilities & WLAN_CAPABILITY_PRIVACY) iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ""); /* TODO: add SuppRates into BSS table */ if (scan) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWRATE; current_val = current_ev + IW_EV_LCP_LEN; pos = scan->sup_rates; for (i = 0; i < sizeof(scan->sup_rates); i++) { if (pos[i] == 0) break; /* Bit rate given in 500 kb/s units (+ 0x80) */ iwe.u.bitrate.value = ((pos[i] & 0x7f) * 500000); current_val = iwe_stream_add_value( current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN); } /* Check if we added any event */ if ((current_val - current_ev) > IW_EV_LCP_LEN) current_ev = current_val; } /* TODO: add BeaconInt,resp_rate,atim into BSS table */ buf = kmalloc(MAX_WPA_IE_LEN * 2 + 30, GFP_ATOMIC); if (buf && scan) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; sprintf(buf, "bcn_int=%d", le16_to_cpu(scan->beacon_interval)); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; sprintf(buf, "resp_rate=%d", le16_to_cpu(scan->rate)); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); if (local->last_scan_type == PRISM2_HOSTSCAN && (capabilities & WLAN_CAPABILITY_IBSS)) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; sprintf(buf, "atim=%d", le16_to_cpu(scan->atim)); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); } } kfree(buf); if (bss && bss->wpa_ie_len > 0 && bss->wpa_ie_len <= MAX_WPA_IE_LEN) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVGENIE; iwe.u.data.length = bss->wpa_ie_len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -