libiw中的函数说明

Search for a command to run...

No comments yet. Be the first to comment.
在这个系列中,主要讨论在Linux下的socket编程,有基本的socket编程文章,有讨论raw socket编程的文章,有在应用层编程的文章,也有一些面向数据链路层的编程文章;部分文章涉及IPv6和netlink,大多数文章均附有完整的C语言源代码。
使用工具软件扫描 wifi 信号是一件很平常的事情,在知晓 wifi 密码的前提下,通常我们会尽可能地连接信号质量比较好的 wifi 信号,但是如何通过编程来扫描 wifi 信号并获得这些信号的属性(比如信号强度等),却鲜有文章提及,本文在前面博文的基础上通过实例向读者介绍如何通过编程扫描 wifi 信号,并获得信号的一系列的属性,本文给出了完整的源代码,本文程序在 ubuntu 20.04 下编译测试完成,gcc 版本号 9.4.0;阅读本文并不需要对 IEEE802.11 协议有所了解,但本...
双向链表是一种比单向链表更为灵活的数据结构,与单向链表相比可以有更多的应用场景,本文讨论双向链表的基本概念及实现方法,并着重介绍使用GLib的GList实现单向链表的方法及步骤,本文给出了多个实际范例源代码,旨在帮助学习基于GLib编程的读者较快地掌握GList的使用方法,本文程序在 ubuntu 20.04 下编译测试完成,gcc 版本号 9.4.0;本文适合初学者阅读。 1 双向链表及其实现 在文章《单向链表以及如何使用GLib中的GSList实现单向链表》中,介绍了单向链表以及基于 G...

C 编程框架是开发人员必不可少的工具,编程框架可以为构建强大且性能优异的应用程序提供结构化的基础,本文将对 8 个最佳 C 编程框架和库做出简要的介绍,如果您正在寻找适合初学者的 C 编程框架或旨在进行 C 编程框架比较,相信本文可以给您一定的帮助。 顶级 C 编程框架 – 概述 本文将介绍以下 8 个 C 语言编程框架: 序号框架名称主要特点易于集成下载链接 1GTK全面的小部件集,跨平台支持中等的下载 2Qt跨平台支持,集成开发环境中等的下载 3CMocka轻量级,模...

单向链表是一种基础的数据结构,也是一种简单而灵活的数据结构,本文讨论单向链表的基本概念及实现方法,并着重介绍使用GLib的GSList实现单向链表的方法及步骤,本文给出了多个实际范例源代码,旨在帮助学习基于GLib编程的读者较快地掌握GSList的使用方法,本文程序在 ubuntu 20.04 下编译测试完成,gcc 版本号 9.4.0;本文适合初学者阅读。 1 单向链表及其实现 在文章《使用GLib进行C语言编程的实例》中,简单介绍了 GLib,建议阅读本文前先阅读这篇文章; 单向链表是一...

本文将讨论使用GLib进行编程的基本步骤,GLib是一个跨平台的,用C语言编写的3个底层库(以前是5个)的集合,GLib提供了多种高级的数据结构,如内存块、双向和单向链表、哈希表等,GLib还实现了线程相关的函数、多线程编程以及相关的工具,例如原始变量访问、互斥锁、异步队列等,GLib主要由GNOME开发;本文是使用GLib编程的入门文章,旨在通过实例帮助希望学习GLib编程的读者较快地入门,本文将给出多个使用GLib库编程范例的源代码,本文程序在 ubuntu 20.04 下编译测试完成,gc...

打开电脑连接wifi是一件很平常的事情,但这些事情通常都是操作系统下的wifi管理程序替我们完成的,如何在程序中扫描wifi信号其实资料并不多,前面已经有两篇文章介绍了如何使用ioctl()扫描wifi信号,但其实在Linux下有一个简单的库对这些ioctl()的操作进行了封装,这个库就是libiw,使用libiw可以简化编程,本文介绍了如果使用libiw对wifi信号进行扫描的基本方法,本文将给出完整的源代码,本文程序在 ubuntu 20.04 下编译测试完成,gcc 版本号 9.4.0;尽...

