按之前计划的,这期我们来看 driver如何告诉supplicant自己(被要求)做的一些事情以及结果
老样子,adb logcat -c /adb logcat -s wpa_supplicant
会发现如下的类似打印
06-24 11:58:41.768 31436 31436 D wpa_supplicant: nl80211: Drv Event 33 (NL80211_CMD_TRIGGER_SCAN) received for wlan0
于是我们定位了 driver与supplicant通信的关键一环
还记得之前 wpa_supplicant 初始化过程中调用的 nl80211_global_init 吗
nl80211_global_init //上述的 global_init
global->netlink = netlink_init(cfg);
wpa_driver_nl80211_init_nl_global(global)
//这里涉及到 netlink 的使用,没必要深究
nl80211_register_eloop_read(&global->nl_event, wpa_driver_nl80211_event_receive, global->nl_cb, 0);
eloop_register_read_sock(nl_socket_get_fd(*handle), wpa_driver_nl80211_event_receive, global->nl_cb, *handle); // 所以我们知道通过netlink报过来的事件都由 wpa_driver_nl80211_event_receive 处理
global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
这里其实描述的有些错误
在 nl80211_register_eloop_read 之前有一行
nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_global_event, global);
目前看不大懂,但大致能猜到这是设置 netlink80211 报上来事件时会调用的回调函数
int process_global_event(struct nl_msg *msg, void *arg)
dl_list_for_each_safe(drv, tmp, &global->interfaces, struct wpa_driver_nl80211_data, list) {
for (bss = drv->first_bss; bss; bss = bss->next) {
do_process_drv_event(bss, gnlh->cmd, tb);
return NL_SKIP;
}
}
遍历每个 interface 的每个bss,处理nl80211报上来的事件
static void do_process_drv_event(struct i802_bss *bss, int cmd, struct nlattr **tb) {
wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s", cmd, nl80211_command_to_string(cmd), bss->ifname);
switch(cmd) {
case NL80211_CMD_TRIGGER_SCAN:
wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL);
break;
case ###:
mlme_event_###(###);
break;
case ###:
nl80211_###(###);
break;
default:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event (cmd=%d)", cmd);
break;
}
}
对各种case的处理看起来有3类,实际最后的处理都是 wpa_supplicant
wpa_supplicant_event 是一个800多行的函数,里面按 event_type 对各种事件做处理,事件相关的数据都放在wpa_event_data中传入
do_process_drv_event 一定要做的事情就是 按事先沟通好的格式从 struct nlattr **tb 这个二维数组中取出数据,以便下一步处理
以 NL80211_CMD_NEW_SCAN_RESULTS 为例我们看下 wpa_supplicant_event 的处理
case EVENT_SCAN_RESULTS:
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
wpa_s->scan_res_handler = NULL;
wpa_s->own_scan_running = 0;
wpa_s->radio->external_scan_req_interface = NULL;
wpa_s->last_scan_req = NORMAL_SCAN_REQ;
break;
}
if (!(data && data->scan_info.external_scan) &&
os_reltime_initialized(&wpa_s->scan_start_time)) {
struct os_reltime now, diff;
os_get_reltime(&now);
os_reltime_sub(&now, &wpa_s->scan_start_time, &diff);
wpa_s->scan_start_time.sec = 0;
wpa_s->scan_start_time.usec = 0;
wpa_dbg(wpa_s, MSG_DEBUG, "Scan completed in %ld.%06ld seconds",
diff.sec, diff.usec);
}
if (wpa_supplicant_event_scan_results(wpa_s, data))
break; /* interface may have been removed */
if (!(data && data->scan_info.external_scan))
wpa_s->own_scan_running = 0;
if (data && data->scan_info.nl_scan_event)
wpa_s->radio->external_scan_req_interface = NULL;
radio_work_check_next(wpa_s);
break;
可以看出 wpa_supplicant_event 会根据事件类型调用 更多 wpa_supplicant_event_ 前缀的api
就看到这里吧。
有一点感悟是 supplicant 的架构设计很严苛,牢记每一层 api 的前缀可以帮助读者很快掌握每个函数应该做到的事情
例如,supplicant通报fwk事件的api大部分都有 wpas_notify 前缀,再比如这期我们看到的 wpa_supplicant_event 则是supplicant自己内部的处理,nl80211的一些ops都是 nl80211_ 前缀