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进行监听,示意图如下。
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, ¶ms),将会调用 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)); }
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 点击打开链接 这里的,作为一个菜鸟深知理解的还不够到位,写这些东西也花了好几天时间,主要是为了加强自己的学习效果,里面肯定有错误的地方,希望能够得到指正。
接下来将写一篇hostapd的整体梳理,给自己一个完整的交代吧。