android wifi

  • bc9 用 android で wifi を使えるようにする手順です。

    android-1.5r3 branch を使用して動作確認を行いました。
    使用した USB wifi は I-O data WN-G54/USB です。

    android の GUI からの wifi のコントロールを可能にするには、
    android-1.5r3/hardware/libhardware_legacy/wifi/wifi.c 
    の修正が必要になります。(build すると libnetutils に link されます。)
    ここに特定のデバイスを前提にした処理を実装する必要があるので、
    新しいデバイスに対応させるには新規に処理を追加・調整する必要があります。

    現在の android のつくりでは、同じ device driver を使う USB wifi であれば異なるハードを差し替えて使用できますが、
    使用する driver の異なる何種類かのハードに同時に対応させるということにはかなり手間がかかります。

    android-1.5r3/development/pdk/docs/guide/wifi.jd に wifi portging の解説文書があります。
    (javadoc の html への変換に関しては mydroid/development/pdk/README を参照してください。)

手順

以下の手順は、bc9/bc9-oe-sdk setupbc9/bc9-android-sdk setup に従って
kernel の rebuild、android userland の build を行っています。

無線LAN driverを有効にした Kernel の作成

  • 今回は gumstix/bc9 で使用実績のある I-O DATA WN-G54/USB を使用します。
    driver は linux-2.6.29/drivers/net/wireless/rt2x00/rt73usb.ko です。
    これは rt2x00lib.ko と rt2x00usb.ko に依存し、rt73.bin という firmware を必要とします。
    firmware の入手は ralinkこちら
    Ralink の driver および firmware 配布ページはファイルの URL が変更になり、
    ダウンロードに名前とメールアドレスの入力が必要になりました。
    入手の手間を省きこのページから直接ダウンロードできるよう、ファイルをページに添付します。
    fileRT71W_Firmware_V1.8.zip

まず driver をモジュールとして build し、OpenEmbedded Linux 上で使用できることを確認します。
rt73.bin は /lib/firmware/ に配置します。
wpa_supplicant を使った接続の方法は /etc/network/interfaces にある設定例を参考にします。

$ wpa_passphrase SSID PASS_PHRASE

の出力結果を /etc/wpa_supplicant.conf に書いて使用しますが、これだけでは暗号化方式などの指定が足りないため接続できません。
http://ubuntuforums.org/showthread.php?t=263136&page=11
などを参考に必要な設定を追加します。
例:

network={
    ssid="hoge"
    key_mgmt=WPA-PSK
    proto=WPA WPA2
    pairwise=CCMP TKIP
    group=CCMP TKIP WEP104 WEP40
    # psk="beatcraft"
    psk=1954c17037ac0255e310e30377008d5e732edb603bb4b27ee92d14e4b0d91919
}

これを正しく記述したら以下のコマンドで接続を確認します。

$ wpa_supplicant -Dwext -iwlan0 -c/etc/wpa_supplicant.conf

OpenEmbedded の場合はこれで wlan0 が up し dhcp で IPアドレスを取得します。

wpa_supplicant を含む android build

wpa_supplicant 有効にして android を build し、コマンドラインで 無線接続を確認します。

wpa_supplicant の build

android-1.5r3/external/wpa_supplicant/.config を以下のように修正します。

$ diff -u .config.orig .config
--- .config.orig	2009-08-05 22:00:52.000000000 +0900
+++ .config	2009-08-11 16:22:36.000000000 +0900
@@ -19,13 +19,13 @@
 CONFIG_PKCS12=y
 # CONFIG_PCSC=y
 CONFIG_SMARTCARD=y
-# CONFIG_WIRELESS_EXTENSION=y
+CONFIG_WIRELESS_EXTENSION=y
 CONFIG_CTRL_IFACE=y
 # CONFIG_DRIVER_HOSTAP=y
 # CONFIG_DRIVER_HERMES=y
 # CONFIG_DRIVER_MADWIFI=y
 # CONFIG_DRIVER_ATMEL=y
-# CONFIG_DRIVER_WEXT=y
+CONFIG_DRIVER_WEXT=y
 # CONFIG_DRIVER_NDISWRAPPER=y
 # CONFIG_DRIVER_BROADCOM=y
 # CONFIG_DRIVER_IPW=y

android-1.5r3/build/target/board/generic/BoardConfig.mk に以下を追加します。

