系列说明
大致简单了解了无线通信在底层的组成,接收和发送之后,接下来希望能更系统地对信息从user space至kernel space,至kernel对信息的使用,发送和接收等一系列步骤进行总结说明。以便后续将wifi的ssid,密码,加密方式等需要的信息填充入beacon帧中进行发送端组包,接收端解包的处理。
这一章先从user space层的hostapd开始说起,主要目的在于了解hostapd是怎么将hostapd.conf配置文件下的配置内容传递给底层,让底层根据这些信息做相应处理的。
以下链接是对我了解hostapd过程中起到很大帮助的网址链接:
hostapd源代码分析(一):网络接口和BSS的初始化
hostapd源代码分析(二):hostapd的工作机制
hostapd源代码分析(三):管理帧的收发和处理
wifi相关知识点网址链接
该篇主要对:hostapd作用,hostapd网络接口和BSS初始化,hostapd信息传输机制,socket注册回调。三个模块进行说明。
一、hostapd作用
hostapd 是一个用户态用于AP和认证服务器的守护进程。它实现了IEEE 802.11相关的接入管理,IEEE 802.1X/WPA/WPA2/EAP 认证, RADIUS客户端,EAP服务器和RADIUS 认证服务器。Linux下支持的驱动有:Host AP,madwifi,基于mac80211的驱动。
从上面的一段话中可以了解到,hostapd仅是用于当设备处于ap模式时,进行设备底层的初始化,对需要连接该热点的设备认证及管理。并没有参与相关底层协议帧的组合和发送。
二、hostapd的网络接口和BSS初始化
2.1、简要说明
在该模块中,hostapd主要进行网络接口及网络网卡的初始化。初始化相应的接收回调函数,网卡相关执行信息的设置以及创建与kernel space层的socket句柄。
2.2、hostapd初始化
了解hostapd初始化之前首先了解以下两个结构体,因为这两个结构体在hostapd中使用的次数最多,也就是扮演的角色最关键。
/*--------------hostapd中两个关键的结构体----------*/
/**
* struct hostapd_iface - hostapd per-interface data structure
*/
struct hostapd_iface {
struct hostapd_config *conf: 保存对网络接口的配置(从配置文件hostapd.conf中加载)
sizt_t num_bss: 此接口下辖的BSS 个数
struct hostapd_data **bss:BSS 列表,描述各BSS 的配置
。。。
};
/**
* struct hostapd_data - hostapd per-BSS data structure
*/
struct hostapd_data {
struct hostapd_bss_config *conf:保存BSS 的配置信息(从配置文件hostapd.conf 中加载)
u8 own_addr[ETH_ALEN]:表示此BSS 的BSSID (ETH_ALEN 为6,u8 其实是unsigned char)
struct wpa_driver_ops *driver:指向一组驱动程序接口,用来和内核交互。(这里是用的nl80211)
。。。
};
//!!!以上结构体中写出的是最主要的结构体变量,其他的结构体变量暂时不需要重点了解。
接下来观察main函数中的几个重要的初始化。将以main中接口为入口进行展开说明。
/*----------------hostapd的main函数------------------*/
int main(int argc, char** argv)
{
...
if (hostapd_global_init(&interfaces, entropy_file)) //global的初始化
return -1;
/* Initialize interfaces */
for (i = 0; i < interfaces.count; i++)
{
interfaces.iface[i] = hostapd_interface_init(&interfaces, //对每个网络接口(物理网卡)初始化
argv[optind + i],
debug);
if (!interfaces.iface[i])
goto out;
}
if (hostapd_global_run(&interfaces, daemonize, pid_file)) //下一模块再进行说明
goto out;
...
}
/*----------------hostapd_global_init函数---------------*/
//global 初始化接口
static int hostapd_global_init(struct hapd_interfaces *interfaces,
const char *entropy_file)
{
int i;
os_memset(&global, 0, sizeof(global));
hostapd_logger_register_cb(hostapd_logger_cb);
if (eap_server_register_methods()) { //初始化认证服务器算法
wpa_printf(MSG_ERROR, "Failed to register EAP methods");
return -1;
}
if (eloop_init()) { //eloop初始化 主要为初始化eloop_data结构体
wpa_printf(MSG_ERROR, "Failed to initialize event loop");
return -1;
}
random_init(entropy_file);
eloop_register_signal_terminate(handle_term, interfaces); //相关信号处理回调初始化
for (i = 0; wpa_drivers[i]; i++)
global.drv_count++;
if (global.drv_count == 0) {
wpa_printf(MSG_ERROR, "No drivers enabled");
return -1;
}
global.drv_priv = os_calloc(global.drv_count, sizeof(void *)); //申请driver驱动私有数据空间
if (global.drv_priv == NULL)
return -1;
return 0;
}
/*-------------hostapd_interface_init函数--------------*/
//hostapd_interface_init:网卡初始化
static struct hostapd_iface *
hostapd_interface_init(struct hapd_interfaces *interfaces,
const char *config_fname, int debug)
{
struct hostapd_iface *iface;
int k;
wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
iface = hostapd_init(config_fname); //用于初始化网卡,iface为hostapd_init的(struct hostapd_iface结构体)返回值
if (!iface)
return NULL;
iface->interfaces = interfaces;
for (k = 0; k < debug; k++) {
if (iface->bss[0]->conf->logger_stdout_level > 0)
iface->bss[0]->conf->logger_stdout_level--;
}
if (iface->conf->bss[0].iface[0] != 0 ||
hostapd_drv_none(iface->bss[0]))
{
if (hostapd_driver_init(iface) || //初始化网络驱动
hostapd_setup_interface(iface)) { //设置网络接口
hostapd_interface_deinit_free(iface);
return NULL;
}
}
return iface;
}
/*---------------hostapd_init函数----------------*/
/**
* hostapd_init - Allocate and initialize per-interface data
* @config_file: Path to the configuration file
* Returns: Pointer to the allocated interface data or %NULL on failure
*
* This function is used to allocate main data structures for per-interface
* data. The allocated data buffer will be freed by calling
* hostapd_cleanup_iface().
*/
static struct hostapd_iface * hostapd_init(const char *config_file)
{
struct hostapd_iface *hapd_iface = NULL;
struct hostapd_config *conf = NULL;
struct hostapd_data *hapd;
size_t i;
hapd_iface = os_zalloc(sizeof(*hapd_iface));
if (hapd_iface == NULL)
goto fail;
hapd_iface->config_fname = os_strdup(config_file);
if (hapd_iface->config_fname == NULL)
goto fail;
conf = hostapd_config_read(hapd_iface->config_fname); //用于读取配置文件中的配置信息,一般的配置文件名(hostapd.conf)
if (conf == NULL)
goto fail;
hapd_iface->conf = conf;
hapd_iface->num_bss = conf->num_bss; //从配置中获取BSS的个数
hapd_iface->bss = os_calloc(conf->num_bss, //分配BSS列表空间
sizeof(struct hostapd_data *));
if (hapd_iface->bss == NULL)
goto fail;
for (i = 0; i < conf->num_bss; i++) {
hapd = hapd_iface->bss[i] =
hostapd_alloc_bss_data(hapd_iface, conf, //初始化每个BSS数据结构
&conf->bss[i]);
if (hapd == NULL)
goto fail;
hapd->msg_ctx = hapd;
hapd->setup_complete_cb = hostapd_setup_complete_cb;
}
return hapd_iface;
fail:
if (conf)
hostapd_config_free(conf);
if (hapd_iface) {
os_free(hapd_iface->config_fname);
os_free(hapd_iface->bss);
os_free(hapd_iface);
}
return NULL;
}