现在的位置: 首页 > 综合 > 正文

Broadcom fullmac WLAN 驱动解析(2)

2013年11月19日 ⁄ 综合 ⁄ 共 14708字 ⁄ 字号 评论关闭

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

抱歉!评论已关闭.