💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
这篇主要对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://box.kancloud.cn/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, &params) 语句,用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,感觉有点不值,有时候问自己为什么要花时间去弄明白人家已经做好的东西呢,直接拿过来用不就好了吗,没办法,也许嵌入式开发就是这样吧,也许是性格使然。