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 fd
= nl_socket_get_fd(nls
->nl_sock
);
56 if (fcntl(fd
, F_SETFD
, fcntl(fd
, F_GETFD
) | FD_CLOEXEC
) < 0) {
61 if (genl_ctrl_alloc_cache(nls
->nl_sock
, &nls
->nl_cache
)) {
66 nls
->nl80211
= genl_ctrl_search_by_name(nls
->nl_cache
, "nl80211");
72 nls
->nlctrl
= genl_ctrl_search_by_name(nls
->nl_cache
, "nlctrl");
88 static int nl80211_msg_error(struct sockaddr_nl
*nla
,
89 struct nlmsgerr
*err
, void *arg
)
96 static int nl80211_msg_finish(struct nl_msg
*msg
, void *arg
)
103 static int nl80211_msg_ack(struct nl_msg
*msg
, void *arg
)
110 static int nl80211_msg_response(struct nl_msg
*msg
, void *arg
)
115 static void nl80211_free(struct nl80211_msg_conveyor
*cv
)
130 static struct nl80211_msg_conveyor
* nl80211_new(struct genl_family
*family
,
133 static struct nl80211_msg_conveyor cv
;
135 struct nl_msg
*req
= NULL
;
136 struct nl_cb
*cb
= NULL
;
142 cb
= nl_cb_alloc(NL_CB_DEFAULT
);
146 genlmsg_put(req
, 0, 0, genl_family_get_id(family
), 0, flags
, cmd
, 0);
164 static struct nl80211_msg_conveyor
* nl80211_ctl(int cmd
, int flags
)
166 if (nl80211_init() < 0)
169 return nl80211_new(nls
->nlctrl
, cmd
, flags
);
172 static struct nl80211_msg_conveyor
* nl80211_msg(const char *ifname
,
175 int ifidx
= -1, phyidx
= -1;
176 struct nl80211_msg_conveyor
*cv
;
178 if (nl80211_init() < 0)
181 if (!strncmp(ifname
, "phy", 3))
182 phyidx
= atoi(&ifname
[3]);
183 else if (!strncmp(ifname
, "radio", 5))
184 phyidx
= atoi(&ifname
[5]);
185 else if (!strncmp(ifname
, "mon.", 4))
186 ifidx
= if_nametoindex(&ifname
[4]);
188 ifidx
= if_nametoindex(ifname
);
190 if ((ifidx
< 0) && (phyidx
< 0))
193 cv
= nl80211_new(nls
->nl80211
, cmd
, flags
);
198 NLA_PUT_U32(cv
->msg
, NL80211_ATTR_IFINDEX
, ifidx
);
201 NLA_PUT_U32(cv
->msg
, NL80211_ATTR_WIPHY
, phyidx
);
210 static struct nl80211_msg_conveyor
* nl80211_send(
211 struct nl80211_msg_conveyor
*cv
,
212 int (*cb_func
)(struct nl_msg
*, void *), void *cb_arg
214 static struct nl80211_msg_conveyor rcv
;
218 nl_cb_set(cv
->cb
, NL_CB_VALID
, NL_CB_CUSTOM
, cb_func
, cb_arg
);
220 nl_cb_set(cv
->cb
, NL_CB_VALID
, NL_CB_CUSTOM
, nl80211_msg_response
, &rcv
);
222 if (nl_send_auto_complete(nls
->nl_sock
, cv
->msg
) < 0)
225 nl_cb_err(cv
->cb
, NL_CB_CUSTOM
, nl80211_msg_error
, &err
);
226 nl_cb_set(cv
->cb
, NL_CB_FINISH
, NL_CB_CUSTOM
, nl80211_msg_finish
, &err
);
227 nl_cb_set(cv
->cb
, NL_CB_ACK
, NL_CB_CUSTOM
, nl80211_msg_ack
, &err
);
230 nl_recvmsgs(nls
->nl_sock
, cv
->cb
);
241 static struct nlattr
** nl80211_parse(struct nl_msg
*msg
)
243 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
244 static struct nlattr
*attr
[NL80211_ATTR_MAX
+ 1];
246 nla_parse(attr
, NL80211_ATTR_MAX
, genlmsg_attrdata(gnlh
, 0),
247 genlmsg_attrlen(gnlh
, 0), NULL
);
253 static int nl80211_subscribe_cb(struct nl_msg
*msg
, void *arg
)
255 struct nl80211_group_conveyor
*cv
= arg
;
257 struct nlattr
**attr
= nl80211_parse(msg
);
258 struct nlattr
*mgrpinfo
[CTRL_ATTR_MCAST_GRP_MAX
+ 1];
262 if (!attr
[CTRL_ATTR_MCAST_GROUPS
])
265 nla_for_each_nested(mgrp
, attr
[CTRL_ATTR_MCAST_GROUPS
], mgrpidx
)
267 nla_parse(mgrpinfo
, CTRL_ATTR_MCAST_GRP_MAX
,
268 nla_data(mgrp
), nla_len(mgrp
), NULL
);
270 if (mgrpinfo
[CTRL_ATTR_MCAST_GRP_ID
] &&
271 mgrpinfo
[CTRL_ATTR_MCAST_GRP_NAME
] &&
272 !strncmp(nla_data(mgrpinfo
[CTRL_ATTR_MCAST_GRP_NAME
]),
273 cv
->name
, nla_len(mgrpinfo
[CTRL_ATTR_MCAST_GRP_NAME
])))
275 cv
->id
= nla_get_u32(mgrpinfo
[CTRL_ATTR_MCAST_GRP_ID
]);
283 static int nl80211_subscribe(const char *family
, const char *group
)
285 struct nl80211_group_conveyor cv
= { .name
= group
, .id
= -ENOENT
};
286 struct nl80211_msg_conveyor
*req
;
288 req
= nl80211_ctl(CTRL_CMD_GETFAMILY
, 0);
291 NLA_PUT_STRING(req
->msg
, CTRL_ATTR_FAMILY_NAME
, family
);
292 nl80211_send(req
, nl80211_subscribe_cb
, &cv
);
298 return nl_socket_add_membership(nls
->nl_sock
, cv
.id
);
302 static int nl80211_wait_cb(struct nl_msg
*msg
, void *arg
)
304 struct nl80211_event_conveyor
*cv
= arg
;
305 struct genlmsghdr
*gnlh
= nlmsg_data(nlmsg_hdr(msg
));
307 if (gnlh
->cmd
== cv
->wait
)
308 cv
->recv
= gnlh
->cmd
;
313 static int nl80211_wait_seq_check(struct nl_msg
*msg
, void *arg
)
318 static int nl80211_wait(const char *family
, const char *group
, int cmd
)
320 struct nl80211_event_conveyor cv
= { .wait
= cmd
};
323 if (nl80211_subscribe(family
, group
))
326 cb
= nl_cb_alloc(NL_CB_DEFAULT
);
331 nl_cb_set(cb
, NL_CB_SEQ_CHECK
, NL_CB_CUSTOM
, nl80211_wait_seq_check
, NULL
);
332 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, nl80211_wait_cb
, &cv
);
335 nl_recvmsgs(nls
->nl_sock
, cb
);
343 static int nl80211_freq2channel(int freq
)
349 return (freq
- 2407) / 5;
351 return (freq
/ 5) - 1000;
354 static char * nl80211_getval(const char *ifname
, const char *buf
, const char *key
)
357 char lkey
[64] = { 0 };
358 const char *ln
= buf
;
359 static char lval
[256] = { 0 };
361 int matched_if
= ifname
? 0 : 1;
364 for( i
= 0, len
= strlen(buf
); i
< len
; i
++ )
366 if (!lkey
[0] && (buf
[i
] == ' ' || buf
[i
] == '\t'))
370 else if (!lkey
[0] && (buf
[i
] == '='))
372 if ((&buf
[i
] - ln
) > 0)
373 memcpy(lkey
, ln
, min(sizeof(lkey
) - 1, &buf
[i
] - ln
));
375 else if (buf
[i
] == '\n')
379 memcpy(lval
, ln
+ strlen(lkey
) + 1,
380 min(sizeof(lval
) - 1, &buf
[i
] - ln
- strlen(lkey
) - 1));
382 if ((ifname
!= NULL
) &&
383 (!strcmp(lkey
, "interface") || !strcmp(lkey
, "bss")) )
385 matched_if
= !strcmp(lval
, ifname
);
387 else if (matched_if
&& !strcmp(lkey
, key
))
394 memset(lkey
, 0, sizeof(lkey
));
395 memset(lval
, 0, sizeof(lval
));
402 static int nl80211_ifname2phy_cb(struct nl_msg
*msg
, void *arg
)
405 struct nlattr
**attr
= nl80211_parse(msg
);
407 if (attr
[NL80211_ATTR_WIPHY_NAME
])
408 memcpy(buf
, nla_data(attr
[NL80211_ATTR_WIPHY_NAME
]),
409 nla_len(attr
[NL80211_ATTR_WIPHY_NAME
]));
416 static char * nl80211_ifname2phy(const char *ifname
)
418 static char phy
[32] = { 0 };
419 struct nl80211_msg_conveyor
*req
;
421 memset(phy
, 0, sizeof(phy
));
423 req
= nl80211_msg(ifname
, NL80211_CMD_GET_WIPHY
, 0);
426 nl80211_send(req
, nl80211_ifname2phy_cb
, phy
);
430 return phy
[0] ? phy
: NULL
;
433 static char * nl80211_hostapd_info(const char *ifname
)
436 char path
[32] = { 0 };
437 static char buf
[4096] = { 0 };
440 if ((phy
= nl80211_ifname2phy(ifname
)) != NULL
)
442 snprintf(path
, sizeof(path
), "/var/run/hostapd-%s.conf", phy
);
444 if ((conf
= fopen(path
, "r")) != NULL
)
446 fread(buf
, sizeof(buf
) - 1, 1, conf
);
456 static inline int nl80211_wpactl_recv(int sock
, char *buf
, int blen
)
459 struct timeval tv
= { 2, 0 };
464 memset(buf
, 0, blen
);
467 if (select(sock
+ 1, &rfds
, NULL
, NULL
, &tv
) < 0)
470 if (!FD_ISSET(sock
, &rfds
))
473 return recv(sock
, buf
, blen
, 0);
476 static char * nl80211_wpactl_info(const char *ifname
, const char *cmd
,
482 size_t remote_length
, local_length
;
483 static char buffer
[10240] = { 0 };
485 struct sockaddr_un local
= { 0 };
486 struct sockaddr_un remote
= { 0 };
489 sock
= socket(PF_UNIX
, SOCK_DGRAM
, 0);
493 remote
.sun_family
= AF_UNIX
;
494 remote_length
= sizeof(remote
.sun_family
) + sprintf(remote
.sun_path
,
495 "/var/run/wpa_supplicant-%s/%s", ifname
, ifname
);
497 if (fcntl(sock
, F_SETFD
, fcntl(sock
, F_GETFD
) | FD_CLOEXEC
) < 0)
500 if (connect(sock
, (struct sockaddr
*) &remote
, remote_length
))
503 local
.sun_family
= AF_UNIX
;
504 local_length
= sizeof(local
.sun_family
) +
505 sprintf(local
.sun_path
, "/var/run/iwinfo-%s-%d", ifname
, getpid());
507 if (bind(sock
, (struct sockaddr
*) &local
, local_length
))
513 send(sock
, "ATTACH", 6, 0);
515 if (nl80211_wpactl_recv(sock
, buffer
, sizeof(buffer
)) <= 0)
520 send(sock
, cmd
, strlen(cmd
), 0);
522 while( numtry
++ < 5 )
524 if (nl80211_wpactl_recv(sock
, buffer
, sizeof(buffer
)) <= 0)
532 if ((!event
&& buffer
[0] != '<') || (event
&& strstr(buffer
, event
)))
541 if (local
.sun_family
)
542 unlink(local
.sun_path
);
547 static inline int nl80211_readint(const char *path
)
553 if ((fd
= open(path
, O_RDONLY
)) > -1)
555 if (read(fd
, buffer
, sizeof(buffer
)) > 0)
564 static char * nl80211_phy2ifname(const char *ifname
)
566 int fd
, ifidx
= -1, cifidx
= -1, phyidx
= -1;
568 static char nif
[IFNAMSIZ
] = { 0 };
575 else if (!strncmp(ifname
, "phy", 3))
576 phyidx
= atoi(&ifname
[3]);
577 else if (!strncmp(ifname
, "radio", 5))
578 phyidx
= atoi(&ifname
[5]);
580 memset(nif
, 0, sizeof(nif
));
584 if ((d
= opendir("/sys/class/net")) != NULL
)
586 while ((e
= readdir(d
)) != NULL
)
588 snprintf(buffer
, sizeof(buffer
),
589 "/sys/class/net/%s/phy80211/index", e
->d_name
);
591 if (nl80211_readint(buffer
) == phyidx
)
593 snprintf(buffer
, sizeof(buffer
),
594 "/sys/class/net/%s/ifindex", e
->d_name
);
596 if ((cifidx
= nl80211_readint(buffer
)) >= 0 &&
597 ((ifidx
< 0) || (cifidx
< ifidx
)))
600 strncpy(nif
, e
->d_name
, sizeof(nif
));
609 return nif
[0] ? nif
: NULL
;
612 static char * nl80211_ifadd(const char *ifname
)
616 static char nif
[IFNAMSIZ
] = { 0 };
617 struct nl80211_msg_conveyor
*req
, *res
;
619 req
= nl80211_msg(ifname
, NL80211_CMD_NEW_INTERFACE
, 0);
622 snprintf(nif
, sizeof(nif
), "tmp.%s", ifname
);
624 NLA_PUT_STRING(req
->msg
, NL80211_ATTR_IFNAME
, nif
);
625 NLA_PUT_U32(req
->msg
, NL80211_ATTR_IFTYPE
, NL80211_IFTYPE_STATION
);
627 nl80211_send(req
, NULL
, NULL
);
638 static void nl80211_ifdel(const char *ifname
)
640 struct nl80211_msg_conveyor
*req
;
642 req
= nl80211_msg(ifname
, NL80211_CMD_DEL_INTERFACE
, 0);
645 NLA_PUT_STRING(req
->msg
, NL80211_ATTR_IFNAME
, ifname
);
647 nl80211_send(req
, NULL
, NULL
);
654 static void nl80211_hostapd_hup(const char *ifname
)
658 char *phy
= nl80211_ifname2phy(ifname
);
662 snprintf(buf
, sizeof(buf
), "/var/run/wifi-%s.pid", phy
);
663 if ((fd
= open(buf
, O_RDONLY
)) > 0)
665 if (read(fd
, buf
, sizeof(buf
)) > 0)
677 int nl80211_probe(const char *ifname
)
679 return !!nl80211_ifname2phy(ifname
);
682 void nl80211_close(void)
687 genl_family_put(nls
->nlctrl
);
690 genl_family_put(nls
->nl80211
);
693 nl_socket_free(nls
->nl_sock
);
696 nl_cache_free(nls
->nl_cache
);
703 int nl80211_get_mode(const char *ifname
, int *buf
)
705 return wext_get_mode(ifname
, buf
);
708 int nl80211_get_ssid(const char *ifname
, char *buf
)
712 if (!wext_get_ssid(ifname
, buf
))
716 else if ((ssid
= nl80211_hostapd_info(ifname
)) &&
717 (ssid
= nl80211_getval(ifname
, ssid
, "ssid")))
719 memcpy(buf
, ssid
, strlen(ssid
));
726 int nl80211_get_bssid(const char *ifname
, char *buf
)
729 unsigned char mac
[6];
731 if (!wext_get_bssid(ifname
, buf
))
735 else if ((bssid
= nl80211_hostapd_info(ifname
)) &&
736 (bssid
= nl80211_getval(ifname
, bssid
, "bssid")))
738 mac
[0] = strtol(&bssid
[0], NULL
, 16);
739 mac
[1] = strtol(&bssid
[3], NULL
, 16);
740 mac
[2] = strtol(&bssid
[6], NULL
, 16);
741 mac
[3] = strtol(&bssid
[9], NULL
, 16);
742 mac
[4] = strtol(&bssid
[12], NULL
, 16);
743 mac
[5] = strtol(&bssid
[15], NULL
, 16);
745 sprintf(buf
, "%02X:%02X:%02X:%02X:%02X:%02X",
746 mac
[0], mac
[1], mac
[2], mac
[3], mac
[4], mac
[5]);
754 int nl80211_get_channel(const char *ifname
, int *buf
)
758 if (!wext_get_channel(ifname
, buf
))
761 else if ((first
= nl80211_phy2ifname(nl80211_ifname2phy(ifname
))) != NULL
)
762 return wext_get_channel(first
, buf
);
767 int nl80211_get_frequency(const char *ifname
, int *buf
)
771 if (!wext_get_frequency(ifname
, buf
))
774 else if ((first
= nl80211_phy2ifname(nl80211_ifname2phy(ifname
))) != NULL
)
775 return wext_get_frequency(first
, buf
);
780 int nl80211_get_txpower(const char *ifname
, int *buf
)
782 return wext_get_txpower(ifname
, buf
);
786 static int nl80211_fill_signal_cb(struct nl_msg
*msg
, void *arg
)
790 struct nl80211_rssi_rate
*rr
= arg
;
791 struct nlattr
**attr
= nl80211_parse(msg
);
792 struct nlattr
*sinfo
[NL80211_STA_INFO_MAX
+ 1];
793 struct nlattr
*rinfo
[NL80211_RATE_INFO_MAX
+ 1];
795 static struct nla_policy stats_policy
[NL80211_STA_INFO_MAX
+ 1] = {
796 [NL80211_STA_INFO_INACTIVE_TIME
] = { .type
= NLA_U32
},
797 [NL80211_STA_INFO_RX_BYTES
] = { .type
= NLA_U32
},
798 [NL80211_STA_INFO_TX_BYTES
] = { .type
= NLA_U32
},
799 [NL80211_STA_INFO_RX_PACKETS
] = { .type
= NLA_U32
},
800 [NL80211_STA_INFO_TX_PACKETS
] = { .type
= NLA_U32
},
801 [NL80211_STA_INFO_SIGNAL
] = { .type
= NLA_U8
},
802 [NL80211_STA_INFO_TX_BITRATE
] = { .type
= NLA_NESTED
},
803 [NL80211_STA_INFO_LLID
] = { .type
= NLA_U16
},
804 [NL80211_STA_INFO_PLID
] = { .type
= NLA_U16
},
805 [NL80211_STA_INFO_PLINK_STATE
] = { .type
= NLA_U8
},
808 static struct nla_policy rate_policy
[NL80211_RATE_INFO_MAX
+ 1] = {
809 [NL80211_RATE_INFO_BITRATE
] = { .type
= NLA_U16
},
810 [NL80211_RATE_INFO_MCS
] = { .type
= NLA_U8
},
811 [NL80211_RATE_INFO_40_MHZ_WIDTH
] = { .type
= NLA_FLAG
},
812 [NL80211_RATE_INFO_SHORT_GI
] = { .type
= NLA_FLAG
},
815 if (attr
[NL80211_ATTR_STA_INFO
])
817 if (!nla_parse_nested(sinfo
, NL80211_STA_INFO_MAX
,
818 attr
[NL80211_ATTR_STA_INFO
], stats_policy
))
820 if (sinfo
[NL80211_STA_INFO_SIGNAL
])
822 dbm
= nla_get_u8(sinfo
[NL80211_STA_INFO_SIGNAL
]);
823 rr
->rssi
= rr
->rssi
? (int8_t)((rr
->rssi
+ dbm
) / 2) : dbm
;
826 if (sinfo
[NL80211_STA_INFO_TX_BITRATE
])
828 if (!nla_parse_nested(rinfo
, NL80211_RATE_INFO_MAX
,
829 sinfo
[NL80211_STA_INFO_TX_BITRATE
],
832 if (rinfo
[NL80211_RATE_INFO_BITRATE
])
834 mbit
= nla_get_u16(rinfo
[NL80211_RATE_INFO_BITRATE
]);
836 ? (int16_t)((rr
->rate
+ mbit
) / 2) : mbit
;
846 static void nl80211_fill_signal(const char *ifname
, struct nl80211_rssi_rate
*r
)
850 struct nl80211_msg_conveyor
*req
;
855 if ((d
= opendir("/sys/class/net")) != NULL
)
857 while ((de
= readdir(d
)) != NULL
)
859 if (!strncmp(de
->d_name
, ifname
, strlen(ifname
)) &&
860 (!de
->d_name
[strlen(ifname
)] ||
861 !strncmp(&de
->d_name
[strlen(ifname
)], ".sta", 4)))
863 req
= nl80211_msg(de
->d_name
, NL80211_CMD_GET_STATION
,
868 nl80211_send(req
, nl80211_fill_signal_cb
, r
);
878 int nl80211_get_bitrate(const char *ifname
, int *buf
)
880 struct nl80211_rssi_rate rr
;
882 if (!wext_get_bitrate(ifname
, buf
))
885 nl80211_fill_signal(ifname
, &rr
);
889 *buf
= (rr
.rate
* 100);
896 int nl80211_get_signal(const char *ifname
, int *buf
)
898 struct nl80211_rssi_rate rr
;
900 if (!wext_get_signal(ifname
, buf
))
903 nl80211_fill_signal(ifname
, &rr
);
914 static int nl80211_get_noise_cb(struct nl_msg
*msg
, void *arg
)
917 struct nlattr
**tb
= nl80211_parse(msg
);
918 struct nlattr
*si
[NL80211_SURVEY_INFO_MAX
+ 1];
920 static struct nla_policy sp
[NL80211_SURVEY_INFO_MAX
+ 1] = {
921 [NL80211_SURVEY_INFO_FREQUENCY
] = { .type
= NLA_U32
},
922 [NL80211_SURVEY_INFO_NOISE
] = { .type
= NLA_U8
},
925 if (!tb
[NL80211_ATTR_SURVEY_INFO
])
928 if (nla_parse_nested(si
, NL80211_SURVEY_INFO_MAX
,
929 tb
[NL80211_ATTR_SURVEY_INFO
], sp
))
932 if (!si
[NL80211_SURVEY_INFO_NOISE
])
935 if (!*noise
|| si
[NL80211_SURVEY_INFO_IN_USE
])
936 *noise
= (int8_t)nla_get_u8(si
[NL80211_SURVEY_INFO_NOISE
]);
942 int nl80211_get_noise(const char *ifname
, int *buf
)
945 struct nl80211_msg_conveyor
*req
;
947 req
= nl80211_msg(ifname
, NL80211_CMD_GET_SURVEY
, NLM_F_DUMP
);
952 nl80211_send(req
, nl80211_get_noise_cb
, &noise
);
965 int nl80211_get_quality(const char *ifname
, int *buf
)
969 if (wext_get_quality(ifname
, buf
))
973 if (!nl80211_get_signal(ifname
, &signal
))
975 /* A positive signal level is usually just a quality
976 * value, pass through as-is */
982 /* The cfg80211 wext compat layer assumes a signal range
983 * of -110 dBm to -40 dBm, the quality value is derived
984 * by adding 110 to the signal level */
989 else if (signal
> -40)
992 *buf
= (signal
+ 110);
1000 int nl80211_get_quality_max(const char *ifname
, int *buf
)
1002 if (wext_get_quality_max(ifname
, buf
))
1003 /* The cfg80211 wext compat layer assumes a maximum
1010 int nl80211_get_encryption(const char *ifname
, char *buf
)
1015 struct iwinfo_crypto_entry
*c
= (struct iwinfo_crypto_entry
*)buf
;
1017 /* WPA supplicant */
1018 if ((res
= nl80211_wpactl_info(ifname
, "STATUS", NULL
)) &&
1019 (val
= nl80211_getval(NULL
, res
, "pairwise_cipher")))
1022 if (strstr(val
, "WEP"))
1024 if (strstr(val
, "WEP-40"))
1025 c
->pair_ciphers
|= IWINFO_CIPHER_WEP40
;
1027 else if (strstr(val
, "WEP-104"))
1028 c
->pair_ciphers
|= IWINFO_CIPHER_WEP104
;
1031 c
->group_ciphers
= c
->pair_ciphers
;
1033 c
->auth_suites
|= IWINFO_KMGMT_NONE
;
1034 c
->auth_algs
|= IWINFO_AUTH_OPEN
; /* XXX: assumption */
1040 if (strstr(val
, "TKIP"))
1041 c
->pair_ciphers
|= IWINFO_CIPHER_TKIP
;
1043 else if (strstr(val
, "CCMP"))
1044 c
->pair_ciphers
|= IWINFO_CIPHER_CCMP
;
1046 else if (strstr(val
, "NONE"))
1047 c
->pair_ciphers
|= IWINFO_CIPHER_NONE
;
1049 else if (strstr(val
, "WEP-40"))
1050 c
->pair_ciphers
|= IWINFO_CIPHER_WEP40
;
1052 else if (strstr(val
, "WEP-104"))
1053 c
->pair_ciphers
|= IWINFO_CIPHER_WEP104
;
1056 if ((val
= nl80211_getval(NULL
, res
, "group_cipher")))
1058 if (strstr(val
, "TKIP"))
1059 c
->group_ciphers
|= IWINFO_CIPHER_TKIP
;
1061 else if (strstr(val
, "CCMP"))
1062 c
->group_ciphers
|= IWINFO_CIPHER_CCMP
;
1064 else if (strstr(val
, "NONE"))
1065 c
->group_ciphers
|= IWINFO_CIPHER_NONE
;
1067 else if (strstr(val
, "WEP-40"))
1068 c
->group_ciphers
|= IWINFO_CIPHER_WEP40
;
1070 else if (strstr(val
, "WEP-104"))
1071 c
->group_ciphers
|= IWINFO_CIPHER_WEP104
;
1075 if ((val
= nl80211_getval(NULL
, res
, "key_mgmt")))
1077 if (strstr(val
, "WPA2"))
1080 else if (strstr(val
, "WPA"))
1084 if (strstr(val
, "PSK"))
1085 c
->auth_suites
|= IWINFO_KMGMT_PSK
;
1087 else if (strstr(val
, "EAP") || strstr(val
, "802.1X"))
1088 c
->auth_suites
|= IWINFO_KMGMT_8021x
;
1090 else if (strstr(val
, "NONE"))
1091 c
->auth_suites
|= IWINFO_KMGMT_NONE
;
1094 c
->enabled
= (c
->wpa_version
&& c
->auth_suites
) ? 1 : 0;
1101 else if ((res
= nl80211_hostapd_info(ifname
)))
1103 if ((val
= nl80211_getval(ifname
, res
, "wpa")) != NULL
)
1104 c
->wpa_version
= atoi(val
);
1106 val
= nl80211_getval(ifname
, res
, "wpa_key_mgmt");
1108 if (!val
|| strstr(val
, "PSK"))
1109 c
->auth_suites
|= IWINFO_KMGMT_PSK
;
1111 if (val
&& strstr(val
, "EAP"))
1112 c
->auth_suites
|= IWINFO_KMGMT_8021x
;
1114 if (val
&& strstr(val
, "NONE"))
1115 c
->auth_suites
|= IWINFO_KMGMT_NONE
;
1117 if ((val
= nl80211_getval(ifname
, res
, "wpa_pairwise")) != NULL
)
1119 if (strstr(val
, "TKIP"))
1120 c
->pair_ciphers
|= IWINFO_CIPHER_TKIP
;
1122 if (strstr(val
, "CCMP"))
1123 c
->pair_ciphers
|= IWINFO_CIPHER_CCMP
;
1125 if (strstr(val
, "NONE"))
1126 c
->pair_ciphers
|= IWINFO_CIPHER_NONE
;
1129 if ((val
= nl80211_getval(ifname
, res
, "auth_algs")) != NULL
)
1133 c
->auth_algs
|= IWINFO_AUTH_OPEN
;
1137 c
->auth_algs
|= IWINFO_AUTH_SHARED
;
1141 c
->auth_algs
|= IWINFO_AUTH_OPEN
;
1142 c
->auth_algs
|= IWINFO_AUTH_SHARED
;
1149 for (i
= 0; i
< 4; i
++)
1151 snprintf(k
, sizeof(k
), "wep_key%d", i
);
1153 if ((val
= nl80211_getval(ifname
, res
, k
)))
1155 if ((strlen(val
) == 5) || (strlen(val
) == 10))
1156 c
->pair_ciphers
|= IWINFO_CIPHER_WEP40
;
1158 else if ((strlen(val
) == 13) || (strlen(val
) == 26))
1159 c
->pair_ciphers
|= IWINFO_CIPHER_WEP104
;
1164 c
->group_ciphers
= c
->pair_ciphers
;
1165 c
->enabled
= (c
->wpa_version
|| c
->pair_ciphers
) ? 1 : 0;
1174 static int nl80211_get_assoclist_cb(struct nl_msg
*msg
, void *arg
)
1176 struct nl80211_array_buf
*arr
= arg
;
1177 struct iwinfo_assoclist_entry
*e
= arr
->buf
;
1178 struct nlattr
**attr
= nl80211_parse(msg
);
1179 struct nlattr
*sinfo
[NL80211_STA_INFO_MAX
+ 1];
1180 struct nlattr
*rinfo
[NL80211_RATE_INFO_MAX
+ 1];
1182 static struct nla_policy stats_policy
[NL80211_STA_INFO_MAX
+ 1] = {
1183 [NL80211_STA_INFO_INACTIVE_TIME
] = { .type
= NLA_U32
},
1184 [NL80211_STA_INFO_RX_PACKETS
] = { .type
= NLA_U32
},
1185 [NL80211_STA_INFO_TX_PACKETS
] = { .type
= NLA_U32
},
1186 [NL80211_STA_INFO_RX_BITRATE
] = { .type
= NLA_NESTED
},
1187 [NL80211_STA_INFO_TX_BITRATE
] = { .type
= NLA_NESTED
},
1188 [NL80211_STA_INFO_SIGNAL
] = { .type
= NLA_U8
},
1191 static struct nla_policy rate_policy
[NL80211_RATE_INFO_MAX
+ 1] = {
1192 [NL80211_RATE_INFO_BITRATE
] = { .type
= NLA_U16
},
1193 [NL80211_RATE_INFO_MCS
] = { .type
= NLA_U8
},
1194 [NL80211_RATE_INFO_40_MHZ_WIDTH
] = { .type
= NLA_FLAG
},
1195 [NL80211_RATE_INFO_SHORT_GI
] = { .type
= NLA_FLAG
},
1198 /* advance to end of array */
1200 memset(e
, 0, sizeof(*e
));
1202 if (attr
[NL80211_ATTR_MAC
])
1203 memcpy(e
->mac
, nla_data(attr
[NL80211_ATTR_MAC
]), 6);
1205 if (attr
[NL80211_ATTR_STA_INFO
] &&
1206 !nla_parse_nested(sinfo
, NL80211_STA_INFO_MAX
,
1207 attr
[NL80211_ATTR_STA_INFO
], stats_policy
))
1209 if (sinfo
[NL80211_STA_INFO_SIGNAL
])
1210 e
->signal
= nla_get_u8(sinfo
[NL80211_STA_INFO_SIGNAL
]);
1212 if (sinfo
[NL80211_STA_INFO_INACTIVE_TIME
])
1213 e
->inactive
= nla_get_u32(sinfo
[NL80211_STA_INFO_INACTIVE_TIME
]);
1215 if (sinfo
[NL80211_STA_INFO_RX_PACKETS
])
1216 e
->rx_packets
= nla_get_u32(sinfo
[NL80211_STA_INFO_RX_PACKETS
]);
1218 if (sinfo
[NL80211_STA_INFO_TX_PACKETS
])
1219 e
->tx_packets
= nla_get_u32(sinfo
[NL80211_STA_INFO_TX_PACKETS
]);
1221 if (sinfo
[NL80211_STA_INFO_RX_BITRATE
] &&
1222 !nla_parse_nested(rinfo
, NL80211_RATE_INFO_MAX
,
1223 sinfo
[NL80211_STA_INFO_RX_BITRATE
], rate_policy
))
1225 if (rinfo
[NL80211_RATE_INFO_BITRATE
])
1227 nla_get_u16(rinfo
[NL80211_RATE_INFO_BITRATE
]) * 100;
1229 if (rinfo
[NL80211_RATE_INFO_MCS
])
1230 e
->rx_rate
.mcs
= nla_get_u8(rinfo
[NL80211_RATE_INFO_MCS
]);
1232 if (rinfo
[NL80211_RATE_INFO_40_MHZ_WIDTH
])
1233 e
->rx_rate
.is_40mhz
= 1;
1235 if (rinfo
[NL80211_RATE_INFO_SHORT_GI
])
1236 e
->rx_rate
.is_short_gi
= 1;
1239 if (sinfo
[NL80211_STA_INFO_TX_BITRATE
] &&
1240 !nla_parse_nested(rinfo
, NL80211_RATE_INFO_MAX
,
1241 sinfo
[NL80211_STA_INFO_TX_BITRATE
], rate_policy
))
1243 if (rinfo
[NL80211_RATE_INFO_BITRATE
])
1245 nla_get_u16(rinfo
[NL80211_RATE_INFO_BITRATE
]) * 100;
1247 if (rinfo
[NL80211_RATE_INFO_MCS
])
1248 e
->tx_rate
.mcs
= nla_get_u8(rinfo
[NL80211_RATE_INFO_MCS
]);
1250 if (rinfo
[NL80211_RATE_INFO_40_MHZ_WIDTH
])
1251 e
->tx_rate
.is_40mhz
= 1;
1253 if (rinfo
[NL80211_RATE_INFO_SHORT_GI
])
1254 e
->tx_rate
.is_short_gi
= 1;
1258 e
->noise
= 0; /* filled in by caller */
1264 int nl80211_get_assoclist(const char *ifname
, char *buf
, int *len
)
1269 struct nl80211_msg_conveyor
*req
;
1270 struct nl80211_array_buf arr
= { .buf
= buf
, .count
= 0 };
1271 struct iwinfo_assoclist_entry
*e
;
1273 if ((d
= opendir("/sys/class/net")) != NULL
)
1275 while ((de
= readdir(d
)) != NULL
)
1277 if (!strncmp(de
->d_name
, ifname
, strlen(ifname
)) &&
1278 (!de
->d_name
[strlen(ifname
)] ||
1279 !strncmp(&de
->d_name
[strlen(ifname
)], ".sta", 4)))
1281 req
= nl80211_msg(de
->d_name
, NL80211_CMD_GET_STATION
,
1286 nl80211_send(req
, nl80211_get_assoclist_cb
, &arr
);
1294 if (!nl80211_get_noise(ifname
, &noise
))
1295 for (i
= 0, e
= arr
.buf
; i
< arr
.count
; i
++, e
++)
1298 *len
= (arr
.count
* sizeof(struct iwinfo_assoclist_entry
));
1305 static int nl80211_get_txpwrlist_cb(struct nl_msg
*msg
, void *arg
)
1308 int ch_cur
, ch_cmp
, bands_remain
, freqs_remain
;
1310 struct nlattr
**attr
= nl80211_parse(msg
);
1311 struct nlattr
*bands
[NL80211_BAND_ATTR_MAX
+ 1];
1312 struct nlattr
*freqs
[NL80211_FREQUENCY_ATTR_MAX
+ 1];
1313 struct nlattr
*band
, *freq
;
1315 static struct nla_policy freq_policy
[NL80211_FREQUENCY_ATTR_MAX
+ 1] = {
1316 [NL80211_FREQUENCY_ATTR_FREQ
] = { .type
= NLA_U32
},
1317 [NL80211_FREQUENCY_ATTR_DISABLED
] = { .type
= NLA_FLAG
},
1318 [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN
] = { .type
= NLA_FLAG
},
1319 [NL80211_FREQUENCY_ATTR_NO_IBSS
] = { .type
= NLA_FLAG
},
1320 [NL80211_FREQUENCY_ATTR_RADAR
] = { .type
= NLA_FLAG
},
1321 [NL80211_FREQUENCY_ATTR_MAX_TX_POWER
] = { .type
= NLA_U32
},
1324 ch_cur
= *dbm_max
; /* value int* is initialized with channel by caller */
1327 nla_for_each_nested(band
, attr
[NL80211_ATTR_WIPHY_BANDS
], bands_remain
)
1329 nla_parse(bands
, NL80211_BAND_ATTR_MAX
, nla_data(band
),
1330 nla_len(band
), NULL
);
1332 nla_for_each_nested(freq
, bands
[NL80211_BAND_ATTR_FREQS
], freqs_remain
)
1334 nla_parse(freqs
, NL80211_FREQUENCY_ATTR_MAX
,
1335 nla_data(freq
), nla_len(freq
), freq_policy
);
1337 ch_cmp
= nl80211_freq2channel(nla_get_u32(
1338 freqs
[NL80211_FREQUENCY_ATTR_FREQ
]));
1340 if ((!ch_cur
|| (ch_cmp
== ch_cur
)) &&
1341 freqs
[NL80211_FREQUENCY_ATTR_MAX_TX_POWER
])
1343 *dbm_max
= (int)(0.01 * nla_get_u32(
1344 freqs
[NL80211_FREQUENCY_ATTR_MAX_TX_POWER
]));
1354 int nl80211_get_txpwrlist(const char *ifname
, char *buf
, int *len
)
1357 int dbm_max
= -1, dbm_cur
, dbm_cnt
;
1358 struct nl80211_msg_conveyor
*req
;
1359 struct iwinfo_txpwrlist_entry entry
;
1361 if (nl80211_get_channel(ifname
, &ch_cur
))
1364 req
= nl80211_msg(ifname
, NL80211_CMD_GET_WIPHY
, 0);
1367 /* initialize the value pointer with channel for callback */
1370 nl80211_send(req
, nl80211_get_txpwrlist_cb
, &dbm_max
);
1376 for (dbm_cur
= 0, dbm_cnt
= 0;
1378 dbm_cur
++, dbm_cnt
++)
1380 entry
.dbm
= dbm_cur
;
1381 entry
.mw
= iwinfo_dbm2mw(dbm_cur
);
1383 memcpy(&buf
[dbm_cnt
* sizeof(entry
)], &entry
, sizeof(entry
));
1386 entry
.dbm
= dbm_max
;
1387 entry
.mw
= iwinfo_dbm2mw(dbm_max
);
1389 memcpy(&buf
[dbm_cnt
* sizeof(entry
)], &entry
, sizeof(entry
));
1392 *len
= dbm_cnt
* sizeof(entry
);
1399 static void nl80211_get_scancrypto(const char *spec
,
1400 struct iwinfo_crypto_entry
*c
)
1402 if (strstr(spec
, "WPA") || strstr(spec
, "WEP"))
1406 if (strstr(spec
, "WPA2-") && strstr(spec
, "WPA-"))
1409 else if (strstr(spec
, "WPA2"))
1412 else if (strstr(spec
, "WPA"))
1415 else if (strstr(spec
, "WEP"))
1416 c
->auth_algs
= IWINFO_AUTH_OPEN
| IWINFO_AUTH_SHARED
;
1419 if (strstr(spec
, "PSK"))
1420 c
->auth_suites
|= IWINFO_KMGMT_PSK
;
1422 if (strstr(spec
, "802.1X") || strstr(spec
, "EAP"))
1423 c
->auth_suites
|= IWINFO_KMGMT_8021x
;
1425 if (strstr(spec
, "WPA-NONE"))
1426 c
->auth_suites
|= IWINFO_KMGMT_NONE
;
1429 if (strstr(spec
, "TKIP"))
1430 c
->pair_ciphers
|= IWINFO_CIPHER_TKIP
;
1432 if (strstr(spec
, "CCMP"))
1433 c
->pair_ciphers
|= IWINFO_CIPHER_CCMP
;
1435 if (strstr(spec
, "WEP-40"))
1436 c
->pair_ciphers
|= IWINFO_CIPHER_WEP40
;
1438 if (strstr(spec
, "WEP-104"))
1439 c
->pair_ciphers
|= IWINFO_CIPHER_WEP104
;
1441 c
->group_ciphers
= c
->pair_ciphers
;
1450 struct nl80211_scanlist
{
1451 struct iwinfo_scanlist_entry
*e
;
1456 static void nl80211_get_scanlist_ie(struct nlattr
**bss
,
1457 struct iwinfo_scanlist_entry
*e
)
1459 int ielen
= nla_len(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]);
1460 unsigned char *ie
= nla_data(bss
[NL80211_BSS_INFORMATION_ELEMENTS
]);
1461 static unsigned char ms_oui
[3] = { 0x00, 0x50, 0xf2 };
1463 while (ielen
>= 2 && ielen
>= ie
[1])
1468 memcpy(e
->ssid
, ie
+ 2, min(ie
[1], IWINFO_ESSID_MAX_SIZE
));
1472 iwinfo_parse_rsn(&e
->crypto
, ie
+ 2, ie
[1],
1473 IWINFO_CIPHER_CCMP
, IWINFO_KMGMT_8021x
);
1476 case 221: /* Vendor */
1477 if (ie
[1] >= 4 && !memcmp(ie
+ 2, ms_oui
, 3) && ie
[5] == 1)
1478 iwinfo_parse_rsn(&e
->crypto
, ie
+ 6, ie
[1] - 4,
1479 IWINFO_CIPHER_TKIP
, IWINFO_KMGMT_PSK
);
1488 static int nl80211_get_scanlist_cb(struct nl_msg
*msg
, void *arg
)
1493 struct nl80211_scanlist
*sl
= arg
;
1494 struct nlattr
**tb
= nl80211_parse(msg
);
1495 struct nlattr
*bss
[NL80211_BSS_MAX
+ 1];
1497 static struct nla_policy bss_policy
[NL80211_BSS_MAX
+ 1] = {
1498 [NL80211_BSS_TSF
] = { .type
= NLA_U64
},
1499 [NL80211_BSS_FREQUENCY
] = { .type
= NLA_U32
},
1500 [NL80211_BSS_BSSID
] = { },
1501 [NL80211_BSS_BEACON_INTERVAL
] = { .type
= NLA_U16
},
1502 [NL80211_BSS_CAPABILITY
] = { .type
= NLA_U16
},
1503 [NL80211_BSS_INFORMATION_ELEMENTS
] = { },
1504 [NL80211_BSS_SIGNAL_MBM
] = { .type
= NLA_U32
},
1505 [NL80211_BSS_SIGNAL_UNSPEC
] = { .type
= NLA_U8
},
1506 [NL80211_BSS_STATUS
] = { .type
= NLA_U32
},
1507 [NL80211_BSS_SEEN_MS_AGO
] = { .type
= NLA_U32
},
1508 [NL80211_BSS_BEACON_IES
] = { },
1511 if (!tb
[NL80211_ATTR_BSS
] ||
1512 nla_parse_nested(bss
, NL80211_BSS_MAX
, tb
[NL80211_ATTR_BSS
],
1514 !bss
[NL80211_BSS_BSSID
])
1519 if (bss
[NL80211_BSS_CAPABILITY
])
1520 caps
= nla_get_u16(bss
[NL80211_BSS_CAPABILITY
]);
1524 memset(sl
->e
, 0, sizeof(*sl
->e
));
1525 memcpy(sl
->e
->mac
, nla_data(bss
[NL80211_BSS_BSSID
]), 6);
1528 sl
->e
->mode
= IWINFO_OPMODE_ADHOC
;
1530 sl
->e
->mode
= IWINFO_OPMODE_MASTER
;
1533 sl
->e
->crypto
.enabled
= 1;
1535 if (bss
[NL80211_BSS_FREQUENCY
])
1536 sl
->e
->channel
= nl80211_freq2channel(nla_get_u32(
1537 bss
[NL80211_BSS_FREQUENCY
]));
1539 if (bss
[NL80211_BSS_INFORMATION_ELEMENTS
])
1540 nl80211_get_scanlist_ie(bss
, sl
->e
);
1542 if (bss
[NL80211_BSS_SIGNAL_MBM
])
1544 sl
->e
->signal
= nla_get_u32(bss
[NL80211_BSS_SIGNAL_MBM
]) / 100;
1546 rssi
= sl
->e
->signal
- 0x100;
1550 else if (rssi
> -40)
1553 sl
->e
->quality
= (rssi
+ 110);
1554 sl
->e
->quality_max
= 70;
1557 if (sl
->e
->crypto
.enabled
&& !sl
->e
->crypto
.wpa_version
)
1559 sl
->e
->crypto
.auth_algs
= IWINFO_AUTH_OPEN
| IWINFO_AUTH_SHARED
;
1560 sl
->e
->crypto
.pair_ciphers
= IWINFO_CIPHER_WEP40
| IWINFO_CIPHER_WEP104
;
1569 static int nl80211_get_scanlist_nl(const char *ifname
, char *buf
, int *len
)
1571 struct nl80211_msg_conveyor
*req
;
1572 struct nl80211_scanlist sl
= { .e
= (struct iwinfo_scanlist_entry
*)buf
};
1574 req
= nl80211_msg(ifname
, NL80211_CMD_TRIGGER_SCAN
, 0);
1577 nl80211_send(req
, NULL
, NULL
);
1581 nl80211_wait("nl80211", "scan", NL80211_CMD_NEW_SCAN_RESULTS
);
1583 req
= nl80211_msg(ifname
, NL80211_CMD_GET_SCAN
, NLM_F_DUMP
);
1586 nl80211_send(req
, nl80211_get_scanlist_cb
, &sl
);
1590 *len
= sl
.len
* sizeof(struct iwinfo_scanlist_entry
);
1591 return *len
? 0 : -1;
1594 int nl80211_get_scanlist(const char *ifname
, char *buf
, int *len
)
1596 int freq
, rssi
, qmax
, count
;
1598 char ssid
[128] = { 0 };
1599 char bssid
[18] = { 0 };
1600 char cipher
[256] = { 0 };
1602 /* Got a radioX pseudo interface, find some interface on it or create one */
1603 if (!strncmp(ifname
, "radio", 5))
1605 /* Reuse existing interface */
1606 if ((res
= nl80211_phy2ifname(ifname
)) != NULL
)
1608 return nl80211_get_scanlist(res
, buf
, len
);
1611 /* Need to spawn a temporary iface for scanning */
1612 else if ((res
= nl80211_ifadd(ifname
)) != NULL
)
1614 count
= nl80211_get_scanlist(res
, buf
, len
);
1620 struct iwinfo_scanlist_entry
*e
= (struct iwinfo_scanlist_entry
*)buf
;
1622 /* WPA supplicant */
1623 if ((res
= nl80211_wpactl_info(ifname
, "SCAN", "CTRL-EVENT-SCAN-RESULTS")))
1625 if ((res
= nl80211_wpactl_info(ifname
, "SCAN_RESULTS", NULL
)))
1627 nl80211_get_quality_max(ifname
, &qmax
);
1629 /* skip header line */
1630 while (*res
++ != '\n');
1634 while (sscanf(res
, "%17s %d %d %255s%*[ \t]%127[^\n]\n",
1635 bssid
, &freq
, &rssi
, cipher
, ssid
) > 0)
1638 e
->mac
[0] = strtol(&bssid
[0], NULL
, 16);
1639 e
->mac
[1] = strtol(&bssid
[3], NULL
, 16);
1640 e
->mac
[2] = strtol(&bssid
[6], NULL
, 16);
1641 e
->mac
[3] = strtol(&bssid
[9], NULL
, 16);
1642 e
->mac
[4] = strtol(&bssid
[12], NULL
, 16);
1643 e
->mac
[5] = strtol(&bssid
[15], NULL
, 16);
1646 memcpy(e
->ssid
, ssid
, min(strlen(ssid
), sizeof(e
->ssid
) - 1));
1648 /* Mode (assume master) */
1649 e
->mode
= IWINFO_OPMODE_MASTER
;
1652 e
->channel
= nl80211_freq2channel(freq
);
1660 /* The cfg80211 wext compat layer assumes a signal range
1661 * of -110 dBm to -40 dBm, the quality value is derived
1662 * by adding 110 to the signal level */
1665 else if (rssi
> -40)
1668 e
->quality
= (rssi
+ 110);
1676 e
->quality_max
= qmax
;
1679 nl80211_get_scancrypto(cipher
, &e
->crypto
);
1681 /* advance to next line */
1682 while (*res
&& *res
++ != '\n');
1687 memset(ssid
, 0, sizeof(ssid
));
1688 memset(bssid
, 0, sizeof(bssid
));
1689 memset(cipher
, 0, sizeof(cipher
));
1692 *len
= count
* sizeof(struct iwinfo_scanlist_entry
);
1700 /* Got a temp interface, don't create yet another one */
1701 if (!strncmp(ifname
, "tmp.", 4))
1703 if (!iwinfo_ifup(ifname
))
1706 nl80211_get_scanlist_nl(ifname
, buf
, len
);
1707 iwinfo_ifdown(ifname
);
1711 /* Spawn a new scan interface */
1714 if (!(res
= nl80211_ifadd(ifname
)))
1717 if (!iwinfo_ifmac(res
))
1720 /* if we can take the new interface up, the driver supports an
1721 * additional interface and there's no need to tear down the ap */
1722 if (iwinfo_ifup(res
))
1724 nl80211_get_scanlist_nl(res
, buf
, len
);
1728 /* driver cannot create secondary interface, take down ap
1730 else if (iwinfo_ifdown(ifname
) && iwinfo_ifup(res
))
1732 nl80211_get_scanlist_nl(res
, buf
, len
);
1734 iwinfo_ifup(ifname
);
1735 nl80211_hostapd_hup(ifname
);
1747 static int nl80211_get_freqlist_cb(struct nl_msg
*msg
, void *arg
)
1749 int bands_remain
, freqs_remain
;
1751 struct nl80211_array_buf
*arr
= arg
;
1752 struct iwinfo_freqlist_entry
*e
= arr
->buf
;
1754 struct nlattr
**attr
= nl80211_parse(msg
);
1755 struct nlattr
*bands
[NL80211_BAND_ATTR_MAX
+ 1];
1756 struct nlattr
*freqs
[NL80211_FREQUENCY_ATTR_MAX
+ 1];
1757 struct nlattr
*band
, *freq
;
1759 static struct nla_policy freq_policy
[NL80211_FREQUENCY_ATTR_MAX
+ 1] = {
1760 [NL80211_FREQUENCY_ATTR_FREQ
] = { .type
= NLA_U32
},
1761 [NL80211_FREQUENCY_ATTR_DISABLED
] = { .type
= NLA_FLAG
},
1762 [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN
] = { .type
= NLA_FLAG
},
1763 [NL80211_FREQUENCY_ATTR_NO_IBSS
] = { .type
= NLA_FLAG
},
1764 [NL80211_FREQUENCY_ATTR_RADAR
] = { .type
= NLA_FLAG
},
1765 [NL80211_FREQUENCY_ATTR_MAX_TX_POWER
] = { .type
= NLA_U32
},
1768 nla_for_each_nested(band
, attr
[NL80211_ATTR_WIPHY_BANDS
], bands_remain
)
1770 nla_parse(bands
, NL80211_BAND_ATTR_MAX
,
1771 nla_data(band
), nla_len(band
), NULL
);
1773 nla_for_each_nested(freq
, bands
[NL80211_BAND_ATTR_FREQS
], freqs_remain
)
1775 nla_parse(freqs
, NL80211_FREQUENCY_ATTR_MAX
,
1776 nla_data(freq
), nla_len(freq
), NULL
);
1778 if (!freqs
[NL80211_FREQUENCY_ATTR_FREQ
] ||
1779 freqs
[NL80211_FREQUENCY_ATTR_DISABLED
])
1782 e
->mhz
= nla_get_u32(freqs
[NL80211_FREQUENCY_ATTR_FREQ
]);
1783 e
->channel
= nl80211_freq2channel(e
->mhz
);
1786 freqs
[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN
] ||
1787 freqs
[NL80211_FREQUENCY_ATTR_NO_IBSS
] ||
1788 freqs
[NL80211_FREQUENCY_ATTR_RADAR
]
1799 int nl80211_get_freqlist(const char *ifname
, char *buf
, int *len
)
1801 struct nl80211_msg_conveyor
*req
;
1802 struct nl80211_array_buf arr
= { .buf
= buf
, .count
= 0 };
1804 req
= nl80211_msg(ifname
, NL80211_CMD_GET_WIPHY
, 0);
1807 nl80211_send(req
, nl80211_get_freqlist_cb
, &arr
);
1813 *len
= arr
.count
* sizeof(struct iwinfo_freqlist_entry
);
1820 static int nl80211_get_country_cb(struct nl_msg
*msg
, void *arg
)
1823 struct nlattr
**attr
= nl80211_parse(msg
);
1825 if (attr
[NL80211_ATTR_REG_ALPHA2
])
1826 memcpy(buf
, nla_data(attr
[NL80211_ATTR_REG_ALPHA2
]), 2);
1833 int nl80211_get_country(const char *ifname
, char *buf
)
1836 struct nl80211_msg_conveyor
*req
;
1838 req
= nl80211_msg(ifname
, NL80211_CMD_GET_REG
, 0);
1841 nl80211_send(req
, nl80211_get_country_cb
, buf
);
1851 int nl80211_get_countrylist(const char *ifname
, char *buf
, int *len
)
1854 struct iwinfo_country_entry
*e
= (struct iwinfo_country_entry
*)buf
;
1855 const struct iwinfo_iso3166_label
*l
;
1857 for (l
= IWINFO_ISO3166_NAMES
, count
= 0; l
->iso3166
; l
++, e
++, count
++)
1859 e
->iso3166
= l
->iso3166
;
1860 e
->ccode
[0] = (l
->iso3166
/ 256);
1861 e
->ccode
[1] = (l
->iso3166
% 256);
1864 *len
= (count
* sizeof(struct iwinfo_country_entry
));
1868 static int nl80211_get_hwmodelist_cb(struct nl_msg
*msg
, void *arg
)
1871 int bands_remain
, freqs_remain
;
1873 struct nlattr
**attr
= nl80211_parse(msg
);
1874 struct nlattr
*bands
[NL80211_BAND_ATTR_MAX
+ 1];
1875 struct nlattr
*freqs
[NL80211_FREQUENCY_ATTR_MAX
+ 1];
1876 struct nlattr
*band
, *freq
;
1880 if (attr
[NL80211_ATTR_WIPHY_BANDS
])
1882 nla_for_each_nested(band
, attr
[NL80211_ATTR_WIPHY_BANDS
], bands_remain
)
1884 nla_parse(bands
, NL80211_BAND_ATTR_MAX
,
1885 nla_data(band
), nla_len(band
), NULL
);
1887 if (bands
[NL80211_BAND_ATTR_HT_CAPA
])
1888 caps
= nla_get_u16(bands
[NL80211_BAND_ATTR_HT_CAPA
]);
1890 /* Treat any nonzero capability as 11n */
1892 *modes
|= IWINFO_80211_N
;
1894 nla_for_each_nested(freq
, bands
[NL80211_BAND_ATTR_FREQS
],
1897 nla_parse(freqs
, NL80211_FREQUENCY_ATTR_MAX
,
1898 nla_data(freq
), nla_len(freq
), NULL
);
1900 if (!freqs
[NL80211_FREQUENCY_ATTR_FREQ
])
1903 if (nla_get_u32(freqs
[NL80211_FREQUENCY_ATTR_FREQ
]) < 2485)
1905 *modes
|= IWINFO_80211_B
;
1906 *modes
|= IWINFO_80211_G
;
1910 *modes
|= IWINFO_80211_A
;
1919 int nl80211_get_hwmodelist(const char *ifname
, int *buf
)
1921 struct nl80211_msg_conveyor
*req
;
1923 req
= nl80211_msg(ifname
, NL80211_CMD_GET_WIPHY
, 0);
1926 nl80211_send(req
, nl80211_get_hwmodelist_cb
, buf
);
1930 return *buf
? 0 : -1;
1933 int nl80211_get_mbssid_support(const char *ifname
, int *buf
)
1935 /* Test whether we can create another interface */
1936 char *nif
= nl80211_ifadd(ifname
);
1940 *buf
= (iwinfo_ifmac(nif
) && iwinfo_ifup(nif
));
1951 int nl80211_get_hardware_id(const char *ifname
, char *buf
)
1956 /* Got a radioX pseudo interface, find some interface on it or create one */
1957 if (!strncmp(ifname
, "radio", 5))
1959 /* Reuse existing interface */
1960 if ((res
= nl80211_phy2ifname(ifname
)) != NULL
)
1962 rv
= wext_get_hardware_id(res
, buf
);
1965 /* Need to spawn a temporary iface for finding IDs */
1966 else if ((res
= nl80211_ifadd(ifname
)) != NULL
)
1968 rv
= wext_get_hardware_id(res
, buf
);
1974 rv
= wext_get_hardware_id(ifname
, buf
);
1977 /* Failed to obtain hardware IDs, search board config */
1980 rv
= iwinfo_hardware_id_from_mtd((struct iwinfo_hardware_id
*)buf
);
1986 static const struct iwinfo_hardware_entry
*
1987 nl80211_get_hardware_entry(const char *ifname
)
1989 struct iwinfo_hardware_id id
;
1991 if (nl80211_get_hardware_id(ifname
, (char *)&id
))
1994 return iwinfo_hardware(&id
);
1997 int nl80211_get_hardware_name(const char *ifname
, char *buf
)
1999 const struct iwinfo_hardware_entry
*hw
;
2001 if (!(hw
= nl80211_get_hardware_entry(ifname
)))
2002 sprintf(buf
, "Generic MAC80211");
2004 sprintf(buf
, "%s %s", hw
->vendor_name
, hw
->device_name
);
2009 int nl80211_get_txpower_offset(const char *ifname
, int *buf
)
2011 const struct iwinfo_hardware_entry
*hw
;
2013 if (!(hw
= nl80211_get_hardware_entry(ifname
)))
2016 *buf
= hw
->txpower_offset
;
2020 int nl80211_get_frequency_offset(const char *ifname
, int *buf
)
2022 const struct iwinfo_hardware_entry
*hw
;
2024 if (!(hw
= nl80211_get_hardware_entry(ifname
)))
2027 *buf
= hw
->frequency_offset
;