main()
int main(int argc, char *argv[])
{
int c, i;
// 重要的数据结构1
struct wpa_interface *ifaces, *iface;
int iface_count, exitcode = -1;
struct wpa_params params;
// 重要的数据结构2
struct wpa_global *global;
if (os_program_init())
return -1;
os_memset(¶ms, 0, sizeof(params));
// 设置log等级,external/wpa_supplicant_8/hostapd/src/utils/wpa_debug.c中也会设置 log等级,但是在这里会被重新修改
params.wpa_debug_level = MSG_INFO;
iface = ifaces = os_zalloc(sizeof(struct wpa_interface));
if (ifaces == NULL)
return -1;
iface_count = 1;
// 标准输入输出重定向到/dev/null
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;
// 添加调试log,便于code分析
wpa_printf(MSG_ERROR,"argv:\t -%c %s\n", c, optarg);
switch (c) {
case 'b':
iface->bridge_ifname = optarg;
break;
case 'B':
params.daemonize++;
break;
case 'c':
// 指定的配置文件如:wpa_supplicant.conf
iface->confname = optarg;
break;
case 'C':
iface->ctrl_interface = optarg;
break;
case 'D':
// 驱动名称如 -Dnl80211
iface->driver = optarg;
break;
case 'd':
// log 等级
#ifdef CONFIG_NO_STDOUT_DEBUG
printf("Debugging disabled with "
"CONFIG_NO_STDOUT_DEBUG=y build time "
"option.\n");
goto out;
#else /* CONFIG_NO_STDOUT_DEBUG */
params.wpa_debug_level--;
break;
#endif /* CONFIG_NO_STDOUT_DEBUG */
case 'e':
params.entropy_file = optarg;
break;
#ifdef CONFIG_DEBUG_FILE
case 'f':
params.wpa_debug_file_path = optarg;
break;
#endif /* CONFIG_DEBUG_FILE */
case 'g':
params.ctrl_interface = optarg;
break;
case 'G':
params.ctrl_interface_group = optarg;
break;
case 'h':
usage();
exitcode = 0;
goto out;
case 'i':
//网络接口名称
iface->ifname = optarg;
break;
case 'I':
iface->confanother = optarg;
break;
case 'K':
params.wpa_debug_show_keys++;
break;
case 'L':
license();
exitcode = 0;
goto out;
#ifdef CONFIG_P2P
case 'm':
params.conf_p2p_dev = optarg;
break;
#endif /* CONFIG_P2P */
case 'o':
params.override_driver = optarg;
break;
case 'O':
params.override_ctrl_interface = optarg;
break;
case 'p':
iface->driver_param = optarg;
break;
case 'P':
os_free(params.pid_file);
params.pid_file = os_rel2abs_path(optarg);
break;
case 'q':
params.wpa_debug_level++;
break;
#ifdef CONFIG_DEBUG_SYSLOG
case 's':
params.wpa_debug_syslog++;
break;
#endif /* CONFIG_DEBUG_SYSLOG */
#ifdef CONFIG_DEBUG_LINUX_TRACING
case 'T':
params.wpa_debug_tracing++;
break;
#endif /* CONFIG_DEBUG_LINUX_TRACING */
case 't':
params.wpa_debug_timestamp++;
break;
#ifdef CONFIG_DBUS
case 'u':
params.dbus_ctrl_interface = 1;
break;
#endif /* CONFIG_DBUS */
case 'v':
printf("%s\n", wpa_supplicant_version);
exitcode = 0;
goto out;
case 'W':
params.wait_for_monitor++;
break;
#ifdef CONFIG_MATCH_IFACE
case 'M':
params.match_iface_count++;
iface = os_realloc_array(params.match_ifaces,
params.match_iface_count,
sizeof(struct wpa_interface));
if (!iface)
goto out;
params.match_ifaces = iface;
iface = ¶ms.match_ifaces[params.match_iface_count -
1];
os_memset(iface, 0, sizeof(*iface));
break;
#endif /* CONFIG_MATCH_IFACE */
case 'N':
iface_count++;
iface = os_realloc_array(ifaces, iface_count,
sizeof(struct wpa_interface));
if (iface == NULL)
goto out;
ifaces = iface;
iface = &ifaces[iface_count - 1];
os_memset(iface, 0, sizeof(*iface));
break;
default:
usage();
exitcode = 0;
goto out;
}
}
exitcode = 0;
//主要函数1 : 创建并初始化一个global
global = wpa_supplicant_init(¶ms);
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");
}
// 初始化 fst
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;
}
// 主要函数2 : 支持多个无线网络设备,
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 */
// 启动, wpa_supplicant 通过epoll 方式实现多路I/O复用
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;
}
重要的数据结构1 : wpa_interface:
每个wpa_interface对象描述一个无线网络设备,对应一个wpa_supplicant,
struct wpa_interface { /** * confname - Configuration name (file or profile) name * * This can also be %NULL when a configuration file is not used. In * that case, ctrl_interface must be set to allow the interface to be * configured. */ const char *confname; // 配置文件名 /** * confanother - Additional configuration name (file or profile) name * * This can also be %NULL when the additional configuration file is not * used. */ const char *confanother; /** * ctrl_interface - Control interface parameter * * If a configuration file is not used, this variable can be used to * set the ctrl_interface parameter that would have otherwise been read * from the configuration file. If both confname and ctrl_interface are * set, ctrl_interface is used to override the value from configuration * file. */ const char *ctrl_interface; //控制接口路径 /** * driver - Driver interface name, or %NULL to use the default driver */ const char *driver; // 对应的驱动名 /** * driver_param - Driver interface parameters * * If a configuration file is not used, this variable can be used to * set the driver_param parameters that would have otherwise been read * from the configuration file. If both confname and driver_param are * set, driver_param is used to override the value from configuration * file. */ const char *driver_param; /** * ifname - Interface name */ const char *ifname; //网络接口设备名 /** * bridge_ifname - Optional bridge interface name * * If the driver interface (ifname) is included in a Linux bridge * device, the bridge interface may need to be used for receiving EAPOL * frames. This can be enabled by setting this variable to enable * receiving of EAPOL frames from an additional interface. */ const char *bridge_ifname; /** * p2p_mgmt - Interface used for P2P management (P2P Device operations) * * Indicates whether wpas_p2p_init() must be called for this interface. * This is used only when the driver supports a dedicated P2P Device * interface that is not a network interface. */ int p2p_mgmt; };
重要的数据结构2, wpa_global :
wpa_global对象描述全局上下文信息
struct wpa_global { struct wpa_supplicant *ifaces; // 指向wpa_supplicant对象链表 struct wpa_params params; struct ctrl_iface_global_priv *ctrl_iface; // 对应全局控制接口,如果设置了该接口,其他wap_interface设置的控制接口将被代替 struct wpas_dbus_priv *dbus; struct wpas_binder_priv *binder; void **drv_priv; // = wpa_drivers[i]->global_init():包含driver所需要的全局上下文信息 size_t drv_count; struct os_time suspend_time; struct p2p_data *p2p; struct wpa_supplicant *p2p_init_wpa_s; struct wpa_supplicant *p2p_group_formation; struct wpa_supplicant *p2p_invite_group; u8 p2p_dev_addr[ETH_ALEN]; struct os_reltime p2p_go_wait_client; struct dl_list p2p_srv_bonjour; /* struct p2p_srv_bonjour */ struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */ int p2p_disabled; int cross_connection; struct wpa_freq_range_list p2p_disallow_freq; struct wpa_freq_range_list p2p_go_avoid_freq; enum wpa_conc_pref { WPA_CONC_PREF_NOT_SET, WPA_CONC_PREF_STA, WPA_CONC_PREF_P2P } conc_pref; unsigned int p2p_per_sta_psk:1; unsigned int p2p_fail_on_wps_complete:1; unsigned int p2p_24ghz_social_channels:1; unsigned int pending_p2ps_group:1; unsigned int pending_group_iface_for_p2ps:1; unsigned int pending_p2ps_group_freq; #ifdef CONFIG_WIFI_DISPLAY int wifi_display; #define MAX_WFD_SUBELEMS 10 struct wpabuf *wfd_subelem[MAX_WFD_SUBELEMS]; #endif /* CONFIG_WIFI_DISPLAY */ struct psk_list_entry *add_psk; /* From group formation */ };
综上
main函数主要做了如下事情:
1. 解析启动参数
2. global = wpa_supplicant_init(¶ms);
3. fst_global_init()
4. wpa_s = wpa_supplicant_add_iface(global, &ifaces[i], NULL);
5. exitcode = wpa_supplicant_run(global);
启动参数:
device/qcom/common/rootdir/etc/init.qcom.rc
service wpa_supplicant /vendor/bin/hw/wpa_supplicant \
-O/data/vendor/wifi/wpa/sockets -puse_p2p_group_interface=1 -dd \
-g@android:vendor_wpa_wlan0
# we will start as root and wpa_supplicant will switch to user wifi
# after setting up the capabilities required for WEXT
# user wifi
# group wifi inet keystore
interface android.hardware.wifi.supplicant@1.0::ISupplicant default
interface android.hardware.wifi.supplicant@1.1::ISupplicant default
class main
socket vendor_wpa_wlan0 dgram 660 wifi wifi
disabled
oneshot
启动参数log:
E wpa_supplicant: argv: -O /data/vendor/wifi/wpa/sockets
E wpa_supplicant: argv: -p use_p2p_group_interface=1
E wpa_supplicant: argv: -d (null)
E wpa_supplicant: argv: -d (null)
E wpa_supplicant: argv: -g @android:vendor_wpa_wlan0