wifi構成ツールwpa_についてcliおよびwpa_supplicant単純分析

44192 ワード

最近、同社で新製品のスマートAndroidロボットを開発し、rk 3229開発ボードを使い始めた.wifiをデバッグする際によく使われるツールwap_cli、demoボードのデバッグを開始するときwpa_cliは正常に使用できます.しかし、製品はBluetooth機能をサポートする必要があるため、博通のAP 6212のwifiモジュールを交換しました.demoが使用するrtl 8616 wifiモジュール.新しいハードウェアのwap_が見つかりましたcliは使用できません.デバッグの進捗に影響します.次のように誤報する
Failed to connect to non-global ctrl_ifname: wlan0  error: No such file or directory
Could not connect to wpa_supplicant: wlan0 - re-trying

このエラーの原因は、関連するwaln 0というsocket通信ノードが見つからないためです.通常、このsocketはこのディレクトリの下で通信ノード/data/misc/wifi/sockets/wlan0を確立しますが、新しいハードウェアの下では関連ノードが確立されていないことに気づきました.デバッグを続けてlog情報を追加するとctrl_interfaceはロックの原因を定義していません.params.override_ctrl_interfaceが定義されたらokです.wifiのsupplicantモジュールがinit.rcで起動すると、wifiチップによってトリガされるサービスが異なります.例えばrtl wifi
service rtw_suppl_con /system/bin/wpa_supplicant_rtl \
    -ip2p0 -Dnl80211 -c/data/misc/wifi/p2p_supplicant.conf \
    -e/data/misc/wifi/entropy.bin -N \
    -iwlan0 -Dnl80211 -c/data/misc/wifi/wpa_supplicant.conf \
    -O/data/misc/wifi/sockets \
    -g@android:wpa_wlan0
    class main
    socket wpa_wlan0 dgram 660 wifi wifi
    disabled
    oneshot

これは博通です.
service wpa_supplicant /system/bin/wpa_supplicant \
    -iwlan0 -Dnl80211 -c/data/misc/wifi/wpa_supplicant.conf \
    -I/system/etc/wifi/wpa_supplicant_overlay.conf \
    -e/data/misc/wifi/entropy.bin -g@android:wpa_wlan0
    class main
    socket wpa_wlan0 dgram 660 wifi wifi
    disabled
    oneshot

-iネットワークソケット通信ノードを指定ここではwlan 0を指定します
-D   wifi          nl80211
-C    wpa_supplicant                 
   /data/misc/wifi/wpa_supplicant.conf
-I         
-g    ctrl_interface =  @android:wpa_   -i   waln0  

ここはちょっとよくわかりませんctrl_interface = @android:wpa_wlan 0ですが、本当にコードでctrl_interfaceはctrlになりますinterface =/data/misc/wifi/sockets. 具体的な転換原因は自分ではあまり注目していない.知っていることがあれば言ってもいいです.一般的にプロファイルの内容は次のとおりです.
ctrl_interface=/data/misc/wifi/sockets
update_config=1
ap_scan=1

ctrl_interface=/data/misc/wifi/socketsおよび-g@android:wpa_wlan 0のソースコードでの体現
case 'g':
            params.ctrl_interface = optarg;
            break;

