【wpa_supplicant】driver如何告诉supplicant自己做的一些事情以及结果

本文深入探讨了driver如何通过nl80211与wpa_supplicant进行通信,重点分析了NL80211_CMD_TRIGGER_SCAN事件的处理流程,包括事件的接收、回调函数nl_cb_set的设置以及wpa_supplicant_event函数的角色。wpa_supplicant_event根据不同的事件类型调用相应处理函数,确保网络连接的顺畅。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

按之前计划的,这期我们来看 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_event
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_ 前缀

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值