Broadcom WLAN驱动解析

现在我们来看看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);
}

上一节已经分析过,这里bus->ops->txctl就是调用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获取的扫描结果的格式。

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值