* android wifi [#a2541a6c] -bc9 用 android で wifi を使えるようにする手順です。~ ~ android-1.5r3 branch を使用して動作確認を行いました。~ 使用した USB wifi は [[I-O data WN-G54/USB>http://www.iodata.jp/product/network/adp/wn-g54usb/]] です。~ ~ 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 を参照してください。)~ *手順 [#jdfd407d] 以下の手順は、[[bc9/bc9-oe-sdk setup:http://labs.beatcraft.com/ja/index.php?bc9%2Fbc9-oe-sdk%20setup#t72a21c2]] や [[bc9/bc9-android-sdk setup:http://labs.beatcraft.com/ja/index.php?bc9%2Fbc9-android-sdk%20setup#m93cc150]] に従って~ kernel の rebuild、android userland の build を行っています。~ ** 無線LAN driverを有効にした Kernel の作成 [#o51f866d] -今回は 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>http://www.ralinktech.com/ralink/Home/Support/Linux.html]] の[[こちら>http://www.ralinktech.com.tw/data/RT71W_Firmware_V1.8.zip]]。%%)~ Ralink の driver および firmware 配布ページはファイルの URL が変更になり、~ ダウンロードに名前とメールアドレスの入力が必要になりました。~ 入手の手間を省きこのページから直接ダウンロードできるよう、ファイルをページに添付します。~ &ref(RT71W_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_suppicant を含む android build [#rb42472d] ** wpa_supplicant を含む android build [#rb42472d] wpa_supplicant 有効にして android を build し、コマンドラインで 無線接続を確認します。~ ***wpa_supplicant の build [#s53479b6] 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 の修正 [#me9dc16e] 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 の調整 [#le999e9b] 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 [#r3682f94] -[[google groupe android-porting 内の thread>http://groups.google.co.jp/group/android-porting/browse_thread/thread/126310f20d406bd7/]] -[[Android x86 で mini9 の無線LAN が動いた>http://whitesc3.blog7.fc2.com/blog-entry-108.html]] -[[GUI で無線LAN 接続できた>http://whitesc3.blog7.fc2.com/blog-entry-111.html]]