これが疑問の場所です2つの明らかな違いは確かに同じctrlを指しています.interface ap_scan=1-wpasはネットワーク0、2-駆動はupdateのスキャンと接続を担当します.config=1プロファイルの更新を許可
int main(int argc, char *argv[])
{
    case 'c':
            iface->confname = optarg;
            break;
        case 'C':
            iface->ctrl_interface = optarg;
            break;
        case 'D':
            iface->driver = optarg;
            break;
        case 'd':
#ifdef CONFIG_NO_STDOUT_DEBUG
            printf("Debugging disabled with "
                   "CONFIG_NO_STDOUT_DEBUG=y build time "
                   "option.
"
); goto out; #else /* CONFIG_NO_STDOUT_DEBUG */ params.wpa_debug_level--; break; #endif /* CONFIG_NO_STDOUT_DEBUG */ case 'e': params.entropy_file = optarg; break; #ifdef CONFIG_DEBUG_FILE case 'f': params.wpa_debug_file_path = optarg; break; #endif /* CONFIG_DEBUG_FILE */ case 'g': params.ctrl_interface = optarg; break; case 'G': params.ctrl_interface_group = optarg; break; case 'h': usage(); exitcode = 0; goto out; case 'i': iface->ifname = optarg; 、、、、、、、、 global = wpa_supplicant_init(&params); for (i = 0; exitcode == 0 && i < iface_count; i++) { struct wpa_supplicant *wpa_s; 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; } // wpa_supplicant_add_iface wpa_s = wpa_supplicant_add_iface(global, &ifaces[i]); } if (exitcode == 0) exitcode = wpa_supplicant_run(global);

wpa_supplicant_Init関数機能はstruct wpaを初期化することです.global*globalという構造体wpa_globalはグローバルな性質のコンテキスト情報である.ifaces変数によってwpaを指しますsupplicantオブジェクト.(1)wpa_interfaceは、無線デバイスを記述するために使用される.このパラメータは初期化時に使用されます.(2)wpa_globalはグローバルな性質のコンテキスト情報である.ifaces変数によってwpaを指しますsupplicantオブジェクト.(3)wpa_supplicantはwpa_supplicantのコアデータ構造.1つのinterfaceは1つのwpaに対応しますsupplicantオブジェクトで、内部に非常に多くのメンバー変数が含まれています.(4)ctrl_iface_global_privはグローバル制御インタフェースの情報であり、内部には通信用のsocketハンドルが含まれている.
wpa_supplicant_init()
{
            return    
    struct wpa_global *global;
        global = os_zalloc(sizeof(*global));
    if (global == NULL)
        return NULL;
    dl_list_init(&global->p2p_srv_bonjour);
    dl_list_init(&global->p2p_srv_upnp);
    global->params.daemonize = params->daemonize;
    global->params.wait_for_monitor = params->wait_for_monitor;
    global->params.dbus_ctrl_interface = params->dbus_ctrl_interface;
    if (params->pid_file)
        global->params.pid_file = os_strdup(params->pid_file);
    if (params->ctrl_interface)
        global->params.ctrl_interface =
            os_strdup(params->ctrl_interface);
                  。      。   socket               
    if (params->ctrl_interface_group)
        global->params.ctrl_interface_group =
            os_strdup(params->ctrl_interface_group);
    if (params->override_driver)
        global->params.override_driver =
            os_strdup(params->override_driver);
    if (params->override_ctrl_interface)
        global->params.override_ctrl_interface =
            os_strdup(params->override_ctrl_interface);
  params     global  wpa_params 
   ctrl_iface_global_priv,       socket   ,    socket     ctrl_interface。
global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);

}
wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
{
    struct ctrl_iface_global_priv *priv;

    priv = os_zalloc(sizeof(*priv));
    if (priv == NULL)
        return NULL;
    dl_list_init(&priv->ctrl_dst);
    priv->global = global;
    priv->sock = -1;

    if (global->params.ctrl_interface == NULL)
        ctrl_interface    。      。         socket
        return priv;
  socket           wpa_cli  framework     
    if (wpas_global_ctrl_iface_open_sock(global, priv) < 0) {
        os_free(priv);
        return NULL;
    }

    wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);

    return priv;
}

static int wpas_global_ctrl_iface_open_sock(struct wpa_global *global,
                        struct ctrl_iface_global_priv *priv)
{
    struct sockaddr_un addr;
         ctrl_interface=/data/misc/wifi/sockets
    const char *ctrl = global->params.ctrl_interface;
    int flags;

#ifdef ANDROID
     ctrl=@android:wpa_wlan0,   ctrl + 9 = wlan0
    if (os_strncmp(ctrl, "@android:", 9) == 0) {
           socket
        priv->sock = android_get_control_socket(ctrl + 9);
        if (priv->sock < 0) {
            wpa_printf(MSG_ERROR, "Failed to open Android control "
                   "socket '%s'", ctrl + 9);
            goto fail;
        }
        wpa_printf(MSG_DEBUG, "Using Android control socket '%s'",
               ctrl + 9);
        goto havesock;
    }