WPA_BUILD_SUPPLICANT := true
BOARD_WPA_SUPPLICANT_DRIVER := WEXT

android-1.5r3/external/wpa_supplicant/wpa_supplicant.conf を以下のように修正します。

~/android-1.5r3$ diff -u external/wpa_supplicant/wpa_supplicant.conf.orig external/wpa_supplicant/wpa_supplicant.conf
--- external/wpa_supplicant/wpa_supplicant.conf.orig	2009-08-11 16:31:15.000000000 +0900
+++ external/wpa_supplicant/wpa_supplicant.conf	2009-08-11 16:31:58.000000000 +0900
@@ -72,7 +72,8 @@
 # DACL (which will reject all connections). See README-Windows.txt for more
 # information about SDDL string format.
 #
-ctrl_interface=tiwlan0
+#ctrl_interface=wlan0
+ctrl_interface=DIR=/data/system/wpa_supplicant GROUP=system
 
 # IEEE 802.1X/EAPOL version
 # wpa_supplicant is implemented based on IEEE Std 802.1X-2004 which defines

これで make を実行すると out/target/product/generic/system/bin/ に wpa_supplicant と wpa_cli が build されているので
android の shell から実行し無線アクセスポイントに接続できることを確認します。
android 上では insmod して firmware が読み込まれても wlan0 は自動で up しないので、

# system/bin/wpa_supplicant -Dwext -iwlan0 -c/system/etc/wpa_supplicant.conf
# netcfg wlan0 dhcp

と入力し dhcp によるアドレス取得もコマンドで行う必要があります。

wifi.c の修正

wifi.c を修正して android の GUI から操作可能にします。
rt73usb.ko とそれが依存している driver を順に insmod すると rt73.bin が USB wifi に load されて
wlan0 として利用可能になります。
(android には modprobe がありませんので、依存関係のある driver を一括して load することはできません。
依存関係を満たすよう一つずつ順番の insmod する必要があります。)
そこで wpa_supplicant で wifi の SSID、PSK などを設定し、wlan0 を up して dhcp でアドレスを取得します。
android-1.5r3/hardware/libhardware_legacy/wifi/wifi.c を以下のように修正します。

--- wifi.c.orig 2009-08-11 10:56:03.000000000 +0900
+++ wifi.c      2009-08-12 17:02:49.000000000 +0900
@@ -48,10 +48,16 @@
 // TODO: use new ANDROID_SOCKET mechanism, once support for multiple
 // sockets is in

-static const char IFACE_DIR[]           = "/data/system/wpa_supplicant";
-static const char DRIVER_MODULE_NAME[]  = "wlan";
-static const char DRIVER_MODULE_TAG[]   = "wlan ";
-static const char DRIVER_MODULE_PATH[]  = "/system/lib/modules/wlan.ko";
+static const char IFACE_DIR[]                          = "/data/system/wpa_supplicant";
+static const char DRIVER_MODULE_NAME[]                 = "rt73usb";
+static const char DRIVER_MODULE_TAG[]                  = "rt73usb ";
+static const char DRIVER_MODULE_PATH[]                 = "/system/lib/modules/rt73usb.ko";
+static const char RT2X00_LIB_DRIVER_MODULE_NAME[]      = "rt2x00lib";
+static const char RT2X00_LIB_DRIVER_MODULE_TAG[]       = "rt2x00lib ";
+static const char RT2X00_LIB_DRIVER_MODULE_PATH[]      = "/system/lib/modules/rt2x00lib.ko";
+static const char RT2X00_LIB_USB_DRIVER_MODULE_NAME[]  = "rt2x00usb";
+static const char RT2X00_LIB_USB_DRIVER_MODULE_TAG[]   = "rt2x00usb";
+static const char RT2X00_LIB_USB_DRIVER_MODULE_PATH[]  = "/system/lib/modules/rt2x00usb.ko";
 static const char FIRMWARE_LOADER[]     = "wlan_loader";
 static const char DRIVER_PROP_NAME[]    = "wlan.driver.status";
 static const char SUPPLICANT_NAME[]     = "wpa_supplicant";
@@ -66,6 +72,7 @@
     unsigned int size;
     int ret;

+    LOGI("%s\n", __FUNCTION__);
     module = load_file(filename, &size);
     if (!module)
         return -1;
@@ -82,6 +89,7 @@
     int ret = -1;
     int maxtry = 10;

