BroadcomfullmacWLAN驅動解析(轉)

現在我們來看看scan是怎麼處理的。

一、先來看看如何發送scan command給WLAN firmware

以Android平臺爲例,我們從Android framework的code開始看起。

1. 在WifiStateMachine.java中有如下函數

 public void startScan(boolean forceActive) {
sendMessage(obtainMessage(CMD_START_SCAN, forceActive ?
SCAN_ACTIVE : SCAN_PASSIVE, 0));
}

2. processMessage()函數會處理CMD_START_SCAN

 @Override
public boolean processMessage(Message message) {
if (DBG) log(getName() + message.toString() + "\n");
boolean eventLoggingEnabled = true;
switch(message.what) {
case CMD_SET_SCAN_TYPE:
if (message.arg1 == SCAN_ACTIVE) {
WifiNative.setScanModeCommand(true);
} else {
WifiNative.setScanModeCommand(false);
}
break;
// 處理CMD_START_SCAN
case CMD_START_SCAN:
eventLoggingEnabled = false;
WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE);
mScanResultIsPending = true;
break;
...
default:
return NOT_HANDLED;
}
if (eventLoggingEnabled) {
EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
}
return HANDLED;
}

3. 接下來就會執行到JNI函數裏面

static jboolean android_net_wifi_scanCommand(JNIEnv* env, jobject, jboolean forceActive)
{
jboolean result;
// Ignore any error from setting the scan mode.
// The scan will still work.
if (forceActive && !sScanModeActive)
doSetScanMode(true);
// 關鍵是這裏,"SCAN"這個字符串命令
result = doBooleanCommand("OK", "SCAN");
if (forceActive && !sScanModeActive)
doSetScanMode(sScanModeActive);
return result;
}

4. 繼續跟進doBooleanCommand()

static jboolean doBooleanCommand(const char* expect, const char* fmt, ...)
{
char buf[BUF_SIZE];
va_list args;
va_start(args, fmt);
int byteCount = vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
if (byteCount < 0 || byteCount >= BUF_SIZE) {
return JNI_FALSE;
}
char reply[BUF_SIZE];
if (doCommand(buf, reply, sizeof(reply)) != 0) {
return JNI_FALSE;
}
return (strcmp(reply, expect) == 0);
}

5. 調用doCommand()

static int doCommand(const char *cmd, char *replybuf, int replybuflen)
{
size_t reply_len = replybuflen - 1;
// 這裏已經調用Android HAL層的API了
if (::wifi_command(cmd, replybuf, &reply_len) != 0)
return -1;
else {
// Strip off trailing newline
if (reply_len > 0 && replybuf[reply_len-1] == '\n')
replybuf[reply_len-1] = '\0';
else
replybuf[reply_len] = '\0';
return 0;
}
}

6. 執行到了wifi.c中的wifi_command()

int wifi_command(const char *command, char *reply, size_t *reply_len)
{
// 後面會提到ctrl_conn是怎麼來的
return wifi_send_command(ctrl_conn, command, reply, reply_len);
}

int wifi_send_command(struct wpa_ctrl *ctrl, const char *cmd, char *reply, size_t *reply_len)
{
int ret;
if (ctrl_conn == NULL) {
LOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd);
return -1;
}
// 注意這裏,調用了wpa_supplicant的接口!這裏cmd就是之前傳遞的參數"SCAN"
ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), reply, reply_len, NULL);
if (ret == -2) {
LOGD("'%s' command timed out.\n", cmd);
/* unblocks the monitor receive socket for termination */
write(exit_sockets[0], "T", 1);
return -2;
} else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {
return -1;
}
if (strncmp(cmd, "PING", 4) == 0) {
reply[*reply_len] = '\0';
}
return 0;
}

7. wpa_ctrl_request要能成功發送command的話,之前就必須先得調用wpa_ctrl_open(), 所以我們來看一下wifi_connect_to_supplicant():

int wifi_connect_to_supplicant()
{
char ifname[256];
char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
/* Make sure supplicant is running */
if (!property_get(SUPP_PROP_NAME, supp_status, NULL)
|| strcmp(supp_status, "running") != 0) {
LOGE("Supplicant not running, cannot connect");
return -1;
}
if (access(IFACE_DIR, F_OK) == 0) {
snprintf(ifname, sizeof(ifname), "%s/%s", IFACE_DIR, iface);
} else {
strlcpy(ifname, iface, sizeof(ifname));
}
// 這裏是ctrl_conn
ctrl_conn = wpa_ctrl_open(ifname);
if (ctrl_conn == NULL) {
LOGE("Unable to open connection to supplicant on \"%s\": %s",
ifname, strerror(errno));
return -1;
}
// 這裏是monitor_conn
monitor_conn = wpa_ctrl_open(ifname);
if (monitor_conn == NULL) {
wpa_ctrl_close(ctrl_conn);
ctrl_conn = NULL;
return -1;
}
if (wpa_ctrl_attach(monitor_conn) != 0) {
wpa_ctrl_close(monitor_conn);
wpa_ctrl_close(ctrl_conn);
ctrl_conn = monitor_conn = NULL;
return -1;
}
if (socketpair(AF_UNIX, SOCK_STREAM, 0, exit_sockets) == -1) {
wpa_ctrl_close(monitor_conn);
wpa_ctrl_close(ctrl_conn);
ctrl_conn = monitor_conn = NULL;
return -1;
}
return 0;
}

這裏的iface是從property中取出來的:

property_get("wifi.interface", iface, WIFI_TEST_INTERFACE);

這個值是預先由OEM廠商設定好的,比如device/samsung/tuna/device.mk中有下面的code:

wifi.interface=wlan0

8. 那接下來就是要走到wpa_supplicant中了,要去處理這個"SCAN" command。要知道是在哪裏處理command, 還得看一下wpa_supplicant的初始化過程:

