###1. wpa_supplicant_scan()

WPAS 中, 扫描任务由 wpa_supplicant_scan() 来完成

通过向 eloop 核心注册timeout事件, 到期后触发 wpa_supplicant_scan()执行, 实现了定时扫描, 若循环触发定时扫描, 则还可以实现周期扫描

WPAS 中有4个接口来控制 wpa_supplicant_scan 任务:

  • wpa_supplicant_update_scan_int() 更新扫描间隔时间
  • wpa_supplicant_req_scan() 开始调度扫描任务
  • wpa_supplicant_cancel_scan() 停止调度扫描任务
  • wpas_scan_scheduled() 扫描任务是否被调度

###2. WPAS 中的周期扫描

若当前未连接到AP, 且 WPAS 不处于DISCONNECTED的状态, 并且保存了未被disable的AP, 则WPAS会发起周期扫描

周期扫描的 间隔时间存储在 struct wpa_supplicant.scan_interval 成员中:

  • 初始值为10秒
  • 可以通过 wpa_cli 的“SCAN_INTERVAL” cmd 来设置间隔时间 (android framework中设置为15s)

如下情况会终止周期扫描

  • 在连接上AP后, 会停止周期扫描
  • android上, 灭屏后, 会设置PNO扫描, 因此也会停止WPAS的周期扫

###3. sched scan

如果wifi driver支持sched scan的话, WPAS可以使用sched scan来进行定时扫描

sched scan 的扫描间隔存储在 struct wpa_supplicant.sched_scan_interval 中

  • 默认值为10s
  • 可以在wpa_supplicant.conf中使用“sched_scan_interval”项来配置
  • android上在 “frameworks/base/core/res/res/values/config.xml” 中的 “config_wifi_supplicant_scan_interval” 项设置

WPAS中的 sched scan 的接口为:

//设置定时扫描间隔并且开始扫描
int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
			    struct wpa_driver_scan_params *params,
			    int interval)

//停止定时扫描
int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s)

//这两个接口是通过调用上述2个接口实现的, 会自动处理 MAX_SCAN_SSID 的问题
int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s)

//同上2个接口, 但是延时开始定时扫描
int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
			      int sec, int usec)
void wpa_supplicant_cancel_delayed_sched_scan(struct wpa_supplicant *wpa_s)

###4. PNO scan

PNO (Prefered Network Offloading) 机制使得上层应用可以请求wifi firmware扫描指定的ssid:

  • 上层应用给出一份 SSID 列表给wifi firmware
  • 在进入 early suspend时, 开始PNO扫描, 在late resume之后停止扫描

PNO 通常用于在android设备灭屏后, 未连接AP, 但是保存了AP的情况下进行扫描, 以选择合适的AP并且连接

PNO是利用上述的sched scan来实现的, 因此, 其默认的扫描间隔即是 sched scan 的默认扫描间隔, 为了省电考虑, 通常, PNO 扫描的时间是指数递增的, 例如, 设定递增次数为6, 则

  1. 以默认值10s扫描6次
  2. 以20s扫描6次
  3. 以40s扫描6次
  4. 以80s扫描6次
  5. 以160s扫描6次
  6. 以320s扫描6次
  7. 以320s间隔扫描, 直到停止PNO

在WPAS中使用 “set pno” cmd 来开关PNO scan

set pno 1
set pno 0

不同的wifi driver, 实现的PNO接口也有所差异, 支持的具体参数也可能有差别

android中可以在“frameworks/base/core/res/res/values/config.xml”中利用 “config_wifi_background_scan_support”项来配置是否使用 PNO 扫描

android上PNO扫描被称为background scan, 请不要和WPAS的background scan混淆

###5. background scan

当STA在ESS(有多个BSS)中移动时,在信号不好的情况下, 需要要从一个BSS漫游到另一个BSS, 为了增强漫游的无缝体验(在扫描过程中, STA不能收发数据帧), STA可以采用background scan(定时扫描一小段时间, 或者空闲时才扫描)

WPAS使用模块的形式来实现bgscan, 每一种bgscan的实现都需要实现如下的接口

struct bgscan_ops {
	const char *name;
	void * (*init)(struct wpa_supplicant *wpa_s, const char *params, const struct wpa_ssid *ssid);
	void (*deinit)(void *priv);

	int (*notify_scan)(void *priv, struct wpa_scan_results *scan_res);
	void (*notify_beacon_loss)(void *priv);
	void (*notify_signal_change)(void *priv, int above,
			     int current_signal,
			     int current_noise,
			     int current_txrate);
};

WPAS 使用如下的接口来 开启/停止 bgscan

void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)

WPAS当前支持如下2种bgscan的实现:

  • bgscan simple : 需要配置编译选项 “CONFIG_BGSCAN_SIMPLE”
  • bgscan learn : 需要配置编译选项 “CONFIG_BGSCAN_LEARN”

在编译所需的 bgscn 模块后, 在使用时还需要在 wpa_supplicant.conf 进行配置, 其语法为

// bgscan simple
bgscan="simple:<short bgscan interval in seconds>:<signal strength threshold>:<long interval>"

// bgscan learn
bgscan="learn:&lt;short bgscan interval in seconds&gt;:<&lt;signal strength threshold&gt;:&lt;long interval&gt;[:&lt;database file name&gt;]"

例如:

bgscan="simple:30:-45:300"
bgscan="learn:30:-45:300:/etc/wpa_supplicant/network1.bgscan"

使用如下的方式来 disable bgscan

bgscan=""

若打开了 bgscan, WPAS 在进入 COMPLETED 状态后开启 bgscan, 小于 ASSOCIATED 状态后, 关闭 bgscan

wifi roaming可以在WPAS中实现, 也可以在 wifi driver 或者 wifi firmware中实现,因此要根据需要来配置bgscan

###6. autoscan

autoscan 类似于 bgscan, 但是 autoscan 是在 DISCNONECT 和 INACTIVE 状态下工作

WPAS 以模块的方式来实现,autoscan, 每一种autoscan的实现需要提供如下的接口:

struct autoscan_ops {
	const char *name;
	void * (*init)(struct wpa_supplicant *wpa_s, const char *params);
	void (*deinit)(void *priv);
	int (*notify_scan)(void *priv, struct wpa_scan_results *scan_res);
};

WPAS使用如下的接口来 开启/停止 autoscan

void wpa_supplicant_start_autoscan(struct wpa_supplicant *wpa_s)
void wpa_supplicant_stop_autoscan(struct wpa_supplicant *wpa_s)

WPAS 当前支持2种autoscan的实现:

  • exponential : 扫描间隔指数递增, 编译时需要打开 CONFIG_AUTOSCAN_EXPONENTIAL
  • periodic : 扫描间隔固定, 编译时需要打开CONFIG_AUTOSCAN_PERIODIC

使用 autoscan 还需要在 wpa_supplicant.conf 中进行配置, 例如

// 扫描间隔指数递增, 3,9, 27...300 s
autoscan=exponential:3:300

// 扫描间隔固定为30s
autoscan=periodic:30

若开启了autoscan, 则 在进入 DISCONNECT 或者 INACTIVE 状态后, 开启 autoscan, 进入 AUTHENTICATING 状态后停止 autoscan