2 * iwinfo - Wireless Information Library - NL80211 Backend
4 * Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org>
6 * The iwinfo library is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
10 * The iwinfo library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with the iwinfo library. If not, see http://www.gnu.org/licenses/.
18 * The signal handling code is derived from the official madwifi tools,
19 * wlanconfig.c in particular. The encryption property handling was
20 * inspired by the hostapd madwifi driver.
22 * Parts of this code are derived from the Linux iw utility.
25 #include "iwinfo_nl80211.h"
26 #include "iwinfo_wext.h"
28 #define min(x, y) ((x) < (y)) ? (x) : (y)
30 static struct nl80211_state
*nls
= NULL
;
32 static int nl80211_init(void)
38 nls
= malloc(sizeof(struct nl80211_state
));
44 nls
->nl_sock
= nl_socket_alloc();
50 if( genl_connect(nls
->nl_sock
)) {
55 if( genl_ctrl_alloc_cache(nls
->nl_sock
, &nls
->nl_cache
)) {
60 nls
->nl80211
= genl_ctrl_search_by_name(nls
->nl_cache
, "nl80211");
72 if( nls
&& nls
->nl_sock
)
73 nl_socket_free(nls
->nl_sock
);
75 if( nls
&& nls
->nl_cache
)
76 nl_cache_free(nls
->nl_cache
);
86 static int nl80211_msg_error(struct sockaddr_nl
*nla
,
87 struct nlmsgerr
*err
, void *arg
)
94 static int nl80211_msg_finish(struct nl_msg
*msg
, void *arg
)
101 static int nl80211_msg_ack(struct nl_msg
*msg
, void *arg
)
108 static int nl80211_msg_response(struct nl_msg
*msg
, void *arg
)
110 struct nl80211_msg_conveyor
*cv
= arg
;
115 cv
->hdr
= nlmsg_data(nlmsg_hdr(cv
->msg
));
117 nla_parse(cv
->attr
, NL80211_ATTR_MAX
,
118 genlmsg_attrdata(cv
->hdr
, 0),
119 genlmsg_attrlen(cv
->hdr
, 0), NULL
);
124 static void nl80211_free(struct nl80211_msg_conveyor
*cv
)
133 static struct nl80211_msg_conveyor
* nl80211_msg(const char *ifname
, int cmd
, int flags
)
135 static struct nl80211_msg_conveyor cv
;
138 struct nl_msg
*req
= NULL
;
139 struct nl_cb
*cb
= NULL
;
141 if( nl80211_init() < 0 )
144 if( !strncmp(ifname
, "mon.", 4) )
145 ifidx
= if_nametoindex(&ifname
[4]);
147 ifidx
= if_nametoindex(ifname
);
156 cb
= nl_cb_alloc(NL_CB_DEFAULT
);
160 genlmsg_put(req
, 0, 0, genl_family_get_id(nls
->nl80211
), 0,
163 NLA_PUT_U32(req
, NL80211_ATTR_IFINDEX
, ifidx
);
184 static void nl80211_cb(struct nl80211_msg_conveyor
*cv
,
185 int (*cb
)(struct nl_msg
*, void *), void *arg
)
188 nl_cb_set(cv
->cb
, NL_CB_VALID
, NL_CB_CUSTOM
, cb
, arg
);
191 static struct nl80211_msg_conveyor
* nl80211_send(struct nl80211_msg_conveyor
*cv
)
193 static struct nl80211_msg_conveyor rcv
;
197 nl_cb_set(cv
->cb
, NL_CB_VALID
, NL_CB_CUSTOM
, nl80211_msg_response
, &rcv
);
199 if( nl_send_auto_complete(nls
->nl_sock
, cv
->msg
) < 0 )
202 nl_cb_err(cv
->cb
, NL_CB_CUSTOM
, nl80211_msg_error
, &err
);
203 nl_cb_set(cv
->cb
, NL_CB_FINISH
, NL_CB_CUSTOM
, nl80211_msg_finish
, &err
);
204 nl_cb_set(cv
->cb
, NL_CB_ACK
, NL_CB_CUSTOM
, nl80211_msg_ack
, &err
);
207 nl_recvmsgs(nls
->nl_sock
, cv
->cb
);
218 static int nl80211_freq2channel(int freq
)
224 return (freq
- 2407) / 5;
226 return (freq
/ 5) - 1000;
229 static char * nl80211_getval(const char *buf
, const char *key
)
232 char lkey
[64] = { 0 };
233 const char *ln
= buf
;
234 static char lval
[256] = { 0 };
236 for( i
= 0, len
= strlen(buf
); i
< len
; i
++ )
238 if( !lkey
[0] && (buf
[i
] == ' ' || buf
[i
] == '\t') )
242 else if( !lkey
[0] && (buf
[i
] == '=') )
244 if( (&buf
[i
] - ln
) > 0 )
245 memcpy(lkey
, ln
, min(sizeof(lkey
) - 1, &buf
[i
] - ln
));
247 else if( buf
[i
] == '\n' )
249 if( lkey
[0] && !strcmp(lkey
, key
) )
251 memcpy(lval
, ln
+ strlen(lkey
) + 1,
252 min(sizeof(lval
) - 1, &buf
[i
] - ln
- strlen(lkey
) - 1));
258 memset(lkey
, 0, sizeof(lkey
));
259 memset(lval
, 0, sizeof(lval
));
266 static char * nl80211_ifname2phy(const char *ifname
)
268 static char phy
[32] = { 0 };
269 struct nl80211_msg_conveyor
*req
, *res
;
271 req
= nl80211_msg(ifname
, NL80211_CMD_GET_WIPHY
, 0);
274 res
= nl80211_send(req
);
277 if( res
->attr
[NL80211_ATTR_WIPHY_NAME
] )
279 snprintf(phy
, sizeof(phy
), "%s",
280 nla_get_string(res
->attr
[NL80211_ATTR_WIPHY_NAME
]));
287 return phy
[0] ? phy
: NULL
;
290 static char * nl80211_hostapd_info(const char *ifname
)
293 char path
[32] = { 0 };
294 static char buf
[4096] = { 0 };
297 if( (phy
= nl80211_ifname2phy(ifname
)) != NULL
)
299 snprintf(path
, sizeof(path
), "/var/run/hostapd-%s.conf", phy
);
301 if( (conf
= fopen(path
, "r")) != NULL
)
303 fread(buf
, sizeof(buf
) - 1, 1, conf
);
313 static char * nl80211_wpasupp_info(const char *ifname
, const char *cmd
)
317 size_t remote_length
, local_length
;
318 static char buffer
[1024] = { 0 };
320 struct timeval tv
= { 2, 0 };
321 struct sockaddr_un local
= { 0 };
322 struct sockaddr_un remote
= { 0 };
326 sock
= socket(PF_UNIX
, SOCK_DGRAM
, 0);
330 remote
.sun_family
= AF_UNIX
;
331 remote_length
= sizeof(remote
.sun_family
) + sprintf(remote
.sun_path
,
332 "/var/run/wpa_supplicant-%s/%s", ifname
, ifname
);
334 if( connect(sock
, (struct sockaddr
*) &remote
, remote_length
) )
337 local
.sun_family
= AF_UNIX
;
338 local_length
= sizeof(local
.sun_family
) + sprintf(local
.sun_path
,
339 "/var/run/iwinfo-%s-%d", ifname
, getpid());
341 if( bind(sock
, (struct sockaddr
*) &local
, local_length
) )
344 send(sock
, cmd
, strlen(cmd
), 0);
351 if( select(sock
+ 1, &rfds
, NULL
, NULL
, &tv
) < 0 )
354 if( !FD_ISSET(sock
, &rfds
) )
357 if( (len
= recv(sock
, buffer
, sizeof(buffer
), 0)) <= 0 )
362 if( buffer
[0] != '<' )
370 unlink(local
.sun_path
);
376 int nl80211_probe(const char *ifname
)
378 return !!nl80211_ifname2phy(ifname
);
381 int nl80211_get_mode(const char *ifname
, char *buf
)
383 return wext_get_mode(ifname
, buf
);
386 int nl80211_get_ssid(const char *ifname
, char *buf
)
390 if( !wext_get_ssid(ifname
, buf
) )
394 else if( (ssid
= nl80211_hostapd_info(ifname
)) &&
395 (ssid
= nl80211_getval(ssid
, "ssid")) )
397 memcpy(buf
, ssid
, strlen(ssid
));
404 int nl80211_get_bssid(const char *ifname
, char *buf
)
407 unsigned char mac
[6];
409 if( !wext_get_bssid(ifname
, buf
) )
413 else if( (bssid
= nl80211_hostapd_info(ifname
)) &&
414 (bssid
= nl80211_getval(bssid
, "bssid")) )
416 mac
[0] = strtol(&bssid
[0], NULL
, 16);
417 mac
[1] = strtol(&bssid
[3], NULL
, 16);
418 mac
[2] = strtol(&bssid
[6], NULL
, 16);
419 mac
[3] = strtol(&bssid
[9], NULL
, 16);
420 mac
[4] = strtol(&bssid
[12], NULL
, 16);
421 mac
[5] = strtol(&bssid
[15], NULL
, 16);
423 sprintf(buf
, "%02X:%02X:%02X:%02X:%02X:%02X",
424 mac
[0], mac
[1], mac
[2], mac
[3], mac
[4], mac
[5]);
432 int nl80211_get_channel(const char *ifname
, int *buf
)
434 return wext_get_channel(ifname
, buf
);
437 int nl80211_get_frequency(const char *ifname
, int *buf
)
439 return wext_get_frequency(ifname
, buf
);
442 int nl80211_get_txpower(const char *ifname
, int *buf
)
444 return wext_get_txpower(ifname
, buf
);
448 static int nl80211_get_signal_cb(struct nl_msg
*msg
, void *arg
)
452 struct nl80211_rssi_rate
*rr
= arg
;
454 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
455 struct nlattr
*attr
[NL80211_ATTR_MAX
+ 1];
456 struct nlattr
*sinfo
[NL80211_STA_INFO_MAX
+ 1];
457 struct nlattr
*rinfo
[NL80211_RATE_INFO_MAX
+ 1];
459 static struct nla_policy stats_policy
[NL80211_STA_INFO_MAX
+ 1] = {
460 [NL80211_STA_INFO_INACTIVE_TIME
] = { .type
= NLA_U32
},
461 [NL80211_STA_INFO_RX_BYTES
] = { .type
= NLA_U32
},
462 [NL80211_STA_INFO_TX_BYTES
] = { .type
= NLA_U32
},
463 [NL80211_STA_INFO_RX_PACKETS
] = { .type
= NLA_U32
},
464 [NL80211_STA_INFO_TX_PACKETS
] = { .type
= NLA_U32
},
465 [NL80211_STA_INFO_SIGNAL
] = { .type
= NLA_U8
},
466 [NL80211_STA_INFO_TX_BITRATE
] = { .type
= NLA_NESTED
},
467 [NL80211_STA_INFO_LLID
] = { .type
= NLA_U16
},
468 [NL80211_STA_INFO_PLID
] = { .type
= NLA_U16
},
469 [NL80211_STA_INFO_PLINK_STATE
] = { .type
= NLA_U8
},
472 static struct nla_policy rate_policy
[NL80211_RATE_INFO_MAX
+ 1] = {
473 [NL80211_RATE_INFO_BITRATE
] = { .type
= NLA_U16
},
474 [NL80211_RATE_INFO_MCS
] = { .type
= NLA_U8
},
475 [NL80211_RATE_INFO_40_MHZ_WIDTH
] = { .type
= NLA_FLAG
},
476 [NL80211_RATE_INFO_SHORT_GI
] = { .type
= NLA_FLAG
},
479 nla_parse(attr
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
480 genlmsg_attrlen(gnlh
, 0), NULL
);
482 if( attr
[NL80211_ATTR_STA_INFO
] )
484 if( !nla_parse_nested(sinfo
, NL80211_STA_INFO_MAX
,
485 attr
[NL80211_ATTR_STA_INFO
], stats_policy
) )
487 if( sinfo
[NL80211_STA_INFO_SIGNAL
] )
489 dbm
= nla_get_u8(sinfo
[NL80211_STA_INFO_SIGNAL
]);
490 rr
->rssi
= rr
->rssi
? (int8_t)((rr
->rssi
+ dbm
) / 2) : dbm
;
493 if( sinfo
[NL80211_STA_INFO_TX_BITRATE
] )
495 if( !nla_parse_nested(rinfo
, NL80211_RATE_INFO_MAX
,
496 sinfo
[NL80211_STA_INFO_TX_BITRATE
], rate_policy
) )
498 if( rinfo
[NL80211_RATE_INFO_BITRATE
] )
500 mbit
= nla_get_u16(rinfo
[NL80211_RATE_INFO_BITRATE
]);
502 ? (int16_t)((rr
->rate
+ mbit
) / 2) : mbit
;
512 int nl80211_get_bitrate(const char *ifname
, int *buf
)
514 struct nl80211_rssi_rate rr
;
515 struct nl80211_msg_conveyor
*req
;
517 if( !wext_get_bitrate(ifname
, buf
) )
520 req
= nl80211_msg(ifname
, NL80211_CMD_GET_STATION
, NLM_F_DUMP
);
526 nl80211_cb(req
, nl80211_get_signal_cb
, &rr
);
532 *buf
= (rr
.rate
* 100);
540 int nl80211_get_signal(const char *ifname
, int *buf
)
542 struct nl80211_rssi_rate rr
;
543 struct nl80211_msg_conveyor
*req
;
545 if( !wext_get_signal(ifname
, buf
) )
548 req
= nl80211_msg(ifname
, NL80211_CMD_GET_STATION
, NLM_F_DUMP
);
554 nl80211_cb(req
, nl80211_get_signal_cb
, &rr
);
568 int nl80211_get_noise(const char *ifname
, int *buf
)
570 struct nl80211_msg_conveyor
*req
, *res
;
571 struct nlattr
*si
[NL80211_SURVEY_INFO_MAX
+ 1];
573 static struct nla_policy sp
[NL80211_SURVEY_INFO_MAX
+ 1] = {
574 [NL80211_SURVEY_INFO_FREQUENCY
] = { .type
= NLA_U32
},
575 [NL80211_SURVEY_INFO_NOISE
] = { .type
= NLA_U8
},
578 req
= nl80211_msg(ifname
, NL80211_CMD_GET_SURVEY
, NLM_F_DUMP
);
581 res
= nl80211_send(req
);
584 if( res
->attr
[NL80211_ATTR_SURVEY_INFO
] )
586 if( !nla_parse_nested(si
, NL80211_SURVEY_INFO_MAX
,
587 res
->attr
[NL80211_ATTR_SURVEY_INFO
], sp
) )
589 *buf
= (int8_t)nla_get_u8(si
[NL80211_SURVEY_INFO_NOISE
]);
601 int nl80211_get_quality(const char *ifname
, int *buf
)
605 if( wext_get_quality(ifname
, buf
) )
609 if( !nl80211_get_signal(ifname
, &signal
) )
611 /* A positive signal level is usually just a quality
612 * value, pass through as-is */
618 /* The cfg80211 wext compat layer assumes a signal range
619 * of -110 dBm to -40 dBm, the quality value is derived
620 * by adding 110 to the signal level */
625 else if( signal
> -40 )
628 *buf
= (signal
+ 110);
636 int nl80211_get_quality_max(const char *ifname
, int *buf
)
638 if( wext_get_quality_max(ifname
, buf
) )
639 /* The cfg80211 wext compat layer assumes a maximum
646 int nl80211_get_encryption(const char *ifname
, char *buf
)
651 struct iwinfo_crypto_entry
*c
= (struct iwinfo_crypto_entry
*)buf
;
654 if( (res
= nl80211_hostapd_info(ifname
)) &&
655 nl80211_getval(res
, "interface") )
657 if( (val
= nl80211_getval(res
, "auth_algs")) && (val
> 0) )
659 c
->auth_suites
|= IWINFO_KMGMT_NONE
;
663 c
->auth_algs
|= IWINFO_AUTH_OPEN
;
667 c
->auth_algs
|= IWINFO_AUTH_SHARED
;
671 c
->auth_algs
|= IWINFO_AUTH_OPEN
;
672 c
->auth_algs
|= IWINFO_AUTH_SHARED
;
679 for( i
= 0; i
< 4; i
++ )
681 snprintf(k
, sizeof(k
), "wep_key%d", i
);
683 if( (val
= nl80211_getval(res
, k
)) )
685 if( (strlen(val
) == 5) || (strlen(val
) == 10) )
686 c
->pair_ciphers
|= IWINFO_CIPHER_WEP40
;
688 else if( (strlen(val
) == 13) || (strlen(val
) == 26) )
689 c
->pair_ciphers
|= IWINFO_CIPHER_WEP104
;
693 c
->group_ciphers
= c
->pair_ciphers
;
699 if( (val
= nl80211_getval(res
, "wpa")) != NULL
)
700 c
->wpa_version
= atoi(val
);
703 val
= nl80211_getval(res
, "wpa_key_mgmt");
705 if( !val
|| strstr(val
, "PSK") )
706 c
->auth_suites
|= IWINFO_KMGMT_PSK
;
708 if( val
&& strstr(val
, "EAP") )
709 c
->auth_suites
|= IWINFO_KMGMT_8021x
;
711 if( val
&& strstr(val
, "NONE") )
712 c
->auth_suites
|= IWINFO_KMGMT_NONE
;
715 if( (val
= nl80211_getval(res
, "wpa_pairwise")) != NULL
)
717 if( strstr(val
, "TKIP") )
718 c
->pair_ciphers
|= IWINFO_CIPHER_TKIP
;
720 if( strstr(val
, "CCMP") )
721 c
->pair_ciphers
|= IWINFO_CIPHER_CCMP
;
723 if( strstr(val
, "NONE") )
724 c
->pair_ciphers
|= IWINFO_CIPHER_NONE
;
728 c
->group_ciphers
= c
->pair_ciphers
;
729 c
->enabled
= (c
->auth_algs
|| c
->auth_suites
) ? 1 : 0;
735 else if( (res
= nl80211_wpasupp_info(ifname
, "STATUS")) &&
736 (val
= nl80211_getval(res
, "pairwise_cipher")) )
739 if( strstr(val
, "WEP") )
741 if( strstr(val
, "WEP-40") )
742 c
->pair_ciphers
|= IWINFO_CIPHER_WEP40
;
744 else if( strstr(val
, "WEP-104") )
745 c
->pair_ciphers
|= IWINFO_CIPHER_WEP104
;
748 c
->group_ciphers
= c
->pair_ciphers
;
750 c
->auth_suites
|= IWINFO_KMGMT_NONE
;
751 c
->auth_algs
|= IWINFO_AUTH_OPEN
; /* XXX: assumption */
757 if( strstr(val
, "TKIP") )
758 c
->pair_ciphers
|= IWINFO_CIPHER_TKIP
;
760 else if( strstr(val
, "CCMP") )
761 c
->pair_ciphers
|= IWINFO_CIPHER_CCMP
;
763 else if( strstr(val
, "NONE") )
764 c
->pair_ciphers
|= IWINFO_CIPHER_NONE
;
766 else if( strstr(val
, "WEP-40") )
767 c
->pair_ciphers
|= IWINFO_CIPHER_WEP40
;
769 else if( strstr(val
, "WEP-104") )
770 c
->pair_ciphers
|= IWINFO_CIPHER_WEP104
;
773 if( (val
= nl80211_getval(res
, "group_cipher")) )
775 if( strstr(val
, "TKIP") )
776 c
->group_ciphers
|= IWINFO_CIPHER_TKIP
;
778 else if( strstr(val
, "CCMP") )
779 c
->group_ciphers
|= IWINFO_CIPHER_CCMP
;
781 else if( strstr(val
, "NONE") )
782 c
->group_ciphers
|= IWINFO_CIPHER_NONE
;
784 else if( strstr(val
, "WEP-40") )
785 c
->group_ciphers
|= IWINFO_CIPHER_WEP40
;
787 else if( strstr(val
, "WEP-104") )
788 c
->group_ciphers
|= IWINFO_CIPHER_WEP104
;
792 if( (val
= nl80211_getval(res
, "key_mgmt")) )
794 if( strstr(val
, "WPA2") )
797 else if( strstr(val
, "WPA") )
801 if( strstr(val
, "PSK") )
802 c
->auth_suites
|= IWINFO_KMGMT_PSK
;
804 else if( strstr(val
, "EAP") || strstr(val
, "802.1X") )
805 c
->auth_suites
|= IWINFO_KMGMT_8021x
;
807 else if( strstr(val
, "NONE") )
808 c
->auth_suites
|= IWINFO_KMGMT_NONE
;
811 c
->enabled
= (c
->wpa_version
&& c
->auth_suites
) ? 1 : 0;
821 static int nl80211_get_assoclist_cb(struct nl_msg
*msg
, void *arg
)
823 struct nl80211_assoc_count
*ac
= arg
;
824 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
825 struct nlattr
*attr
[NL80211_ATTR_MAX
+ 1];
826 struct nlattr
*sinfo
[NL80211_STA_INFO_MAX
+ 1];
828 static struct nla_policy stats_policy
[NL80211_STA_INFO_MAX
+ 1] = {
829 [NL80211_STA_INFO_INACTIVE_TIME
] = { .type
= NLA_U32
},
830 [NL80211_STA_INFO_RX_BYTES
] = { .type
= NLA_U32
},
831 [NL80211_STA_INFO_TX_BYTES
] = { .type
= NLA_U32
},
832 [NL80211_STA_INFO_RX_PACKETS
] = { .type
= NLA_U32
},
833 [NL80211_STA_INFO_TX_PACKETS
] = { .type
= NLA_U32
},
834 [NL80211_STA_INFO_SIGNAL
] = { .type
= NLA_U8
},
835 [NL80211_STA_INFO_TX_BITRATE
] = { .type
= NLA_NESTED
},
836 [NL80211_STA_INFO_LLID
] = { .type
= NLA_U16
},
837 [NL80211_STA_INFO_PLID
] = { .type
= NLA_U16
},
838 [NL80211_STA_INFO_PLINK_STATE
] = { .type
= NLA_U8
},
841 nla_parse(attr
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
842 genlmsg_attrlen(gnlh
, 0), NULL
);
844 if( attr
[NL80211_ATTR_MAC
] )
845 memcpy(ac
->entry
->mac
, nla_data(attr
[NL80211_ATTR_MAC
]), 6);
847 if( attr
[NL80211_ATTR_STA_INFO
] )
849 if( !nla_parse_nested(sinfo
, NL80211_STA_INFO_MAX
,
850 attr
[NL80211_ATTR_STA_INFO
], stats_policy
) )
852 if( sinfo
[NL80211_STA_INFO_SIGNAL
] )
853 ac
->entry
->signal
= nla_get_u8(sinfo
[NL80211_STA_INFO_SIGNAL
]);
857 ac
->entry
->noise
= ac
->noise
;
864 int nl80211_get_assoclist(const char *ifname
, char *buf
, int *len
)
866 struct nl80211_assoc_count ac
;
867 struct nl80211_msg_conveyor
*req
;
869 nl80211_get_noise(ifname
, &ac
.noise
);
871 req
= nl80211_msg(ifname
, NL80211_CMD_GET_STATION
, NLM_F_DUMP
);
875 ac
.entry
= (struct iwinfo_assoclist_entry
*)buf
;
877 nl80211_cb(req
, nl80211_get_assoclist_cb
, &ac
);
881 *len
= (ac
.count
* sizeof(struct iwinfo_assoclist_entry
));
888 int nl80211_get_txpwrlist(const char *ifname
, char *buf
, int *len
)
890 int ch_cur
, ch_cmp
, bands_remain
, freqs_remain
;
891 int dbm_max
= -1, dbm_cur
, dbm_cnt
;
892 struct nl80211_msg_conveyor
*req
, *res
;
893 struct nlattr
*bands
[NL80211_BAND_ATTR_MAX
+ 1];
894 struct nlattr
*freqs
[NL80211_FREQUENCY_ATTR_MAX
+ 1];
895 struct nlattr
*band
, *freq
;
896 struct iwinfo_txpwrlist_entry entry
;
898 static struct nla_policy freq_policy
[NL80211_FREQUENCY_ATTR_MAX
+ 1] = {
899 [NL80211_FREQUENCY_ATTR_FREQ
] = { .type
= NLA_U32
},
900 [NL80211_FREQUENCY_ATTR_DISABLED
] = { .type
= NLA_FLAG
},
901 [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN
] = { .type
= NLA_FLAG
},
902 [NL80211_FREQUENCY_ATTR_NO_IBSS
] = { .type
= NLA_FLAG
},
903 [NL80211_FREQUENCY_ATTR_RADAR
] = { .type
= NLA_FLAG
},
904 [NL80211_FREQUENCY_ATTR_MAX_TX_POWER
] = { .type
= NLA_U32
},
907 if( nl80211_get_channel(ifname
, &ch_cur
) )
910 req
= nl80211_msg(ifname
, NL80211_CMD_GET_WIPHY
, 0);
913 res
= nl80211_send(req
);
916 nla_for_each_nested(band
,
917 res
->attr
[NL80211_ATTR_WIPHY_BANDS
], bands_remain
)
919 nla_parse(bands
, NL80211_BAND_ATTR_MAX
, nla_data(band
),
920 nla_len(band
), NULL
);
922 nla_for_each_nested(freq
,
923 bands
[NL80211_BAND_ATTR_FREQS
], freqs_remain
)
925 nla_parse(freqs
, NL80211_FREQUENCY_ATTR_MAX
,
926 nla_data(freq
), nla_len(freq
), freq_policy
);
928 ch_cmp
= nl80211_freq2channel(
929 nla_get_u32(freqs
[NL80211_FREQUENCY_ATTR_FREQ
]));
931 if( (ch_cmp
== ch_cur
) &&
932 freqs
[NL80211_FREQUENCY_ATTR_MAX_TX_POWER
] )
934 dbm_max
= (int)(0.01 * nla_get_u32(
935 freqs
[NL80211_FREQUENCY_ATTR_MAX_TX_POWER
]));
949 for( dbm_cur
= 0, dbm_cnt
= 0;
951 dbm_cur
+= 2, dbm_cnt
++ )
954 entry
.mw
= wext_dbm2mw(dbm_cur
);
956 memcpy(&buf
[dbm_cnt
* sizeof(entry
)], &entry
, sizeof(entry
));
960 entry
.mw
= wext_dbm2mw(dbm_max
);
962 memcpy(&buf
[dbm_cnt
* sizeof(entry
)], &entry
, sizeof(entry
));
965 *len
= dbm_cnt
* sizeof(entry
);
972 static void nl80211_get_scancrypto(const char *spec
,
973 struct iwinfo_crypto_entry
*c
)
975 if( strstr(spec
, "OPEN") )
983 if( strstr(spec
, "WPA2-") && strstr(spec
, "WPA-") )
986 else if( strstr(spec
, "WPA2") )
989 else if( strstr(spec
, "WPA") )
992 else if( strstr(spec
, "WEP") )
993 c
->auth_algs
= IWINFO_AUTH_OPEN
| IWINFO_AUTH_SHARED
;
996 if( strstr(spec
, "PSK") )
997 c
->auth_suites
|= IWINFO_KMGMT_PSK
;
999 if( strstr(spec
, "802.1X") || strstr(spec
, "EAP") )
1000 c
->auth_suites
|= IWINFO_KMGMT_8021x
;
1002 if( strstr(spec
, "WPA-NONE") )
1003 c
->auth_suites
|= IWINFO_KMGMT_NONE
;
1006 if( strstr(spec
, "TKIP") )
1007 c
->pair_ciphers
|= IWINFO_CIPHER_TKIP
;
1009 if( strstr(spec
, "CCMP") )
1010 c
->pair_ciphers
|= IWINFO_CIPHER_CCMP
;
1012 if( strstr(spec
, "WEP-40") )
1013 c
->pair_ciphers
|= IWINFO_CIPHER_WEP40
;
1015 if( strstr(spec
, "WEP-104") )
1016 c
->pair_ciphers
|= IWINFO_CIPHER_WEP104
;
1018 c
->group_ciphers
= c
->pair_ciphers
;
1022 int nl80211_get_scanlist(const char *ifname
, char *buf
, int *len
)
1024 int freq
, rssi
, qmax
, count
;
1027 char ssid
[128] = { 0 };
1028 char bssid
[18] = { 0 };
1029 char cipher
[256] = { 0 };
1031 struct iwinfo_scanlist_entry
*e
= (struct iwinfo_scanlist_entry
*)buf
;
1033 /* WPA supplicant */
1034 if( (res
= nl80211_wpasupp_info(ifname
, "SCAN")) &&
1035 !strcmp(res
, "OK\n") )
1039 if( (res
= nl80211_wpasupp_info(ifname
, "SCAN_RESULTS")) )
1041 nl80211_get_quality_max(ifname
, &qmax
);
1043 /* skip header line */
1044 while( *res
++ != '\n' );
1048 while( sscanf(res
, "%17s %d %d %255s %127[^\n]\n",
1049 bssid
, &freq
, &rssi
, cipher
, ssid
) > 0 )
1052 e
->mac
[0] = strtol(&bssid
[0], NULL
, 16);
1053 e
->mac
[1] = strtol(&bssid
[3], NULL
, 16);
1054 e
->mac
[2] = strtol(&bssid
[6], NULL
, 16);
1055 e
->mac
[3] = strtol(&bssid
[9], NULL
, 16);
1056 e
->mac
[4] = strtol(&bssid
[12], NULL
, 16);
1057 e
->mac
[5] = strtol(&bssid
[15], NULL
, 16);
1060 memcpy(e
->ssid
, ssid
,
1061 min(strlen(ssid
), sizeof(e
->ssid
) - 1));
1063 /* Mode (assume master) */
1064 sprintf((char *)e
->mode
, "Master");
1067 e
->channel
= nl80211_freq2channel(freq
);
1075 /* The cfg80211 wext compat layer assumes a signal range
1076 * of -110 dBm to -40 dBm, the quality value is derived
1077 * by adding 110 to the signal level */
1080 else if( rssi
> -40 )
1083 e
->quality
= (rssi
+ 110);
1091 e
->quality_max
= qmax
;
1094 nl80211_get_scancrypto(cipher
, &e
->crypto
);
1096 /* advance to next line */
1097 while( *res
&& *res
++ != '\n' );
1103 *len
= count
* sizeof(struct iwinfo_scanlist_entry
);
1111 if( (res
= nl80211_ifname2phy(ifname
)) != NULL
)
1114 * This is a big ugly hack, just look away.
1117 sprintf(cmd
, "ifconfig %s down 2>/dev/null", ifname
);
1118 if( WEXITSTATUS(system(cmd
)) )
1121 sprintf(cmd
, "iw phy %s interface add scan.%s "
1122 "type station 2>/dev/null", res
, ifname
);
1123 if( WEXITSTATUS(system(cmd
)) )
1126 sprintf(cmd
, "ifconfig scan.%s up 2>/dev/null", ifname
);
1127 if( WEXITSTATUS(system(cmd
)) )
1130 sprintf(cmd
, "scan.%s", ifname
);
1131 wext_get_scanlist(cmd
, buf
, len
);
1134 sprintf(cmd
, "ifconfig scan.%s down 2>/dev/null", ifname
);
1135 (void) WEXITSTATUS(system(cmd
));
1137 sprintf(cmd
, "iw dev scan.%s del 2>/dev/null", ifname
);
1138 (void) WEXITSTATUS(system(cmd
));
1140 sprintf(cmd
, "ifconfig %s up 2>/dev/null", ifname
);
1141 (void) WEXITSTATUS(system(cmd
));
1143 sprintf(cmd
, "killall -HUP hostapd 2>/dev/null");
1144 (void) WEXITSTATUS(system(cmd
));
1153 int nl80211_get_freqlist(const char *ifname
, char *buf
, int *len
)
1155 return wext_get_freqlist(ifname
, buf
, len
);
1158 int nl80211_get_mbssid_support(const char *ifname
, int *buf
)
1160 /* We assume that multi bssid is always possible */