分析wpa_supplicant起始函数main源码
wpa_supplicant的目录及文件
本篇blog的源码来源于安卓10,对应的wpa_supplicant版本为8。
先来看下wpa_supplicant代码的目录结构
源码目录:
xxx@ubuntu-07:~/workspace/rk3399-android-10/external/wpa_supplicant_8$ ls
Android.mk CONTRIBUTIONS hostapd MODULE_LICENSE_BSD_LIKE OWNERS src wpa_supplicant
CleanSpec.mk COPYING hs20 NOTICE README tests
xxx@ubuntu-07:~/workspace/rk3399-android-10/external/wpa_supplicant_8$ cd src/
xxx@ubuntu-07:~/workspace/rk3399-android-10/external/wpa_supplicant_8/src$ ls
ap crypto eap_common eapol_supp eap_server l2_packet Makefile pae rsn_supp utils
common drivers eapol_auth eap_peer fst lib.rules p2p radius tls wps
关于上面每个文件夹大致的功能是什么网上有很多blog来讲述,讲的也非常清楚,可自行查看。
main
分析初始化之前,先看下安卓10跑起来后,在控制台输入logcat指令以后输出的系统debug信息。
logcat输出:
[17:16:13][ 46.176721] init: starting service 'wpa_supplicant'...
。。。。。一些其他的init输出
[17:16:13]11-18 11:10:06.091 +0000 2017 2017 I wpa_supplicant: argc = 2
第一句话是系统内核输出的,并非wpa_supplicant;这句话意味着wpas服务被启动,即调用了wpas的开始函数。经对比上方的输出和下方的代码,即可知,wpa_supplicant服务一开始进入的函数就是它~/wpa_supplicant/main.c里的main函数,上面贴出的最后一句输出和对应main里的printf对应上了。
wpa_supplicant的main函数:~/rk3399-android-10/external/wpa_supplicant_8/wpa_supplicant/main.c
#define BROADCOM_MODULE_NAME "[broadcom]"
#define REALTEK_MODULE_NAME "[realtek]"
#define SSV_MODULE_NAME "[ssv]"
#define ESP_MODULE_NAME "[esp]"
int main(int argc, char *argv[])
{
int ret = -1;
char module_type[20]={0};//实际上没有使用到
wpa_printf(MSG_INFO,"argc = %d\n",argc);
//这就是log里输出的那句,说明这是整个wpas服务的起始函数
//至于谁实际上调用了这个main函数并将argc和argv传进来,我暂时没找到,希望清楚这里的大佬指导一下
if(argc == 2) {
if (check_wifi_chip_type() == REALTEK_WIFI) {//别的文件里定义的函数和属性,见之后贴出的代码
wpa_printf(MSG_INFO,"Start rtl_wpa_supplicant\n");
ret = read_wpa_param_config(REALTEK_MODULE_NAME,argv[1]);//根据不同的芯片类型,读取wpa_config.txt中的不同属性
//REALTEK_MODULE_NAME为上方定义的全局变量
} else if (check_wifi_chip_type() == BROADCOM_WIFI) {//以下同上
wpa_printf(MSG_INFO,"Start bcm_wpa_supplicant\n");
ret = read_wpa_param_config(BROADCOM_MODULE_NAME,argv[1]);
} else if (check_wifi_chip_type() == RK912_WIFI ||
check_wifi_chip_type() == SSV_WIFI) {
wpa_printf(MSG_INFO,"Start ssv_wpa_supplicant\n");
ret = read_wpa_param_config(SSV_MODULE_NAME,argv[1]);
} else if (check_wifi_chip_type() == ESP_WIFI) {
wpa_printf(MSG_INFO,"Start esp_wpa_supplicant\n");
ret = read_wpa_param_config(ESP_MODULE_NAME,argv[1]);
} else {
wpa_printf(MSG_INFO,"Start wpa_supplicant\n");
ret = read_wpa_param_config(BROADCOM_MODULE_NAME,argv[1]);
}
} else {//如果传进来的第一个参数并非2,则调用main_loop
wpa_printf(MSG_INFO,"Start wpa_supplicant\n");
ret = main_loop(argc, argv);
}
return ret;
}
int main_loop(int argc, char *argv[])//不是本文重点,可忽略不看,只需知道是argv里各类参数的解析即可
{
int c, i;
struct wpa_interface *ifaces, *iface;
int iface_count, exitcode = -1;
struct wpa_params params;
struct wpa_global *global;
if (os_program_init())
return -1;
os_memset(¶ms, 0, sizeof(params));
params.wpa_debug_level = MSG_DEBUG;
iface = ifaces = os_zalloc(sizeof(struct wpa_interface));
if (ifaces == NULL)
return -1;
iface_count = 1;
wpa_supplicant_fd_workaround(1);
for (;;) {
c = getopt(argc, argv,
"b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuvW");
if (c < 0)
break;
switch (c) {//其实这部分,就相当于是解析wpa_config.txt里的参数的步骤
case 'b':
iface->bridge_ifname = optarg;
break;
case 'B':
params.daemonize++;
break;
。。。。。。
default:
usage();
exitcode = 0;
goto out;
}
}
exitcode = 0;
global = wpa_supplicant_init(¶ms);//调用初始化wpa_supplicant的函数
if (global == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize wpa_supplicant");
exitcode = -1;
goto out;
} else {
wpa_printf(MSG_INFO, "Successfully initialized "
"wpa_supplicant");
}
if (fst_global_init()) {
wpa_printf(MSG_ERROR, "Failed to initialize FST");
exitcode = -1;
goto out;
}
#if defined(CONFIG_FST) && defined(CONFIG_CTRL_IFACE)
if (!fst_global_add_ctrl(fst_ctrl_cli))
wpa_printf(MSG_WARNING, "Failed to add CLI FST ctrl");
#endif
for (i = 0; exitcode == 0 && i < iface_count; i++) {
struct wpa_supplicant *wpa_s;
if ((ifaces[i].confname == NULL &&
ifaces[i].ctrl_interface == NULL) ||
ifaces[i].ifname == NULL) {
if (iface_count == 1 && (params.ctrl_interface ||
#ifdef CONFIG_MATCH_IFACE
params.match_iface_count ||
#endif /* CONFIG_MATCH_IFACE */
params.dbus_ctrl_interface))
break;
usage();
exitcode = -1;
break;
}
wpa_s = wpa_supplicant_add_iface(global, &ifaces[i], NULL);
if (wpa_s == NULL) {
exitcode = -1;
break;
}
}
#ifdef CONFIG_MATCH_IFACE
if (exitcode == 0)
exitcode = wpa_supplicant_init_match(global);
#endif /* CONFIG_MATCH_IFACE */
if (exitcode == 0)
exitcode = wpa_supplicant_run(global);
wpa_supplicant_deinit(global);
fst_global_deinit();
out:
wpa_supplicant_fd_workaround(0);
os_free(ifaces);
#ifdef CONFIG_MATCH_IFACE
os_free(params.match_ifaces);
#endif /* CONFIG_MATCH_IFACE */
os_free(params.pid_file);
os_program_deinit();
return exitcode;
}
check_wifi_chip_type_string
文件位置:src/common/wpa_common.c
static char wifi_type[64] = {0};
extern int check_wifi_chip_type_string(char *type);
int check_wifi_chip_type()
{
int type;
if (wifi_type[0] == 0) {//若未赋值,则调用check_wifi_chip_type_string
//函数定义位置在~/android10/frameworks/opt/net/wifi/libwifi_hal/rk_wifi_ctrl.cpp中
check_wifi_chip_type_string(wifi_type);
//调用完上面的函数,会将wifi_type赋值成当前能检测到的wifi chip的类型名称
wpa_printf(MSG_INFO,"Current wifi chip is %s\n",wifi_type);
}
if (0 == strncmp(wifi_type, "RTL", 3)) {
type = REALTEK_WIFI;
} else if (0 == strncmp(wifi_type, "SSV", 3)) {
type = SSV_WIFI;
} else if (0 == strncmp(wifi_type, "ESP", 3)) {
type = ESP_WIFI;
} else if (0 == strncmp(wifi_type, "RK912", 5)) {
type = RK912_WIFI;
} else {
type = BROADCOM_WIFI;
}
return type;
}
这个函数调用完毕,会返回当前所使用wifi_chip的类型名称,以便在main中匹配到不同的if分支。
上述代码涉及到的一些定义见下:
定义所在文件位置:src/common/defs.h
/**
* enum wifi type
*/
enum wifi_tpye {
REALTEK_WIFI = 1,
BROADCOM_WIFI,
SSV_WIFI,
ESP_WIFI,
RK912_WIFI,
};
read_wpa_param_config
文件位置:~/rk3399-android-10/external/wpa_supplicant_8/wpa_supplicant/main.c
int read_wpa_param_config(char *module_name, char *file_path) {
char *wpa_param[50] = {0};
char wpa_param_buf[50][50];
int wpa_param_len = 0;
char buf[256] = {0};
FILE *fp = NULL;
char *pos;
int ret = -1;
int found = 0;
int i;
fp = fopen(file_path, "r");//打开文件,~/rk3399-android-10/device/rockchip/common/wpa_config.txt
wpa_printf(MSG_INFO,"module_name = %s\n",module_name);
if (fp == NULL) {
wpa_printf(MSG_ERROR,"%s not found\n",file_path);
return -1;
}
while(fgets(buf, sizeof(buf) -1, fp)) {//读取文件内容,截取字符串
pos = buf;
while (*pos != '\0') {
if (*pos == '\n' || *pos == ' ') {
*pos = '\0';
break;
}
pos++;
}
if(found == 0) {//需要找到文件中,与当前所求模块对应的一系列参数
if(strstr(buf,module_name)) {
found = 1;
wpa_printf(MSG_INFO,"found %s\n",module_name);
}
continue;
}
if(buf[0] == '\n' || buf[0] == '\0'|| buf[0] == '#' || buf[0] == ' ' || buf[0] == '[') {
wpa_printf(MSG_INFO,"wpa_param_len = %d\n",wpa_param_len);
break;
}
strcpy(wpa_param_buf[wpa_param_len],buf);
wpa_param_len++;//截取这些params字符串存储到wpa_param_buf中
}
fclose(fp);
for(i = 0; i < wpa_param_len; i++) {
wpa_param[i] = wpa_param_buf[i];//按行将每一行参数存到wpa_param中对应的行里
wpa_printf(MSG_INFO,"wpa_param_len = %d | wpa_param[%d] = %s\n",wpa_param_len,i,wpa_param[i]);
}
if(wpa_param_len > 0)
ret = main_loop(wpa_param_len,wpa_param);//跳转到main_loop中解析具体的每项参数,并且据此初始化一些接口
else
wpa_printf(MSG_ERROR,"%s not found\n",module_name);
return ret;
}
wpa_config.txt
文件位置:~/rk3399-android-10/device/rockchip/common/wpa_config.txt
里面的内容大致如下:
[broadcom]
/vendor/bin/hw/wpa_supplicant
-O/data/vendor/wifi/wpa/sockets
-puse_p2p_group_interface=1
-g@android:wpa_wlan0
[realtek]
/vendor/bin/hw/wpa_supplicant
-O/data/vendor/wifi/wpa/sockets
-g@android:wpa_wlan0
......
//还有很多其他厂商的wpas配置信息
如果需要移植wifi驱动,则需要配置好与wpa_supplicant交互的各类属性接口。