多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
1. 程序在哪里加载了配置文件呢? 在哪里设进去了呢? main 中hostapd_interface_init  调用 hostapd_init ,conf = interfaces->config_read_cb(hapd_iface->config_fname);  其实config_read_cb 指向hostapd_config_read 函数,它将配置文件(config_fname)中的配置选项读取到 conf 对象中,便后面使用。 hostapd_interface_init有调用hostapd_setup_interface 将config里面的值设置进进程里面。 2.中断处理函数在哪里注册? 注册了哪些中断处理函数呢? 在main函数的开始,定义了一个对象: struct hostapd_interfaces interfaces 这个对象在整个程序中起到一定贯穿作用,我们来看看hostapd_global_init()中对中断注册函数的调用(这个调用其他版本也可能在别的地方): ~~~ eloop_register_signal_terminate(handle_term, interfaces); ~~~ 这里分成了两部分,handle_term将调用函数 ~~~ static void handle_term(int sig, void *eloop_ctx, void *signal_ctx) { wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig); eloop_terminate(); } void eloop_terminate(void) { eloop.terminate = 1; } ~~~ 这里将terminate 置1,在后面能够引起 eloop_run中的while循环退出,而interfaces部分,将会在eloop_register_signal函数中赋值给 eloop.signal.user_data,以便中断处理函数调用,同时将eloop.pending_terminate 置1。 3.socket在哪里创建的呢? socket文件描述符集怎么实现select监听, ioctl控制呢? main 中hostapd_interface_init  调用 hostapd_init, hapd_inface-> ctrl_inface_init = hostapd_ctrl_inface_init, 其实调用的是hostapd_ctrl_inface_init函数,这个函数的重要性就不强调了,因为它在数据 收发中起到关键的作用。 hostapd_ctrl_inface_init函数使用了socket函数(注意第一个选项是PF_UNIX)、bind函数、connect函数、eloop_register_read_sock函数等直接和 l2_packet_linux.c 相关。 接着eloop_run函数while循环中将使用select对socket进行监听,示意图如下。 ![](https://box.kancloud.cn/2016-04-15_57108d8ddd9cb.jpg) 4.数据包是怎么发送接收的呢? l2_packet_send 和 l2_packet_receive这两个函数在 src/ l2_packet/ l2_packet_linux.c 中, l2_packet_init 函数中使用ioctrl监听数据,然后通过socket将数据发送出去。 5.那么hostapd进程是怎么样和madwifi进行交互的呢?  将在后面madwifi部分介绍了 6.驱动是在什么时候加载进内核的呢? main 中hostapd_interface_init  调用hostapd_driver_init,里面有一句hapd->driver->hapd_init(hapd, &params),将会调用 src/ driver / dirver_madwifi.c 中的 madwifi_init函数。 Madwifi_init 调用了l2_packet_init() 函数, 该函数有实现很多功能,参见src下的l2_packet目录,譬如windows下可用的winpcap等,这实际就是类似抓包的了,不过在链路层而已。 调用的时候drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL,handle_read, drv, 1);注册了handle_read。意思就是收到ETH_P_EAPOL协议帧后调用handle_read handle_read实现如下: ~~~ static void handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) { struct madwifi_driver_data *drv = ctx; struct hostapd_data *hapd = drv->hapd; struct sta_info *sta; sta = ap_get_sta(hapd, src_addr); if (!sta || !(sta->flags & WLAN_STA_ASSOC)) { printf("Data frame from not associated STA %s/n", ether_sprintf(src_addr)); /* XXX cannot happen */ return; } ieee802_1x_receive(hapd, src_addr, buf + sizeof(struct l2_ethhdr), len - sizeof(struct l2_ethhdr)); } ~~~ 在此,调用了ieee802_1x_receive。 l2_packet_init里面调用了int eloop_register_read_sock(int sock, eloop_sock_handler handler, void *eloop_data, void *user_data) 这里handler即l2_packet_receive,最后通过 static int eloop_sock_table_add_sock(struct eloop_sock_table *table, int sock, eloop_sock_handler handler,  void *eloop_data, void *user_data) 将socket可读消息的handler回调函数设为了l2_packet_receive。 再一次看这个,当select到read-sock有消息时,最终call到这里 static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx) 到这里hostapd这个程序写的差不多了,里面好多东西都是参考或者说是copy   [点击打开链接](http://blog.csdn.net/njzhujinhua/article/category/2442809) 这里的,作为一个菜鸟深知理解的还不够到位,写这些东西也花了好几天时间,主要是为了加强自己的学习效果,里面肯定有错误的地方,希望能够得到指正。 接下来将写一篇hostapd的整体梳理,给自己一个完整的交代吧。