Google OS実験室 ~Moonlight 明日香~

GoogleのAndroidで遊び始めて, すでに6年以上が経った. Androidは思った以上の発展を遂げている. この技術を使って, 新しいことにチャレンジだ!!

Androidで無線LAN接続にチャレンジ!! (2)

第2回は, Android-x86のソースコードや設定ファイルの変更箇所についてまとめる予定であったが, ソースコードの変更箇所の解説が長くなったので今回はこれだけにする.

・ Dell Inspiron 6400 
・ Android-x86 1.6 2010-1-25版
・ 匿名WLAN SDIOカード(某社評価用サンプルのため)

1. Wi-Fi制御ライブラリ
 WLANドライバソフトのロード/アンロードのための関数を修正する.
ここでは, WLANデバイスドライバは架空のwlan_if.ko, wlan_sdio.koとしているが, Linuxで動作実績のあるWLANデバイス/ドライバソフトであれば同じように組み込み可能と思われる.
ソース : ./hardware/libhardware_legacy/wifi/wifi.c
以下, 本来のコードを青字, 修正部分を赤字, コメントを斜体字で記す.
1.1 ドライバ名等の定義
1) WLANファームウェアのロードの有無
 WLANドライバソフトをロード(insmod)しても, WLANのファームウェアがダウンロードされない場合は, WIFI_FIRMWARE_LOADERにWLANのファームウェアダウンロードを行うプログラム(スクリプト含む)を指定する.
 今回使用したWLANデバイスはWLANドライバをロードすると, ファームウェアもデバイスにダウンロードされるので修正なし.
#ifndef WIFI_FIRMWARE_LOADER
#define WIFI_FIRMWARE_LOADER  ""
#endif
2) Wi-Fiインタフェース名の設定
 WLANデバイスが認識されたときに設定されるインタフェース名に指定する. インタフェース名は, iwconfigやifconfigで確認できる.
 今回使用したWLANデバイスは"eth1"と認識されるので, WIFI_TEST_INTERFACEを"sta"から"eth1"に修正した.
#define WIFI_TEST_INTERFACE            
"eth1"
3) WLANドライバソフトの設定
 ドライバ名やドライバソフトのファイル名等を設定する.
本来, システム属性"wlan.modname"や"wlan.modpath"で設定するのが正しい(?)ようだが, 今回2つのドライバソフトをロードする必要があったので, Android 1.5の修正[1]を参考に以下を追加した.
static const char WLAN_IF_DRIVER_NAME[] = "wlan_if";
static const char WLAN_IF_DRIVER_PATH[] = "wlan_if.ko";
static const char WLAN_SDIO_DRIVER_NAME[] = "wlan_sdio";
static const char WLAN_SDIO_DRIVER_PATH[] = "wlan_sdio.ko";

1.2 WLANドライバソフトのロード
 wifi_load_driver()関数をWLANデバイスにあわせて修正する.
int wifi_load_driver()
{
    char driver_status[PROPERTY_VALUE_MAX];
    char driver_path[SYSFS_PATH_MAX];
    int count = 100; /* wait at most 20 seconds for completion */

    ** WLANドライバがすでにロードされているかチェック **
    if (check_driver_loaded())
        return 0;
    ** wlan.modpathを使用しないで, デバイスドライバへのパスを作成 **

    // if (!property_get("wlan.modpath",driver_status,NULL))
    //    return -1;

    snprintf(driver_path, SYSFS_PATH_MAX-1, "%s/%s",
             MODULE_DEFAULT_DIR, WLAN_IF_DRIVER_PATH);
    ** WLANドライバソフトのロード **
    if (insmod(driver_path, "") < 0) 
        return -1;

    ** 2つめのWLANドライバソフトのロード **
    snprintf(driver_path, SYSFS_PATH_MAX-1, "%s/%s",
             MODULE_DEFAULT_DIR, WLAN_SDIO_DRIVER_PATH);
    if (insmod(driver_path, "") < 0) 
        return -1;

    ** ファームウェアのダウンロード **
    **    必要なし : ファームウェアが起動するのをまって, "wlan.driver.status=ok"に設定 **
    **    必要あり : "ctl.start"にファームウェアをダウンロードするプログラムを設定 **
    **                 プログラムの起動はサービスマネージャが行う **

    if (strcmp(FIRMWARE_LOADER,"") == 0) {
        usleep(500000); 
        property_set(DRIVER_PROP_NAME, "ok");
    }
    else {
        property_set("ctl.start", FIRMWARE_LOADER);
    }

    sched_yield();
    ** ファームウェアが起動する("wlan.driver.status=ok")のを待つ **
    while (count-- > 0) {
        usleep(500000);
        if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) {
            if (strcmp(driver_status, "ok") == 0) {
                /* Update the system prop */
                // get_driver_info();
                property_set("wlan.interface", "eth1");
                return 0;
            }
            else if (strcmp(DRIVER_PROP_NAME, "failed") == 0) 
                return -1;
        }
        usleep(200000);
    }
    property_set(DRIVER_PROP_NAME, "timeout");
    return -1;
}
1.3 WLANドライバソフトのアンロード
 wifi_unload_driver()関数をWLANデバイスにあわせて修正する.

int wifi_unload_driver()
{
    char driver_status[PROPERTY_VALUE_MAX];

#if 0
    int count = 20; /* wait at most 10 seconds for completion */

    if (!property_get("wlan.modname",driver_status,NULL))
        return -1;
    if (rmmod(driver_status) == 0) {
        while (count-- > 0) {
            if (!check_driver_loaded())
                break;
            usleep(500000);
        }
        if (count) {
            return 0;
        }
        return -1;
    } else
        return -1;
#else
    ** 2つのドライバソフトを順にアンロード **
    if (rmmod(WLAN_SDIO_DRIVER_NAME) == 0) {
        usleep(1000000);
    }
    else {
        LOGE("Unloading WLAN SDIO driver Failed ");
        return -1;
    }
    if (rmmod(WLAN_IF_DRIVER_NAME) == 0) {
        usleep(1000000);
    }
    else {
        LOGE("Unloading WLAN IF driver Failed ");
        return -1;
    }
    property_set(DRIVER_PROP_NAME, "unloaded");
    return 0;
#endif
}
1.3 ドライバソフトのロード状態チェック
 check_driver_loaded()関数のロード状態のチェック部分が誤っているように思えるが...
static int check_driver_loaded() {
    char driver_status[PROPERTY_VALUE_MAX];
    int ret;

    if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) {
        ** ドライバソフトのロードが完了すると, "wlan.driver.status=ok"となるはず!! **/
        if ( strcmp(driver_status, "ok") == 0) {
            return 1;  /* driver loaded */
        } else {
            return 0;  /* Someone has unloaded driver */
        }
    }

    /*
     * This may be the first time we are here and the init
     * script may already installed the driver for us. In
     * that case, we just need to check sys/classs/net/
     * to find the right driver
     */
    // if (!(ret = get_driver_info())) {
        property_set(DRIVER_PROP_NAME, "unloaded");
    // }
    return ret;
} 

2. wpa_supplicant
 wpa_supplicantのソースコードの中に, WLANインタフェース名に依存する部分があるので変更する.
ソース : ./external/wpa_suplicant/driver_wext.c
 WLANインタフェース名を"wlan"から"eth"に修正し, ifname2に"wifi"が設定されるようにする.
ifname2に"wifi"を設定されないと, dhcpcdが起動されないように見えた.
実際のところは, はっきりいってよく分かっていない...
static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
{
    int flags;

    (省略)
    wpa_driver_wext_get_range(drv);
    drv->ifindex = if_nametoindex(drv->ifname);

    if (os_strncmp(drv->ifname, "eth", 3) == 0) {
        /*
         * Host AP driver may use both wlan# and wifi# interface in
         * wireless events. Since some of the versions included WE-18
         * support, let's add the alternative ifindex also from
         * driver_wext.c for the time being. This may be removed at
         * some point once it is believed that old versions of the
         * driver are not in use anymore.
         */
         char ifname2[IFNAMSIZ + 1];
         os_strncpy(ifname2, drv->ifname, sizeof(ifname2));
         os_memcpy(ifname2, "wifi", 4);
         wpa_driver_wext_alternative_ifindex(drv, ifname2);
     }
     wpa_driver_wext_send_oper_ifla(drv, 1, IF_OPER_DORMANT);
}

3. Wi-Fiサービス
 WifiStateTrackerのソースコードの中に, WLANインタフェース名に依存する部分があるので変更する.
ソース : ./frameworks/base/wifi/java/adnroid/net/wifi/WifiStateTracker.java
public class WifiStateTracker extends NetworkStateTracker {
     (省略)
    public void handleMessage(Message msg) {
        Intent intent;

        switch (msg.what) {
            case EVENT_SUPPLICANT_CONNECTION:
                mInterfaceName = SystemProperties.get("wlan.interface",
"eth1");
                sDnsPropNames = new String[] {
                    "dhcp." + mInterfaceName + ".dns1",
                    "dhcp." + mInterfaceName + ".dns2"
                };
                mRunState = RUN_STATE_RUNNING;
                noteRunState();
                checkUseStaticIp();
                     (省略)
         }
    }
}

今回は, ソースコードの変更箇所についてまとめてみた.
第3回では, 設定や動作の確認方法などについてまとめてみる予定.

--------
参考URL:
 [1] BC::BEATCRAFT Android_Wi-Fi

Androidで無線LAN接続にチャレンジ!! (1)

Dell PC上に載せたAndroid-x86で無線LAN接続にチャレンジしてみた.
Web上の記事[1][2]などを参考にトライしたがGUIからうまく接続できなかったので, Android-x86のWi-Fi制御について少し調べてみた.
一応, Android-x86からGUIからAP接続できるようになったので, 少し整理し, 2-3回に分けてまとめてみる.
第1回は, AndroidのWi-Fi制御部分がどのように構成されているか概要をまとめてみた.

1. Wi-Fi制御の各ブロックとソースコード
AndroidのWi-Fi制御部分を簡単にまとめてみると, 以下のような構造になっているようである.
Wifi_block

1.1 Wi-Fiサービス
 Wi-Fiサービスに関するソースコードは, 以下のディレクトリにある.
 ./frameworks/base/services/java/com/android/server
   ・ ConnectivityService.java
   ・ WifiService.java
   ・ WifiWatchdogService.java

1.2 Wi-Fiクラス
  Wi-Fiを利用するためのjavaクラスであり, ソースコードは以下のディレクトリにある.
 ./frameworks/base/wifi/java/android/net/wifi
    ・WifiConfiguration.java
   ・WifiInfo.java
   ・WifiManager.java
   ・WifiMonitor.java
   ・WifiNative.java
   ・WifiStateTracker.java
   ・ScanResult.java
   ・SupplicantState.java

1.3 Wi-Fi JNIライブラリ
  JavaプログラムからWi-Fi制御を行うC/C++コードを呼び出すためのAPIで, ソースコードは以下にある.
 ./frameworks/base/core/jni/android_net_wifi_Wifi.cpp

1.4 Wifi制御ライブラリ
 Wi-Fi制御ライブラリは, WLANドライバソフトのロード/アンロードや, wpa_supplicant, dhcpの制御を行う関数群であり, ソースコードは以下にある.
  ./hardware/libhardware_legacy/wifi/wifi.c
1.5 wpa_supplicant
 wpa_supplicantはIEEE802.1x/WPAを無線LANクライアントに提供するツールであり, ソースコードは以下のディレクトリにある.
 ./external/wpa_supplicant
1.6 dhcpcd
 dhcpcdはDHCPクライアントデーモンであり, ソースコードは以下のディレクトリにある.
 ./external/dhcpcd
1.7 Wi-Fiデバイス/ドライバソフト
 Linuxで動作実績のあるWLANデバイス/ドライバソフトであれば, Androidでも問題なく動作すると思う.



2. Wi-Fi制御の下回りの関係
Wi-Fi制御の下回りであるWi-Fi制御ライブラリとwpa_supplicant, dhcpcdとの関係を整理してみた. (まだよくわかっていない部分もあるが...)
Wifi_ctrl

2.1 WLANドライバのロード/アンロード
 ConnectivityServiceからWifiServiceが起動されると, wifi_load_deriver()がコールされ, WLANドライバソフトのロード(insmod)が行われる. WLANドライバソフトのロードが完了し, WLANデバイスが起動すると"wlan.device.status=ok"となる.
 WLANドライバソフトをアンロード(rmmod)する際には, wifi_unload_driver()がコールされ, WLANデバイスを停止させる.
2.2 wpa_supplicantの起動
 WifiServiceからwifi_start_wpa_supplicant()がコールされる. wifi_start_supplicant()が"ctl.start=wpa_supplicant"を設定すると, サービスマネージャによりwpa_supplicantが起動する. wpa_supplicantが動作しているときは, "init.svc.wpa_supplicant=running"となる.
 wpa_supplicantを停止させる場合には, wifi_stop_wpasupplicant()がコールされ, "ctl.stop=wpa_supplicant"を設定すると, サービスマネージャによりwpa_supplicantが停止する. wpa_supplicantが停止すると"init.svc.wpa_supplicant=stopped"となる.
2.3 dhcpcdの起動
  wpa_supplicantを経由してAPとの接続が完了すると, "EVENT_SUPPLICANT_CONNECTION"イベントメッセージがどこからか発行され, WifiStateTrackerがdhcpcdを起動する. dhcpcdが起動すると, "init.svc.dhcpXXX=running"となる.

今回は, Wi-Fi制御部分がどのように構成されているかについてまとめてみた.
第2回では, ソースコードの修正や設定ファイル等についてまとめてみる予定.

-----
参照URL:
 [1] ネットブックでAndroidを動かす(3)
 [2] BC::BEATCRAFT Android_Wi-Fi


livedoor プロフィール
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

記事検索



  • ライブドアブログ