8.1 從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(&params, 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();
...
exitcode = 0;
global = wpa_supplicant_init(&params);
if (global == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize wpa_supplicant");
exitcode = -1;
goto out;
}
for (i = 0; exitcode == 0 && i < iface_count; i++) {
if ((ifaces[i].confname == NULL &&
ifaces[i].ctrl_interface == NULL) ||
ifaces[i].ifname == NULL) {
if (iface_count == 1 && (params.ctrl_interface ||
params.dbus_ctrl_interface))
break;
usage();
exitcode = -1;
break;
}
// 注意這裏
if (wpa_supplicant_add_iface(global, &ifaces[i]) == NULL)
exitcode = -1;
}
...
return exitcode;
}

8.2 調用wpa_supplicant_add_iface()

struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
struct wpa_interface *iface)
{
struct wpa_supplicant *wpa_s;
struct wpa_interface t_iface;
struct wpa_ssid *ssid;
if (global == NULL || iface == NULL)
return NULL;
// 非常重要!這裏給wpa_s分配了內存空間
wpa_s = wpa_supplicant_alloc();
if (wpa_s == NULL)
return NULL;
wpa_s->global = global;
t_iface = *iface;
...
// 注意這裏,wpa_s作爲參數傳遞給了wpa_supplicant_init_iface()
if (wpa_supplicant_init_iface(wpa_s, &t_iface)) {
wpa_printf(MSG_DEBUG, "Failed to add interface %s",
iface->ifname);
wpa_supplicant_deinit_iface(wpa_s, 0);
os_free(wpa_s);
return NULL;
}
...
return wpa_s;
}

8.3 調用wpa_supplicant_init_iface()

static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
struct wpa_interface *iface)
{
const char *ifname, *driver;
struct wpa_driver_capa capa;
...
// 在main()中,iface->confname是由-c參數傳進來的
if (iface->confname) {
#ifdef CONFIG_BACKEND_FILE
wpa_s->confname = os_rel2abs_path(iface->confname);
if (wpa_s->confname == NULL) {
wpa_printf(MSG_ERROR, "Failed to get absolute path "
"for configuration file '%s'.",
iface->confname);
return -1;
}
wpa_printf(MSG_DEBUG, "Configuration file '%s' -> '%s'",
iface->confname, wpa_s->confname);
#else /* CONFIG_BACKEND_FILE */
wpa_s->confname = os_strdup(iface->confname);
#endif /* CONFIG_BACKEND_FILE */
// 注意wpa_s->conf是從iface->confname指向的那個文件讀取來的
// 也就是啓動wpa_supplicant的命令行中-c參數後面的那個文件名
wpa_s->conf = wpa_config_read(wpa_s->confname);
if (wpa_s->conf == NULL) {
wpa_printf(MSG_ERROR, "Failed to read or parse "
"configuration '%s'.", wpa_s->confname);
return -1;
}
/*
* Override ctrl_interface and driver_param if set on command
* line.
*/
if (iface->ctrl_interface) {
os_free(wpa_s->conf->ctrl_interface);
wpa_s->conf->ctrl_interface =
os_strdup(iface->ctrl_interface);
}
if (iface->driver_param) {
os_free(wpa_s->conf->driver_param);
wpa_s->conf->driver_param =
os_strdup(iface->driver_param);
}
} else
wpa_s->conf = wpa_config_alloc_empty(iface->ctrl_interface,
iface->driver_param);
...
if (wpa_supplicant_driver_init(wpa_s) < 0)
return -1;
if (wpa_s->conf->country[0] && wpa_s->conf->country[1] &&
wpa_drv_set_country(wpa_s, wpa_s->conf->country)) {
wpa_printf(MSG_DEBUG, "Failed to set country");
return -1;
}
wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
if (wpas_wps_init(wpa_s))
return -1;
if (wpa_supplicant_init_eapol(wpa_s) < 0)
return -1;
wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
// 目前我們只關心這裏,注意wpa_s作爲參數傳給了wpa_supplicant_ctrl_iface_init()
wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
...
if (wpa_bss_init(wpa_s) < 0)
return -1;
return 0;
}

8.4 調用wpa_supplicant_ctrl_iface_init()

struct ctrl_iface_priv *
wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
{
...
// 這裏第二個參數便是handler
eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
wpa_s, priv);
wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
os_free(buf);
return priv;
...
}

8.5 顯然所有的command將會在wpa_supplicant_ctrl_iface_receive()中收到

static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
void *sock_ctx)
{
// 注意這裏得到了wpa_s
struct wpa_supplicant *wpa_s = eloop_ctx;
struct ctrl_iface_priv *priv = sock_ctx;
char buf[256];
int res;
struct sockaddr_un from;
socklen_t fromlen = sizeof(from);
char *reply = NULL;
size_t reply_len = 0;
int new_attached = 0;
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
perror("recvfrom(ctrl_iface)");
return;
}
buf[res] = '\0';
if (os_strcmp(buf, "ATTACH") == 0) {
if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen))
reply_len = 1;
else {
new_attached = 1;
reply_len = 2;
}
} else if (os_strcmp(buf, "DETACH") == 0) {
if (wpa_supplicant_ctrl_iface_detach(priv, &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 {
// 除了上面三種command之外的其它command,就在下面得到處理
reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
&reply_len);
}
if (reply) {
sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
fromlen);
os_free(reply);
} else if (reply_len == 1) {
sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
fromlen);
} else if (reply_len == 2) {
sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
fromlen);
}
if (new_attached)
eapol_sm_notify_ctrl_attached(wpa_s->eapol);
}

9. 在wpa_supplicant_ctrl_iface_process()中處理"SCAN" command

char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len)
{
char *reply;
const int reply_size = 2048;
int ctrl_rsp = 0;
int reply_len;
...
reply = os_malloc(reply_size);
if (reply == NULL) {
*resp_len = 1;
return NULL;
}
os_memcpy(reply, "OK\n", 3);
reply_len = 3;
if (os_strcmp(buf, "PING") == 0) {
os_memcpy(reply, "PONG\n", 5);
reply_len = 5;
}
...
else if (os_strcmp(buf, "SCAN") == 0) {
wpa_s->scan_req = 2;
// 注意這裏
wpa_supplicant_req_scan(wpa_s, 0, 0);
} else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
reply_len = wpa_supplicant_ctrl_iface_scan_results(
wpa_s, reply, reply_size);
}
...
else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
}
if (reply_len < 0) {
os_memcpy(reply, "FAIL\n", 5);
reply_len = 5;
}
if (ctrl_rsp)
eapol_sm_notify_ctrl_response(wpa_s->eapol);
*resp_len = reply_len;
return reply;
}

10. 調用wpa_supplicant_req_scan() 

void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
{
...
if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) &&
wpa_s->conf->ap_scan == 1) {
// 可以看到ssid是從wpa_s->conf中得到的
// 在Android framework中,當用戶在UI在選定一個AP/SSID連接時,
// Settings App會調用到WifiManager的方法addNetwork()
// 從而最終set到wpa_s->conf->ssid
// 而WifiManager的另外一個方法saveNetwork()則會讓wpa_supplicant
// 把wpa_s->conf再寫到iface->confname指向的文件中
// 以後會把這部分邏輯分析一下
struct wpa_ssid *ssid = wpa_s->conf->ssid;
while (ssid) {
if (!ssid->disabled && ssid->scan_ssid)
break;
ssid = ssid->next;
}
if (ssid) {
wpa_msg(wpa_s, MSG_DEBUG, "Not rescheduling scan to "
"ensure that specific SSID scans occur");
return;
}
}
wpa_msg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec",
sec, usec);
eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
// 注意第三個參數是handler
 eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL);
}

可以看到通過timer的handler即將會觸發wpa_supplicant_scan().

11. 調用wpa_supplicant_scan()

static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct wpa_ssid *ssid;
int scan_req = 0, ret;
struct wpabuf *wps_ie = NULL;
...
params.filter_ssids = wpa_supplicant_build_filter_ssids(
wpa_s->conf, &params.num_filter_ssids);
// 注意這裏
ret = wpa_supplicant_trigger_scan(wpa_s, &params);
wpabuf_free(wps_ie);
os_free(params.freqs);
os_free(params.filter_ssids);
if (ret) {
wpa_printf(MSG_WARNING, "Failed to initiate AP scan.");
if (prev_state != wpa_s->wpa_state)
wpa_supplicant_set_state(wpa_s, prev_state);
wpa_supplicant_req_scan(wpa_s, 1, 0);
}
}

 12. 調用wpa_supplicant_trigger_scan() 

int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
struct wpa_driver_scan_params *params)
{
int ret;
wpa_supplicant_notify_scanning(wpa_s, 1);
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
ret = ieee80211_sta_req_scan(wpa_s, params);
else // 注意這裏
ret = wpa_drv_scan(wpa_s, params);
if (ret) {
wpa_supplicant_notify_scanning(wpa_s, 0);
wpas_notify_scan_done(wpa_s, 0);
} else
wpa_s->scan_runs++;
return ret;
}

13. 調用wpa_drv_scan()

static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s,
struct wpa_driver_scan_params *params)
{
if (wpa_s->driver->scan2)
return wpa_s->driver->scan2(wpa_s->drv_priv, params);
return -1;
}

14. 這裏我們假定採用了nl80211接口,那麼driver_nl80211.c中的wpa_driver_nl80211_scan()將會被觸發

static int wpa_driver_nl80211_scan(void *priv,
struct wpa_driver_scan_params *params)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
int ret = 0, timeout;
struct nl_msg *msg, *ssids, *freqs;
size_t i;
msg = nlmsg_alloc();
ssids = nlmsg_alloc();
freqs = nlmsg_alloc();
if (!msg || !ssids || !freqs) {
nlmsg_free(msg);
nlmsg_free(ssids);
nlmsg_free(freqs);
return -1;
}
os_free(drv->filter_ssids);
drv->filter_ssids = params->filter_ssids;
params->filter_ssids = NULL;
drv->num_filter_ssids = params->num_filter_ssids;
// 關鍵是這個NL80211_CMD_TRIGGER_SCAN命令
genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
NL80211_CMD_TRIGGER_SCAN, 0);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
for (i = 0; i < params->num_ssids; i++) {
wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
params->ssids[i].ssid,
params->ssids[i].ssid_len);
NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len,
params->ssids[i].ssid);
}
if (params->num_ssids)
nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
if (params->extra_ies) {
wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan extra IEs",
params->extra_ies, params->extra_ies_len);
NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,
params->extra_ies);
}
if (params->freqs) {
for (i = 0; params->freqs[i]; i++) {
wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
"MHz", params->freqs[i]);
NLA_PUT_U32(freqs, i + 1, params->freqs[i]);
}
nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
...
}

15. scan message經由netlink進入到Linux內核當中去處理。

由nl80211.c中的nl80211_ops中的定義可以知道對應的command handler:

 {
.cmd = NL80211_CMD_TRIGGER_SCAN,
.doit = nl80211_trigger_scan,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
NL80211_FLAG_NEED_RTNL,
},

16. 調用nl80211_trigger_scan()

static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
{
...
request->wdev = wdev;
request->wiphy = &rdev->wiphy;
request->scan_start = jiffies;
rdev->scan_req = request;
// 只看這邊最關鍵的代碼:
err = rdev_scan(rdev, request);
if (!err) {
nl80211_send_scan_start(rdev, wdev);
if (wdev->netdev)
dev_hold(wdev->netdev);
} else {
out_free:
rdev->scan_req = NULL;
kfree(request);
}
return err;
}

17. 調用rdev_scan()

static inline int rdev_scan(struct cfg80211_registered_device *rdev,
struct cfg80211_scan_request *request)
{
int ret;
trace_rdev_scan(&rdev->wiphy, request);
ret = rdev->ops->scan(&rdev->wiphy, request);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}

18. 根據上一節的分析,brcmf_cfg80211_scan()被調用

static s32
brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
{
struct net_device *ndev = request->wdev->netdev;
s32 err = 0;
brcmf_dbg(TRACE, "Enter\n");
if (!check_vif_up(container_of(request->wdev,
struct brcmf_cfg80211_vif, wdev)))
return -EIO;
err = brcmf_cfg80211_escan(wiphy, ndev, request, NULL);
if (err)
brcmf_err("scan error (%d)\n", err);
brcmf_dbg(TRACE, "Exit\n");
return err;
}

19. 調用brcmf_cfg80211_escan()

static s32
brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
struct cfg80211_scan_request *request,
struct cfg80211_ssid *this_ssid)
{
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
struct cfg80211_ssid *ssids;
struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int;
u32 passive_scan;
bool escan_req;
bool spec_scan;
s32 err;
u32 SSID_len;
...
escan_req = false;
if (request) {
/* scan bss */
ssids = request->ssids;
escan_req = true;
} else {
/* scan in ibss */
/* we don't do escan in ibss */
ssids = this_ssid;
}
cfg->scan_request = request;
set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
if (escan_req) {
// 注意這裏給run函數指針賦值
cfg->escan_info.run = brcmf_run_escan;
err = brcmf_p2p_scan_prep(wiphy, request, ifp->vif);
if (err)
goto scan_out;
// 執行brcmf_do_escan
err = brcmf_do_escan(cfg, wiphy, ndev, request);
if (err)
goto scan_out;
}
...
return 0;
...
}

20. 調用brcmf_do_escan()

static s32
brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
struct net_device *ndev, struct cfg80211_scan_request *request)
{
s32 err;
u32 passive_scan;
struct brcmf_scan_results *results;
struct escan_info *escan = &cfg->escan_info;
brcmf_dbg(SCAN, "Enter\n");
escan->ndev = ndev;
escan->wiphy = wiphy;
escan->escan_state = WL_ESCAN_STATE_SCANNING;
passive_scan = cfg->active_scan ? 0 : 1;
err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN,
passive_scan);
if (err) {
brcmf_err("error (%d)\n", err);
return err;
}
brcmf_set_mpc(ndev, 0);
results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
results->version = 0;
results->count = 0;
results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
// 執行run函數
err = escan->run(cfg, ndev, request, WL_ESCAN_ACTION_START);
if (err)
brcmf_set_mpc(ndev, 1);
return err;
}

21. 調用brcmf_run_escan()

static s32
brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev,
struct cfg80211_scan_request *request, u16 action)
{
s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
offsetof(struct brcmf_escan_params_le, params_le);
struct brcmf_escan_params_le *params;
s32 err = 0;
brcmf_dbg(SCAN, "E-SCAN START\n");
if (request != NULL) {
/* Allocate space for populating ssids in struct */
params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
/* Allocate space for populating ssids in struct */
params_size += sizeof(struct brcmf_ssid) * request->n_ssids;
}
params = kzalloc(params_size, GFP_KERNEL);
if (!params) {
err = -ENOMEM;
goto exit;
}
BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
// 配置scan參數
brcmf_escan_prep(&params->params_le, request);
params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
params->action = cpu_to_le16(action);
params->sync_id = cpu_to_le16(0x1234);
// 向firmware發送"escan"命令
err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "escan",
params, params_size);
if (err) {
if (err == -EBUSY)
brcmf_dbg(INFO, "system busy : escan canceled\n");
else
brcmf_err("error (%d)\n", err);
}
kfree(params);
exit:
return err;
}

這裏有必要進入brcmf_run_escan()看看,因爲這裏涉及到scan參數的配置。

static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
struct cfg80211_scan_request *request)
{
u32 n_ssids;
u32 n_channels;
s32 i;
s32 offset;
u16 chanspec;
char *ptr;
struct brcmf_ssid_le ssid_le;
...
if (n_ssids > 0) {
// 這種情況應該是active scan?
offset = offsetof(struct brcmf_scan_params_le, channel_list) +
n_channels * sizeof(u16);
offset = roundup(offset, sizeof(u32));
ptr = (char *)params_le + offset;
for (i = 0; i < n_ssids; i++) {
memset(&ssid_le, 0, sizeof(ssid_le));
ssid_le.SSID_len =
cpu_to_le32(request->ssids[i].ssid_len);
memcpy(ssid_le.SSID, request->ssids[i].ssid,
request->ssids[i].ssid_len);
if (!ssid_le.SSID_len)
brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
else
brcmf_dbg(SCAN, "%d: scan for %s size =%d\n",
i, ssid_le.SSID, ssid_le.SSID_len);
memcpy(ptr, &ssid_le, sizeof(ssid_le));
ptr += sizeof(ssid_le);
}
} else {
// n_ssids爲0的情況應該是passive scan?
brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
if ((request->ssids) && request->ssids->ssid_len) {
brcmf_dbg(SCAN, "SSID %s len=%d\n",
params_le->ssid_le.SSID,
request->ssids->ssid_len);
params_le->ssid_le.SSID_len =
cpu_to_le32(request->ssids->ssid_len);
memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
request->ssids->ssid_len);
}
}
/* Adding mask to channel numbers */
params_le->channel_num =
cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
(n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
}

這裏關於active scan/passive scan目前還是我的猜測,依據是wpa_supplicant中關於wpa_driver_scan_params的一些註釋:

/**
* struct wpa_driver_scan_params - Scan parameters
* Data for struct wpa_driver_ops::scan2().
*/
struct wpa_driver_scan_params {
/**
* ssids - SSIDs to scan for
*/
struct wpa_driver_scan_ssid {
/**
* ssid - specific SSID to scan for (ProbeReq)
* %NULL or zero-length SSID is used to indicate active scan
* with wildcard SSID.
*/
const u8 *ssid;
/**
* ssid_len: Length of the SSID in octets
*/
size_t ssid_len;
} ssids[WPAS_MAX_SCAN_SSIDS];
/**
* num_ssids - Number of entries in ssids array
* Zero indicates a request for a passive scan.
*/
size_t num_ssids;
/**
* extra_ies - Extra IE(s) to add into Probe Request or %NULL
*/
const u8 *extra_ies;
/**
* extra_ies_len - Length of extra_ies in octets
*/
size_t extra_ies_len;
/**
* freqs - Array of frequencies to scan or %NULL for all frequencies
*
* The frequency is set in MHz. The array is zero-terminated.
*/
int *freqs;
/**
* filter_ssids - Filter for reporting SSIDs
*
* This optional parameter can be used to request the driver wrapper to
* filter scan results to include only the specified SSIDs. %NULL
* indicates that no filtering is to be done. This can be used to
* reduce memory needs for scan results in environments that have large
* number of APs with different SSIDs.
*
* The driver wrapper is allowed to take this allocated buffer into its
* own use by setting the pointer to %NULL. In that case, the driver
* wrapper is responsible for freeing the buffer with os_free() once it
* is not needed anymore.
*/
struct wpa_driver_scan_filter {
u8 ssid[32];
size_t ssid_len;
} *filter_ssids;
/**
* num_filter_ssids - Number of entries in filter_ssids array
*/
size_t num_filter_ssids;
};

22. 調用brcmf_fil_iovar_data_set()

s32
brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data,
u32 len)
{
struct brcmf_pub *drvr = ifp->drvr;
s32 err;
u32 buflen;
mutex_lock(&drvr->proto_block);
brcmf_dbg(FIL, "name=%s, len=%d\n", name, len);
brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf,
sizeof(drvr->proto_buf));
if (buflen) {
// 注意這裏
err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf,
buflen, true);
} else {
err = -EPERM;
brcmf_err("Creating iovar failed\n");
}
mutex_unlock(&drvr->proto_block);
return err;
}

23. 調用brcmf_fil_cmd_data()

static s32
brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
{
struct brcmf_pub *drvr = ifp->drvr;
s32 err;
if (drvr->bus_if->state != BRCMF_BUS_DATA) {
brcmf_err("bus is down. we have nothing to do.\n");
return -EIO;
}
if (data != NULL)
len = min_t(uint, len, BRCMF_DCMD_MAXLEN);
if (set)
err = brcmf_proto_cdc_set_dcmd(drvr, ifp->ifidx, cmd, data,
len);
else
err = brcmf_proto_cdc_query_dcmd(drvr, ifp->ifidx, cmd, data,
len);
if (err >= 0)
err = 0;
else
brcmf_err("Failed err=%d\n", err);
return err;
}

24. 調用brcmf_proto_cdc_set_dcmd()

int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
void *buf, uint len)
{
struct brcmf_proto *prot = drvr->prot;
struct brcmf_proto_cdc_dcmd *msg = &prot->msg;
int ret = 0;
u32 flags, id;
brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len);
memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd));
msg->cmd = cpu_to_le32(cmd);
msg->len = cpu_to_le32(len);
flags = (++prot->reqid << CDC_DCMD_ID_SHIFT) | CDC_DCMD_SET;
flags = (flags & ~CDC_DCMD_IF_MASK) |
(ifidx << CDC_DCMD_IF_SHIFT);
msg->flags = cpu_to_le32(flags);
if (buf)
memcpy(prot->buf, buf, len);
// 注意這裏
ret = brcmf_proto_cdc_msg(drvr);
if (ret < 0)
goto done;
ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len);
if (ret < 0)
goto done;
...
done:
return ret;
}

25. 調用brcmf_proto_cdc_msg()

static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr)
{
struct brcmf_proto *prot = drvr->prot;
int len = le32_to_cpu(prot->msg.len) +
sizeof(struct brcmf_proto_cdc_dcmd);
brcmf_dbg(CDC, "Enter\n");
/* NOTE : cdc->msg.len holds the desired length of the buffer to be
* returned. Only up to CDC_MAX_MSG_SIZE of this buffer area
* is actually sent to the dongle
*/
if (len > CDC_MAX_MSG_SIZE)
len = CDC_MAX_MSG_SIZE;
/* Send request */
return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&prot->msg, len);
}

26. 通過brcmf_bus_txctl()發送request

static inline
int brcmf_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint len)
{
return bus->ops->txctl(bus->dev, msg, len);
}

27. 上一節已經分析過,這裏會調用brcmf_sdbrcm_bus_txctl()

static int
brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
{
u8 *frame;
u16 len;
u32 swheader;
uint retries = 0;
u8 doff = 0;
int ret = -1;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
struct brcmf_sdio *bus = sdiodev->bus;
unsigned long flags;
...
if (ret == -1) {
brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(),
frame, len, "Tx Frame:\n");
brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && BRCMF_CTL_ON()) &&
BRCMF_HDRS_ON(),
frame, min_t(u16, len, 16), "TxHdr:\n");
do {
sdio_claim_host(bus->sdiodev->func[1]);
// 通過brcmf_tx_frame發送數據
ret = brcmf_tx_frame(bus, frame, len);
sdio_release_host(bus->sdiodev->func[1]);
} while (ret < 0 && retries++ < TXRETRIES);
}
...
}

至此,已經把scan command和對應的參數發給WLAN firmware了。接下來就是等待scan result.

二、從WLAN firmware接收scan result

我們從上一節分析過的brcmf_rx_frames()開始看起。

1. 觸發brcmf_rx_frames()

void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
{
...
skb_queue_walk_safe(skb_list, skb, pnext) {
skb_unlink(skb, skb_list);
...
/* Process special event packets and then discard them */
// scan result就是special event packets
// 所以要在這邊處理
brcmf_fweh_process_skb(drvr, skb, &ifidx);
if (drvr->iflist[ifidx]) {
ifp = drvr->iflist[ifidx];
ifp->ndev->last_rx = jiffies;
}
if (!(ifp->ndev->flags & IFF_UP)) {
brcmu_pkt_buf_free_skb(skb);
continue;
}
ifp->stats.rx_bytes += skb->len;
ifp->stats.rx_packets++;
if (in_interrupt())
netif_rx(skb);
else
/* If the receive is not processed inside an ISR,
* the softirqd must be woken explicitly to service
* the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled
* by netif_rx_ni(), but in earlier kernels, we need
* to do it manually.
*/
netif_rx_ni(skb);
}
}

2. 進入到brcmf_fweh_process_skb()

static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,
struct sk_buff *skb, u8 *ifidx)
{
struct brcmf_event *event_packet;
u8 *data;
u16 usr_stype;
/* only process events when protocol matches */
if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL))
return;
/* check for BRCM oui match */
event_packet = (struct brcmf_event *)skb_mac_header(skb);
data = (u8 *)event_packet;
data += BRCMF_EVENT_OUI_OFFSET;
if (memcmp(BRCM_OUI, data, DOT11_OUI_LEN))
return;
/* final match on usr_subtype */
data += DOT11_OUI_LEN;
usr_stype = get_unaligned_be16(data);
if (usr_stype != BCMILCP_BCM_SUBTYPE_EVENT)
return;
// 注意這裏
 brcmf_fweh_process_event(drvr, event_packet, ifidx);
}

3. 調用brcmf_fweh_process_event()

void brcmf_fweh_process_event(struct brcmf_pub *drvr,
struct brcmf_event *event_packet, u8 *ifidx)
{
...
event = kzalloc(sizeof(*event) + datalen, alloc_flag);
if (!event)
return;
event->code = code;
event->ifidx = *ifidx;
/* use memcpy to get aligned event message */
memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg));
memcpy(event->data, data, datalen);
memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN);
// 注意這裏
brcmf_fweh_queue_event(fweh, event);
}

4. 調用brcmf_fweh_queue_event()

static void brcmf_fweh_queue_event(struct brcmf_fweh_info *fweh,
struct brcmf_fweh_queue_item *event)
{
ulong flags;
spin_lock_irqsave(&fweh->evt_q_lock, flags);
list_add_tail(&event->q, &fweh->event_q);
spin_unlock_irqrestore(&fweh->evt_q_lock, flags);
schedule_work(&fweh->event_work); // 注意這個work queue
}

這裏的event_work()是在brcmf_fweh_attach()中初始化的(調用順序:brcmf_sdbrcm_probe() -> brcmf_attach() -> brcmf_fweh_attach())

void brcmf_fweh_attach(struct brcmf_pub *drvr)
{
struct brcmf_fweh_info *fweh = &drvr->fweh;
INIT_WORK(&fweh->event_work, brcmf_fweh_event_worker);
spin_lock_init(&fweh->evt_q_lock);
INIT_LIST_HEAD(&fweh->event_q);
}

5. 顯然brcmf_fweh_event_worker()將會被調用

static void brcmf_fweh_event_worker(struct work_struct *work)
{
...
while ((event = brcmf_fweh_dequeue_event(fweh))) {
...
/* special handling of interface event */
if (event->code == BRCMF_E_IF) {
brcmf_fweh_handle_if_event(drvr, &emsg, event->data);
goto event_free;
}
ifp = drvr->iflist[emsg.bsscfgidx];
// 目前我們只關心brcmf_fweh_call_event_handler()
err = brcmf_fweh_call_event_handler(ifp, event->code, &emsg,
event->data);
if (err) {
brcmf_err("event handler failed (%d)\n",
event->code);
err = 0;
}
event_free:
kfree(event);
}

6. 進入到brcmf_fweh_call_event_handler()

static int brcmf_fweh_call_event_handler(struct brcmf_if *ifp,
enum brcmf_fweh_event_code code,
struct brcmf_event_msg *emsg,
void *data)
{
struct brcmf_fweh_info *fweh;
int err = -EINVAL;
if (ifp) {
fweh = &ifp->drvr->fweh;
/* handle the event if valid interface and handler */
if (ifp->ndev && fweh->evt_handler[code])
err = fweh->evt_handler[code](ifp, emsg, data);
else
brcmf_err("unhandled event %d ignored\n", code);
} else {
brcmf_err("no interface object\n");
}
return err;
}

代碼很清楚的顯示這裏firmware的事件是由fweh->evt_handler來處理的。那我們必須得瞭解fweh->evt_handler是怎麼被初始化的。

在上一節中曾經分析過brcmf_cfg80211_attach(), 該函數會調用wl_init_priv():

static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
{
s32 err = 0;
cfg->scan_request = NULL;
cfg->pwr_save = true;
cfg->roam_on = true; /* roam on & off switch.
we enable roam per default */
cfg->active_scan = true; /* we do active scan for
specific scan per default */
cfg->dongle_up = false; /* dongle is not up yet */
err = brcmf_init_priv_mem(cfg);
if (err)
return err;
brcmf_register_event_handlers(cfg);
mutex_init(&cfg->usr_sync);
brcmf_init_escan(cfg); // 現在我們只關心scan
brcmf_init_conf(cfg->conf);
init_completion(&cfg->vif_disabled);
return err;
}

繼續跟進brcmf_init_ecan():

static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
{
// 這裏註冊了handler!
brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
brcmf_cfg80211_escan_handler);
cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
/* Init scan_timeout timer */
init_timer(&cfg->escan_timeout);
cfg->escan_timeout.data = (unsigned long) cfg;
cfg->escan_timeout.function = brcmf_escan_timeout;
INIT_WORK(&cfg->escan_timeout_work,
brcmf_cfg80211_escan_timeout_worker);
}

很顯然,對於firmware報上來的BRCMF_E_ESCAN_RESULT事件,fweh->evt_handler就是brcmf_cfg80211_escan_handler().

7. 調用brcmf_cfg80211_escan_handler()

static s32
brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
const struct brcmf_event_msg *e, void *data)
{
...
if (status == BRCMF_E_STATUS_PARTIAL) {
...
} else {
cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
goto exit;
if (cfg->scan_request) {
cfg->bss_list = (struct brcmf_scan_results *)
cfg->escan_info.escan_buf;
brcmf_inform_bss(cfg);
aborted = status != BRCMF_E_STATUS_SUCCESS;
// 注意這裏
 brcmf_notify_escan_complete(cfg, ndev, aborted,
false);
} else
brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
status);
}
exit:
return err;

8. 調用brcmf_notify_escan_complete()

s32
brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
struct net_device *ndev,
bool aborted, bool fw_abort)
{
...
/*
* e-scan can be initiated by scheduled scan
* which takes precedence.
*/
if (cfg->sched_escan) {
brcmf_dbg(SCAN, "scheduled scan completed\n");
cfg->sched_escan = false;
if (!aborted)
cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
brcmf_set_mpc(ndev, 1);
} else if (scan_request) {
brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
aborted ? "Aborted" : "Done");
// 注意這裏
 cfg80211_scan_done(scan_request, aborted);
brcmf_set_mpc(ndev, 1);
}
if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
return err;
}

9. 調用cfg80211_scan_done()

void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
{
trace_cfg80211_scan_done(request, aborted);
WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
request->aborted = aborted;
queue_work(cfg80211_wq, &wiphy_to_dev(request->wiphy)->scan_done_wk); // 又是work queue
}

這裏的work queue是在wiphy_new()被初始化的:

INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);

10. 那麼接下來就是調用__cfg80211_scan_done()

void __cfg80211_scan_done(struct work_struct *wk)
{
struct cfg80211_registered_device *rdev;
rdev = container_of(wk, struct cfg80211_registered_device,
scan_done_wk);
cfg80211_lock_rdev(rdev);
___cfg80211_scan_done(rdev, false);
cfg80211_unlock_rdev(rdev);
}

11. 調用___cfg80211_scan_done()

void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
{
...
/*
* This must be before sending the other events!
* Otherwise, wpa_supplicant gets completely confused with
* wext events.
*/
if (wdev->netdev)
cfg80211_sme_scan_done(wdev->netdev);
if (request->aborted) {
nl80211_send_scan_aborted(rdev, wdev);
} else {
if (request->flags & NL80211_SCAN_FLAG_FLUSH) {
/* flush entries from previous scans */
spin_lock_bh(&rdev->bss_lock);
__cfg80211_bss_expire(rdev, request->scan_start);
spin_unlock_bh(&rdev->bss_lock);
}
// 這裏通過nl80211去通知user space
 nl80211_send_scan_done(rdev, wdev);
}
...
}

12. 調用nl80211_send_scan_done()

void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev)
{
struct sk_buff *msg;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return;
// 注意這裏的消息名字
if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,
NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
nlmsg_free(msg);
return;
}
genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
nl80211_scan_mcgrp.id, GFP_KERNEL);
}

13. 接下來wpa_supplicant就會接收到NL80211_CMD_NEW_SCAN_RESULTS

static int process_event(struct nl_msg *msg, void *arg)
{
struct wpa_driver_nl80211_data *drv = arg;
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
struct nlattr *tb[NL80211_ATTR_MAX + 1];
union wpa_event_data data;
...
switch (gnlh->cmd) {
...
case NL80211_CMD_NEW_SCAN_RESULTS:
wpa_printf(MSG_DEBUG, "nl80211: New scan results available");
drv->scan_complete_events = 1;
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
drv->ctx);
send_scan_event(drv, 0, tb);
break;
...
default:
wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", gnlh->cmd);
break;
}
return NL_SKIP;
}

14. 調用send_scan_event()

static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
struct nlattr *tb[])
{
union wpa_event_data event;
struct nlattr *nl;
int rem;
struct scan_info *info;
#define MAX_REPORT_FREQS 50
int freqs[MAX_REPORT_FREQS];
int num_freqs = 0;
os_memset(&event, 0, sizeof(event));
info = &event.scan_info;
info->aborted = aborted;
...
// 注意事件EVENT_SCAN_RESULTS
wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
}

15. 進入到wpa_supplicant_event()

void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
struct wpa_supplicant *wpa_s = ctx;
u16 reason_code = 0;
switch (event) {
...
#ifndef CONFIG_NO_SCAN_PROCESSING
case EVENT_SCAN_RESULTS:
wpa_supplicant_event_scan_results(wpa_s, data);
break;
#endif /* CONFIG_NO_SCAN_PROCESSING */
...
default:
wpa_printf(MSG_INFO, "Unknown event %d", event);
break;
}
}

16. 調用wpa_supplicant_event_scan_results()

static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
struct wpa_bss *selected;
struct wpa_ssid *ssid = NULL;
struct wpa_scan_results *scan_res;
int ap = 0;
#ifdef CONFIG_AP
if (wpa_s->ap_iface)
ap = 1;
#endif /* CONFIG_AP */
wpa_supplicant_notify_scanning(wpa_s, 0);
// 去從driver取得scan result
scan_res = wpa_supplicant_get_scan_results(wpa_s,
data ? &data->scan_info :
NULL, 1);
if (scan_res == NULL) {
if (wpa_s->conf->ap_scan == 2 || ap)
return;
wpa_printf(MSG_DEBUG, "Failed to get scan results - try "
"scanning again");
wpa_supplicant_req_new_scan(wpa_s, 1, 0);
return;
}
if (wpa_s->scan_res_handler) {
wpa_s->scan_res_handler(wpa_s, scan_res);
wpa_s->scan_res_handler = NULL;
wpa_scan_results_free(scan_res);
return;
}
if (ap) {
wpa_printf(MSG_DEBUG, "Ignore scan results in AP mode");
wpa_scan_results_free(scan_res);
return;
}
wpa_printf(MSG_DEBUG, "New scan results available");
// 發出事件"CTRL-EVENT-SCAN-RESULTS "
// Android framework中的WifiMonitor將會收到
 wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
wpas_notify_scan_results(wpa_s);
wpas_notify_scan_done(wpa_s, 1);
...
}

這裏需要一下wpa_supplicant_get_scan_results(), 它非常重要。

struct wpa_scan_results *
wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
struct scan_info *info, int new_scan)
{
struct wpa_scan_results *scan_res;
size_t i;
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
scan_res = ieee80211_sta_get_scan_results(wpa_s);
else
// 這個函數最終會觸發了wpa_driver_nl80211_get_scan_results(),
// 從而向driver發出了NL80211_CMD_GET_SCAN命令,收到這個命令之後,
// driver會把scan result dump出來。
scan_res = wpa_drv_get_scan_results2(wpa_s);
if (scan_res == NULL) {
wpa_printf(MSG_DEBUG, "Failed to get scan results");
return NULL;
}
// 排序掃描結果
qsort(scan_res->res, scan_res->num, sizeof(struct wpa_scan_res *),
wpa_scan_result_compar);
wpa_bss_update_start(wpa_s);
for (i = 0; i < scan_res->num; i++)
// 把掃描結果update到wpa_s結果中去,後面要用到
wpa_bss_update_scan_res(wpa_s, scan_res->res[i]);
wpa_bss_update_end(wpa_s, info, new_scan);
return scan_res;
}

17. 前面提到了Android framework中的WifiMonitor. 現在就進入到WifiMonitor中來分析如何處理事件"CTRL-EVENT-SCAN-RESULTS "的

 class MonitorThread extends Thread {
public MonitorThread() {
super("WifiMonitor");
}
public void run() {
if (connectToSupplicant()) {
// Send a message indicating that it is now possible to send commands
// to the supplicant
 mStateMachine.sendMessage(SUP_CONNECTION_EVENT);
} else {
mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
return;
}
//noinspection InfiniteLoopStatement
for (;;) {
String eventStr = WifiNative.waitForEvent();
...
/*
* Map event name into event enum
*/
int event;
if (eventName.equals(CONNECTED_STR))
event = CONNECTED;
...
// 這裏便是scan result的事件
else if (eventName.equals(SCAN_RESULTS_STR))
event = SCAN_RESULTS;
...
else
event = UNKNOWN;
...
if (event == STATE_CHANGE) {
handleSupplicantStateChange(eventData);
}
...
else {
handleEvent(event, eventData);
}
mRecvErrors = 0;
}
}
...
/**
* Handle all supplicant events except STATE-CHANGE
* @param event the event type
* @param remainder the rest of the string following the
* event name and &quot;&#8195;&#8212;&#8195;&quot;
*/
void handleEvent(int event, String remainder) {
switch (event) {
...
// 處理scan result
case SCAN_RESULTS:
mStateMachine.sendMessage(SCAN_RESULTS_EVENT);
break;
case UNKNOWN:
break;
}
}
...
}

18. 很明顯,將會到WifiStateMachine中進一步處理SCAN_RESULT_EVENT

 class SupplicantStartedState extends State {
...
@Override
public boolean processMessage(Message message) {
if (DBG) log(getName() + message.toString() + "\n");
WifiConfiguration config;
boolean eventLoggingEnabled = true;
switch(message.what) {
...
case WifiMonitor.SCAN_RESULTS_EVENT:
eventLoggingEnabled = false;
setScanResults(WifiNative.scanResultsCommand());
sendScanResultsAvailableBroadcast();
mScanResultIsPending = false;
break;
...
default:
return NOT_HANDLED;
}
if (eventLoggingEnabled) {
EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
}
return HANDLED;
}
...
}

19. 這裏先調用WifiNative.scanResultsCommand()去獲取掃描結果,然後傳遞給setScanResult()。我們進入到JNI函數去看看

static jstring android_net_wifi_scanResultsCommand(JNIEnv* env, jobject)
{
return doStringCommand(env, "SCAN_RESULTS");
}

20. 又發了"SCAN_RESULT"這個命令給wpa_supplicant

wpa_supplicant_ctrl_iface_process()調用wpa_supplicant_ctrl_iface_scan_results來處理該命令:

static int wpa_supplicant_ctrl_iface_scan_results(
struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
{
char *pos, *end;
struct wpa_bss *bss;
int ret;
pos = buf;
end = buf + buflen;
ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
"flags / ssid\n");
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
// 前面我們提到,wpa_supplicant_get_scan_results()中已經把掃描結果update到wpa_s結構中
// 那麼這兒就用到了,針對wpa_s->bss_id中的每個bss做處理
ret = wpa_supplicant_ctrl_iface_scan_result(bss, pos,
end - pos);
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
}
return pos - buf;
}

21. 調用wpa_supplicant_ctrl_iface_scan_result()去格式化字符串

/* Format one result on one text line into a buffer. */
static int wpa_supplicant_ctrl_iface_scan_result(
const struct wpa_bss *bss, char *buf, size_t buflen)
{
...
}

最終,Android framework就拿到了格式化好的掃描結果。

22. 調用setScanResults()

 /**
* scanResults input format
* 00:bb:cc:dd:cc:ee 2427 166 [WPA-EAP-TKIP][WPA2-EAP-CCMP] Net1
* 00:bb:cc:dd:cc:ff 2412 165 [WPA-EAP-TKIP][WPA2-EAP-CCMP] Net2
*/
private void setScanResults(String scanResults) {
if (scanResults == null) {
return;
}
List<ScanResult> scanList = new ArrayList<ScanResult>();
int lineCount = 0;
int scanResultsLen = scanResults.length();
// Parse the result string, keeping in mind that the last line does
// not end with a newline.
for (int lineBeg = 0, lineEnd = 0; lineEnd <= scanResultsLen; ++lineEnd) {
if (lineEnd == scanResultsLen || scanResults.charAt(lineEnd) == '\n') {
++lineCount;
if (lineCount == 1) {
lineBeg = lineEnd + 1;
continue;
}
if (lineEnd > lineBeg) {
String line = scanResults.substring(lineBeg, lineEnd);
ScanResult scanResult = parseScanResult(line);
if (scanResult != null) {
scanList.add(scanResult);
} else {
//TODO: hidden network handling
 }
}
lineBeg = lineEnd + 1;
}
}
mScanResults = scanList;
}

該函數的註釋就很清楚的顯示了從wpa_supplicant獲取的掃描結果的格式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章