📄 iw-json.c.svn-base
字号:
/*
* iw-info. Outputs wireless interface list in JSON format.
*
* Based on Wireless Tools, see
* <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html/>
*
* Copyright (c) 1997-2007 Jean Tourrilhes <jt@hpl.hp.com>
* Copyright (C) 2008 OpenRB.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __user
#define __user
#endif
#ifndef IW_QUAL_RCPI
#define IW_QUAL_RCPI 0x80
#endif
#define KILO 1e3
#define MEGA 1e6
#define GIGA 1e9
#define IW_NUM_OPER_MODE 7
#define PROC_NET_WIRELESS "/proc/net/wireless"
#define LOG10_MAGIC 1.25892541179
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <errno.h>
#include <sys/types.h>
#include <linux/types.h>
#include <net/ethernet.h>
#include <wireless.h>
typedef struct iw_statistics iwstats;
typedef struct iw_range iwrange;
typedef struct iw_param iwparam;
typedef struct iw_freq iwfreq;
typedef struct iw_quality iwqual;
typedef struct iw_priv_args iwprivargs;
typedef struct sockaddr sockaddr;
typedef struct wireless_config {
char name[IFNAMSIZ + 1];
int has_nwid;
iwparam nwid;
int has_freq;
double freq;
int freq_flags;
int has_key;
unsigned char key[IW_ENCODING_TOKEN_MAX];
int key_size;
int key_flags;
int has_essid;
int essid_on;
char essid[IW_ESSID_MAX_SIZE + 1];
int has_mode;
int mode;
} wireless_config;
typedef struct wireless_info {
struct wireless_config b;
int has_sens;
iwparam sens;
int has_nickname;
char nickname[IW_ESSID_MAX_SIZE + 1];
int has_ap_addr;
sockaddr ap_addr;
int has_bitrate;
iwparam bitrate;
int has_power;
iwparam power;
int has_txpower;
iwparam txpower;
int has_stats;
iwstats stats;
int has_range;
iwrange range;
} wireless_info;
const char * const iw_operation_mode[] = {
"auto",
"adhoc",
"sta",
"ap",
"repeater",
"secondary",
"monitor",
"unknown"
};
inline int iw_get_ext(int skfd, const char * ifname, int request, struct iwreq * pwrq) {
strncpy(pwrq->ifr_name, ifname, IFNAMSIZ);
return(ioctl(skfd, request, pwrq));
}
inline int iw_ether_cmp(const struct ether_addr* eth1, const struct ether_addr* eth2) {
return memcmp(eth1, eth2, sizeof(*eth1));
}
inline char * iw_get_ifname(char * name, int nsize, char * buf) {
char * end;
while (isspace(*buf)) {
buf++;
}
end = strstr(buf, ": ");
if((end == NULL) || (((end - buf) + 1) > nsize)) {
return NULL;
}
memcpy(name, buf, (end - buf));
name[end - buf] = '\0';
return end;
}
int iw_get_range_info(int skfd, const char * ifname, iwrange * range) {
struct iwreq wrq;
char buffer[sizeof(iwrange) * 2];
/* Cleanup */
bzero(buffer, sizeof(buffer));
wrq.u.data.pointer = (caddr_t) buffer;
wrq.u.data.length = sizeof(buffer);
wrq.u.data.flags = 0;
if (iw_get_ext(skfd, ifname, SIOCGIWRANGE, &wrq) < 0) {
return -1;
}
memcpy((char *) range, buffer, sizeof(iwrange));
return 0;
}
int iw_get_stats(int skfd, const char * ifname, iwstats * stats, const iwrange * range) {
struct iwreq wrq;
wrq.u.data.pointer = (caddr_t) stats;
wrq.u.data.length = sizeof(struct iw_statistics);
wrq.u.data.flags = 1;
strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
if (iw_get_ext(skfd, ifname, SIOCGIWSTATS, &wrq) < 0) {
return -1;
}
return 0;
}
int iw_sockets_open(void) {
static const int families[] = {
AF_INET, AF_IPX, AF_AX25, AF_APPLETALK
};
unsigned int i;
int sock;
for(i = 0; i < sizeof(families)/sizeof(int); ++i) {
sock = socket(families[i], SOCK_DGRAM, 0);
if(sock >= 0) {
return sock;
}
}
return -1;
}
double iw_freq2float(const iwfreq * in) {
int i;
double res = (double) in->m;
for(i = 0; i < in->e; i++) {
res *= 10;
}
return res;
}
int iw_channel_to_freq(int channel, double * pfreq, const struct iw_range * range) {
int has_freq = 0;
int k;
/* Check if the driver support only channels or if it has frequencies */
for(k = 0; k < range->num_frequency; k++) {
if((range->freq[k].e != 0) || (range->freq[k].m > (int) KILO)) {
has_freq = 1;
}
}
if (!has_freq) {
return -1;
}
/* Find the correct frequency in the list */
for(k = 0; k < range->num_frequency; k++) {
if(range->freq[k].i == channel) {
*pfreq = iw_freq2float(&(range->freq[k]));
return channel;
}
}
return -2;
}
int iw_mwatt2dbm(int in) {
double fin = (double) in;
int res = 0;
while (fin > 10.0) {
res += 10;
fin /= 10.0;
}
while(fin > 1.000001) {
res += 1;
fin /= LOG10_MAGIC;
}
return res;
}
int iw_get_basic_config(int skfd, const char * ifname, wireless_config * info) {
struct iwreq wrq;
memset((char *) info, 0, sizeof(struct wireless_config));
/* Get wireless name */
if (iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0) {
return -1;
}
else {
strncpy(info->name, wrq.u.name, IFNAMSIZ);
info->name[IFNAMSIZ] = '\0';
}
/* Get network ID */
if (iw_get_ext(skfd, ifname, SIOCGIWNWID, &wrq) >= 0) {
info->has_nwid = 1;
memcpy(&(info->nwid), &(wrq.u.nwid), sizeof(iwparam));
}
/* Get frequency / channel */
if (iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) >= 0) {
info->has_freq = 1;
info->freq = iw_freq2float(&(wrq.u.freq));
info->freq_flags = wrq.u.freq.flags;
}
/* Get encryption information */
wrq.u.data.pointer = (caddr_t) info->key;
wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
wrq.u.data.flags = 0;
if (iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) >= 0) {
info->has_key = 1;
info->key_size = wrq.u.data.length;
info->key_flags = wrq.u.data.flags;
}
/* Get ESSID */
wrq.u.essid.pointer = (caddr_t) info->essid;
wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
wrq.u.essid.flags = 0;
if (iw_get_ext(skfd, ifname, SIOCGIWESSID, &wrq) >= 0) {
info->has_essid = 1;
info->essid_on = wrq.u.data.flags;
}
/* Get operation mode */
if (iw_get_ext(skfd, ifname, SIOCGIWMODE, &wrq) >= 0) {
info->has_mode = 1;
/* Note : event->u.mode is unsigned, no need to check <= 0 */
if (wrq.u.mode < IW_NUM_OPER_MODE) {
info->mode = wrq.u.mode;
}
else {
info->mode = IW_NUM_OPER_MODE;
}
}
return 0;
}
void iw_print_escaped(const char * raw) {
int i, len = strlen(raw);
char c;
putchar('"');
for (i = 0; i < len; i++) {
c = raw[i];
if (c > 31 && c < 127) {
if (c == '"' || c == '\\') {
putchar('\\');
}
putchar(c);
}
}
putchar('"');
}
int get_info(int skfd, char * ifname, struct wireless_info * info) {
struct iwreq wrq;
memset((char *) info, 0, sizeof(struct wireless_info));
if (iw_get_basic_config(skfd, ifname, &(info->b)) < 0) {
struct ifreq ifr;
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
return (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) ? -ENODEV : -ENOTSUP;
}
if(iw_get_range_info(skfd, ifname, &(info->range)) >= 0) {
info->has_range = 1;
}
/* Get AP address */
if (iw_get_ext(skfd, ifname, SIOCGIWAP, &wrq) >= 0) {
info->has_ap_addr = 1;
memcpy(&(info->ap_addr), &(wrq.u.ap_addr), sizeof (sockaddr));
}
/* Get bit rate */
if (iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) >= 0) {
info->has_bitrate = 1;
memcpy(&(info->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
}
/* Get stats */
if (iw_get_stats(skfd, ifname, &(info->stats), &info->range) >= 0) {
info->has_stats = 1;
}
/* Get NickName */
wrq.u.essid.pointer = (caddr_t) info->nickname;
wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
wrq.u.essid.flags = 0;
if (iw_get_ext(skfd, ifname, SIOCGIWNICKN, &wrq) >= 0 && wrq.u.data.length > 1) {
info->has_nickname = 1;
}
/* tx power */
if (info->has_range && iw_get_ext(skfd, ifname, SIOCGIWTXPOW, &wrq) >= 0) {
info->has_txpower = 1;
memcpy(&(info->txpower), &(wrq.u.txpower), sizeof(iwparam));
}
return 0;
}
char * get_ieee(const char * bname) {
char buf[ IFNAMSIZ + 1];
char * res;
int i = 1, s = 9;
buf[0] = '"';
while (i < (IFNAMSIZ - 2) && bname[s] ) {
buf[i++] = bname[s++];
}
if (i == 1) {
sprintf (buf, "null");
}
else {
buf[i++] = '"';
buf[i] = '\0';
}
res = (char *) malloc(strlen(buf) + 1);
return strcpy(res, buf);
}
void display_info(struct wireless_info * info, char * ifname) {
printf("\"%s\": {\"ieee\": %s", ifname, get_ieee(info->b.name) );
/* Display ESSID */
if (info->b.has_essid && info->b.essid_on) {
printf(", \"ssid\": ");
iw_print_escaped(info->b.essid);
}
/* Display NickName */
if (info->has_nickname && info->nickname) {
printf(", \"nickname\": ");
iw_print_escaped(info->nickname);
}
/* Display the current mode of operation */
if (info->b.has_mode) {
printf(", \"mode\": \"%s\"", iw_operation_mode[info->b.mode]);
}
/* Display frequency / channel */
if (info->b.has_freq) {
double freq = info->b.freq;
int channel = -1;
if (info->has_range && (freq < KILO)) {
channel = iw_channel_to_freq((int) freq, &freq, &info->range);
}
printf(", \"freq\": %g", (freq < KILO ? freq : freq / MEGA));
}
/* Display the address of the current Access Point */
if (info->has_ap_addr) {
if ((info->b.has_mode) && (info->b.mode == IW_MODE_ADHOC)) {
printf(", \"cell\": ");
}
else {
printf(", \"ap\": ");
}
const struct ether_addr ether_zero = {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }};
const struct ether_addr ether_bcast = {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }};
const struct ether_addr * ether_wap = (const struct ether_addr *) info->ap_addr.sa_data;
if (!iw_ether_cmp(ether_wap, ðer_zero) || !iw_ether_cmp(ether_wap, ðer_bcast)) {
printf("null");
}
else {
printf("\"%02X:%02X:%02X:%02X:%02X:%02X\"",
ether_wap->ether_addr_octet[0], ether_wap->ether_addr_octet[1], ether_wap->ether_addr_octet[2],
ether_wap->ether_addr_octet[3], ether_wap->ether_addr_octet[4], ether_wap->ether_addr_octet[5]);
}
}
/* Display the currently used/set bit-rate */
if (info->has_bitrate) {
printf(", \"bitrate\": %.2f", info->bitrate.value / MEGA);
}
/* Display the Transmit Power */
if (info->has_txpower && !info->txpower.disabled) {
int dbm;
if (info->txpower.flags & IW_TXPOW_MWATT) {
dbm = iw_mwatt2dbm(info->txpower.value);
}
else {
dbm = info->txpower.value;
}
printf(", \"txpower\": %d", dbm);
}
/* Display encryption information */
if (info->b.has_key) {
if ((info->b.key_flags & IW_ENCODE_DISABLED) || (info->b.key_size == 0)) {
printf(", \"security\": null");
}
else {
if (info->b.key_flags & IW_ENCODE_RESTRICTED) {
printf(", \"security\": \"restricted\"");
}
else if (info->b.key_flags & IW_ENCODE_OPEN) {
printf(", \"security\": \"open\"");
}
}
}
/* Display statistics */
if (info->has_stats) {
if (info->has_range && ((info->stats.qual.level != 0) || (info->stats.qual.updated & (IW_QUAL_DBM | IW_QUAL_RCPI)))) {
if (!(info->stats.qual.updated & IW_QUAL_QUAL_INVALID)) {
printf(", \"quality\": %d, \"maxquality\": %d", info->stats.qual.qual, info->range.max_qual.qual);
}
}
else {
printf(", \"quality\": %d", info->stats.qual.qual);
}
}
printf("}");
}
int print_info(int skfd, char * ifname) {
struct wireless_info info;
int rc = get_info(skfd, ifname, &info);
if (!rc) {
display_info(&info, ifname);
}
return rc;
}
int main(void) {
char buff[1024];
FILE * fh;
int skfd, first = 1;
/* Create a channel to the NET kernel. */
if ((skfd = iw_sockets_open()) < 0) {
perror("socket");
exit(-1);
}
printf("{");
fh = fopen(PROC_NET_WIRELESS, "r");
if (fh != NULL) {
/* Success : use data from /proc/net/wireless */
fgets(buff, sizeof(buff), fh);
fgets(buff, sizeof(buff), fh);
/* Read each device line */
while (fgets(buff, sizeof(buff), fh)) {
char name[IFNAMSIZ + 1];
char *s;
if ((buff[0] == '\0') || (buff[1] == '\0')) {
continue;
}
s = iw_get_ifname(name, sizeof(name), buff);
if (s) {
if (first) {
first = 0;
}
else {
printf(", ");
}
print_info(skfd, name);
}
}
fclose(fh);
}
printf("}");
close(skfd);
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -