📄 ieee80211_wireless.c
字号:
vap->iv_bss->ni_txpower = 2 * rrq->value; ic->ic_newtxpowlimit = 2 * rrq->value; ic->ic_flags |= IEEE80211_F_TXPOW_FIXED; } else return -EINVAL; } else { /* * No channel set yet */ if (ic->ic_txpowlimit/2 >= rrq->value) { vap->iv_bss->ni_txpower = 2 * rrq->value; ic->ic_newtxpowlimit = 2 * rrq->value; ic->ic_flags |= IEEE80211_F_TXPOW_FIXED; } else return -EINVAL; } } else { if (!fixed) /* no change */ return 0; ic->ic_flags &= ~IEEE80211_F_TXPOW_FIXED; }done: return IS_UP(ic->ic_dev) ? ic->ic_reset(ic->ic_dev) : 0;}static intieee80211_ioctl_giwtxpow(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra){ struct ieee80211vap *vap = dev->priv; struct ieee80211com *ic = vap->iv_ic; rrq->value = vap->iv_bss->ni_txpower / 2; rrq->fixed = (ic->ic_flags & IEEE80211_F_TXPOW_FIXED) != 0; rrq->disabled = (rrq->fixed && rrq->value == 0); rrq->flags = IW_TXPOW_DBM; return 0;}struct waplistreq { /* XXX: not the right place for declaration? */ struct ieee80211vap *vap; struct sockaddr addr[IW_MAX_AP]; struct iw_quality qual[IW_MAX_AP]; int i;};static voidwaplist_cb(void *arg, const struct ieee80211_scan_entry *se){ struct waplistreq *req = arg; int i = req->i; if (i >= IW_MAX_AP) return; req->addr[i].sa_family = ARPHRD_ETHER; if (req->vap->iv_opmode == IEEE80211_M_HOSTAP) IEEE80211_ADDR_COPY(req->addr[i].sa_data, se->se_macaddr); else IEEE80211_ADDR_COPY(req->addr[i].sa_data, se->se_bssid); set_quality(&req->qual[i], se->se_rssi); req->i = i + 1;}static intieee80211_ioctl_iwaplist(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra){ struct ieee80211vap *vap = dev->priv; struct ieee80211com *ic = vap->iv_ic; struct waplistreq req; /* XXX off stack */ req.vap = vap; req.i = 0; ieee80211_scan_iterate(ic, waplist_cb, &req); data->length = req.i; memcpy(extra, &req.addr, req.i * sizeof(req.addr[0])); data->flags = 1; /* signal quality present (sort of) */ memcpy(extra + req.i * sizeof(req.addr[0]), &req.qual, req.i * sizeof(req.qual[0])); return 0;}#ifdef SIOCGIWSCANstatic intieee80211_ioctl_siwscan(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra){ struct ieee80211vap *vap = dev->priv; /* * XXX don't permit a scan to be started unless we * know the device is ready. For the moment this means * the device is marked up as this is the required to * initialize the hardware. It would be better to permit * scanning prior to being up but that'll require some * changes to the infrastructure. */ if (!IS_UP(vap->iv_dev)) return -EINVAL; /* XXX */ /* XXX always manual... */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: active scan request\n", __func__); preempt_scan(dev, 100, 100);#if WIRELESS_EXT > 17 if (data && (data->flags & IW_SCAN_THIS_ESSID)) { struct iw_scan_req req; struct ieee80211_scan_ssid ssid; int copyLength; IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: SCAN_THIS_ESSID requested\n", __func__); if (data->length > sizeof req) { copyLength = sizeof req; } else { copyLength = data->length; } memset(&req, 0, sizeof req); if (copy_from_user(&req, data->pointer, copyLength)) return -EFAULT; memcpy(&ssid.ssid, req.essid, sizeof ssid.ssid); ssid.len = req.essid_len; IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: requesting scan of essid '%s'\n", __func__, ssid.ssid); (void) ieee80211_start_scan(vap, IEEE80211_SCAN_ACTIVE | IEEE80211_SCAN_NOPICK | IEEE80211_SCAN_ONCE, IEEE80211_SCAN_FOREVER, 1, &ssid); return 0; }#endif (void) ieee80211_start_scan(vap, IEEE80211_SCAN_ACTIVE | IEEE80211_SCAN_NOPICK | IEEE80211_SCAN_ONCE, IEEE80211_SCAN_FOREVER, /* XXX use ioctl params */ vap->iv_des_nssid, vap->iv_des_ssid); return 0;}#if WIRELESS_EXT > 14/* * Encode a WPA or RSN information element as a custom * element using the hostap format. */static u_intencode_ie(void *buf, size_t bufsize, const u_int8_t *ie, size_t ielen, const char *leader, size_t leader_len){ u_int8_t *p; int i; if (bufsize < leader_len) return 0; p = buf; memcpy(p, leader, leader_len); bufsize -= leader_len; p += leader_len; for (i = 0; i < ielen && bufsize > 2; i++) p += sprintf(p, "%02x", ie[i]); return (i == ielen ? p - (u_int8_t *)buf : 0);}#endif /* WIRELESS_EXT > 14 */struct iwscanreq { /* XXX: right place for this declaration? */ struct ieee80211vap *vap; char *current_ev; char *end_buf; int mode;};static voidgiwscan_cb(void *arg, const struct ieee80211_scan_entry *se){ struct iwscanreq *req = arg; struct ieee80211vap *vap = req->vap; char *current_ev = req->current_ev; char *end_buf = req->end_buf;#if WIRELESS_EXT > 14 char buf[64 * 2 + 30];#endif struct iw_event iwe; char *current_val; int j; if (current_ev >= end_buf) return; /* WPA/!WPA sort criteria */ if ((req->mode != 0) ^ (se->se_wpa_ie != NULL)) return; memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; if (vap->iv_opmode == IEEE80211_M_HOSTAP) IEEE80211_ADDR_COPY(iwe.u.ap_addr.sa_data, se->se_macaddr); else IEEE80211_ADDR_COPY(iwe.u.ap_addr.sa_data, se->se_bssid); current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; if (vap->iv_opmode == IEEE80211_M_HOSTAP) { iwe.u.data.length = vap->iv_des_nssid > 0 ? vap->iv_des_ssid[0].len : 0; current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, vap->iv_des_ssid[0].ssid); } else { iwe.u.data.length = se->se_ssid[1]; current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, (char *) se->se_ssid+2); } if (se->se_capinfo & (IEEE80211_CAPINFO_ESS|IEEE80211_CAPINFO_IBSS)) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWMODE; iwe.u.mode = se->se_capinfo & IEEE80211_CAPINFO_ESS ? IW_MODE_MASTER : 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; iwe.u.freq.m = se->se_chan->ic_freq * 100000; iwe.u.freq.e = 1; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVQUAL; set_quality(&iwe.u.qual, se->se_rssi); current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWENCODE; if (se->se_capinfo & IEEE80211_CAPINFO_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, ""); memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWRATE; current_val = current_ev + IW_EV_LCP_LEN; /* NB: not sorted, does it matter? */ for (j = 0; j < se->se_rates[1]; j++) { int r = se->se_rates[2 + j] & IEEE80211_RATE_VAL; if (r != 0) { iwe.u.bitrate.value = r * (1000000 / 2); current_val = iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN); } } for (j = 0; j < se->se_xrates[1]; j++) { int r = se->se_xrates[2+j] & IEEE80211_RATE_VAL; if (r != 0) { iwe.u.bitrate.value = r * (1000000 / 2); current_val = iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN); } } /* remove fixed header if no rates were added */ if ((current_val - current_ev) > IW_EV_LCP_LEN) current_ev = current_val;#if WIRELESS_EXT > 14 memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; snprintf(buf, sizeof(buf), "bcn_int=%d", se->se_intval); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); if (se->se_rsn_ie != NULL) {#ifdef IWEVGENIE memset(&iwe, 0, sizeof(iwe)); memcpy(buf, se->se_rsn_ie, se->se_rsn_ie[1] + 2); iwe.cmd = IWEVGENIE; iwe.u.data.length = se->se_rsn_ie[1] + 2;#else static const char rsn_leader[] = "rsn_ie="; memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; if (se->se_rsn_ie[0] == IEEE80211_ELEMID_RSN) iwe.u.data.length = encode_ie(buf, sizeof(buf), se->se_rsn_ie, se->se_rsn_ie[1] + 2, rsn_leader, sizeof(rsn_leader) - 1);#endif if (iwe.u.data.length != 0) current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); } if (se->se_wpa_ie != NULL) {#ifdef IWEVGENIE memset(&iwe, 0, sizeof(iwe)); memcpy(buf, se->se_wpa_ie, se->se_wpa_ie[1] + 2); iwe.cmd = IWEVGENIE; iwe.u.data.length = se->se_wpa_ie[1] + 2;#else static const char wpa_leader[] = "wpa_ie="; memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; iwe.u.data.length = encode_ie(buf, sizeof(buf), se->se_wpa_ie, se->se_wpa_ie[1] + 2, wpa_leader, sizeof(wpa_leader) - 1);#endif if (iwe.u.data.length != 0) current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); } if (se->se_wme_ie != NULL) { static const char wme_leader[] = "wme_ie="; memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; iwe.u.data.length = encode_ie(buf, sizeof(buf), se->se_wme_ie, se->se_wme_ie[1] + 2, wme_leader, sizeof(wme_leader) - 1); if (iwe.u.data.length != 0) current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); } if (se->se_ath_ie != NULL) { static const char ath_leader[] = "ath_ie="; memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; iwe.u.data.length = encode_ie(buf, sizeof(buf), se->se_ath_ie, se->se_ath_ie[1] + 2, ath_leader, sizeof(ath_leader) - 1); if (iwe.u.data.length != 0) current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); }#endif /* WIRELESS_EXT > 14 */ req->current_ev = current_ev;}static intieee80211_ioctl_giwscan(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra){ struct ieee80211vap *vap = dev->priv; struct ieee80211com *ic = vap->iv_ic; struct iwscanreq req; req.vap = vap; req.current_ev = extra; req.end_buf = extra + IW_SCAN_MAX_DATA; /* * Do two passes to ensure WPA/non-WPA scan candidates * are sorted to the front. This is a hack to deal with * the wireless extensions capping scan results at * IW_SCAN_MAX_DATA bytes. In densely populated environments * it's easy to overflow this buffer (especially with WPA/RSN * information elements). Note this sorting hack does not * guarantee we won't overflow anyway. */ req.mode = vap->iv_flags & IEEE80211_F_WPA; ieee80211_scan_iterate(ic, giwscan_cb, &req); req.mode = req.mode ? 0 : IEEE80211_F_WPA; ieee80211_scan_iterate(ic, giwscan_cb, &req); data->length = req.current_ev - extra; return 0;}#endif /* SIOCGIWSCAN */static intcipher2cap(int cipher){ switch (cipher) { case IEEE80211_CIPHER_WEP: return IEEE80211_C_WEP; case IEEE80211_CIPHER_AES_OCB: return IEEE80211_C_AES; case IEEE80211_CIPHER_AES_CCM: return IEEE80211_C_AES_CCM; case IEEE80211_CIPHER_CKIP: return IEEE80211_C_CKIP; case IEEE80211_CIPHER_TKIP: return IEEE80211_C_TKIP; } return 0;}#define IEEE80211_MODE_TURBO_STATIC_A IEEE80211_MODE_MAXstatic intieee80211_convert_mode(const char *mode){#define TOUPPER(c) ((((c) > 0x60) && ((c) < 0x7b)) ? ((c) - 0x20) : (c)) static const struct { char *name; int mode; } mappings[] = { /* NB: need to order longest strings first for overlaps */ { "11AST" , IEEE80211_MODE_TURBO_STATIC_A }, { "AUTO" , IEEE80211_MODE_AUTO }, { "11A" , IEEE80211_MODE_11A }, { "11B" , IEEE80211_MODE_11B }, { "11G" , IEEE80211_MODE_11G }, { "FH" , IEEE80211_MODE_FH }, { "0" , IEEE80211_MODE_AUTO }, { "1" , IEEE80211_MODE_11A }, { "2" , IEEE80211_MODE_11B }, { "3" , IEEE80211_MODE_11G }, { "4" , IEEE80211_MODE_FH }, { "5" , IEEE80211_MODE_TURBO_STATIC_A }, { NULL } }; int i, j; const char *cp; for (i = 0; mappings[i].name != NULL; i++) { cp = mappings[i].name; for (j = 0; j < strlen(mode) + 1; j++) { /* convert user-specified string to upper case */ if (TOUPPER(mode[j]) != cp[j]) break; if (cp[j] == '\0') return mappings[i].mode; } } return -1;#undef TOUPPER}static intieee80211_ioctl_setmode(struct net_device *dev, struct iw_request_info *info, struct iw_point *wri, char *extra){ struct ieee80211vap *vap = dev->priv; struct ieee80211com *ic = vap->iv_ic; struct ifreq ifr; char s[6]; /* big enough for ``11adt'' */ int retv, mode, ifr_mode, itr_count; if (ic->ic_media.ifm_cur == NULL) return -EINVAL; if (wri->length > sizeof(s)) /* silently truncate */ wri->length = sizeof(s); if (copy_from_user(s, wri->pointer, wri->length)) return -EINVAL; s[sizeof(s)-1] = '\0'; /* ensure null termination */ mode = ieee80211_convert_mode(s); if (mode < 0) return -EINVAL; if(ieee80211_check_mode_consistency(ic,mode,vap->iv_des_chan)) { /* * error in AP mode. * overwrite channel selection in other modes. */ if (vap->iv_opmode == IEEE80211_M_HOSTAP) return -EINVAL; else vap->iv_des_chan=IEEE80211_CHAN_ANYC; } ifr_mode = mode; memset(&ifr, 0, sizeof(ifr)); ifr.ifr_media = ic->ic_media.ifm_cur->ifm_media &~ IFM_MMASK;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -