Wpa_supplicant工作流程分析
wpa_supplicant官网:https://w1.fi/wpa_supplicant/
wpa_supplicant源码下载官网地址:https://w1.fi/releases/
本文分析基于版本:V2.6
1. 初始化
wpa_supplicant/main.c
在main()中,完成了四件事。先看一下源代码,我们再来一一分析。
int main(int argc, char *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_INFO;
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) {
case 'b':
iface->bridge_ifname = optarg;
break;
case 'B':
params.daemonize++;
break;
case 'c':
iface->confname = optarg;
break;
case 'C':
iface->ctrl_interface = optarg;
break;
case 'D':
iface->driver = optarg;
break;
case 'd':
#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;
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");
}
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;
}
- 解析init.rc(这种情况是设备开机自启动wpa_supplicant进程时wpa_supplicant做的操作)或者是用户输入(如我们手动启动wpa_supplicant进程)的相关参数。一般格式如下:
wpa_supplicant/system/bin/wpa_supplicant -Dwext -iwlan0 -c /data/misc/wifi/wpa_supplicant.conf
-D : 表示用那种驱动程序,一般默认是wext。现在大部分
都是用nl80211。
-i : 表示网络接口名称
-c : 表示配置文件名称
从源码中我们可以看到,在main中,wpa_supplicant会根据传进来的参数填充iface和param这两个结构体。
-
调用wpa_supplicant_init()进行一些初始化的操作。
wpa_supplicant_init()返回的数据指针可用于添加和删除
网络接口。
-
调用wpa_supplicant_add_iface()来添加控制接口。
- 创建一个wpa_supplicant结构体。
- 调用wpa_supplicant_init_iface()去做一些出初始化接口的工作。
-
调用wpa_supplicant_run()运行wpa_supplicant事件主循环。
对eloop循环进行配置后调用eloop_run)()让eloop循环run起来。然后wpa_supplicant就在这个循环中处理来自上层的命令和来自下层的事件。
2. wpa_supplicant如何接收和响应上层命令
void eloop_run(void)
{
#ifdef CONFIG_ELOOP_POLL
int num_poll_fds;
int timeout_ms = 0;
#endif /* CONFIG_ELOOP_POLL */
#ifdef CONFIG_ELOOP_SELECT
fd_set *rfds, *wfds, *efds;
struct timeval _tv;
#endif /* CONFIG_ELOOP_SELECT */
#ifdef CONFIG_ELOOP_EPOLL
int timeout_ms = -1;
#endif /* CONFIG_ELOOP_EPOLL */
#ifdef CONFIG_ELOOP_KQUEUE
struct timespec ts;
#endif /* CONFIG_ELOOP_KQUEUE */
int res;
struct os_reltime tv, now;
#ifdef CONFIG_ELOOP_SELECT
rfds = os_malloc(sizeof(*rfds));
wfds = os_malloc(sizeof(*wfds));
efds = os_malloc(sizeof(*efds));
if (rfds == NULL || wfds == NULL || efds == NULL)
goto out;
#endif /* CONFIG_ELOOP_SELECT */
while (!eloop.terminate &&
(!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
struct eloop_timeout *timeout;
if (eloop.pending_terminate) {
/*
* This may happen in some corner cases where a signal
* is received during a blocking operation. We need to
* process the pending signals and exit if requested to
* avoid hitting the SIGALRM limit if the blocking
* operation took more than two seconds.
*/
eloop_process_pending_signals();
if (eloop.terminate)
break;
}
timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
list);
if (timeout) {
os_get_reltime(&now);
if (os_reltime_before(&now, &timeout->time))
os_reltime_sub(&timeout->time, &now, &tv);
else
tv.sec = tv.usec = 0;
#if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL)
timeout_ms = tv.sec * 1000 + tv.usec / 1000;
#endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */
#ifdef CONFIG_ELOOP_SELECT
_tv.tv_sec = tv.sec;
_tv.tv_usec = tv.usec;
#endif /* CONFIG_ELOOP_SELECT */
#ifdef CONFIG_ELOOP_KQUEUE
ts.tv_sec = tv.sec;
ts.tv_nsec = tv.usec * 1000L;
#endif /* CONFIG_ELOOP_KQUEUE */
}
#ifdef CONFIG_ELOOP_POLL
num_poll_fds = eloop_sock_table_set_fds(
&eloop.readers, &eloop.writers, &eloop.exceptions,
eloop.pollfds, eloop.pollfds_map,
eloop.max_pollfd_map);
res = poll(eloop.pollfds, num_poll_fds,
timeout ? timeout_ms : -1);
#endif /* CONFIG_ELOOP_POLL */
#ifdef CONFIG_ELOOP_SELECT
eloop_sock_table_set_fds(&eloop.readers, rfds);
eloop_sock_table_set_fds(&eloop.writers, wfds);
eloop_sock_table_set_fds(&eloop.exceptions, efds);
res = select(eloop.max_sock + 1, rfds, wfds, efds,
timeout ? &_tv : NULL);
#endif /* CONFIG_ELOOP_SELECT */
#ifdef CONFIG_ELOOP_EPOLL
if (eloop.count == 0) {
res = 0;
} else {
res = epoll_wait(eloop.epollfd, eloop.epoll_events,
eloop.count, timeout_ms);
}
#endif /* CONFIG_ELOOP_EPOLL */
#ifdef CONFIG_ELOOP_KQUEUE
if (eloop.count == 0) {
res = 0;
} else {
res = kevent(eloop.kqueuefd, NULL, 0,
eloop.kqueue_events, eloop.kqueue_nevents,
timeout ? &ts : NULL);
}
#endif /* CONFIG_ELOOP_KQUEUE */
if (res < 0 && errno != EINTR && errno != 0) {
wpa_printf(MSG_ERROR, "eloop: %s: %s",
#ifdef CONFIG_ELOOP_POLL
"poll"
#endif /* CONFIG_ELOOP_POLL */
#ifdef CONFIG_ELOOP_SELECT
"select"
#endif /* CONFIG_ELOOP_SELECT */
#ifdef CONFIG_ELOOP_EPOLL
"epoll"
#endif /* CONFIG_ELOOP_EPOLL */
#ifdef CONFIG_ELOOP_KQUEUE
"kqueue"
#endif /* CONFIG_ELOOP_EKQUEUE */
, strerror(errno));
goto out;
}
eloop.readers.changed = 0;
eloop.writers.changed = 0;
eloop.exceptions.changed = 0;
eloop_process_pending_signals();
/* check if some registered timeouts have occurred */
timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
list);
if (timeout) {
os_get_reltime(&now);
if (!os_reltime_before(&now, &timeout->time)) {
void *eloop_data = timeout->eloop_data;
void *user_data = timeout->user_data;
eloop_timeout_handler handler =
timeout->handler;
eloop_remove_timeout(timeout);
handler(eloop_data, user_data);
}
}
if (res <= 0)
continue;
if (eloop.readers.changed ||
eloop.writers.changed ||
eloop.exceptions.changed) {
/*
* Sockets may have been closed and reopened with the
* same FD in the signal or timeout handlers, so we
* must skip the previous results and check again
* whether any of the currently registered sockets have
* events.
*/
continue;
}
#ifdef CONFIG_ELOOP_POLL
eloop_sock_table_dispatch(&eloop.readers, &eloop.writers,
&eloop.exceptions, eloop.pollfds_map,
eloop.max_pollfd_map);
#endif /* CONFIG_ELOOP_POLL */
/*
*调用select系统调用以轮询几类事件:相关fd是否可读、可写
*是否有异常发生、超时。
*如果相关事件发生时,eloop_sock_table_dispatch()将按照*下面的方式来处理它,它会通过调用相关的handler()回调函数来*处理这些事件。
*/
#ifdef CONFIG_ELOOP_SELECT
eloop_sock_table_dispatch(&eloop.readers, rfds);
eloop_sock_table_dispatch(&eloop.writers, wfds);
eloop_sock_table_dispatch(&eloop.exceptions, efds);
#endif /* CONFIG_ELOOP_SELECT */
#ifdef CONFIG_ELOOP_EPOLL
eloop_sock_table_dispatch(eloop.epoll_events, res);
#endif /* CONFIG_ELOOP_EPOLL */
#ifdef CONFIG_ELOOP_KQUEUE
eloop_sock_table_dispatch(eloop.kqueue_events, res);
#endif /* CONFIG_ELOOP_KQUEUE */
}
eloop.terminate = 0;
out:
#ifdef CONFIG_ELOOP_SELECT
os_free(rfds);
os_free(wfds);
os_free(efds);
#endif /* CONFIG_ELOOP_SELECT */
return;
}
3. handler()回调函数的注册
以read事件为例:
不同类型的事件来源会写自己的handler函数,如udp、unix通用等。最终都会调用一下接口:
-->eloop_register_read_sock()
-->eloop_register_sock()
-->eloop_get_sock_table() //不同类型返回不同的table
-->eloop_sock_table_add_sock() //将其添加到table->table[i].handler
通过上面这个流程,先关handler()回调函数就被注册到table,当相关事件发生后,在调用相关的handler()对事件进行处理。
4. wpa_supplicant 扫描流程分析
在上一小节中说到了注册handler()回调函数,其中一个read事件的handler()注册接口如下:
eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,wpa_s, priv);
该接口注册了一个wpa_supplicant_ctrl_iface_receive()的handler。
- wpa_supplicant_ctrl_iface_receive()的主要工作是监听socket,并且处理来自相关socket的command。下面来看下该函数的源码:
static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,void *sock_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct ctrl_iface_priv *priv = sock_ctx;
char buf[4096];
int res;
struct sockaddr_storage from;
socklen_t fromlen = sizeof(from);
char *reply = NULL, *reply_buf = NULL;
size_t reply_len = 0;
int new_attached = 0;
//recvform()监听相关socket
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *)&from,&fromlen);
if (res < 0) {
wpa_printf(MSG_ERROR,"recvfrom(ctrl_iface): %s",strerror(errno));
return;
}
buf[res] = '\0';
if (os_strcmp(buf, "ATTACH") == 0) {
if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from,fromlen, 0))
reply_len = 1;
else {
new_attached = 1;
reply_len = 2;
}
} else if (os_strcmp(buf, "DETACH") == 0) {
if(wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, &from,fromlen))
reply_len = 1;
else
reply_len = 2;
} else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen,buf + 6))
reply_len = 1;
else
reply_len = 2;
} else {
/*
*将相关命令,交给wpa_supplicant_ctrl_iface_process() *来处理。
*/
reply_buf = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
&reply_len);
reply = reply_buf;
....
/*
*将相关的处理结果反馈给相应的socket。
*/
if (reply) {
wpas_ctrl_sock_debug("ctrl_sock-sendto", sock, reply,
reply_len);
if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
fromlen) < 0) {
int _errno = errno;
wpa_dbg(wpa_s, MSG_DEBUG,
"ctrl_iface sendto failed: %d - %s",
_errno, strerror(_errno));
if (_errno == ENOBUFS || _errno == EAGAIN) {
/*
* The socket send buffer could be full. This
* may happen if client programs are not
* receiving their pending messages. Close and
* reopen the socket as a workaround to avoid
* getting stuck being unable to send any new
* responses.
*/
sock = wpas_ctrl_iface_reinit(wpa_s, priv);
if (sock < 0) {
wpa_dbg(wpa_s, MSG_DEBUG, "Failed to reinitialize ctrl_iface socket");
}
}
if (new_attached) {
wpa_dbg(wpa_s, MSG_DEBUG, "Failed to send response to ATTACH - detaching");
new_attached = 0;
wpa_supplicant_ctrl_iface_detach(
&priv->ctrl_dst, &from, fromlen);
}
}
}
os_free(reply_buf);
if (new_attached)
eapol_sm_notify_ctrl_attached(wpa_s->eapol);
}
-
wpa_supplicant_ctrl_iface_process()
wpa_supplicant_ctrl_iface_process()接口会对命令的类型进行判断,如“SCAN”
···
else if(os_strcmp(buf,"SCAN") == 0)
if(!wpa_s->scan_ongoing){
wpa_s->scan_req = 2;
wpa_supplicant_req_scan(wpa_s,0,0);
}else
wpa_printf(MSG_DEBUG,"Ongoing Scan action...");
...
- wpa_ctrl_scan() 处理扫描命令
- wpa_supplicant_req_scan 安排对附近的AP进行扫描
- wpa_supplicant通过前面讲到的‘-D“参数调用driver的ioctl接口。这里可以看到wpa_supplicant对下的一些驱动接口。
const struct wpa_driver_ops *const wpa_drivers[] =
{
#ifdef CONFIG_DRIVER_NL80211
&wpa_driver_nl80211_ops,
#endif /* CONFIG_DRIVER_NL80211 */
#ifdef CONFIG_DRIVER_WEXT
&wpa_driver_wext_ops,
#endif /* CONFIG_DRIVER_WEXT */
#ifdef CONFIG_DRIVER_HOSTAP
&wpa_driver_hostap_ops,
#endif /* CONFIG_DRIVER_HOSTAP */
#ifdef CONFIG_DRIVER_BSD
&wpa_driver_bsd_ops,
#endif /* CONFIG_DRIVER_BSD */
#ifdef CONFIG_DRIVER_OPENBSD
&wpa_driver_openbsd_ops,
#endif /* CONFIG_DRIVER_OPENBSD */
#ifdef CONFIG_DRIVER_NDIS
&wpa_driver_ndis_ops,
#endif /* CONFIG_DRIVER_NDIS */
#ifdef CONFIG_DRIVER_WIRED
&wpa_driver_wired_ops,
#endif /* CONFIG_DRIVER_WIRED */
#ifdef CONFIG_DRIVER_MACSEC_QCA
&wpa_driver_macsec_qca_ops,
#endif /* CONFIG_DRIVER_MACSEC_QCA */
#ifdef CONFIG_DRIVER_ROBOSWITCH
&wpa_driver_roboswitch_ops,
#endif /* CONFIG_DRIVER_ROBOSWITCH */
#ifdef CONFIG_DRIVER_ATHEROS
&wpa_driver_atheros_ops,
#endif /* CONFIG_DRIVER_ATHEROS */
#ifdef CONFIG_DRIVER_NONE
&wpa_driver_none_ops,
#endif /* CONFIG_DRIVER_NONE */
NULL
};
//以wext为例看看它支持的相关接口
const struct wpa_driver_ops wpa_driver_wext_ops = {
.name = "wext",
.desc = "Linux wireless extensions (generic)",
.get_bssid = wpa_driver_wext_get_bssid,
.get_ssid = wpa_driver_wext_get_ssid,
.set_key = wpa_driver_wext_set_key,
.set_countermeasures = wpa_driver_wext_set_countermeasures,
.scan2 = wpa_driver_wext_scan,
.get_scan_results2 = wpa_driver_wext_get_scan_results,
.deauthenticate = wpa_driver_wext_deauthenticate,
.associate = wpa_driver_wext_associate,
.init = wpa_driver_wext_init,
.deinit = wpa_driver_wext_deinit,
.add_pmkid = wpa_driver_wext_add_pmkid,
.remove_pmkid = wpa_driver_wext_remove_pmkid,
.flush_pmkid = wpa_driver_wext_flush_pmkid,
.get_capa = wpa_driver_wext_get_capa,
.set_operstate = wpa_driver_wext_set_operstate,
.get_radio_name = wext_get_radio_name,
.signal_poll = wpa_driver_wext_signal_poll,
.status = wpa_driver_wext_status,
};
- wpa_supplicant_scan —> wpa_supplicant_trigger_scan 请求driver进行scan
int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
struct wpa_driver_scan_params *params)
{
struct wpa_driver_scan_params *ctx;
if (wpa_s->scan_work) {
wpa_dbg(wpa_s, MSG_INFO, "Reject scan trigger since one is already pending");
return -1;
}
ctx = wpa_scan_clone_params(params);
if (!ctx ||
radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0)
{
wpa_scan_free_params(ctx);
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=-1");
return -1;
}
return 0;
}
-
radio_add_work–>wpas_trigger_scan_cb(回调函数)–>wpa_drv_scan
调用之前指定驱动所注册的函数,比如之前-D参数指定的驱动,假如指定的是wext,那么会调用到wpa_s->driver->scan2调用到
wpa_driver_wext_scan
(这个在前面有提到过,这个结构体wpa_driver_wext_ops会注册这个接口)通过ioctl将扫描指令下发给driver。
static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s,struct wpa_driver_scan_params *params)
{
#ifdef CONFIG_TESTING_OPTIONS
if (wpa_s->test_failure == WPAS_TEST_FAILURE_SCAN_TRIGGER)
return -EBUSY;
#endif /* CONFIG_TESTING_OPTIONS */
//此处回去选择调用相关驱动注册的scan接口
if (wpa_s->driver->scan2)
return wpa_s->driver->scan2(wpa_s->drv_priv, params);
return -1;
}
...
int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params)
{
....//省略无关代码
//通过ioctl()接口将扫描请求下发到driver,drv->ioctl_sock在下面会讲到
if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
wpa_printf(MSG_ERROR, "ioctl[SIOCSIWSCAN]: %s",
strerror(errno));
ret = -1;
}
....//省略无关代码
}
//ioctl()接口中使用了drv->ioctl_sock,它是来自于wpa_driver_wext_init(),该函数主要对wext driver接口进行初始化,如下:
void * wpa_driver_wext_init(void *ctx, const char *ifname)
{
struct wpa_driver_wext_data *drv;
struct netlink_config *cfg;
struct rfkill_config *rcfg;
char path[128];
struct stat buf;
drv = os_zalloc(sizeof(*drv));
if (drv == NULL)
return NULL;
drv->ctx = ctx;
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
os_snprintf(path, sizeof(path), "/sys/class/net/%s/phy80211", ifname);
if (stat(path, &buf) == 0) {
wpa_printf(MSG_DEBUG, "WEXT: cfg80211-based driver detected");
drv->cfg80211 = 1;
wext_get_phy_name(drv);
}
//我们用到的drv->ioctl_sock,在此处创建以及初始化
drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (drv->ioctl_sock < 0) {
wpa_printf(MSG_ERROR, "socket(PF_INET,SOCK_DGRAM): %s",strerror(errno));
goto err1;
}
cfg = os_zalloc(sizeof(*cfg));
if (cfg == NULL)
goto err1;
cfg->ctx = drv;
cfg->newlink_cb = wpa_driver_wext_event_rtm_newlink;
cfg->dellink_cb = wpa_driver_wext_event_rtm_dellink;
drv->netlink = netlink_init(cfg);
if (drv->netlink == NULL) {
os_free(cfg);
goto err2;
}
rcfg = os_zalloc(sizeof(*rcfg));
if (rcfg == NULL)
goto err3;
rcfg->ctx = drv;
os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname));
rcfg->blocked_cb = wpa_driver_wext_rfkill_blocked;
rcfg->unblocked_cb = wpa_driver_wext_rfkill_unblocked;
drv->rfkill = rfkill_init(rcfg);
if (drv->rfkill == NULL) {
wpa_printf(MSG_DEBUG, "WEXT: RFKILL status not available");
os_free(rcfg);
}
drv->mlme_sock = -1;
if (wpa_driver_wext_finish_drv_init(drv) < 0)
goto err3;
wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 1);
return drv;
err3:
rfkill_deinit(drv->rfkill);
netlink_deinit(drv->netlink);
err2:
close(drv->ioctl_sock);
err1:
os_free(drv);
return NULL;
}
至此,wpa_supplicant的工作已经全部完成。接下,这个scan指令会继续下发kernel中交给driver去实现。