1 wpa_supplicant 源码下载地址:
wpa_supplicant-2.10 下载地址:wpa_supplicant-2.10
2 wpa_supplicant 学习总结
wpa_supplicant 学习参考网址:wpa_supplicant
2.1 wpa_supplicant 基本概念:
- ** wpa_supplicant 是什么?**
wpa_supplicant 是WPA 请求者,支持WPA 和WPA2(IEEE802.11i/RSN). - ** wpa_supplicant 能干什么?**
wpa_supplicant 被设计成一个“守护程序”,在后台运行充当控制无线连接的后端,主要实现与WPA 身份验证器的秘钥协商,并控制wlan驱动程序的漫游和IEEE802.11身份验证/关联。 - ** wpa_supplicant 支持哪些功能?**
WPA-PSK (“WPA-Personal”)
带有 EAP 的 WPA(例如,使用 RADIUS 身份验证服务器)(“WPA-Enterprise”)
CCMP、TKIP、WEP104、WEP40 的密钥管理
WPA 和完整的 IEEE 802.11i/RSN/WPA2
RSN:PMKSA 缓存、预身份验证
IEEE 802.11r
IEEE 802.11w
Wi-Fi 保护设置 (WPS)
2.2 wpa_supplicant 目录介绍:
- hostapd:
提供AP 功能 - wpa_supplicant:
提供Station & P2P 模式 - src:
存放hostapd & wpa_supplicant 通用的数据结构和处理方法。 hostapd/src & wpa_supplicant/src 链接到此src 目录。
2.3 wpa_supplicant 架构:
- wpa_supplicant 是C/S 结构中的Server 端,通过ctrl i/f 向客户提供通信接口。客户可以使用wpa_cli 将cmd 下发wpa_supplicant.
- wpa_supplicant 所有工作都围绕事件循环(event loop).事件循环基于事件驱动,主线程等待事件发货所能并处理他们。
- wpa_supplicant 需要很多配置,configuration 模块负责该配置。
- EAP & EAPOL 是LLC 层数据,I2_packet 模块负责收发EAP & EAPOL 消息。
- driver i/f 属于driver wrapper,实现驱动无关性。driver_wrapper 与芯片和底层驱动有关。
2.4 wpa_supplicant 源码编译及产物
2.4.1 源码编译方法:
----后续追加----
2.4.2 编译产物:
wpa_supplicant 编译完会生成wpa_supplicant ,同时也会生成wpa_cli.
2.5 wpa_supplican 中wpa_cli 使用:
2.5.1 wpa_cli 基本用法及理解:
$: ifconfig 查看当前网络节点,如有wlan0
$ wpa_cli -i wlan0
$> help //wpa_cli 的所有指令帮助
$> q //退出wpa_cli 命令行
wpa_supplicant 会按照以下方式回应相关信息:
- CTRL-REQ<><><>
- CTRL-RSP<><><>
- CTRL-EVENT-XXX 事件通知
- WPA:XXX 通知事件
- WPS-XXXX 通知事件
2.5.2 wpa_cli 启动p2pl 连接:
启动wpa_supplicant:
1. 启动wpa_supplicant
/usr/local/bin/wpa_supplicant -iwlan0 -Dnl80211 -c /usr/local/etc/wifimanager/wpa_0_8.conf -dddd&
2. ctrl interface 切换到p2p-dev-wlan0
wpa_cli -ip2p-dev-wlan0
3. 命令行执行p2p_find
p2p_find 60
4. 扫描到p2p device 后,停止find:
p2p_stop_find
5. 根据find 到设备的mac 地址进行连接
p2p_connect xxx pbc go_intent=15
2.5.3 wpa_cli 启动p2pg ,手机搜索并加入p2pg:
1. 启动wpa_supplicant
/usr/local/bin/wpa_supplicant -iwlan0 -Dnl80211 -c /usr/local/etc/wifimanager/wpa_0_8.conf -dddd&
2. ctrl interface 切换到p2p-dev-wlan0
wpa_cli -ip2p-dev-wlan0
3. 启动p2pg:
p2p_group_add freq=5
4. 手机搜索并加入p2pG
5. 收到P2P-PROV-DISC-PBC-REQ, 执行wps_pbc
//wpa_cli -i p2p-wlan0-0 有些网卡需要切换ctrl_interface 到p2p-wlan0-0.
wps_pbc
2.6 wpa_supplicant 配置文件说明:
设备不同存放配置文件会有所差异,umaster code 配置文件目录如下:/usr/local/etc/wifimanager/wpa_0_8.conf
常用配置信息说明如下:
-
ctrl_interface
//配置所用的组件,这里为wpa_supplicant -
p2p_no_group_iface=1
//realtek 要求添加的配置项,否则只有root权限才可以读取wpa配置。 -
update_config=1
//是否允许修改配置后wpa_supplicant可以覆盖配置文件,update_config=1表示wpa_cli 和wpa_gui能够永久修改配置。 -
device_name=Default_p2p
//设备名称,UTF8编码的32个字节 -
manufacturer=Realtek
//设备的制造商(64个ASCII特征码) -
model_number=WLAN_CU
//设备型号(32个ASCII特征码) -
serial_number=1234
//设备的序列号(32个ASCII特征码) -
device_type=1-0050F204-1
//设备的主要类型:
• # 1-0050F204-1 (Computer / PC)
• # 1-0050F204-2 (Computer / Server)
• # 5-0050F204-1 (Storage / NAS)
• # 6-0050F204-1 (Network Infrastructure / AP) -
os_version=01020300
//操作系统版本 -
config_methods=virtual_dusplay virtual_push_keypad
//配置方法,虚拟显示、虚拟按钮、键盘 -
wfd_tcpport=
// WFD 所用的control 端口,默认是7326[30]
-
wfd_device_type=
WFD 所选的device type;
WFD 参考网址:https://blog.csdn.net/sui1005316018/article/details/102745952
2.7 wpa_supplicant 结构及相关API
2.7.1 wpa_ctrl 对象及相关接口说明:
接口/对象 | 说明 |
---|---|
wpa_ctrl.h/wpa_ctrl 对象 | 客户端使用的控制对象 |
struct wpa_ctrl* wpa_ctrl_open(const char *ctrl_path) | 获取wpa_ctrl 对象 |
void wpa_ctrl_close(struct wpa_ctrl *ctrl); | 销毁wpa_ctrl 对象 |
int wpa_ctrl_request(struct wpa_ctrl ctrl, const char cmd, size_t cmd_len,char *replay,szie_t *replay_len, void(*msg_cb)(char *msg, size_t len)); | 客户端给wpa_supplicant 发送消息。 发送内容保存至cmd中,wpa_supplicant 执行结果放到replay 中。 如果在执行此cmd 过程中,wpa_supplicant 有消息过来则可以通过msg_cb 来获取处理。 但前提是ms_cd 有提前打开事件通知监听. 这是堵塞的动作,一般至少等待2s钟用来接受反馈的回复消息。 |
int wpa_ctrl_attathc(struct wpa_ctrl *ctrl) | 打开通知事件监听功能 |
int wpa_ctrl_detach(struct wpa_ctrl *ctrl) | 关闭通知事件监听功能 |
int wpa_ctrl_recv(struct wpa_ctrl * ctrl, char *replay, size_t *replay_len ) | 打开通知事件监听功能的wpa_ctrl 才可以使用该接口获取wpa_supplicant 的消息,该接口仅仅是获取信息。// 这个接口是一个堵塞的操作,当没有可用的消息时,就会一直堵塞。 |
int wpa_ctrl_pending(struct wpa_ctrl *ctrl) | 用来检测是否有即将到来的事件消息 |
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) | 获取控制接口的文件描述符 |
wpa_ctrl_cleanup() | 关闭之前创建的wpa_ctrl 对象,清除所有socket file. |
char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl) | 获取wpa_ctrl 对应的ifname. |
通常用法:
- 客户端创建两个wpa_ctrl对象,一个打开事件监听功能的wpa_ctrl 对象将只通过wpa_ctrl_recv 来接收通知事件。
- 另一个wpa_ctrl 专职发送命令和接收回复,由于没有wpa_ctrl_attach ,因此不会受到事件通知。
2.7.2 wpa_interface 结构说明:
-
wpa_interface 用来描述一个无线网络设备。wpa_supplicant 可以支持操作多个无线网络设备,需要添加到wpa_supplicant 中。
-
wpa_interface 定义在wpa_supplicant/wpa_supplicant_i.h 中
结构成员 | 成员作用 |
---|---|
const char * confname | 接口对应的配置文件的名称,wpa_supplicant.conf |
const char * confanother | 是接口对应扩展配置文件的名称,如果没有使用设置为NULL |
const char * ctrl_interface | 控制接口文件即控制接口unix域socket 地址。//如果配置文件没有设置,则使用该项设置interface 的相关参数。如果有配置文件,则此项会被配置文件中的值覆盖。 |
const char * driver | 底层驱动选择,如wext、nl80211等;如果设置NULL 则使用默认driver |
const char *driver_param | 驱动参数 ;//如果配置文件没有设置,则使用该参数作为驱动参数;如果配置文件有设置,则此项会被配置文件覆盖。 |
const char * ifname | 网络接口设备名,如wlan0 |
const char * bridge_ifname | 桥接时使用,如br0,较少使用。 // 可选的桥式接口名称,如果允许额外的interface 接收EAPOL 可以设置该项,较少使用。 |
int p2p_mgmt | p2p管理。 //指示wpas_p2p_init() 是否必须呼叫该接口,主要用于当驱动支持专用P2P Device interface 而不是network interface 时。 |
2.7.3 wpa_params 结构说明:
- 该结构用于wpa_supplicant_init 中,主要是运行的参数。
- 定义在wpa_supplicant/wpa_supplicant_i.h 中
结构成员 | 成员作用 |
---|---|
int daemonize | 是否在后台运行wpa_supplicant 程序 |
int wait_for_monitor | 在wpa_supplicant starting 前是否等待monitor program |
char *pid_file | 指定PID File 的路径。 //如果daemonize 和该值设置,则后台进程也将会写入特定文件。 |
int wpa_debug_level | 设置debug level, 比如MSG_INFO |
int wpa_debug_show_keys | 在debug信息中是否包含关键信息。开发阶段和debug 阶段可以打开,正常关闭 |
int wpa_debug_timestamp | 在debug 信息中是否包含时间信息 |
char *ctrl_interface | 全局ctrl_iface 路径/参数 |
char *ctrl_interface group | 全局ctrl_iface group |
int dbus_ctrl_interface | 使能DBus control interface |
const char *wpa_debug_file_path | 指定debug file, 如果设置NULL则使用标准输出 |
int wpa_debug_syslog | 通过syslog使能log 输出 |
int wpa_debug_tracing | 通过linux tracing 使能log 输出 |
char *override_driver | 在动态interface 使用该参数值覆盖driver parameter,强迫使用特定的driver wrapper. |
char *override_ctrl_interface; | 在动态interface 中,使用该参数覆盖ctrl_interface 参数 |
char *entropy_file | 配置wpa_supplicant自己的entropy 存储当重新启动时 |
char *conf_p2p_dev | 通常设置为NUll |
2.7.4 wpa_supplicant 结构说明:
- 一个interface 对应一个wpa_supplicant
- wpa_supplicant 定义在wpa_supplicant_i.h 中
结构成员 | 成员作用 |
---|---|
struct wpa_global *global | 指向wpa_global 对象 |
struct wpa_supplicant *next | 进程内所有wpa_supplicant 对象都保存在一个单项链表中 |
struct l2_packet_data *l2 | 处理EAP和EAPOL 信息 |
unsigned char own_addr[ETH_ALEN] | 地址 |
char ifname[100] | ifname 如wlan0 |
char *confname | 配置文件,wpa_supplicant.conf |
struct wpa_conf *conf | !! 从配置文件中解析出的配置信息 |
int countermeasures | |
u8 bssid[ETH_ALEN] | 表示当前supplicant 所连接诶的无线网络BSSID |
u8 pending_bssid[ETH_ALEN] | 表示当前supplicant 还处于关联状态时,目标BSSID |
int disconnected | 表示此supplicant 是否被禁止链接到无线网络 |
struct wpa_ssid *current_ssid | 当前使用的wpa_ssid 对象 |
struct wpa_bss *current_bss | 当前使用的wpa_bss对象。 //wpa_bss 对象是无线网络在wpa_supplicant 的代表,包括无线网络的频率, 心跳间隔,capability 信息等 |
int pairwise_cipher | 当前supplicant单播数据加密类型 |
void *drv_priv | 驱动对应上下文信息。driver i/f 接口定义了两个初始化函数,比nl80211 为例有global_init 和init2. init2 返回driver wrapper 上下文信息保存在此结构中 |
void *global_drv_priv | 驱动对应的全局上下文信息。 而global_init 返回值为driver wrapper 全局上下文信息,则保存到wpa_global 的drv_priv 中。 |
int sched_scan_timeout | 计划扫描timeout时间 。该变量与定时扫描功能有关,要求kernel version > 3.0 的wifi 驱动支持。 启动定时扫描需要设置扫描间隔 |
const struct wpa_driver_ops *driver | 此supplicant 对应的驱动对象 |
struct wpa_sm *wpa | wpa 状态机 |
struct eapol_sm *eapol | eapol 状态机 |
struct ctrl_iface_priv *ctrl_iface | 此supplicant 对应的控制接口对象 |
enum wpa_states wpa_state | !!!! supplicant 当前的状态 (详见解释) |
struct wpa_blacklist *blacklist | //黑名单,wpa_supplicant 不再连接黑名单中的网络 |
const struct bgscan_ops *bgscan | background 扫描功能 。与后台扫描及漫游技术有关,为增加AP无缝切换,可以bgscan 当发现AP信号强度低于某个阈值时就切换到信号更强的AP。 |
wpa_states 取值:
- WPA_DISCONNECTED: 当前未连接任何无线网络
- WPA_INTERFACE_DISABLED:当前wpa_supplicant 所使用的网络设备被禁用
- WPA_INACTIVE:表示当前wpa_supplicant 没有可连接的无线网络,比如周围无无线网络,或周围有无线网络但没有配置信息(如无设置密码)不能发起认证和关联请求。
- WPA_SCANNING: 当前wpa_supplicant 正在扫描无线网络中
- WPA_AUTHENTICATING: 当前wpa_supplicant 正在身份验证中
- WPA_ASSOCIATING: 当前wpa_supplicant 正在关联过程中
- WPA_ASSOCIATED: 表明此wpa_supplicant 成功关联到某个AP
- WPA_4WAY_HANDSHAKE: 表明此wpa_supplicant 处于4次握手处理过程中。PSK (WPA/WPA2-personal)策略 STA 收到第一个EAPOL 数据包就进入该状态,而WPA-Enterprise 完成身份验证就进入此状态。
- WPA_GROUP_HANDSHAKE:表明STA处于组秘钥握手协议处理过程中。STA完成4次握手并收到组播秘钥交换第一帧数据后进入此状态。
- WPA_COMPLETED: 所有认证过程完成,wpa_supplicant 正式加入某个无线网络。
2.7.5 wpa_global 结构说明:
- wpa_global 是一个全局性质的上下文信息。
- wpa_global 对象通过wpa_supplicant_init()获得
- 定义在wpa_supplicant_i.h 中
结构成员 | 成员作用 |
---|---|
struct wpa_supplicant* ifaces | ifaces 指向wpa_supplicant 对象链表,一个interface 对应一个wpa_supplicant 对象。 |
struct wpa_params params | 运行参数 |
struct ctrl_iface_global_priv* ctrl_ifaces | 全局控制接口的信息,包含一个用于通信的socket 句柄 |
void **drv_priv | drv_priv 包含driver wrapper 所需的全局上下文信息 |
size_t drv_count | driver wrapper 中的个数。 |
- wpa_global 有一个全局控制接口,如果设置该接口,其它wpa_interface 设置的控制接口将被替代。
2.7.6 wpa_ssid 结构和说明:
- wpa_ssid 用于存储某个无线网络的配置信息(如支持的安全类型,优先级等)。
- 该结构是wpa_supplicant.conf 中无线网络配置项在代码中的反应
结构成员 | 成员作用 |
---|---|
struct wpa_ssid *next | 在global list 中下一个network. //该表的HEAD 存储在wpa_config 中ssid |
struct wpa_ssid *pnext | 在per-priority list 中的Next network. // 该表的HEAD 存储在wpa_config 的pssid |
int id | network 的唯一标识符。 当network 创建时会分配唯一的id. |
int priority | priority group. //默认该值都为0,但是有些网络有详细优先级信息,优先级高的网络会更快扫描和连接。 |
u8 *ssid | 网络热点名称 |
size_t ssid_len | ssid 的长度 |
u8 bssid[ETH_ALEN] | 连接AP 时使用,如果是p2p group ,该参数代表GO 的Device Address. |
u8 *bssid_blacklist | BSSID 的黑名单,不允许连接的网络 |
u8 *bssid_whitelist | BSSID 白名单,允许访问的BSSID |
int bssid_set | 当前网路是否有配置BSSID |
u8 go_p2p_dev_addr[ETH_ALEN] | GO 的P2P Device 地址 |
u8 psk[32] | psk 共享秘钥 |
int psk_set | psk 是否配置 ,如果该项配置则psk 使用SSID 和passphrase 参数 |
char *passphrase | 8-63 个字符, 该变量只和WPA/WPA2-PSK 模式有关,用于存储输入的字符串密码,但规范中要求的也是PSK.,所以WPA_Supplicant 根据会它和ssid 进行一定计算得到最终使用的PSK. |
char *sae_password | SAE Password |
int pairwise_cpher | 加密套件,该参数是用于单播数据加密的秘钥类型(即数据收发两方使用的数据加密方法),如CCMP/TKIP/WEP 等 |
int group_cpher | 用于组播加密的秘钥类型 |
int key_mgnt | 秘钥管理类型,默然是PSK | IEEE802.X |
int proto | 该无线网络支持的安全保护类型,有WPA 和RSN. 默认是WPA|RSN |
int auth_alg | 该无线网络支持的身份验证类型,常用的是包括Open System (如果使用WPA 或RSN 必须选择Open System)和Shared key .定义在defs.h 中 |
int scan_ssid | 是否使用probe request 扫描此ssid 对应的无线网络 |
int eapol_flags: | 与WEP Key 有关 |
struct epa_peer_config eap | eap peer 端的设置信息 |
int proactive_key_caching | 秘钥暂存功能,与OPC(Opportunistic PMK Caching )技术有关。(1个控制器+多个ap 组成的架构)Sta与同一个ZONE 中的ap0 身份验证得到PMK0 后,当切换到其它AP时不需要再进行身份验证,其它ap1 根据pmk0 得到pmk1.直接进行后面的握手环节 |
enum wpas_mode mode | 网络模式中的组件类型 |
int disabled | 0: 无线网络可用;1:禁止使用;2:该无线网络和p2p 有关 |
pairwise_cipher 常用加密套件:
wpa_supplicant/src/common/defs.h
#define WPA_CIPHER_NONE BIT(0)
#define WPA_CIPHER_WEP40 BIT(0)
#define WPA_CIPHER_WEP104 BIT(0)
#define WPA_CIPHER_TKIP BIT(0) //加密套件TKIP
#define WPA_CIPHER_CCMP BIT(0) //加密套件CCMP
key_mgmt:
该成员和802.11 中的AKM suit 相关。AKM(Authentication and key management 身份验证和秘钥管理) suite 定义一套算法用于Supplicant 和Authenticator 之间交换身份和秘钥信息。
定义在wpa_supplicant/src/common/defs.h
默认的AKM suite 是PSK+802.X, 在wpa_supplicant/config_ssid.h
wpas_mode:
- WPAS_MODE_INFRA=0: 代表基础网络结构的STA
- WPAS_MODE_IBSS=1;代表IBSS 网络的模式
- WPAS_MODE_AP=2;代表基础结构型网络中的AP
- WPAS_MODE_P2P_GO=3; 代表GO。
2.7.7 eloop 事件循环 相关 结构和API
结构/API | 含义 |
---|---|
struct eloop_data() | |
eloop_register_read_sock() | 注册读事件, 当socket 上有读事件就会触发handle 函数 |
eloop_register_sock() | 注册读,写,异常,timeout 事件,根据传入参数决定 |
eloop_register_signal() | 注册信号事件 |
eloop_sock_table_set_fds() | 将外界设置的读、写、异常等事件添加到fd_set 中去 |
eloop_sock_table_dispatch(&eloop.reads, rfds) | 处理读事件,写,异常事件类似。 |
wpa_supplicant.c wpa_supplicant_init_iface() 根据配置文件初始化interface
2.7.7 driver 相关结构及API
supplicant/src/driver/driver.c 中
const struct wpa_driver_ops *const wpa_drivers[]={
&wpa_driver_nl80211_ops, // 获取热点等对应接口
......
}
wifi spec 下载网址:
WPA3-Specification 下载:WPA3_SPEC
https://www.wi-fi.org/download.php?file=/sites/default/files/private/WPA3_Specification_v3.0.pdf