打开电脑连接wifi是一件很平常的事情,但这些事情通常都是操作系统下的wifi管理程序替我们完成的,如何在程序中连接指定的wifi其实很少有资料介绍,在网络专栏的文章中,有两篇是关于wfi编程的文章,其中对无线网卡的操作都是通过ioctl()完成的,显得有些繁琐和晦涩,但其实WE(Wireless Extensions)有一个简单的库libiw,这个库的实现也是使用ioctl(),但是经过封装后,会使wifi编程变得容易一些,本文为一篇资料类的文章,主要描述libiw中API的调用方法。
本文是通过阅读 libiw 的源码 iwlib.c 和 iwlib.h 以及一些 wifi 工具软件的源码总结而成;
项目 Wireless Tools 中的 iwlib.c 和 iwlib.h 组成了 libiw
git clone https://github.com/HewlettPackard/wireless-tools
gcc -Os -W -Wall -Wstrict-prototypes -Wmissing-prototypes -Wshadow -Wpointer-arith -Wcast-qual -Winline -I. -MMD -fPIC -c -o iwlib.so iwlib.c
gcc -shared -o libiw.so.29 -Wl,-soname,libiw.so.29 -lm -lc iwlib.so
编译静态库 libiw.a
rm -f libiw.a
ar cru libiw.a iwlib.so
ranlib libiw.a
在 ubuntu 上,要使用 libiw 需要单独安装,安装方法非常容易:
sudo apt update
sudo apt install libiw-dev
要说明的是,使用 apt 安装的 libiw,看到的动态链接库为 libiw.so.30,但是使用这个项目的开源版本编译出来的动态链接库为 libiw.so.29,版本略有不同,从 iwlib.h 看,libiw.so.30 更新于 2009 年,而开源项目的源代码更新于 2007 年,二者还是有一些差距的;
libiw.h 看,libiw.so.30 中包含了一些 libiw.so.29 中没有的函数,但总体看,区别不是很大。int iw_sockets_open(void);void iw_enum_devices(int skfd, iw_enum_handler fn, char *args[], int count);int iw_get_kernel_we_version(void);int iw_print_version_info(const char *toolname);int iw_get_range_info(int skfd, const char *ifname, iwrange *range);int iw_get_priv_info(int skfd, const char *ifname, iwprivargs ** ppriv);int iw_get_basic_config(int skfd, const char *ifname, wireless_config *info);int iw_set_basic_config(int skfd, const char *ifname, wireless_config *info);int iw_protocol_compare(const char *protocol1, const char *protocol2);void iw_essid_escape(char *dest, const char *src, const int slen);int iw_essid_unescape(char *dest, const char *src);void iw_float2freq(double in, iwfreq *out);double iw_freq2float(const iwfreq *in);void iw_print_freq_value(char *buffer, int buflen, double freq);void iw_print_freq(char *buffer, int buflen, double freq, int channel, int freq_flags);int iw_freq_to_channel(double freq, const struct iw_range *range);int iw_channel_to_freq(int channel, double *pfreq, const struct iw_range *range);void iw_print_bitrate(char *buffer, int buflen, int bitrate);int iw_dbm2mwatt(int in);int iw_mwatt2dbm(int in);void iw_print_txpower(char *buffer, int buflen, struct iw_param *txpower);int iw_get_stats(int skfd, const char *ifname, iwstats *stats, const iwrange *range, int has_range);void iw_print_stats(char *buffer, int buflen, const iwqual *qual, const iwrange *range, int has_range);void iw_print_key(char *buffer, int buflen, const unsigned char *key, int key_size, int key_flags);int iw_in_key(const char *input, unsigned char *key);int iw_in_key_full(int skfd, const char *ifname, const char *input, unsigned char *key, __u16 *flags);void iw_print_pm_value(char *buffer, int buflen, int value, int flags, int we_version);void iw_print_pm_mode(char *buffer, int buflen, int flags);void iw_print_retry_value(char *buffer, int buflen, int value, int flags, int we_version);void iw_print_timeval(char *buffer, int buflen, const struct timeval *time, const struct timezone *tz);int iw_check_mac_addr_type(int skfd, const char *ifname);int iw_check_if_addr_type(int skfd, const char *ifname);char *iw_mac_ntop(const unsigned char *mac, int maclen, char *buf, int buflen);void iw_ether_ntop(const struct ether_addr *eth, char *buf);char *iw_sawap_ntop(const struct sockaddr *sap, char *buf);int iw_mac_aton(const char *orig, unsigned char *mac, int macmax);int iw_ether_aton(const char *bufp, struct ether_addr *eth);int iw_in_inet(char *bufp, struct sockaddr *sap);int iw_in_addr(int skfd, const char *ifname, char *bufp, struct sockaddr *sap);MISC SUBROUTINES(1个)
int iw_get_priv_size(int args);EVENT SUBROUTINES(2个)
void iw_init_event_stream(struct stream_descr *stream, char *data, int len);int iw_extract_event_stream(struct stream_descr *stream, struct iw_event *iwe, int we_version);int iw_process_scan(int skfd, char *ifname, int we_version, wireless_scan_head *context);int iw_scan(int skfd, char *ifname, int we_version, wireless_scan_head *context);static inline int iw_set_ext(int skfd, const char *ifname, int request, struct iwreq *pwrq);static inline int iw_get_ext(int skfd, const char *ifname, int request, struct iwreq *pwrq);static inline void iw_sockets_close(int skfd);static inline char *iw_saether_ntop(const struct sockaddr *sap, char* bufp);static inline int iw_saether_aton(const char *bufp, struct sockaddr *sap);static inline void iw_broad_ether(struct sockaddr *sap);static inline void iw_null_ether(struct sockaddr *sap);static inline int iw_ether_cmp(const struct ether_addr* eth1, const struct ether_addr* eth2);int iw_sockets_open(void);-1AF_INET、AF_IPX、AF_AX25、AF_APPLETALK;99% 的情况下可以使用 AF_INET 协议族打开 socket。void iw_enum_devices(int skfd, iw_enum_handler fn, char *args[], int count);iw_sockets_open() 打开的 socket typedef int (*iw_enum_handler)(int skfd, char *ifname, char *args[], int count);
由此可见 fn() 返回的是一个 int,其调用参数有 4 个,skfd 为一个打开的 socket,ifname 为接口名称,args[] 为传递给 fn() 的自定义参数,count 为 args[] 中的参数数量;
/proc/net/wireless 获取无线网络接口名称,然后调用 fn(),并将获得的设备接口名称自动填到 fn() 第二个参数 ifname 上。int iw_get_kernel_we_version(void);/proc/net/wireless 中提取出 WE 的版本号。int iw_print_version_info(const char *toolname);int iw_get_range_info(int skfd, const char *ifname, iwrange *range);struct iw_range,获取的信息将放在 range 指向的 struct iw_range 中,struct iw_range 定义在 wireless.h 中;ioctl() 的 SIOCGIWRANGE 命令获取 range 信息,struct iw_range 结构比较庞大,不同的驱动程序可以返回的信息也不同。int iw_get_priv_info(int skfd, const char *ifname, iwprivargs **ppriv);iw_sockets_open() 打开的 socketstruct iw_priv_args,该结构定义在 wireless.h 中,如下: struct iw_priv_args {
__u32 cmd; /* Number of the ioctl to issue */
__u16 set_args; /* Type and number of args */
__u16 get_args; /* Type and number of args */
char name[IFNAMSIZ]; /* Name of the extension */
};
free(),源码中提示,即便返回的数据长度为 0,仍然要调用 free(*ppriv)。int iw_get_basic_config(int skfd, const char *ifname, wireless_config *info);struct wireless_config,定义如下: typedef struct wireless_config {
char name[IFNAMSIZ + 1]; /* Wireless/protocol name */
int has_nwid;
iwparam nwid; /* Network ID */
int has_freq;
double freq; /* Frequency/channel */
int freq_flags;
int has_key;
unsigned char key[IW_ENCODING_TOKEN_MAX]; /* Encoding key used */
int key_size; /* Number of bytes */
int key_flags; /* Various flags */
int has_essid;
int essid_on;
char essid[IW_ESSID_MAX_SIZE + 1]; /* ESSID (extended network) */
int has_mode;
int mode; /* Operation mode */
} wireless_config;
struct wireless_config 的指针,调用成功将存放获得的无线配置int iw_set_basic_config(int skfd, const char *ifname, wireless_config *info);iw_sockets_open()打开的 socketstruct wireless_config 结构指针;ioctl() 的如下命令已设置无线配置信息:SIOCSGIWNAME、SIOCSIWMODE、SIOCSIWFREQ、SIOCSIWENCODE、SIOCSIWNWID、SIOCSIWESSIDint iw_protocol_compare(const char *protocol1, const char *protocol2);void iw_essid_escape(char *dest, const char *src, const int slen);int iw_essid_unescape(char *dest, const char *src);void iw_float2freq(double in, iwfreq *out);
struct iw_freq)传递给内核struct iw_freq,是一个内核可以接受的频率格式,定义如下: struct iw_freq {
__s32 m; /* Mantissa */
__s16 e; /* Exponent */
__u8 i; /* List index (when in range struct) */
__u8 flags; /* Flags (fixed/auto) */
};
double iw_freq2float(const iwfreq *in);
struct iw_freq)表示的频率转换为浮点数struct iw_freq 表示的频率void iw_print_freq_value(char *buffer, int buflen, double freq);
void iw_print_freq(char *buffer, int buflen, double freq, int channel, int freq_flags);
< 1000 则该值为工作信道(channel),否则为工作频率;当 freq < 1000 时,该函数转换成类似 Channel:5 这样的字符串,否则,转换成类似 Frequency:5.265 GHz 这样的字符串;channel >= 0 时,转换的字符串类似 Frequency:5.265 GHz (Channel 3) 这样的字符串;freq_flags = 1 时,转换出的字符串类似 Frequency=5.265 GHz,否则为 Frequency:5.265 GHzint iw_freq_to_channel(double freq, const struct iw_range *range);
>=0 时表示工作频率所在的工作信道,-2 表示在 range 中没有找到指定的频率 freq,-1 表示 freq < 1000struct iw_range 定义在 wireless.h 中,其中有一个 struct iw_freq 的结构数组,该函数将从这个结构数组(struct iw_freq).freq)中查找与 freq 一致的频率,找到后返回 (struct iw_freq).i,否则返回 -2,当参数 freq < 1000 时,返回 -1int iw_channel_to_freq(int channel, double *pfreq, const struct iw_range *range);
<0 的值struct iw_freq 的定义,struct iw_range 定义在 wireless.h 中,从 range 中的 struct iw_freq 结构数组中的 (struct iw_freq).i 中查找与 channel 一致的项,并将其对应的 (struct iw_freq).freq 存放到 pfreq 中;void iw_print_bitrate(char *buffer, int buflen, int bitrate);
Gb/s、Mb/s、kb/s)表示的字符串Gb/s,当速率 >106 时,单位为 Mb/s,当速率 >1000 时,单位为 kb/s int iw_dbm2mwatt(int in);
int iw_mwatt2dbm(int in);
void iw_print_txpower(char *buffer, int buflen, struct iw_param *txpower);
struct iw_param 时 WE 下的一个通用结构,定义在 wireless.h 中,具体如下: struct iw_param {
__s32 value; /* The value of the parameter itself */
__u8 fixed; /* Hardware should not use auto select */
__u8 disabled; /* Disable the feature */
__u16 flags; /* Various specifc flags (if any) */
};
txpower->value 为发射功率值,当 txpower->flags 的 bit 0 为 1 时,value 的单位为毫瓦(否则为 dBm),当 bit 1 为 1 时表示 value 中的值是一个相对值,没有具体单位int iw_get_stats(int skfd, const char *ifname, iwstats *stats, const iwrange *range, int has_range);
/proc/net/wireless 获取最新的统计数据iw_sockets_open() 打开的 socketstruct iw_statistics,定义在 wireless.h 中,如下: struct iw_statistics {
__u16 status; /* Status - device dependent for now */
struct iw_quality qual; /* Quality of the link (instant/mean/max) */
struct iw_discarded discard; /* Packet discarded counts */
struct iw_missed miss; /* Packet missed counts */
};
struct iw_quality、struct iw_discarded 和 struct iw_missed 均定义在 wireless.h 中/proc/net/wireless 读出的统计信息存放在 stats 指向的 struct iw_statistics 中/proc/net/wireless 文件void iw_print_stats(char *buffer, int buflen, const iwqual *qual, const iwrange *range, int has_range);
struct iw_quality,定义在 wireless.h 中,如下: struct iw_quality {
__u8 qual; /* link quality (%retries, SNR, %missed beacons or better...) */
__u8 level; /* signal level (dBm) */
__u8 noise; /* noise level (dBm) */
__u8 updated; /* Flags to know if updated */
};
range->max_qual.qual、range->max_qual.level 和 range->max_qual.noisevoid iw_print_key(char *buffer, int buflen, const unsigned char *key, int key_size, int key_flags);
int iw_in_key(const char *input, unsigned char *key);
{0X01, 0X2A, 0X0C, 0XE3, ...}{0X41, 0X62, 0X63, 0X31, 0X32, 0X33, ...}int iw_in_key_full(int skfd, const char *ifname, const char *input, unsigned char *key, __u16 *flags);
username:password,否则调用 iw_in_key()range.encoding_login_index 设置 flagsvoid iw_print_pm_value(char *buffer, int buflen, int value, int flags, int we_version);
void iw_print_pm_mode(char *buffer, int buflen, int flags);
void iw_print_retry_value(char *buffer, int buflen, int value, int flags, int we_version);void iw_print_timeval(char *buffer, int buflen, const struct timeval *time, const struct timezone *tz);int iw_check_mac_addr_type(int skfd, const char *ifname);
ioctl() 的 SIOCGIFHWADDR 命令获取 HW 的地址类型,应该为 ARPHRD_ETHER 或者 ARPHRD_IEEE80211int iw_check_if_addr_type(int skfd, const char *ifname);
char *iw_mac_ntop(const unsigned char *mac, int maclen, char *buf, int buflen);
void iw_ether_ntop(const struct ether_addr *eth, char *buf);
struct ether_addr 定义在 ethernet.h 中,如下: struct ether_addr {
uint8_t ether_addr_octet[ETH_ALEN];
} __attribute__ ((__packed__));
iw_mac_ntop() 把一个任意长度的 MAC 地址转换成字符串,其输入参数为一个 unsigned char 数组,iw_ether_ntop() 将一个长度为 6 个字符的 unsigned char 数组转换为字符串,输入参数为 struct ether_addr,两个函数本质上非常相似。char *iw_sawap_ntop(const struct sockaddr *sap, char *buf);
struct sockaddr 定义在文件 socket.h 中,如下: struct sockaddr {
sa_family_t sa_family; /* Common data: address family and length. */
char sa_data[14]; /* Address data. */
};
iw_ether_ntop() 将 socket.sa_data 中的 MAC 地址转换成字符串,这个函数仍然是把 MAC 地址转换为字符串,不过输入参数是 struct sockaddr 而已。
iw_mac_ntop()、iw_ether_ntop()、iw_sawap_ntop()都是把 MAC 地址转换成易读的字符串形式,但各自的输入参数不同,iw_mac_ntop()的输入参数是一个任意长度的二进制数组;iw_ether_ntop()的输入参数是struct ether_addr;iw_sawap_ntop() 的输入参数是struct sockaddr
int iw_mac_aton(const char *orig, unsigned char *mac, int macmax);
int iw_ether_aton(const char *orig, struct ether_addr *eth);
struct ether_addr 在前面有介绍,转换好的二进制以太网地址存放在 eth 中iw_mac_aton() 和 iw_ether_aton() 都是把一个字符串表达的 MAC 地址转换成二进制形式,iw_mac_aton() 的输出参数是一个 unsigned char 数组,iw_ether_aton() 的输出参数是 struct ether_addr,iw_mac_aton() 是任意长度,iw_ether_aton() 是 6 个字符长度。iw_mac_aton()、iw_ether_aton()、
int iw_in_inet(char *bufp, struct sockaddr *sap);
int iw_in_addr(int skfd, const char *ifname, char *bufp, struct sockaddr *sap);
struct sockaddrint iw_get_priv_size(int args);void iw_init_event_stream(struct stream_descr *stream, char *data, int len);
struct stream_descr 定义在 iwlib.h 中,如下: struct stream_descr {
char *end; /* End of the stream */
char *current; /* Current event in stream of events */
char *value; /* Current value in event */
} stream_descr;
int iw_extract_event_stream(struct stream_descr *stream, struct iw_event *iwe, int we_version);
iw_init_event_stream() 初始化的结构struct iw_event 定义在 wireless.h 中,如下: struct iw_event {
__u16 len; /* Real lenght of this stuff */
__u16 cmd; /* Wireless IOCTL */
union iwreq_data u; /* IOCTL fixed payload */
};
int iw_process_scan(int skfd, char *ifname, int we_version, wireless_scan_head *context);
参数:
struct wireless_scan_head,定义在 iwlib.h 中,如下: struct wireless_scan_head {
wireless_scan *result; /* Result of the scan */
int retry; /* Retry level */
} wireless_scan_head;
wireless_scan 就是 struct wireless_scan,定义在 iwlib.h 中,如下:
struct wireless_scan
{
/* Linked list */
struct wireless_scan *next;
/* Cell identifiaction */
int has_ap_addr;
sockaddr ap_addr; /* Access point address */
/* Other information */
struct wireless_config b; /* Basic information */
iwstats stats; /* Signal strength */
int has_stats;
iwparam maxbitrate; /* Max bit rate in bps */
int has_maxbitrate;
}
struct wireless_scan 中,并且以链表形式存储多个多个无线信号的扫描结果;struct wireless_scan 中的 struct wireless_config 在前面有介绍;int iw_scan(int skfd, char *ifname, int we_version, wireless_scan_head *context);
iw_sockets_open() 打开的 socketstatic inline int iw_set_ext(int skfd, const char *ifname, int request, struct iwreq *pwrq);static inline int iw_get_ext(int skfd, const char *ifname, int request, struct iwreq *pwrq);iw_sockets_open() 打开的 socketstruct iwreq 的结构指针,不同的 request,其填写方法也不一样说明:上面这两个内联函数其实是一样的,都是调用指定的
ioctl(),WE 支持的 ioctl 调用方式为:int ioctl(int fd, unsigned long request, struct iwreq *pwrq),其 request 通常有两种,一种是 SIOCS,另一种是 SIOCG,均定义在 wireless.h 中,按照惯例,当 request 为 SIOCS 时,使用iw_set_ext(),当 request 为 SIOCG 时,使用 iw_get_ext()。
static inline void iw_sockets_close(int skfd);
iw_sockets_open() 打开的 socketclose(skfd)static inline char *iw_saether_ntop(const struct sockaddr *sap, char* bufp);
iw_ether_ntop()static inline int iw_saether_aton(const char *bufp, struct sockaddr *sap);
iw_ether_aton() 函数static inline void iw_broad_ether(struct sockaddr *sap);
static inline void iw_null_ether(struct sockaddr *sap);
static inline int iw_ether_cmp(const struct ether_addr* eth1, const struct ether_addr* eth2);
eth1 < eth2 则小于 0,eth1 > eth2 则大于 0,否则等于 0欢迎访问我的博客:https://whowin.cn
email: hengch@163.com
