(七)hostapd整体梳理
最后更新于:2022-04-01 10:53:39
这篇主要对hostapd这个程序做一个整体的梳理,自己也觉得前面说的都好乱,尽是一些代码的分析,过于细节了。
关于EAP状态机的转化,这里就不多说了,[点击打开链接](http://download.csdn.net/detail/lee244868149/8288875) 这里可以下载原文档,知道的是自己不会比原文档写的还好的,所以就放弃了介绍状态机了。
先理解一下 struct hapd_interfaces interfaces 这个结构体对象, 这个结构体里面封装的是一个count成员和一个 struct hostapd_iface **iface成员:
~~~
struct hapd_interfaces interfaces {
size_t count;
struct hostapd_iface **iface; }
~~~
所以interfaces其实是对接口的封装,也许有多张无线网卡,那么就会有多个无线接口(注意区分空中接口),那么hostapd程序的interfaces就会封装多个 iface对象,并用count计数。比如我现在hostapd需要用两张网卡来创建两个接口,一个是2.4G、一个是5G的网络,那么调用hostapd 传入参数时,就需要传入两个配置文件,count将会获得值2,并且会创建两个结构体指针 iface[0]和iface[1] ( struct hostapd_iface *iface[ ] ),用来分别存放两张网卡的各自操作和信息等。
下面只分析一张网卡(注意下面说的网卡都是指无线网卡)的整体过程,因为不同无线网卡的区别主要体现在驱动方面,所以hostapd程序来说,不同网卡之间的处理过程都差不多的(比较数据包格式和通信协议没差啊)。
main函数开始的for循环就不在重复了,主要注意的是-B选项和-e选项指定了 程序以后台进程运行和指定了entropy文件罢了。
下面将以3条线开始整理,分别是 hostapd_global_init() hostapd_interfaces_init() hostapd_global_run() , 关于出错处理时,需要注意一下这个进程的重新加载,判断reloading以后调用execvp()函数实现重载。
### 一、 hostapd_global_init() 实现安全方法的注册、eloop初始化、entropy文件的读取和处理、退出中断的注册
1. 注册方法 eap_server_register_methods()
首先调用各种方法对应的注册函数,定义struct eap_method *eap 对像,给这个对象申请空间后,给eap对象中的操作函数指针赋值,最后使用eap_server_method_register()将本方法添加进 method的链表中。
2.eloop初始化 eloop_init()
将struct eloop_data eloop对象清空后,将eloop.timeout添加到双链表中,最后注册一个SIGSAVE中断,以在特定情况下终止进程。
3.entropy文件的读取和处理 random_init()
4.退出中断的注册 eloop_register_signal_terminate()
这里主要完成eloop.teminate = 1 ,当信号产生时, 这个变量置1,能够让后面的while循环退出,终止程序,第二个参数interfaces主要用来指定这个信号发送给哪张无线网卡(当前无线网卡)。
### 二、 hostapd_interfaces_init() 这个函数很关键,接下来慢慢细说!
struct hostapd_iface *iface 这个对象封装了对接口操作的各种函数以及对接口描述的各种参数。
iface = hostapd_init (config_fname); 注意着句话,函数的返回值赋值给了iface,而传入的参数是config_fname(配置文件路径及名称),我们可以猜想这句话就是要完成将配置文件中的内容读取出来,并存放到iface对象中。
1. 根据配置文件配置接口 hostapd_init()
为了具体一点,现在将代码列出来:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-15_57108d8e0217a.jpg)
首先定义三个结构体对象,分别用来存放接口信息、接口配置信息和报文协议等信息——hostapd_iface、 hostapd_conf、 hostapd_data
hapd_iface->reload_config = hostapd_reload_config 需要刷新或者修改了配置文件需要重新加载的时候,调用这个函数
hapd_iface->config_read_cb = hostapd_config_read 先加载默认的配置,然后加载配置文件中的配置,存放到conf对象中
hapd_iface-> config_fname 存放配置文件的路径信息
hapd_iface->ctrl_iface_init =hostapd_ctrl_iface_init 这个函数很重要,主要对初始化套接字通信,包括调用socket和bind函数eloop_register_read_sock,实现套接字通信,这里调用了hostapd_ctrl_iface_receive(),里面有receivefrom和sendto函数实现通信。
hapd_iface->conf = conf 存放读取的配置信息
hapd->msg_ctx = hapd 这里存放各种要发送的信息,比如报文信息、协议信息等, 因为hapd是struct hostapd_data 结构体对象
接下来对bss进行初始化
2.驱动程序初始化 hostapd_driver_init()
首先对启动可能用到的各种params进行初始化赋值,然后用hapd->driver_priv = hapd->driver-> hostapd_init( hapd, ¶ms) 语句,用params中的参数对驱动进行初始化。
那么hostapd_init调用的是哪里的函数呢?这个路径的指定在初始化iface时,在iface->BSS[0] 中,hostapd_init将会调用 src/ driver / dirver_madwifi.c 中的 madwifi_init函数,具体驱动应用程序做了什么,就不拓展了。
hapd->driver->get_capa 需要留意一下。
3.设置接口配置 hostapd_setup_interface() "setup_interface"
使用的hostapd_data对象还是来自于 iface->bss[0] ,首先使用hostapd_validate_bssid_configuration验证iface中的BSSID是否可用,调用hosta_get_hw_features获取硬件信息,最后调用hostapd_setup_interface_complete返回结果。
其实在上面那个函数中,是做了好多设置才返回的,比如通道、频率、硬件模式(hw_mode)、传输速率、RTS、帧、热拔插、WPS等等。
### 三、 hostapd_global_run()
1. tncs_global_init 初始化
2.os_daemonize()让本进行以守护进程运行
3.eloop_run()
将申请的标准输入、输出、出错文件描述符集,用select函数进行监听,调用eloop_process_pending_signals处理即将到来的中断信号,接下来进行超时处理。
还有关于驱动那一块还没有整理,先留着吧,说不定哪一天兴趣来了在看看,花这么多时间才弄清楚这个小小的hostapd,感觉有点不值,有时候问自己为什么要花时间去弄明白人家已经做好的东西呢,直接拿过来用不就好了吗,没办法,也许嵌入式开发就是这样吧,也许是性格使然。