X-Git-Url: http://git.openwrt.org/?p=project%2Fluci.git;a=blobdiff_plain;f=contrib%2Fpackage%2Fiwinfo%2Fsrc%2Fiwinfo_nl80211.c;h=21797c13de9b76ee8bc4c28377d20bea88e4f929;hp=7f27e25338063e9bb31bfc71232f58f3cd2c965e;hb=0d3fc50989009ca85c0d39bb043bf1317fa5cf60;hpb=7c8824f0faf082f03037b554a4b57da863661fcb diff --git a/contrib/package/iwinfo/src/iwinfo_nl80211.c b/contrib/package/iwinfo/src/iwinfo_nl80211.c index 7f27e25338..21797c13de 100644 --- a/contrib/package/iwinfo/src/iwinfo_nl80211.c +++ b/contrib/package/iwinfo/src/iwinfo_nl80211.c @@ -77,17 +77,7 @@ static int nl80211_init(void) err: - if( nls && nls->nl_sock ) - nl_socket_free(nls->nl_sock); - - if( nls && nls->nl_cache ) - nl_cache_free(nls->nl_cache); - - if( nls ) - free(nls); - - nls = NULL; - + nl80211_close(); return err; } @@ -131,14 +121,14 @@ static int nl80211_msg_response(struct nl_msg *msg, void *arg) static void nl80211_free(struct nl80211_msg_conveyor *cv) { - if( cv && cv->cb ) - nl_cb_put(cv->cb); - - if( cv && cv->msg ) - nlmsg_free(cv->msg); - if( cv ) { + if( cv->cb ) + nl_cb_put(cv->cb); + + if( cv->msg ) + nlmsg_free(cv->msg); + cv->cb = NULL; cv->msg = NULL; } @@ -148,19 +138,21 @@ static struct nl80211_msg_conveyor * nl80211_msg(const char *ifname, int cmd, in { static struct nl80211_msg_conveyor cv; - int ifidx; + int ifidx = -1, phyidx = -1; struct nl_msg *req = NULL; struct nl_cb *cb = NULL; if( nl80211_init() < 0 ) goto err; - if( !strncmp(ifname, "mon.", 4) ) + if( !strncmp(ifname, "radio", 5) ) + phyidx = atoi(&ifname[5]); + else if( !strncmp(ifname, "mon.", 4) ) ifidx = if_nametoindex(&ifname[4]); else ifidx = if_nametoindex(ifname); - if( ifidx < 0 ) + if( (ifidx < 0) && (phyidx < 0) ) return NULL; req = nlmsg_alloc(); @@ -174,7 +166,11 @@ static struct nl80211_msg_conveyor * nl80211_msg(const char *ifname, int cmd, in genlmsg_put(req, 0, 0, genl_family_get_id(nls->nl80211), 0, flags, cmd, 0); - NLA_PUT_U32(req, NL80211_ATTR_IFINDEX, ifidx); + if( ifidx > -1 ) + NLA_PUT_U32(req, NL80211_ATTR_IFINDEX, ifidx); + + if( phyidx > -1 ) + NLA_PUT_U32(req, NL80211_ATTR_WIPHY, phyidx); nlmsg_get(req); @@ -240,13 +236,16 @@ static int nl80211_freq2channel(int freq) return (freq / 5) - 1000; } -static char * nl80211_getval(const char *buf, const char *key) +static char * nl80211_getval(const char *ifname, const char *buf, const char *key) { int i, len; char lkey[64] = { 0 }; const char *ln = buf; static char lval[256] = { 0 }; + int matched_if = ifname ? 0 : 1; + + for( i = 0, len = strlen(buf); i < len; i++ ) { if( !lkey[0] && (buf[i] == ' ' || buf[i] == '\t') ) @@ -260,12 +259,20 @@ static char * nl80211_getval(const char *buf, const char *key) } else if( buf[i] == '\n' ) { - if( lkey[0] && !strcmp(lkey, key) ) + if( lkey[0] ) { memcpy(lval, ln + strlen(lkey) + 1, min(sizeof(lval) - 1, &buf[i] - ln - strlen(lkey) - 1)); - return lval; + if( (ifname != NULL ) && + (!strcmp(lkey, "interface") || !strcmp(lkey, "bss")) ) + { + matched_if = !strcmp(lval, ifname); + } + else if( matched_if && !strcmp(lkey, key) ) + { + return lval; + } } ln = &buf[i+1]; @@ -389,12 +396,114 @@ out: return rv; } +static char * nl80211_phy2ifname(const char *ifname) +{ + int fd, phyidx = 0; + char buffer[64]; + static char nif[IFNAMSIZ] = { 0 }; + + DIR *d; + struct dirent *e; + + if( !strncmp(ifname, "radio", 5) ) + { + phyidx = atoi(&ifname[5]); + + if( (d = opendir("/sys/class/net")) != NULL ) + { + while( (e = readdir(d)) != NULL ) + { + snprintf(buffer, sizeof(buffer), + "/sys/class/net/%s/phy80211/index", e->d_name); + + if( (fd = open(buffer, O_RDONLY)) > 0 ) + { + if( (read(fd, buffer, sizeof(buffer)) > 0) && + (atoi(buffer) == phyidx) ) + { + strncpy(nif, e->d_name, sizeof(nif)); + } + + close(fd); + } + + if( nif[0] ) + break; + } + + closedir(d); + } + } + + return nif[0] ? nif : NULL; +} + +static char * nl80211_add_tempif(const char *ifname) +{ + int phyidx; + char *rv = NULL; + static char nif[IFNAMSIZ] = { 0 }; + struct nl80211_msg_conveyor *req, *res; + + req = nl80211_msg(ifname, NL80211_CMD_NEW_INTERFACE, 0); + if( req ) + { + snprintf(nif, sizeof(nif), "tmp.%s", ifname); + + NLA_PUT_STRING(req->msg, NL80211_ATTR_IFNAME, nif); + NLA_PUT_U32(req->msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_STATION); + + res = nl80211_send(req); + if( res ) + { + rv = nif; + nl80211_free(res); + } + + nla_put_failure: + nl80211_free(req); + } + + return rv; +} + +static void nl80211_del_tempif(const char *ifname) +{ + struct nl80211_msg_conveyor *req, *res; + + req = nl80211_msg(ifname, NL80211_CMD_DEL_INTERFACE, 0); + if( req ) + { + NLA_PUT_STRING(req->msg, NL80211_ATTR_IFNAME, ifname); + + nl80211_free(nl80211_send(req)); + + nla_put_failure: + nl80211_free(req); + } +} + int nl80211_probe(const char *ifname) { return !!nl80211_ifname2phy(ifname); } +void nl80211_close(void) +{ + if( nls ) + { + if( nls->nl_sock ) + nl_socket_free(nls->nl_sock); + + if( nls->nl_cache ) + nl_cache_free(nls->nl_cache); + + free(nls); + nls = NULL; + } +} + int nl80211_get_mode(const char *ifname, char *buf) { return wext_get_mode(ifname, buf); @@ -409,7 +518,7 @@ int nl80211_get_ssid(const char *ifname, char *buf) return 0; } else if( (ssid = nl80211_hostapd_info(ifname)) && - (ssid = nl80211_getval(ssid, "ssid")) ) + (ssid = nl80211_getval(ifname, ssid, "ssid")) ) { memcpy(buf, ssid, strlen(ssid)); return 0; @@ -428,7 +537,7 @@ int nl80211_get_bssid(const char *ifname, char *buf) return 0; } else if( (bssid = nl80211_hostapd_info(ifname)) && - (bssid = nl80211_getval(bssid, "bssid")) ) + (bssid = nl80211_getval(ifname, bssid, "bssid")) ) { mac[0] = strtol(&bssid[0], NULL, 16); mac[1] = strtol(&bssid[3], NULL, 16); @@ -670,10 +779,9 @@ int nl80211_get_encryption(const char *ifname, char *buf) struct iwinfo_crypto_entry *c = (struct iwinfo_crypto_entry *)buf; /* Hostapd */ - if( (res = nl80211_hostapd_info(ifname)) && - nl80211_getval(res, "interface") ) + if( (res = nl80211_hostapd_info(ifname)) ) { - if( (val = nl80211_getval(res, "auth_algs")) && (val > 0) ) + if( (val = nl80211_getval(ifname, res, "auth_algs")) && (val > 0) ) { c->auth_suites |= IWINFO_KMGMT_NONE; @@ -699,7 +807,7 @@ int nl80211_get_encryption(const char *ifname, char *buf) { snprintf(k, sizeof(k), "wep_key%d", i); - if( (val = nl80211_getval(res, k)) ) + if( (val = nl80211_getval(ifname, res, k)) ) { if( (strlen(val) == 5) || (strlen(val) == 10) ) c->pair_ciphers |= IWINFO_CIPHER_WEP40; @@ -715,11 +823,11 @@ int nl80211_get_encryption(const char *ifname, char *buf) } - if( (val = nl80211_getval(res, "wpa")) != NULL ) + if( (val = nl80211_getval(ifname, res, "wpa")) != NULL ) c->wpa_version = atoi(val); - val = nl80211_getval(res, "wpa_key_mgmt"); + val = nl80211_getval(ifname, res, "wpa_key_mgmt"); if( !val || strstr(val, "PSK") ) c->auth_suites |= IWINFO_KMGMT_PSK; @@ -731,7 +839,7 @@ int nl80211_get_encryption(const char *ifname, char *buf) c->auth_suites |= IWINFO_KMGMT_NONE; - if( (val = nl80211_getval(res, "wpa_pairwise")) != NULL ) + if( (val = nl80211_getval(ifname, res, "wpa_pairwise")) != NULL ) { if( strstr(val, "TKIP") ) c->pair_ciphers |= IWINFO_CIPHER_TKIP; @@ -752,7 +860,7 @@ int nl80211_get_encryption(const char *ifname, char *buf) /* WPA supplicant */ else if( (res = nl80211_wpasupp_info(ifname, "STATUS")) && - (val = nl80211_getval(res, "pairwise_cipher")) ) + (val = nl80211_getval(NULL, res, "pairwise_cipher")) ) { /* WEP */ if( strstr(val, "WEP") ) @@ -789,7 +897,7 @@ int nl80211_get_encryption(const char *ifname, char *buf) c->pair_ciphers |= IWINFO_CIPHER_WEP104; - if( (val = nl80211_getval(res, "group_cipher")) ) + if( (val = nl80211_getval(NULL, res, "group_cipher")) ) { if( strstr(val, "TKIP") ) c->group_ciphers |= IWINFO_CIPHER_TKIP; @@ -808,7 +916,7 @@ int nl80211_get_encryption(const char *ifname, char *buf) } - if( (val = nl80211_getval(res, "key_mgmt")) ) + if( (val = nl80211_getval(NULL, res, "key_mgmt")) ) { if( strstr(val, "WPA2") ) c->wpa_version = 2; @@ -924,7 +1032,7 @@ int nl80211_get_txpwrlist(const char *ifname, char *buf, int *len) }; if( nl80211_get_channel(ifname, &ch_cur) ) - return -1; + ch_cur = 0; req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0); if( req ) @@ -947,7 +1055,7 @@ int nl80211_get_txpwrlist(const char *ifname, char *buf, int *len) ch_cmp = nl80211_freq2channel( nla_get_u32(freqs[NL80211_FREQUENCY_ATTR_FREQ])); - if( (ch_cmp == ch_cur) && + if( (!ch_cur || (ch_cmp == ch_cur)) && freqs[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] ) { dbm_max = (int)(0.01 * nla_get_u32( @@ -1047,6 +1155,24 @@ int nl80211_get_scanlist(const char *ifname, char *buf, int *len) char bssid[18] = { 0 }; char cipher[256] = { 0 }; + /* Got a radioX pseudo interface, find some interface on it or create one */ + if( !strncmp(ifname, "radio", 5) ) + { + /* Reuse existing interface */ + if( (res = nl80211_phy2ifname(ifname)) != NULL ) + { + return nl80211_get_scanlist(res, buf, len); + } + + /* Need to spawn a temporary iface for scanning */ + else if( (res = nl80211_add_tempif(ifname)) != NULL ) + { + count = nl80211_get_scanlist(res, buf, len); + nl80211_del_tempif(res); + return count; + } + } + struct iwinfo_scanlist_entry *e = (struct iwinfo_scanlist_entry *)buf; /* WPA supplicant */ @@ -1129,40 +1255,55 @@ int nl80211_get_scanlist(const char *ifname, char *buf, int *len) { if( (res = nl80211_ifname2phy(ifname)) != NULL ) { - /* - * This is a big ugly hack, just look away. - */ + /* Got a temp interface, don't create yet another one */ + if( !strncmp(ifname, "tmp.", 4) ) + { + sprintf(cmd, "ifconfig %s up 2>/dev/null", ifname); + if( WEXITSTATUS(system(cmd)) ) + return -1; - sprintf(cmd, "ifconfig %s down 2>/dev/null", ifname); - if( WEXITSTATUS(system(cmd)) ) - goto out; + wext_get_scanlist(ifname, buf, len); - sprintf(cmd, "iw phy %s interface add scan.%s " - "type station 2>/dev/null", res, ifname); - if( WEXITSTATUS(system(cmd)) ) - goto out; + sprintf(cmd, "ifconfig %s down 2>/dev/null", ifname); + (void) WEXITSTATUS(system(cmd)); - sprintf(cmd, "ifconfig scan.%s up 2>/dev/null", ifname); - if( WEXITSTATUS(system(cmd)) ) - goto out; + return 0; + } - sprintf(cmd, "scan.%s", ifname); - wext_get_scanlist(cmd, buf, len); + /* Spawn a new scan interface */ + else + { + sprintf(cmd, "ifconfig %s down 2>/dev/null", ifname); + if( WEXITSTATUS(system(cmd)) ) + goto out; - out: - sprintf(cmd, "ifconfig scan.%s down 2>/dev/null", ifname); - (void) WEXITSTATUS(system(cmd)); + sprintf(cmd, "iw phy %s interface add scan.%s " + "type station 2>/dev/null", res, ifname); + if( WEXITSTATUS(system(cmd)) ) + goto out; - sprintf(cmd, "iw dev scan.%s del 2>/dev/null", ifname); - (void) WEXITSTATUS(system(cmd)); + sprintf(cmd, "ifconfig scan.%s up 2>/dev/null", ifname); + if( WEXITSTATUS(system(cmd)) ) + goto out; - sprintf(cmd, "ifconfig %s up 2>/dev/null", ifname); - (void) WEXITSTATUS(system(cmd)); + sprintf(cmd, "scan.%s", ifname); + wext_get_scanlist(cmd, buf, len); - sprintf(cmd, "killall -HUP hostapd 2>/dev/null"); - (void) WEXITSTATUS(system(cmd)); + out: + sprintf(cmd, "ifconfig scan.%s down 2>/dev/null", ifname); + (void) WEXITSTATUS(system(cmd)); - return 0; + sprintf(cmd, "iw dev scan.%s del 2>/dev/null", ifname); + (void) WEXITSTATUS(system(cmd)); + + sprintf(cmd, "ifconfig %s up 2>/dev/null", ifname); + (void) WEXITSTATUS(system(cmd)); + + sprintf(cmd, "killall -HUP hostapd 2>/dev/null"); + (void) WEXITSTATUS(system(cmd)); + + return 0; + } } } @@ -1171,7 +1312,60 @@ int nl80211_get_scanlist(const char *ifname, char *buf, int *len) int nl80211_get_freqlist(const char *ifname, char *buf, int *len) { - return wext_get_freqlist(ifname, buf, len); + int count = 0, bands_remain, freqs_remain; + struct nl80211_msg_conveyor *req, *res; + struct nlattr *bands[NL80211_BAND_ATTR_MAX + 1]; + struct nlattr *freqs[NL80211_FREQUENCY_ATTR_MAX + 1]; + struct nlattr *band, *freq; + struct iwinfo_freqlist_entry *e = (struct iwinfo_freqlist_entry *)buf; + + req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0); + if( req ) + { + res = nl80211_send(req); + if( res ) + { + nla_for_each_nested(band, + res->attr[NL80211_ATTR_WIPHY_BANDS], bands_remain) + { + nla_parse(bands, NL80211_BAND_ATTR_MAX, nla_data(band), + nla_len(band), NULL); + + nla_for_each_nested(freq, + bands[NL80211_BAND_ATTR_FREQS], freqs_remain) + { + nla_parse(freqs, NL80211_FREQUENCY_ATTR_MAX, + nla_data(freq), nla_len(freq), NULL); + + if( !freqs[NL80211_FREQUENCY_ATTR_FREQ] || + freqs[NL80211_FREQUENCY_ATTR_DISABLED] ) + continue; + + e->mhz = nla_get_u32(freqs[NL80211_FREQUENCY_ATTR_FREQ]); + e->channel = nl80211_freq2channel(e->mhz); + + e->restricted = ( + freqs[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] || + freqs[NL80211_FREQUENCY_ATTR_NO_IBSS] || + freqs[NL80211_FREQUENCY_ATTR_RADAR] + ) ? 1 : 0; + + e++; + count++; + } + } + nl80211_free(res); + } + nl80211_free(req); + } + + if( count > 0 ) + { + *len = count * sizeof(struct iwinfo_freqlist_entry); + return 0; + } + + return -1; } int nl80211_get_country(const char *ifname, char *buf) @@ -1215,6 +1409,62 @@ int nl80211_get_countrylist(const char *ifname, char *buf, int *len) return 0; } +int nl80211_get_hwmodelist(const char *ifname, int *buf) +{ + int bands_remain, freqs_remain; + struct nl80211_msg_conveyor *req, *res; + struct nlattr *bands[NL80211_BAND_ATTR_MAX + 1]; + struct nlattr *freqs[NL80211_FREQUENCY_ATTR_MAX + 1]; + struct nlattr *band, *freq; + uint16_t caps = 0; + + req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0); + if( req ) + { + res = nl80211_send(req); + if( res ) + { + nla_for_each_nested(band, + res->attr[NL80211_ATTR_WIPHY_BANDS], bands_remain) + { + nla_parse(bands, NL80211_BAND_ATTR_MAX, nla_data(band), + nla_len(band), NULL); + + if( bands[NL80211_BAND_ATTR_HT_CAPA] ) + caps = nla_get_u16(bands[NL80211_BAND_ATTR_HT_CAPA]); + + /* Treat HT20/HT40 as 11n */ + if( caps & (1 << 1) ) + *buf |= IWINFO_80211_N; + + nla_for_each_nested(freq, + bands[NL80211_BAND_ATTR_FREQS], freqs_remain) + { + nla_parse(freqs, NL80211_FREQUENCY_ATTR_MAX, + nla_data(freq), nla_len(freq), NULL); + + if( !freqs[NL80211_FREQUENCY_ATTR_FREQ] ) + continue; + + if( nla_get_u32(freqs[NL80211_FREQUENCY_ATTR_FREQ]) < 2485 ) + { + *buf |= IWINFO_80211_B; + *buf |= IWINFO_80211_G; + } + else + { + *buf |= IWINFO_80211_A; + } + } + } + nl80211_free(res); + } + nl80211_free(req); + } + + return *buf ? 0 : -1; +} + int nl80211_get_mbssid_support(const char *ifname, int *buf) { /* We assume that multi bssid is always possible */