+    LOGI("%s\n", __FUNCTION__);
     while (maxtry-- > 0) {
         ret = delete_module(modname, O_NONBLOCK | O_EXCL);
         if (ret < 0 && errno == EAGAIN)
@@ -91,30 +99,35 @@
     }

     if (ret != 0)
-        LOGD("Unable to unload driver module \"%s\": %s\n",
+        LOGE("Unable to unload driver module \"%s\": %s\n",
              modname, strerror(errno));
     return ret;
 }

 int do_dhcp_request(int *ipaddr, int *gateway, int *mask,
                     int *dns1, int *dns2, int *server, int *lease) {
+    LOGI("1. inside %s\n", __FUNCTION__);
     /* For test driver, always report success */
-    if (strcmp(iface, "sta") == 0)
+    if (strcmp(iface, "wlan0") == 0)
         return 0;

+    LOGI("2. inside %s\n", __FUNCTION__);
     if (ifc_init() < 0)
         return -1;

+    LOGI("3. inside %s\n", __FUNCTION__);
     if (do_dhcp(iface) < 0) {
         ifc_close();
         return -1;
     }
     ifc_close();
     get_dhcp_info(ipaddr, gateway, mask, dns1, dns2, server, lease);
+    LOGI("4. inside %s\n", __FUNCTION__);
     return 0;
 }

 const char *get_dhcp_error_string() {
+    LOGI("Inside %s\n", __FUNCTION__);
     return dhcp_lasterror();
 }

@@ -123,8 +136,10 @@
     FILE *proc;
     char line[sizeof(DRIVER_MODULE_TAG)+10];

+    LOGI("%s\n", __FUNCTION__);
     if (!property_get(DRIVER_PROP_NAME, driver_status, NULL)
             || strcmp(driver_status, "ok") != 0) {
+        LOGE("driver %s has NOT been installed",DRIVER_MODULE_TAG);
         return 0;  /* driver not loaded */
     }
     /*
@@ -140,10 +155,12 @@
     }
     while ((fgets(line, sizeof(line), proc)) != NULL) {
         if (strncmp(line, DRIVER_MODULE_TAG, strlen(DRIVER_MODULE_TAG)) == 0) {
+            LOGI("driver %s has been installed\n",DRIVER_MODULE_TAG);
             fclose(proc);
             return 1;
         }
     }
+    LOGE("Cannot find driver %s in proc",DRIVER_MODULE_TAG);
     fclose(proc);
     property_set(DRIVER_PROP_NAME, "unloaded");
     return 0;
@@ -154,23 +171,34 @@
     char driver_status[PROPERTY_VALUE_MAX];
     int count = 100; /* wait at most 20 seconds for completion */

+    LOGI("Loading WiFi Modules\n");
+    sleep(1);
+
+    // Hack taken from EEPC WiFi path. We have statically linked the WiFi driver
+    // into the kernel, so we simply return and don't attempt to load the driver.
+    // So we set the driver property to ok, since we have already installed it.
+    property_set(DRIVER_PROP_NAME, "ok");
     if (check_driver_loaded()) {
         return 0;
     }
-
-    if (insmod(DRIVER_MODULE_PATH) < 0)
-        return -1;
-      
-    property_set("ctl.start", FIRMWARE_LOADER);
+    insmod(RT2X00_LIB_DRIVER_MODULE_PATH);
+    insmod(RT2X00_LIB_USB_DRIVER_MODULE_PATH);
+    insmod(DRIVER_MODULE_PATH);
+    property_set("ctl.start", 0);
     sched_yield();
     while (count-- > 0) {
+               usleep(500000);
         if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) {
-            if (strcmp(driver_status, "ok") == 0)
+            if (strcmp(driver_status, "ok") == 0) {
+               property_set("ctl.start", "ifcfg_ralink");
+                               usleep(1000000);
+                               //property_set("ctl.start", "dhcpcd");
                 return 0;
-            else if (strcmp(DRIVER_PROP_NAME, "failed") == 0)
+            }
+            else if (strcmp(DRIVER_PROP_NAME, "failed") == 0) {
                 return -1;
+            }
         }
-        usleep(200000);
     }
     property_set(DRIVER_PROP_NAME, "timeout");
     return -1;
@@ -178,20 +206,31 @@

 int wifi_unload_driver()
 {
-    int count = 20; /* wait at most 10 seconds for completion */
-    
+    LOGI("Unloading WiFi Modules\n");
+    sleep(1);
+
     if (rmmod(DRIVER_MODULE_NAME) == 0) {
-       while (count-- > 0) {
-           if (!check_driver_loaded())
-               break;
-           usleep(500000);
-       }
-       if (count) {
-           return 0;
-       }
-       return -1;
-    } else
+        usleep(1000000);
+    } else {
+        LOGE("Unloading Ralink RT73USB WLAN Module Failed\n");
+        return -1;
+    }
+
+    if (rmmod(RT2X00_LIB_USB_DRIVER_MODULE_NAME) == 0) {
+        usleep(1000000);
+    } else {
+        LOGE("Unloading RT2X00_LIB_USB Module Failed\n");
         return -1;
+    }
+
+    if (rmmod(RT2X00_LIB_DRIVER_MODULE_NAME) == 0) {
+        usleep(1000000);
+    } else {
+        LOGE("Unloading RT2X00_LIB Module Failed\n");
+        return -1;
+    }
+
+    return 0;
 }

 int ensure_config_file_exists()
@@ -200,6 +239,7 @@
     int srcfd, destfd;
     int nread;

+    LOGE("%s\n", __FUNCTION__);
     if (access(SUPP_CONFIG_FILE, R_OK|W_OK) == 0) {
         return 0;
     } else if (errno != ENOENT) {
@@ -252,6 +292,7 @@
     unsigned serial = 0;
 #endif

+    LOGI("start %s",__FUNCTION__);
     /* Check whether already running */
     if (property_get(SUPP_PROP_NAME, supp_status, NULL)
             && strcmp(supp_status, "running") == 0) {
@@ -260,7 +301,7 @@

     /* Before starting the daemon, make sure its config file exists */
     if (ensure_config_file_exists() < 0) {
-        LOGE("Wi-Fi will not be enabled");
+        LOGE("Configuration file does not exis. Wi-Fi will not be enabled");
         return -1;
     } 

@@ -291,9 +332,11 @@
         if (pi != NULL) {
             __system_property_read(pi, NULL, supp_status);
             if (strcmp(supp_status, "running") == 0) {
+                LOGI("Wi-Fi is running\n");
                 return 0;
             } else if (pi->serial != serial &&
                     strcmp(supp_status, "stopped") == 0) {
+                LOGI("Wi-Fi has been stopped");
                 return -1;
             }
         }
@@ -313,6 +356,7 @@
     char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
     int count = 50; /* wait at most 5 seconds for completion */

+    LOGI("%s called",__func__);
     /* Check whether supplicant already stopped */
     if (property_get(SUPP_PROP_NAME, supp_status, NULL)
         && strcmp(supp_status, "stopped") == 0) {
@@ -337,6 +381,7 @@
     char ifname[256];
     char supp_status[PROPERTY_VALUE_MAX] = {'\0'};

+    LOGI("%s called",__func__);
     /* Make sure supplicant is running */
     if (!property_get(SUPP_PROP_NAME, supp_status, NULL)
             || strcmp(supp_status, "running") != 0) {
@@ -344,7 +389,7 @@
         return -1;
     }

-    property_get("wifi.interface", iface, "sta");
+    property_get("wifi.interface", iface, "wlan0");

     if (access(IFACE_DIR, F_OK) == 0) {
         snprintf(ifname, sizeof(ifname), "%s/%s", IFACE_DIR, iface);
@@ -352,6 +397,8 @@
         strlcpy(ifname, iface, sizeof(ifname));
     }

+    LOGI("Interface directory = %s", IFACE_DIR);
+    LOGI("Interface name = %s", ifname);
     ctrl_conn = wpa_ctrl_open(ifname);
     if (ctrl_conn == NULL) {
         LOGE("Unable to open connection to supplicant on \"%s\": %s",
@@ -370,6 +417,7 @@
         ctrl_conn = monitor_conn = NULL;
         return -1;
     }
+    LOGI("Connect to Supplicant done\n");
     return 0;
 }

@@ -377,20 +425,26 @@
 {
     int ret;

+    LOGI("%s, cmd = %s\n", __FUNCTION__, cmd);
     if (ctrl_conn == NULL) {
         LOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd);
         return -1;
     }
+
+    memset(reply, 0, *reply_len);
     ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), reply, reply_len, NULL);
     if (ret == -2) {
         LOGD("'%s' command timed out.\n", cmd);
         return -2;
     } else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {
+        LOGI("reply:%s\n",reply);
         return -1;
     }
     if (strncmp(cmd, "PING", 4) == 0) {
         reply[*reply_len] = '\0';
     }
+
+    LOGI("returning reply %s for cmd %s\n", reply, cmd);
     return 0;
 }

@@ -402,10 +456,13 @@
     int result;
    struct timeval tval;
    struct timeval *tptr;
-    
+
+    LOGI("%s called",__func__);
+    LOGI("monitor_conn checking \n");
     if (monitor_conn == NULL)
         return 0;

+    LOGI("calling wpa_ctrl_recv\n");
     result = wpa_ctrl_recv(monitor_conn, buf, &nread);
     if (result < 0) {
         LOGD("wpa_ctrl_recv failed: %s\n", strerror(errno));
@@ -413,6 +470,7 @@
     }
     buf[nread] = '\0';
     /* LOGD("wait_for_event: result=%d nread=%d string=\"%s\"\n", result, nread, buf); */
+    LOGI("wait_for_event: result=%d nread=%d string=\"%s\"\n", result, nread, buf);
     /* Check for EOF on the socket */
     if (result == 0 && nread == 0) {
         /* Fabricate an event to pass up */
@@ -437,11 +495,13 @@
             memmove(buf, match+1, nread+1);
         }
     }
+    LOGI("returning nread\n");
     return nread;
 }

 void wifi_close_supplicant_connection()
 {
+    LOGI("%s called",__func__);
     if (ctrl_conn != NULL) {
         wpa_ctrl_close(ctrl_conn);
         ctrl_conn = NULL;
@@ -454,5 +514,6 @@

 int wifi_command(const char *command, char *reply, size_t *reply_len)
 {
+    LOGI("%s called, cmd:%s",__func__,command);
     return wifi_send_command(ctrl_conn, command, reply, reply_len);
 }

この他、android-1.5r3 のソースコード内で tiwlan0 になっている箇所
(android-1.5r3/external/dhcpcd/android.conf、
frameworks/base/services/java/com/android/server/WifiWatchdogService.java、
android-1.5r3/frameworks/base/wifi/java/android/net/wifi/WifiStateTracker.java)
を wlan0 に修正します。
修正完了後ビルドを行います。

android userland の調整

android の GUI から wifi の on/off ができるよう、rt73usb の kernel module と rt73.bin を
以下のように android の userland 内に配置します。

/system/lib/modules/rt2x00lib.ko
/system/lib/modules/rt2x00usb.ko
/system/lib/modules/rt73usb.ko
/system/etc/firmware/rt73.bin

wifi interface 名を設定するため、/system/build.prop に以下を追加します。

# WiFi settings
wifi.interface = wlan0

GUI から insmod した時、自動で wlan0 が up し dhcp によるアドレス取得ができるよう、init.rc に以下の項目を加えます。

   setprop wifi.interface wlan0
   setprop wlan.driver.status ok

   service ifcfg_ralink /system/bin/ifconfig wlan0 up
   #   disabled
   #   oneshot

   service wpa_supplicant /system/bin/logwrapper /system/bin/wpa_supplicant -Dwext -iwlan0 -c /system/etc/wifi/wpa_supplicant.conf -dd
       disabled
       group system

   service dhcpcd /system/bin/logwrapper /system/bin/dhcpcd -d wlan0
       disabled
       oneshot
       #group system dhcp

   on property:init.svc.wpa_supplicant=stopped
       stop dhcpcd


上記の手順で作成した android userland で GUI から wifi の設定を行うと、
ワイヤレス設定→WiFi Wi-Fi→WiFi で 無線LANの On/Off が変更でき、Off から On にした場合には優先接続先に接続、
接続できない場合には周辺のアクセスポイントをスキャンしてWi-Fiネットワーク(Wi-Fi networks)に
アクセスポイントのリストを表示します。

参考URL


添付ファイル: fileRT71W_Firmware_V1.8.zip 1454件 [詳細]

BC::labsへの質問は、bc9-dev @ googlegroups.com までお願い致します。
トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   最終更新のRSS
Last-modified: 2010-08-12 (木) 15:50:33 (5000d)