    if (os_strncmp(ctrl, "@abstract:", 10) != 0) {
        /*
         * Backwards compatibility - try to open an Android control
         * socket and if that fails, assume this was a UNIX domain
         * socket instead.
         */
        priv->sock = android_get_control_socket(ctrl);
        if (priv->sock >= 0) {
            wpa_printf(MSG_DEBUG,
                   "Using Android control socket '%s'",
                   ctrl);
            goto havesock;
        }
    }
#endif /* ANDROID */



havesock:

    flags = fcntl(priv->sock, F_GETFL);
    if (flags >= 0) {
        flags |= O_NONBLOCK;
        if (fcntl(priv->sock, F_SETFL, flags) < 0) {
            wpa_printf(MSG_INFO, "fcntl(ctrl, O_NONBLOCK): %s",
                   strerror(errno));
            /* Not fatal, continue on.*/
        }
    }
//     conf     。     init.rc service          wpa_supplicant             data/misc/wifi/wpa_supplicant.conf 
    eloop_register_read_sock(priv->sock,
                 wpa_supplicant_global_ctrl_iface_receive,
                 global, priv);

    return 0;

fail:
    if (priv->sock >= 0) {
        close(priv->sock);
        priv->sock = -1;
    }
    return -1;
}


wpa_supplicant_global_ctrl_iface_receive()は、2つのコマンド、インタフェースコマンド、グローバルコマンドを受け入れることができます.クラスコマンドの前に「IFNAME=」があり、コマンドを処理するインタフェースを示し、各インタフェースに対応するwpaを呼び出す.supplicant_ctrl_iface_プロセス()は、対応する処理を行う.もう1つのクラスは、wpa_によってインタフェースが指定されていません.supplicant_global_ctrl_iface_プロセス直接処理.
static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
                             void *sock_ctx)
{
    struct wpa_global *global = eloop_ctx;
    struct ctrl_iface_global_priv *priv = sock_ctx;
    char buf[4096];
    int res;
    struct sockaddr_un from;
    socklen_t fromlen = sizeof(from);
    char *reply = NULL, *reply_buf = NULL;
    size_t reply_len;

    res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
               (struct sockaddr *) &from, &fromlen);
    if (res < 0) {
        wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
               strerror(errno));
        return;
    }
    buf[res] = '\0';

    if (os_strcmp(buf, "ATTACH") == 0) {
        if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from,
                             fromlen))
            reply_len = 1;
        else
            reply_len = 2;
    } else if (os_strcmp(buf, "DETACH") == 0) {
        if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, &from,
                             fromlen))
            reply_len = 1;
        else
            reply_len = 2;
    } else {
    //wpa_supplicant_global_ctrl_iface_process         
        reply_buf = wpa_supplicant_global_ctrl_iface_process(
            global, buf, &reply_len);
        reply = reply_buf;
    }

    if (!reply && reply_len == 1) {
        reply = "FAIL
"
; reply_len = 5; } else if (!reply && reply_len == 2) { reply = "OK
"
; reply_len = 3; } if (reply) { if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen) < 0) { wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s", strerror(errno)); } } os_free(reply_buf); }
char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
                        char *buf, size_t *resp_len)
{
if (os_strcmp(buf, "PING") == 0) {
        os_memcpy(reply, "PONG
"
, 5); reply_len = 5; } else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) { if (wpa_supplicant_global_iface_add(global, buf + 14)) reply_len = -1; } else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) { if (wpa_supplicant_global_iface_remove(global, buf + 17)) reply_len = -1; } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) { reply_len = wpa_supplicant_global_iface_list( global, reply, reply_size); } else if (os_strcmp(buf, "INTERFACES") == 0) { reply_len = wpa_supplicant_global_iface_interfaces( global, reply, reply_size); } else if (os_strcmp(buf, "TERMINATE") == 0) { wpa_supplicant_terminate_proc(global); } else if (os_strcmp(buf, "SUSPEND") == 0) { wpas_notify_suspend(global); } else if (os_strcmp(buf, "RESUME") == 0) { wpas_notify_resume(global); } else if (os_strncmp(buf, "SET ", 4) == 0) { if (wpas_global_ctrl_iface_set(global, buf + 4)) { #ifdef CONFIG_P2P if (global->p2p_init_wpa_s) { os_free(reply); /* Check if P2P redirection would work for this * command. */ return wpa_supplicant_ctrl_iface_process( global->p2p_init_wpa_s, buf, resp_len); } #endif /* CONFIG_P2P */ reply_len = -1; } #ifndef CONFIG_NO_CONFIG_WRITE } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) { if (wpas_global_ctrl_iface_save_config(global)) reply_len = -1; #endif /* CONFIG_NO_CONFIG_WRITE */ } else if (os_strcmp(buf, "STATUS") == 0) { reply_len = wpas_global_ctrl_iface_status(global, reply, reply_size); #ifdef CONFIG_MODULE_TESTS } else if (os_strcmp(buf, "MODULE_TESTS") == 0) { int wpas_module_tests(void); if (wpas_module_tests() < 0) reply_len = -1; #endif /* CONFIG_MODULE_TESTS */ } else { os_memcpy(reply, "UNKNOWN COMMAND
"
, 16); reply_len = 16; } if (reply_len < 0) { os_memcpy(reply, "FAIL
"
, 5); reply_len = 5; } *resp_len = reply_len; return reply; }

wpa_supplicant_global_ctrl_iface_processは主にコマンド解析でwpa_によるcliまたはframeworkから渡されたパラメータ.次に、関連する関数を実行します.ここで注目したいのは
if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
        if (wpas_global_ctrl_iface_save_config(global))
            reply_len = -1;

設定したパラメータを保存します.settings.apkでもwpaでもcliツールはネットワークに接続され、最後に関連するssidとpasswordはwpa_に保存されます.supplicant.confにあります.これも、市場で簡単にwifiを共有するためにroot権限が必要な理由です.root権限がなければ、プロファイルを読み取ることはできません.本当にファイルを保存するコードは
int wpa_config_write(const char *name, struct wpa_config *config)
{
f = fopen(tmp_name, "w");
wpa_config_write_global(f, config);
//    network={
//  ssid="yzs_test"
//  psk="12345ABCDE"
//  key_mgmt=WPA-PSK
//  priority=10
//}
for (ssid = config->ssid; ssid; ssid = ssid->next) {
        if (ssid->key_mgmt == WPA_KEY_MGMT_WPS || ssid->temporary)
            continue; /* do not save temporary networks */
        if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
            !ssid->passphrase)
            continue; /* do not save invalid network */
        fprintf(f, "
network={
"
); wpa_config_write_network(f, ssid); fprintf(f, "}
"
); } fflush(f); }

wpa_configwrite_globalはnetworkホットスポット以外のプロパティ(**ctrl_など)を保存します.interface=/data/misc/wifi/sockets update_config=1 device_name=rk322x_box manufacturer=rockchip model_name=rk322x-box model_number=rk322x-box serial_number=FNM88CD8WC**
wpa_cliはshellの場合に使用されるwifiネットワーク構成ツールです.framework下のwifi.cとはsocketサービスを共用しています.一般的な使用例
wpa_cli -i wlan0 -p /data/misc/wifi/sockets 

次にインタラクティブモードに入ります.この時点で関連wpaが確立されていない場合supplicantサービスは、Failed to connect to wpa_に報告されます.supplicantこの行のコードはwpa_にありますcli.c下
int main(int argc, char *argv[])
{
    int c;
    int daemonize = 0;
    int ret = 0;
    const char *global = NULL;

    if (os_program_init())
        return -1;

    for (;;) {
        c = getopt(argc, argv, "a:Bg:G:hi:p:P:v");
        if (c < 0)
            break;
        switch (c) {
        case 'a':
            action_file = optarg;
            break;
        case 'B':
            daemonize = 1;
            break;
        case 'g':
            global = optarg;
            break;
        case 'G':
            ping_interval = atoi(optarg);
            break;
        case 'h':
            usage();
            return 0;
        case 'v':
            printf("%s
"
, wpa_cli_version); return 0; case 'i': os_free(ctrl_ifname); ctrl_ifname = os_strdup(optarg); printf("ctrl_ifname is ===== %s
"
, ctrl_ifname); break; case 'p': ctrl_iface_dir = optarg; break; case 'P': pid_file = optarg; break; default: usage(); return -1; } } interactive = (argc == optind) && (action_file == NULL); if (interactive) printf("%s

%s

"
, wpa_cli_version, wpa_cli_license); if (eloop_init()) return -1; if (global) { #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE ctrl_conn = wpa_ctrl_open(NULL); #else /* CONFIG_CTRL_IFACE_NAMED_PIPE */ ctrl_conn = wpa_ctrl_open(global); #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ if (ctrl_conn == NULL) { fprintf(stderr, "Failed to connect to wpa_supplicant " "global interface: %s error: %s
"
, global, strerror(errno)); return -1; } if (interactive) { update_ifnames(ctrl_conn); mon_conn = wpa_ctrl_open(global); if (mon_conn) { if (wpa_ctrl_attach(mon_conn) == 0) { wpa_cli_attached = 1; eloop_register_read_sock( wpa_ctrl_get_fd(mon_conn), wpa_cli_mon_receive, NULL, NULL); } else { printf("Failed to open monitor " "connection through global " "control interface
"
); } } } } eloop_register_signal_terminate(wpa_cli_terminate, NULL); if (ctrl_ifname == NULL) ctrl_ifname = wpa_cli_get_default_ifname(); if (interactive) { // socket , socket ctrl_conn mon_conn , wpa_cli_interactive(); } else { // Failed to connect to non-global ctrl_ifname: wlan0 error: No such file or directory if (!global && wpa_cli_open_connection(ctrl_ifname, 0) < 0) { fprintf(stderr, "Failed to connect to non-global " "ctrl_ifname: %s error: %s
"
, ctrl_ifname, strerror(errno)); return -1; } if (action_file) { if (wpa_ctrl_attach(ctrl_conn) == 0) { wpa_cli_attached = 1; } else { printf("Warning: Failed to attach to " "wpa_supplicant.
"
); return -1; } } if (daemonize && os_daemonize(pid_file)) return -1; if (action_file) wpa_cli_action(ctrl_conn); else ret = wpa_request(ctrl_conn, argc - optind, &argv[optind]); } os_free(ctrl_ifname); eloop_destroy(); wpa_cli_cleanup(); return ret; }

wpa_cli_open_Connectionがsocketサービスを開くのに失敗するとエラーが発生します.ctrl_connはwpaに使用されます.cli下へコマンドmonitor_connはwpaを受信するために使用されるsupplicantから送られてきたメッセージ
static int wpa_cli_open_connection(const char *ifname, int attach)
{
    ctrl_conn = wpa_ctrl_open(ifname);
    mon_conn = wpa_ctrl_open(ifname)
    }
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
{
    //    socket   
    ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
    ctrl->local.sun_family = AF_UNIX;
    //   addr.sun_path is data/misc/wifi/sockets/wlan0
    ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
              CONFIG_CTRL_IFACE_CLIENT_DIR "/"
              CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
              (int) getpid(), counter);
//  socket  
bind(ctrl->s, (struct sockaddr *) &ctrl->local,
            sizeof(ctrl->local)) < 0)
            //     
            connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
            sizeof(ctrl->dest)) < 0)
            }