├── assets
├── fork
├── olsrd
├── wifi
├── busybox
├── olsrd_mini.so.0.1
├── olsrd_tas.so.0.1
├── olsrd_bmf.so.1.7.0
├── olsrd_pgraph.so.1.1
├── olsrd_secure.so.0.6
├── olsrd_txtinfo.so.0.1
├── olsrd_dot_draw.so.0.3
├── olsrd_httpinfo.so.0.1
├── olsrd_jsoninfo.so.0.0
├── olsrd_watchdog.so.0.1
├── olsrd_arprefresh.so.0.1
├── olsrd_dyn_gw_plain.so.0.4
├── olsrd_nameservice.so.0.3
├── su_c
├── stop_olsrd
├── do_stop_olsrd
├── del-fake-default-route
├── do_del-fake-default-route
├── script_aria
├── script_samsung
├── su_c_fork
├── script_hero
├── run
└── olsrd.conf
├── libs
├── Shell.jar
├── jackson-core-asl-1.9.7.jar
└── jackson-mapper-asl-1.9.7.jar
├── src
└── net
│ └── commotionwireless
│ ├── olsrinfo
│ └── meshtether
│ ├── ToggleReceiver.java
│ ├── MACPreference.java
│ ├── IPPreference.java
│ ├── MeshIPPreference.java
│ ├── SettingsActivity.java
│ ├── Util.java
│ ├── NativeHelper.java
│ ├── LinksActivity.java
│ ├── InfoActivity.java
│ ├── MeshTetherApp.java
│ ├── StatusActivity.java
│ └── MeshService.java
├── res
├── drawable-hdpi
│ ├── upload.png
│ ├── download.png
│ ├── other_route.png
│ ├── barnacle_error.png
│ ├── comlogo_sm_off.png
│ ├── comlogo_sm_on.png
│ ├── default_route.png
│ ├── ic_tab_selected_recent.png
│ ├── ic_tab_selected_starred.png
│ ├── ic_tab_unselected_recent.png
│ ├── ic_tab_unselected_starred.png
│ ├── ic_tab_selected_friends_list.png
│ └── ic_tab_unselected_friends_list.png
├── drawable-ldpi
│ ├── upload.png
│ ├── download.png
│ ├── other_route.png
│ ├── comlogo_sm_off.png
│ ├── comlogo_sm_on.png
│ └── default_route.png
├── drawable-mdpi
│ ├── upload.png
│ ├── download.png
│ ├── other_route.png
│ ├── comlogo_sm_off.png
│ ├── comlogo_sm_on.png
│ ├── default_route.png
│ ├── ic_tab_selected_recent.png
│ ├── ic_tab_selected_starred.png
│ ├── ic_tab_unselected_recent.png
│ ├── ic_tab_unselected_starred.png
│ ├── ic_tab_selected_friends_list.png
│ └── ic_tab_unselected_friends_list.png
├── drawable-xhdpi
│ ├── download.png
│ ├── upload.png
│ ├── comlogo_sm_on.png
│ └── comlogo_sm_off.png
├── drawable
│ ├── row_background.xml
│ ├── ic_tab_recent.xml
│ ├── ic_tab_starred.xml
│ └── ic_tab_contacts.xml
├── layout
│ ├── traffic.xml
│ ├── main.xml
│ ├── inforow.xml
│ ├── tabhost.xml
│ ├── control.xml
│ └── linkrow.xml
├── menu
│ └── main.xml
├── layout-land
│ ├── main.xml
│ └── control.xml
├── xml
│ └── preferences.xml
└── values
│ └── strings.xml
├── jni
└── Application.mk
├── native
├── Android.mk
├── wifi
│ ├── hardware_legacy_stub.c
│ ├── Android.mk
│ ├── hardware_legacy_stub.h
│ ├── main.cc
│ ├── wifi.hh
│ ├── init.hh
│ └── iwctl.hh
└── include
│ ├── log.hh
│ ├── properties.hh
│ ├── config.hh
│ └── ifctl.hh
├── .gitignore
├── .gitmodules
├── .settings
└── org.eclipse.cdt.core.prefs
├── project.properties
├── .classpath
├── .project
├── README.md
├── AndroidManifest.xml
└── external
└── Makefile
/assets/fork:
--------------------------------------------------------------------------------
1 | ../external/shell-fork/fork
--------------------------------------------------------------------------------
/assets/olsrd:
--------------------------------------------------------------------------------
1 | ../external/olsrd/olsrd
--------------------------------------------------------------------------------
/assets/wifi:
--------------------------------------------------------------------------------
1 | ../native/libs/armeabi/wifi
--------------------------------------------------------------------------------
/assets/busybox:
--------------------------------------------------------------------------------
1 | ../external/busybox/busybox
--------------------------------------------------------------------------------
/libs/Shell.jar:
--------------------------------------------------------------------------------
1 | ../external/shell-fork/Shell.jar
--------------------------------------------------------------------------------
/assets/olsrd_mini.so.0.1:
--------------------------------------------------------------------------------
1 | ../external/olsrd/lib/mini/olsrd_mini.so.0.1
--------------------------------------------------------------------------------
/assets/olsrd_tas.so.0.1:
--------------------------------------------------------------------------------
1 | ../external/olsrd/lib/tas/olsrd_tas.so.0.1
--------------------------------------------------------------------------------
/assets/olsrd_bmf.so.1.7.0:
--------------------------------------------------------------------------------
1 | ../external/olsrd/lib/bmf/olsrd_bmf.so.1.7.0
--------------------------------------------------------------------------------
/assets/olsrd_pgraph.so.1.1:
--------------------------------------------------------------------------------
1 | ../external/olsrd/lib/pgraph/olsrd_pgraph.so.1.1
--------------------------------------------------------------------------------
/assets/olsrd_secure.so.0.6:
--------------------------------------------------------------------------------
1 | ../external/olsrd/lib/secure/olsrd_secure.so.0.6
--------------------------------------------------------------------------------
/assets/olsrd_txtinfo.so.0.1:
--------------------------------------------------------------------------------
1 | ../external/olsrd/lib/txtinfo/olsrd_txtinfo.so.0.1
--------------------------------------------------------------------------------
/assets/olsrd_dot_draw.so.0.3:
--------------------------------------------------------------------------------
1 | ../external/olsrd/lib/dot_draw/olsrd_dot_draw.so.0.3
--------------------------------------------------------------------------------
/assets/olsrd_httpinfo.so.0.1:
--------------------------------------------------------------------------------
1 | ../external/olsrd/lib/httpinfo/olsrd_httpinfo.so.0.1
--------------------------------------------------------------------------------
/assets/olsrd_jsoninfo.so.0.0:
--------------------------------------------------------------------------------
1 | ../external/olsrd/lib/jsoninfo/olsrd_jsoninfo.so.0.0
--------------------------------------------------------------------------------
/assets/olsrd_watchdog.so.0.1:
--------------------------------------------------------------------------------
1 | ../external/olsrd/lib/watchdog/olsrd_watchdog.so.0.1
--------------------------------------------------------------------------------
/assets/olsrd_arprefresh.so.0.1:
--------------------------------------------------------------------------------
1 | ../external/olsrd/lib/arprefresh/olsrd_arprefresh.so.0.1
--------------------------------------------------------------------------------
/assets/olsrd_dyn_gw_plain.so.0.4:
--------------------------------------------------------------------------------
1 | ../external/olsrd/lib/dyn_gw_plain/olsrd_dyn_gw_plain.so.0.4
--------------------------------------------------------------------------------
/assets/olsrd_nameservice.so.0.3:
--------------------------------------------------------------------------------
1 | ../external/olsrd/lib/nameservice/olsrd_nameservice.so.0.3
--------------------------------------------------------------------------------
/src/net/commotionwireless/olsrinfo:
--------------------------------------------------------------------------------
1 | ../../../external/olsrinfo/src/net/commotionwireless/olsrinfo/
--------------------------------------------------------------------------------
/res/drawable-hdpi/upload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-hdpi/upload.png
--------------------------------------------------------------------------------
/res/drawable-ldpi/upload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-ldpi/upload.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/upload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-mdpi/upload.png
--------------------------------------------------------------------------------
/libs/jackson-core-asl-1.9.7.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/libs/jackson-core-asl-1.9.7.jar
--------------------------------------------------------------------------------
/res/drawable-hdpi/download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-hdpi/download.png
--------------------------------------------------------------------------------
/res/drawable-ldpi/download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-ldpi/download.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-mdpi/download.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-xhdpi/download.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/upload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-xhdpi/upload.png
--------------------------------------------------------------------------------
/libs/jackson-mapper-asl-1.9.7.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/libs/jackson-mapper-asl-1.9.7.jar
--------------------------------------------------------------------------------
/res/drawable-hdpi/other_route.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-hdpi/other_route.png
--------------------------------------------------------------------------------
/res/drawable-ldpi/other_route.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-ldpi/other_route.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/other_route.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-mdpi/other_route.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/barnacle_error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-hdpi/barnacle_error.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/comlogo_sm_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-hdpi/comlogo_sm_off.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/comlogo_sm_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-hdpi/comlogo_sm_on.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/default_route.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-hdpi/default_route.png
--------------------------------------------------------------------------------
/res/drawable-ldpi/comlogo_sm_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-ldpi/comlogo_sm_off.png
--------------------------------------------------------------------------------
/res/drawable-ldpi/comlogo_sm_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-ldpi/comlogo_sm_on.png
--------------------------------------------------------------------------------
/res/drawable-ldpi/default_route.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-ldpi/default_route.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/comlogo_sm_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-mdpi/comlogo_sm_off.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/comlogo_sm_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-mdpi/comlogo_sm_on.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/default_route.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-mdpi/default_route.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/comlogo_sm_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-xhdpi/comlogo_sm_on.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/comlogo_sm_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-xhdpi/comlogo_sm_off.png
--------------------------------------------------------------------------------
/jni/Application.mk:
--------------------------------------------------------------------------------
1 | APP_PROJECT_PATH := $(call my-dir)/../native
2 | APP_BUILD_SCRIPT := $(APP_PROJECT_PATH)/Android.mk
3 | APP_MODULES := wifi
4 |
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_tab_selected_recent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-hdpi/ic_tab_selected_recent.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_tab_selected_starred.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-hdpi/ic_tab_selected_starred.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_tab_unselected_recent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-hdpi/ic_tab_unselected_recent.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_tab_selected_recent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-mdpi/ic_tab_selected_recent.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_tab_selected_starred.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-mdpi/ic_tab_selected_starred.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_tab_unselected_recent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-mdpi/ic_tab_unselected_recent.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_tab_unselected_starred.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-hdpi/ic_tab_unselected_starred.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_tab_unselected_starred.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-mdpi/ic_tab_unselected_starred.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_tab_selected_friends_list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-hdpi/ic_tab_selected_friends_list.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_tab_selected_friends_list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-mdpi/ic_tab_selected_friends_list.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_tab_unselected_friends_list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-hdpi/ic_tab_unselected_friends_list.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_tab_unselected_friends_list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/opentechinstitute/commotion-android/HEAD/res/drawable-mdpi/ic_tab_unselected_friends_list.png
--------------------------------------------------------------------------------
/assets/su_c:
--------------------------------------------------------------------------------
1 | #!/system/bin/sh
2 | #
3 | # calling 'su -c' from Java doesn't work so we use a helper script
4 |
5 | # exec su -c ${1:-${brncl_path}/run}
6 | exec ${1:-${brncl_path}/run}
7 |
--------------------------------------------------------------------------------
/assets/stop_olsrd:
--------------------------------------------------------------------------------
1 | #!/system/bin/sh
2 | # main runner (process manager) for barnacle, root required
3 |
4 | : ${brncl_path:=.}
5 |
6 | export brncl_path
7 |
8 | su -c ${brncl_path}/do_stop_olsrd
9 |
--------------------------------------------------------------------------------
/native/Android.mk:
--------------------------------------------------------------------------------
1 |
2 | include $(all-subdir-makefiles)
3 |
4 | # redirect stdout to stderr otherwise make eats it
5 | # TODO this also runs when 'ndk-build clean' is called...
6 | #MAKE_EXTERNAL_LOG := $(shell make -C external 1>&2)
7 |
--------------------------------------------------------------------------------
/assets/do_stop_olsrd:
--------------------------------------------------------------------------------
1 | #!/system/bin/sh
2 | # main runner (process manager) for barnacle, root required
3 |
4 | : ${brncl_path:=.}
5 |
6 | export brncl_path
7 |
8 | kill -15 `cat $brncl_path/../app_log/olsrd.pid`
9 |
10 | $brncl_path/killall olsrd
11 |
--------------------------------------------------------------------------------
/assets/del-fake-default-route:
--------------------------------------------------------------------------------
1 | #!/system/bin/sh
2 | #
3 | # horrible hack to work around the hack of telling Android that our gateway is our own IP
4 | # calling 'su -c' from Java doesn't work so we use a helper script
5 |
6 | exec "${brncl_path}/do_del-fake-default-route"
7 |
--------------------------------------------------------------------------------
/assets/do_del-fake-default-route:
--------------------------------------------------------------------------------
1 | #!/system/bin/sh
2 | #
3 | # horrible hack to work around the hack of telling Android that our gateway is our own IP
4 |
5 | : ${brncl_if_lan:="`getprop wifi.interface`"}
6 |
7 | sleep 15
8 | ${brncl_path}/ip route del default via ${brncl_adhoc_ip} dev $brncl_if_lan
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bin/
2 | gen/
3 | obj/
4 | native/TAGS
5 | native/libs/armeabi/libhardware_legacy.so
6 | native/libs/armeabi/wifi
7 | external/olsrd-build-stamp
8 | external/fork-timestamp
9 | external/shell-jar-timestamp
10 | # ant files generated by 'android update'
11 | build.xml
12 | local.properties
13 | proguard-project.txt
14 |
--------------------------------------------------------------------------------
/assets/script_aria:
--------------------------------------------------------------------------------
1 | #!/system/bin/sh
2 |
3 | set -e
4 |
5 | MODULE=/system/lib/modules/bcm4329.ko
6 | FIRMWARE=/sdcard/fw_bcm4329.bin
7 |
8 | load() {
9 | ls > /dev/null 2>&1 $FIRMWARE || ( echo >&2 "aria: $FIRMWARE not found!" ; exit )
10 | insmod $MODULE firmware_path=$FIRMWARE
11 | }
12 |
13 | unload() {
14 | rmmod $MODULE
15 | }
16 |
17 | $1
18 |
--------------------------------------------------------------------------------
/assets/script_samsung:
--------------------------------------------------------------------------------
1 | #!/system/bin/sh
2 | # NOT TESTED!
3 |
4 | set -e
5 |
6 | MODULE=/lib/modules/dhd.ko
7 | FIRMWARE=/etc/rtecdc.bin
8 |
9 | load() {
10 | ls > /dev/null 2>&1 $FIRMWARE || ( echo 2>&1 "samsung: $FIRMWARE not found!" ; exit )
11 | insmod $MODULE firmware_path=$FIRMWARE nvram_path=/etc/nvram.txt
12 | }
13 |
14 | unload() {
15 | rmmod $MODULE
16 | }
17 |
18 | $1
19 |
20 |
21 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "external/olsrd"]
2 | path = external/olsrd
3 | url = http://olsr.org/git/olsrd.git
4 | [submodule "external/olsrinfo"]
5 | path = external/olsrinfo
6 | url = https://github.com/guardianproject/OlsrInfo.git
7 | [submodule "external/busybox"]
8 | path = external/busybox
9 | url = git://busybox.net/busybox.git
10 | [submodule "external/shell-fork"]
11 | path = external/shell-fork
12 | url = https://github.com/opentechinstitute/shell-fork
13 |
--------------------------------------------------------------------------------
/native/wifi/hardware_legacy_stub.c:
--------------------------------------------------------------------------------
1 | #include "hardware_legacy_stub.h"
2 | int wifi_load_driver() { return -1; }
3 | int wifi_unload_driver() { return -1; }
4 | int wifi_start_supplicant() { return -1; }
5 | int wifi_stop_supplicant() { return -1; }
6 | int wifi_connect_to_supplicant() { return -1; }
7 | void wifi_close_supplicant_connection() { }
8 | int wifi_wait_for_event(char *buf, size_t len) { return -1; }
9 | int wifi_command(const char *command, char *reply, size_t *reply_len) { return -1; }
10 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.cdt.core.prefs:
--------------------------------------------------------------------------------
1 | #Thu May 31 17:19:38 EDT 2012
2 | eclipse.preferences.version=1
3 | environment/project/com.android.toolchain.gcc.779378330/NDK_BASE/delimiter=\:
4 | environment/project/com.android.toolchain.gcc.779378330/NDK_BASE/operation=append
5 | environment/project/com.android.toolchain.gcc.779378330/NDK_BASE/value=/usr/local/android-ndk
6 | environment/project/com.android.toolchain.gcc.779378330/append=true
7 | environment/project/com.android.toolchain.gcc.779378330/appendContributed=true
8 |
--------------------------------------------------------------------------------
/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system use,
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 |
10 | # Indicates whether an apk should be generated for each density.
11 | split.density=false
12 | # Project target.
13 | target=android-8
14 |
--------------------------------------------------------------------------------
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/assets/su_c_fork:
--------------------------------------------------------------------------------
1 | #!/system/bin/sh
2 | #
3 | # calling 'su -c' from Java doesn't work so we use a helper script
4 |
5 | # set defaults
6 | : ${brncl_adhoc_ip:="172.29.5.1"}
7 | : ${brncl_adhoc_netmask:="255.255.0.0"}
8 | : ${brncl_if_lan:="`getprop wifi.interface`"}
9 | : ${brncl_path:=.}
10 | : ${olsrd_conf_path:=olsrd.conf}
11 |
12 | # for init.rc parsing
13 | : ${brncl_hardware:="`getprop ro.hardware`"}
14 |
15 | export brncl_adhoc_ip
16 | export brncl_adhoc_netmask
17 | export brncl_if_lan
18 | export brncl_path
19 | export olsrd_conf_path
20 | export brncl_hardware
21 |
22 | exec su -c "${1:-${brncl_path}/fork}"
23 |
--------------------------------------------------------------------------------
/native/wifi/Android.mk:
--------------------------------------------------------------------------------
1 |
2 | LOCAL_PATH := $(call my-dir)
3 |
4 | # libhardware_legacy stub
5 | include $(CLEAR_VARS)
6 |
7 | LOCAL_MODULE := libhardware_legacy
8 | LOCAL_SRC_FILES := hardware_legacy_stub.c
9 |
10 | include $(BUILD_SHARED_LIBRARY)
11 |
12 | # the main binary
13 |
14 | include $(CLEAR_VARS)
15 |
16 | LOCAL_MODULE := wifi
17 |
18 | LOCAL_SRC_FILES := main.cc
19 | LOCAL_CPP_EXTENSION := .cc
20 | LOCAL_CFLAGS := -Wall -Wextra -Werror -Wno-delete-non-virtual-dtor -O3
21 | LOCAL_C_INCLUDES := $(LOCAL_PATH)/../include
22 |
23 | LOCAL_SHARED_LIBRARIES := libhardware_legacy
24 | LOCAL_LDLIBS := -llog
25 |
26 | include $(BUILD_EXECUTABLE)
27 |
--------------------------------------------------------------------------------
/assets/script_hero:
--------------------------------------------------------------------------------
1 | #!/system/bin/sh
2 | set -e
3 |
4 | CHANNEL=${brncl_lan_channel:-1}
5 | SSID="$brncl_lan_essid"
6 | INIFILE=adhoc.ini
7 | MODULE=/system/lib/modules/wlan.ko
8 |
9 | load() {
10 | cat > $INIFILE <> $INIFILE
18 |
19 | echo "hero: Loading wifi driver..."
20 | insmod $MODULE
21 |
22 | echo "hero: Initializing driver..."
23 | wlan_loader -f /system/etc/wifi/Fw1251r1c.bin -e /proc/calibration -i $INIFILE
24 | }
25 |
26 | unload() {
27 | rmmod $MODULE
28 | }
29 |
30 | $1
31 |
--------------------------------------------------------------------------------
/native/wifi/hardware_legacy_stub.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This just provides stubs to build against. The actual functions
3 | * are provided by a vendor supplied library for interfacing with the
4 | * wifi hardware. This build system does build a
5 | * libhardware_legacy.so, but this is only for linking against, it is
6 | * not deployed at all, since we expect every Android device to
7 | * already have libhardware_legacy.so installed.
8 | */
9 |
10 | #include
11 | int wifi_load_driver();
12 | int wifi_unload_driver();
13 | int wifi_start_supplicant();
14 | int wifi_stop_supplicant();
15 | int wifi_connect_to_supplicant();
16 | void wifi_close_supplicant_connection();
17 | int wifi_wait_for_event(char *buf, size_t len);
18 | int wifi_command(const char *command, char *reply, size_t *reply_len);
19 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | CommotionMeshTether
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/assets/run:
--------------------------------------------------------------------------------
1 | #!/system/bin/sh
2 | # main runner (process manager) for barnacle, root required
3 |
4 | # log environment for debugging
5 | set > $brncl_path/../app_log/environment.log 2>&1
6 |
7 | # zero out debug log so it doesn't get huge
8 | echo "" > $brncl_path/../app_log/olsrd.log 2>&1
9 |
10 |
11 | cd $brncl_path
12 |
13 | # load the driver
14 | # NOTE: Android's shell is ash and there is no "test" or "["
15 | : ${brncl_lan_script:=wifi}
16 |
17 | ./$brncl_lan_script load
18 |
19 | # necessary hack for HTC phones
20 | type ip >/dev/null 2>&1 && ip route del table gprs default >/dev/null 2>&1
21 |
22 | # ifconfig $brncl_if_lan $brncl_adhoc_ip netmask $brncl_adhoc_netmask up
23 | ./wifi config
24 |
25 | # Xperia X10 running Gingerbread needs extra time for wifi config to finish
26 | sleep 1
27 |
28 | # run olsrd
29 | (./olsrd -f "${olsrd_conf_path}" -i $brncl_if_lan > $brncl_path/../app_log/olsrd.log 2>&1) &
30 | echo `ps | ./grep '[o]lsrd' | ./awk '{print $2;}'` > $brncl_path/../app_log/olsrd.pid
31 |
32 | # the association loop
33 | ./wifi assoc
34 |
35 | # cleanup
36 | ./wifi unload
37 |
--------------------------------------------------------------------------------
/res/drawable/row_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
21 |
26 |
27 |
--------------------------------------------------------------------------------
/res/drawable/ic_tab_recent.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/res/drawable/ic_tab_starred.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/res/drawable/ic_tab_contacts.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/res/layout/traffic.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
20 |
21 |
32 |
33 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/hawkinswnaf)
2 | Commotion Mesh Tether
3 | ====================
4 |
5 | Commotion Mesh Tether is a combination of tools to provide OLSR mesh networking
6 | over wifi on an Android phone. It handles setting up the wifi into ad-hoc
7 | mode, setting up the IP address, and running the olsrd program.
8 |
9 | It was originally based on the Barnacle Wifi Tether app.
10 |
11 | https://code.commotionwireless.net/projects/commotion-android/
12 |
13 | How to build
14 | ------------
15 |
16 | Prerequisites:
17 | 1) Android NDK r4 or above
18 | 2) Eclipse and ADT plugin
19 | 3) sudo apt-get install bison flex make sed junit4
20 |
21 | To build native components, run these commands in the root directory of this
22 | project (i.e. /path/to/commotion-android):
23 |
24 | git submodule init
25 | git submodule update
26 | make -C external/
27 | ndk-build
28 |
29 | To build the Android app, import the existing project into Eclipse and export
30 | an .apk file. If you ran the NDK build after already having the project in
31 | Eclipse, you'll need to refresh the project for Eclipse to see the new files.
32 | To do that, right-click on the project, and select "Refresh".
33 |
--------------------------------------------------------------------------------
/assets/olsrd.conf:
--------------------------------------------------------------------------------
1 |
2 | DebugLevel 0
3 | ClearScreen no
4 | IpVersion 4
5 | AllowNoInt yes
6 |
7 | # the mesh interface is specified at run time by the Java app using the -i flag
8 | InterfaceDefaults
9 | {
10 | Ip4Broadcast 255.255.255.255
11 | HelloInterval 6.0
12 | HelloValidityTime 600.0
13 | TcInterval 0.5
14 | TcValidityTime 300.0
15 | MidInterval 10.0
16 | MidValidityTime 300.0
17 | HnaInterval 10.0
18 | HnaValidityTime 300.0
19 | }
20 |
21 | UseHysteresis no
22 | LinkQualityFishEye 0
23 | LinkQualityAlgorithm "etx_ffeth"
24 | LinkQualityLevel 2
25 | Pollrate 0.1
26 |
27 | TcRedundancy 2
28 | MprCoverage 5
29 |
30 | Willingness 3
31 |
32 |
33 | IpcConnect
34 | {
35 | MaxConnections 0
36 | }
37 |
38 | LoadPlugin "/data/data/net.commotionwireless.meshtether/app_bin/olsrd_jsoninfo.so.0.0"
39 | {
40 | PlParam "port" "9090"
41 | PlParam "accept" "0.0.0.0"
42 | }
43 |
44 | #LoadPlugin "/data/data/net.commotionwireless.meshtether/app_bin/olsrd_httpinfo.so.0.1"
45 | #{
46 | # PlParam "Port" "8080"
47 | # PlParam "Net" "0.0.0.0 0.0.0.0"
48 | #}
49 |
50 | #LoadPlugin "/data/data/net.commotionwireless.meshtether/app_bin/olsrd_txtinfo.so.0.1"
51 | #{
52 | # PlParam "port" "2006"
53 | # PlParam "accept" "0.0.0.0"
54 | #}
55 |
56 |
--------------------------------------------------------------------------------
/src/net/commotionwireless/meshtether/ToggleReceiver.java:
--------------------------------------------------------------------------------
1 | package net.commotionwireless.meshtether;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.util.Log;
7 |
8 | public class ToggleReceiver extends BroadcastReceiver {
9 | final static String TAG = "ToggleReceiver";
10 | @Override
11 | public void onReceive(Context context, Intent intent) {
12 | Log.d(TAG, "onReceive " + intent.getAction());
13 | if (MeshTetherApp.ACTION_TOGGLE.equals(intent.getAction())) {
14 | // potential race conditions, but they are benign
15 | MeshService service = MeshService.singleton;
16 | //Log.d(TAG, "service " + ((service == null) ? "null" : "present"));
17 | if (service != null) {
18 | if (!intent.getBooleanExtra("start", false)) {
19 | Log.d(TAG, "stop");
20 | service.stopRequest();
21 | }
22 | } else {
23 | if (intent.getBooleanExtra("start", true)) {
24 | Log.d(TAG, "start");
25 | context.startService(new Intent(context, MeshService.class));
26 | }
27 | }
28 | } else if (MeshTetherApp.ACTION_CHECK.equals(intent.getAction())) {
29 | // FIXME: this is the most inefficient way of finding out the state
30 | MeshService service = MeshService.singleton;
31 | int state = (service != null) ? service.getState() : MeshService.STATE_STOPPED;
32 | MeshTetherApp.broadcastState(context, state);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/native/include/log.hh:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Barnacle Wifi Tether
3 | * Copyright (C) 2010 by Szymon Jakubczak
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #ifndef INCLUDED_LOG_HH
20 | #define INCLUDED_LOG_HH
21 |
22 | #include
23 | #include
24 |
25 | #ifndef TAG
26 | #define TAG
27 | #endif
28 |
29 | #define ERR(...) { fprintf(stderr, TAG __VA_ARGS__); fflush(stderr); }
30 | #define LOG(...) { flock(1, LOCK_EX); fprintf(stdout, TAG __VA_ARGS__); fflush(stdout); flock(1, LOCK_UN); }
31 |
32 | #ifdef __ANDROID__
33 | extern "C" {
34 | #include
35 | }
36 |
37 | #define LOG_LEVEL ANDROID_LOG_DEBUG
38 | #define DBG(...) __android_log_print(LOG_LEVEL, "barnacle", TAG __VA_ARGS__)
39 | #else
40 | #define DBG LOG
41 |
42 | #endif
43 |
44 | #endif // INCLUDED_LOG_HH
45 |
--------------------------------------------------------------------------------
/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
--------------------------------------------------------------------------------
/res/layout-land/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
22 |
23 |
29 |
30 |
37 |
38 |
--------------------------------------------------------------------------------
/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
23 |
24 |
29 |
30 |
36 |
37 |
41 |
42 |
--------------------------------------------------------------------------------
/res/layout/inforow.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
24 |
25 |
31 |
32 |
40 |
41 |
--------------------------------------------------------------------------------
/res/layout/tabhost.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
23 |
24 |
28 |
29 |
33 |
34 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/res/layout/control.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
25 |
26 |
34 |
35 |
43 |
44 |
--------------------------------------------------------------------------------
/native/include/properties.hh:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Barnacle Wifi Tether
3 | * Copyright (C) 2010 by Szymon Jakubczak
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | // see system/core/libcutils/properties.c
20 | #include
21 | #include
22 | #include
23 |
24 | #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
25 | #include
26 |
27 | // this is defined in system/core/include/cutils/sockets.h
28 | #define ANDROID_SOCKET_ENV_PREFIX "ANDROID_SOCKET_"
29 | #define ANDROID_SOCKET_DIR "/dev/socket"
30 |
31 | static
32 | bool property_set(const char *key, const char *value) {
33 | prop_msg msg;
34 | msg.cmd = PROP_MSG_SETPROP;
35 | strcpy((char*) msg.name, key);
36 | strcpy((char*) msg.value, value);
37 |
38 | int s = socket(AF_UNIX, SOCK_STREAM, 0);
39 | if (s < 0)
40 | return false;
41 |
42 | sockaddr_un sa;
43 | sa.sun_family = AF_UNIX;
44 | strncpy(sa.sun_path, ANDROID_SOCKET_DIR "/" PROP_SERVICE_NAME, UNIX_PATH_MAX);
45 | if (connect(s, (sockaddr *)&sa, sizeof(sa)))
46 | return false;
47 |
48 | int r;
49 | while((r = send(s, &msg, sizeof(msg), 0)) < 0) {
50 | if((errno == EINTR) || (errno == EAGAIN)) continue;
51 | break;
52 | }
53 | close(s);
54 |
55 | return (r == sizeof(prop_msg));
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/src/net/commotionwireless/meshtether/MACPreference.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Commotion Mesh Tether
3 | * Copyright (C) 2010 by Szymon Jakubczak
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package net.commotionwireless.meshtether;
20 |
21 | import android.content.Context;
22 | import android.preference.EditTextPreference;
23 | import android.text.method.DigitsKeyListener;
24 | import android.util.AttributeSet;
25 | import android.view.View;
26 | import android.widget.EditText;
27 | import android.widget.Toast;
28 |
29 | /**
30 | * EditTextPreference that allows MAC addresses only
31 | */
32 | public class MACPreference extends EditTextPreference {
33 | public MACPreference(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); }
34 | public MACPreference(Context context, AttributeSet attrs) { super(context, attrs); }
35 | public MACPreference(Context context) { super(context); }
36 |
37 | @Override
38 | protected void onAddEditTextToDialogView(View dialogView, EditText editText) {
39 | editText.setKeyListener(DigitsKeyListener.getInstance("0123456789ABCDEFabcdef:-."));
40 | super.onAddEditTextToDialogView(dialogView, editText);
41 | }
42 |
43 | public static boolean validate(String addr) {
44 | return Util.MACAddress.parse(addr) != null;
45 | }
46 |
47 | @Override
48 | protected void onDialogClosed(boolean positiveResult) {
49 | if (positiveResult) {
50 | // verify now that it's an IP
51 | String addr = getEditText().getText().toString();
52 | if (addr.length() != 0 && !validate(addr)) { // note empty address is fine
53 | Toast.makeText(getContext(),
54 | getContext().getString(R.string.invalidmac),
55 | Toast.LENGTH_SHORT).show();
56 | positiveResult = false;
57 | }
58 | }
59 | super.onDialogClosed(positiveResult);
60 | }
61 | }
--------------------------------------------------------------------------------
/src/net/commotionwireless/meshtether/IPPreference.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Commotion Mesh Tether
3 | * Copyright (C) 2010 by Szymon Jakubczak
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package net.commotionwireless.meshtether;
20 |
21 | import android.content.Context;
22 | import android.preference.EditTextPreference;
23 | import android.text.method.DigitsKeyListener;
24 | import android.util.AttributeSet;
25 | import android.view.View;
26 | import android.widget.EditText;
27 | import android.widget.Toast;
28 |
29 | /**
30 | * EditTextPreference that allows IP addresses only
31 | */
32 | public class IPPreference extends EditTextPreference {
33 | public IPPreference(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); }
34 | public IPPreference(Context context, AttributeSet attrs) { super(context, attrs); }
35 | public IPPreference(Context context) { super(context); }
36 |
37 | @Override
38 | protected void onAddEditTextToDialogView(View dialogView, EditText editText) {
39 | editText.setKeyListener(DigitsKeyListener.getInstance("0123456789."));
40 | super.onAddEditTextToDialogView(dialogView, editText);
41 | }
42 |
43 | public static boolean validate(String addr) {
44 | try {
45 | //if(addr.length() == 0) // don't want empty address
46 | // return false;
47 | if(java.net.InetAddress.getByName(addr) == null)
48 | return false;
49 | } catch (java.net.UnknownHostException e) {
50 | return false;
51 | }
52 | return true;
53 | }
54 |
55 | @Override
56 | protected void onDialogClosed(boolean positiveResult) {
57 | if (positiveResult) {
58 | // verify now that it's an IP
59 | String addr = getEditText().getText().toString();
60 | if (!validate(addr)) {
61 | Toast.makeText(getContext(),
62 | getContext().getString(R.string.invalidip),
63 | Toast.LENGTH_SHORT).show();
64 | positiveResult = false;
65 | }
66 | }
67 | super.onDialogClosed(positiveResult);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/res/layout-land/control.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
25 |
26 |
34 |
35 |
42 |
43 |
55 |
56 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/src/net/commotionwireless/meshtether/MeshIPPreference.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Commotion Mesh Tether
3 | * Copyright (C) 2010 by Szymon Jakubczak
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package net.commotionwireless.meshtether;
20 |
21 | import android.content.Context;
22 | import android.preference.EditTextPreference;
23 | import android.text.method.DigitsKeyListener;
24 | import android.util.AttributeSet;
25 | import android.view.View;
26 | import android.widget.EditText;
27 | import android.widget.Toast;
28 |
29 | /**
30 | * EditTextPreference that allows IP addresses only
31 | */
32 | public class MeshIPPreference extends EditTextPreference {
33 | public MeshIPPreference(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); }
34 | public MeshIPPreference(Context context, AttributeSet attrs) { super(context, attrs); }
35 | public MeshIPPreference(Context context) { super(context); }
36 |
37 | @Override
38 | protected void onAddEditTextToDialogView(View dialogView, EditText editText) {
39 | editText.setKeyListener(DigitsKeyListener.getInstance("0123456789."));
40 | super.onAddEditTextToDialogView(dialogView, editText);
41 | }
42 |
43 | public static boolean validate(String addr) {
44 | if (addr.matches("^[0-9]{1,3}$"))
45 | {
46 | int prefix = Integer.valueOf(addr).intValue();
47 | if (prefix > 0 && prefix < 255)
48 | return true;
49 | else
50 | return false;
51 | }
52 | try {
53 | //if(addr.length() == 0) // don't want empty address
54 | // return false;
55 | if(java.net.InetAddress.getByName(addr) == null)
56 | return false;
57 | } catch (java.net.UnknownHostException e) {
58 | return false;
59 | }
60 | return true;
61 | }
62 |
63 | @Override
64 | protected void onDialogClosed(boolean positiveResult) {
65 | if (positiveResult) {
66 | // verify now that it's an IP
67 | String addr = getEditText().getText().toString();
68 | if (!validate(addr)) {
69 | Toast.makeText(getContext(),
70 | getContext().getString(R.string.invalidmeship),
71 | Toast.LENGTH_SHORT).show();
72 | positiveResult = false;
73 | }
74 | }
75 | super.onDialogClosed(positiveResult);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/res/layout/linkrow.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
26 |
27 |
31 |
32 |
41 |
42 |
43 |
49 |
50 |
56 |
57 |
64 |
65 |
72 |
73 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/src/net/commotionwireless/meshtether/SettingsActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Commotion Mesh Tether
3 | * Copyright (C) 2010 by Szymon Jakubczak
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package net.commotionwireless.meshtether;
20 |
21 | import android.os.Bundle;
22 | import android.preference.EditTextPreference;
23 | import android.preference.ListPreference;
24 | import android.preference.Preference;
25 | import android.preference.PreferenceActivity;
26 | import android.widget.Toast;
27 |
28 | public class SettingsActivity extends PreferenceActivity implements Preference.OnPreferenceChangeListener {
29 | final static int[] prefids = {
30 | R.string.if_lan, R.string.if_wan,
31 | R.string.adhoc_ip, R.string.adhoc_netmask, R.string.adhoc_dns_server, R.string.lan_essid, R.string.lan_bssid, R.string.lan_channel,
32 | R.string.lan_script
33 | };
34 | final static int[] checks = { R.string.lan_wext };
35 |
36 | private void setSummary(Preference p, CharSequence s) {
37 | if ((s != null) && (s.length() > 0)) {
38 | p.setSummary(getString(R.string.current) + s);
39 | } else {
40 | p.setSummary(null);
41 | }
42 | }
43 |
44 | @Override
45 | protected void onCreate(Bundle savedInstanceState) {
46 | super.onCreate(savedInstanceState);
47 | addPreferencesFromResource(R.xml.preferences);
48 |
49 | for (int i = 0; i < prefids.length; ++i) {
50 | Preference pref = findPreference(getString(prefids[i]));
51 | pref.setOnPreferenceChangeListener(this);
52 | if (ListPreference.class.isInstance(pref)) {
53 | ListPreference preference = (ListPreference) pref;
54 | setSummary(preference, preference.getValue());
55 | } else if (EditTextPreference.class.isInstance(pref)) {
56 | EditTextPreference preference = (EditTextPreference) pref;
57 | setSummary(preference, preference.getText());
58 | }
59 | }
60 | for (int i = 0; i < checks.length; ++i) {
61 | Preference pref = findPreference(getString(checks[i]));
62 | pref.setOnPreferenceChangeListener(this);
63 | }
64 | }
65 |
66 | @Override
67 | public boolean onPreferenceChange(Preference pref, Object newValue) {
68 | String key = pref.getKey();
69 | if (key == null) return true;
70 |
71 | if (((MeshTetherApp)getApplication()).isRunning()) {
72 | Toast.makeText(this, getString(R.string.restartneeded), Toast.LENGTH_SHORT).show();
73 | }
74 |
75 | if (ListPreference.class.isInstance(pref) || EditTextPreference.class.isInstance(pref)) {
76 | setSummary(pref, (String)newValue);
77 | } // else don't update summary
78 | return true;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/native/include/config.hh:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Barnacle Wifi Tether
3 | * Copyright (C) 2010 by Szymon Jakubczak
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #ifndef INCLUDED_CONFIG_HH
20 | #define INCLUDED_CONFIG_HH
21 |
22 | #include // for prctl
23 |
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include "log.hh"
29 |
30 | namespace Config {
31 | struct Parser {
32 | virtual bool parse(const char *arg) = 0;
33 | };
34 |
35 | template
36 | struct Unsigned : public Parser {
37 | T ¶m;
38 | Unsigned(T &p) : param(p) {}
39 | bool parse(const char * arg) {
40 | char *p;
41 | unsigned long int val = strtoul(arg, &p, 10);
42 | if (p == arg) return false;
43 | param = (T)val;
44 | return true;
45 | }
46 | };
47 |
48 | typedef Unsigned Uint;
49 | typedef Unsigned Uint8;
50 | typedef Unsigned Uint16;
51 | typedef Unsigned Uint32;
52 | typedef Unsigned Time;
53 | typedef Unsigned Bool;
54 |
55 | struct String : public Parser {
56 | char *param;
57 | size_t sz;
58 | String(char *p, size_t s) : param(p), sz(s) {}
59 | bool parse(const char * arg) {
60 | // TODO: check if arg not over sz
61 | strncpy(param, arg, sz);
62 | return true;
63 | }
64 | };
65 |
66 | struct IP : public Parser {
67 | in_addr_t ¶m;
68 | IP(in_addr_t &p) : param(p) {}
69 | bool parse(const char * arg) {
70 | in_addr_t val = inet_addr(arg);
71 | if (val == INADDR_NONE) return false;
72 | param = val;
73 | return true;
74 | }
75 | };
76 |
77 | struct Param {
78 | const char *name;
79 | Parser *parser;
80 | bool required;
81 |
82 | bool assign() {
83 | const char * val = getenv(name);
84 | if ((val == NULL) || !strlen(val)) {
85 | if (!required) {
86 | return true;
87 | }
88 | ERR("Parameter %s is unset\n", name);
89 | return false;
90 | }
91 | if (!parser->parse(val)) {
92 | ERR("Failed to parse '%s' for %s\n", val, name);
93 | return false;
94 | }
95 | return true;
96 | }
97 | ~Param() { if (parser) delete parser; parser = NULL; }
98 | };
99 |
100 | /**
101 | * Usage:
102 | * int p;
103 | * Param params[] = {
104 | * { "PARAM_NAME", new Unsigned(p), true },
105 | * { "OPTIONAL_PARAM_NAME", new String<20>(p) },
106 | * { 0 }
107 | * };
108 | * return configure(params);
109 | */
110 | bool configure(Param params[]) {
111 | for (Param *p = params; p->name; ++p) {
112 | if (!p->assign())
113 | return false;
114 | }
115 | return true;
116 | }
117 |
118 | }
119 |
120 | #endif // INCLUDED_CONFIG_HH
121 |
122 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
23 |
24 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
42 |
47 |
48 |
53 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
68 |
71 |
74 |
75 |
79 |
80 |
83 |
84 |
85 |
86 |
87 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/native/include/ifctl.hh:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Barnacle Wifi Tether
3 | * Copyright (C) 2010 by Szymon Jakubczak
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #ifndef INCLUDED_IFCTL_HH
20 | #define INCLUDED_IFCTL_HH
21 |
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include // for ifreq, to be compatible with linux/wireless.h
28 |
29 | #include "log.hh"
30 |
31 | static inline bool ether_parse(const char *inp, uint8_t *a) {
32 | for (int i = 0; i < 6; ++i) {
33 | char *p;
34 | a[i] = strtoul(inp, &p, 16);
35 | if (p == inp) return false;
36 | inp = p+1; // skip ':'
37 | }
38 | return true;
39 | }
40 |
41 | /**
42 | * ifconfig equivalent
43 | */
44 | class IfCtl {
45 | protected:
46 | int _sock; // control socket
47 | ifreq _ifr; // ifconfig
48 |
49 | void fail(const char *msg) {
50 | ERR("%s of %s: %s\n", msg, _ifr.ifr_name, strerror(errno));
51 | }
52 |
53 | public:
54 | IfCtl(const char *iface) {
55 | _sock = socket(AF_INET, SOCK_DGRAM, 0); // should never fail
56 | strncpy(_ifr.ifr_name, iface, IFNAMSIZ);
57 | _ifr.ifr_name[IFNAMSIZ-1] = 0;
58 | }
59 | ~IfCtl() { close(_sock); }
60 |
61 | bool setState(bool up) { // set oper state
62 | if (ioctl(_sock, SIOCGIFFLAGS, &_ifr)) {
63 | fail("Could not get flags");
64 | return false;
65 | }
66 | if (up) _ifr.ifr_flags |= IFF_UP;
67 | else _ifr.ifr_flags &= ~IFF_UP;
68 | if (ioctl(_sock, SIOCSIFFLAGS, &_ifr)) {
69 | fail("Could not set flags");
70 | return false;
71 | }
72 | return true;
73 | }
74 |
75 | /// net and mask in network order!
76 | bool setAddress(in_addr_t addr) {
77 | sockaddr_in *sin = (sockaddr_in *) &_ifr.ifr_addr;
78 | sin->sin_family = AF_INET;
79 | sin->sin_port = 0;
80 | sin->sin_addr.s_addr = addr;
81 | if (ioctl(_sock, SIOCSIFADDR, &_ifr)) {
82 | fail("Could not set address");
83 | return false;
84 | }
85 | return true;
86 | }
87 |
88 | bool setMask(in_addr_t mask) {
89 | sockaddr_in *sin = (sockaddr_in *) &_ifr.ifr_netmask;
90 | sin->sin_family = AF_INET;
91 | sin->sin_port = 0;
92 | sin->sin_addr.s_addr = mask;
93 | if (ioctl(_sock, SIOCSIFNETMASK, &_ifr)) {
94 | fail("Could not set netmask");
95 | return false;
96 | }
97 | return true;
98 | }
99 |
100 | bool setMTU(int mtu) {
101 | _ifr.ifr_mtu = mtu;
102 | if (ioctl(_sock, SIOCSIFMTU, &_ifr)) {
103 | fail("Could not set MTU");
104 | return false;
105 | }
106 | return true;
107 | }
108 |
109 | bool isUp() { // get oper state, NOTE: if iface missing it returns false too
110 | if (ioctl(_sock, SIOCGIFFLAGS, &_ifr)) {
111 | // no error message
112 | return false;
113 | }
114 | return _ifr.ifr_flags & IFF_UP;
115 | }
116 |
117 | in_addr_t getAddress() {
118 | if (ioctl(_sock, SIOCGIFADDR, &_ifr)) {
119 | fail("Could not get address");
120 | return INADDR_NONE;
121 | }
122 | return ((sockaddr_in *)&_ifr.ifr_addr)->sin_addr.s_addr;
123 | }
124 |
125 | in_addr_t getMask() {
126 | if (ioctl(_sock, SIOCGIFNETMASK, &_ifr)) {
127 | fail("Could not get netmask");
128 | return INADDR_NONE;
129 | }
130 | return ((sockaddr_in *)&_ifr.ifr_addr)->sin_addr.s_addr;
131 | }
132 |
133 | int getMTU() {
134 | if (ioctl(_sock, SIOCGIFMTU, &_ifr)) {
135 | fail("Could not get MTU");
136 | return -1;
137 | }
138 | return _ifr.ifr_mtu;
139 | }
140 |
141 | bool getHwAddress(uint8_t *addr) {
142 | if (ioctl(_sock, SIOCGIFHWADDR, &_ifr)) {
143 | return false;
144 | }
145 | memcpy(addr, _ifr.ifr_hwaddr.sa_data, 6);
146 | return true;
147 | }
148 | };
149 |
150 | #endif // INCLUDED_IFCTL_HH
151 |
--------------------------------------------------------------------------------
/src/net/commotionwireless/meshtether/Util.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Commotion Mesh Tether
3 | * Copyright (C) 2010 by Szymon Jakubczak
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package net.commotionwireless.meshtether;
20 |
21 | import java.util.ArrayList;
22 |
23 | import android.util.Log;
24 |
25 | public class Util {
26 | static class StyledStringBuilder extends android.text.SpannableStringBuilder {
27 | public StyledStringBuilder() { super(); }
28 | private StyledStringBuilder append(Object obj, String s) {
29 | append(s).setSpan(obj, length()-s.length(), length(), 0);
30 | return this;
31 | }
32 | public StyledStringBuilder append(android.text.style.TextAppearanceSpan obj, String s) {
33 | return append((Object)obj, s);
34 | }
35 | public StyledStringBuilder append(int color, String s) {
36 | return append(new android.text.style.ForegroundColorSpan(color), s);
37 | }
38 | }
39 |
40 | public static class MACAddress {
41 | public final static int LENGTH = 6;
42 | public final byte[] value = new byte[LENGTH];
43 | public static MACAddress parse(String s) {
44 | MACAddress addr = new MACAddress();
45 | String[] parts = s.split(":|-|\\.");
46 | if (parts.length != LENGTH)
47 | return null;
48 | try {
49 | for (int i = 0; i < LENGTH; ++i) {
50 | addr.value[i] = (byte)Integer.parseInt(parts[i], 16);
51 | }
52 | } catch (NumberFormatException e) {
53 | Log.e(MeshTetherApp.TAG, "Unable to parse "+ s, e);
54 | return null;
55 | }
56 | return addr;
57 | }
58 | @Override
59 | public String toString() {
60 | byte[] v = value;
61 | return String.format("%02x:%02x:%02x:%02x:%02x:%02x",
62 | v[0], v[1], v[2], v[3], v[4], v[5]);
63 | }
64 | public int getOctet(int octet) {
65 | return Math.abs(value[octet-1]);
66 | }
67 | }
68 |
69 | public static class TrafficData {
70 | long rx_bytes;
71 | long rx_pkts;
72 | long tx_bytes;
73 | long tx_pkts;
74 | void diff(TrafficData ref, TrafficData cur) {
75 | rx_bytes = cur.rx_bytes - ref.rx_bytes;
76 | rx_pkts = cur.rx_pkts - ref.rx_pkts;
77 | tx_bytes = cur.tx_bytes - ref.tx_bytes;
78 | tx_pkts = cur.tx_pkts - ref.tx_pkts;
79 | }
80 | void minus(TrafficData ref) {
81 | diff(ref, this);
82 | }
83 | void div(long val) {
84 | if (val == 0) return;
85 | rx_bytes /= val;
86 | rx_pkts /= val;
87 | tx_bytes /= val;
88 | tx_pkts /= val;
89 | }
90 | }
91 |
92 | public static class TrafficStats {
93 | private TrafficData start = new TrafficData();
94 | TrafficData total = new TrafficData();
95 | TrafficData rate = new TrafficData();
96 | private long t_last = 0;
97 |
98 | void init(TrafficData td) {
99 | start = td;
100 | t_last = new java.util.Date().getTime(); // in ms
101 | }
102 | void update(TrafficData td) {
103 | td.minus(start);
104 | rate.diff(total, td);
105 | total = td;
106 | long now = new java.util.Date().getTime();
107 | rate.div((now - t_last) / 1000); // per second
108 | t_last = now;
109 | }
110 | }
111 |
112 | public static TrafficData fetchTrafficData(String device) {
113 | // Returns traffic usage for all interfaces starting with 'device'.
114 | TrafficData d = new TrafficData();
115 | if (device == "")
116 | return d;
117 | for (String line : readLinesFromFile("/proc/net/dev")) {
118 | if (line.startsWith(device)) {
119 | line = line.replace(':', ' ');
120 | String[] values = line.split(" +");
121 | d.rx_bytes += Long.parseLong(values[1]);
122 | d.rx_pkts += Long.parseLong(values[2]);
123 | d.tx_bytes += Long.parseLong(values[9]);
124 | d.tx_pkts += Long.parseLong(values[10]);
125 | }
126 | }
127 | return d;
128 | }
129 |
130 | public static ArrayList readLinesFromFile(String filename) {
131 | ArrayList lines = new ArrayList();
132 | try {
133 | java.io.BufferedReader br = toReader(new java.io.FileInputStream(filename));
134 | String line;
135 | while((line = br.readLine()) != null) {
136 | lines.add(line.trim());
137 | }
138 | } catch (Exception e) {
139 | return null;
140 | }
141 | return lines;
142 | }
143 |
144 | public static java.io.BufferedReader toReader(java.io.InputStream is) {
145 | return new java.io.BufferedReader(new java.io.InputStreamReader(is), 8192);
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/res/xml/preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
22 |
27 |
28 |
34 |
35 |
41 |
42 |
46 |
47 |
52 |
57 |
58 |
59 |
65 |
66 |
70 |
74 |
75 |
109 |
110 |
116 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/native/wifi/main.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Barnacle Wifi Tether
3 | * Copyright (C) 2010 by Szymon Jakubczak
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #define TAG "WIFI: "
20 | #include
21 | #include "iwctl.hh"
22 | #include "wifi.hh"
23 |
24 | int config() {
25 | char iflan[IFNAMSIZ];
26 | in_addr_t lan_gw = inet_addr("192.168.5.1");
27 | in_addr_t lan_netmask = inet_addr("255.255.255.0");
28 |
29 | {
30 | using namespace Config;
31 | Param params[] = {
32 | { "brncl_if_lan", new String(iflan, IFNAMSIZ), true },
33 | { "brncl_adhoc_ip", new IP(lan_gw), false },
34 | { "brncl_adhoc_netmask", new IP(lan_netmask), false },
35 | { 0, NULL, false }
36 | };
37 | if (!configure(params))
38 | return -2;
39 | }
40 |
41 | IfCtl ic(iflan);
42 |
43 | bool success = (ic.setAddress(lan_gw)
44 | && ic.setMask(lan_netmask)
45 | && ic.setState(true));
46 |
47 | return success ? 0 : -1;
48 | }
49 |
50 | void cleanup() {
51 | Wifi::stop_supplicant();
52 | }
53 |
54 | int assoc_loop () {
55 | static const size_t BufSize = 64;
56 |
57 | char iflan[IFNAMSIZ];
58 | char essid[BufSize+1] = "olsr.org";
59 | char bssid[BufSize+1] = { '\0' };
60 | char wep[BufSize+1] = { '\0' };
61 | unsigned channel = 7;
62 | bool usewext = false;
63 |
64 | {
65 | using namespace Config;
66 | Param params[] = {
67 | { "brncl_if_lan", new String(iflan, IFNAMSIZ), true },
68 | { "brncl_lan_essid", new String(essid, BufSize), false },
69 | { "brncl_lan_bssid", new String(bssid, BufSize),false },
70 | { "brncl_lan_wep", new String(wep, BufSize), false },
71 | { "brncl_lan_channel", new Uint(channel), false },
72 | { "brncl_lan_wext", new Bool(usewext), false },
73 | { 0, NULL, false }
74 | };
75 | if (!configure(params))
76 | return -2;
77 | }
78 |
79 | char buf[1024];
80 |
81 | IwCtl ic(iflan);
82 | if(ic.setState(true)) { // just in case
83 | ic.setChannel(channel); // ignore return value
84 |
85 | if (usewext) {
86 | // wireless extensions configuration
87 |
88 | if (!ic.setMode()) {
89 | ;//ERR("Failed to set ad-hoc mode\n");
90 | }
91 | if (bssid[0]) {
92 | uint8_t BSS[6];
93 | if (ether_parse(bssid, BSS)) {
94 | if (!ic.setBssid(BSS)) {
95 | ;//ERR("Failed to set BSSID\n");
96 | }
97 | } else ERR("Failed to parse BSSID\n");
98 | }
99 |
100 | if (wep[0]) {
101 | if (!ic.configureWep(wep))
102 | ERR("Failed to configure WEP\n");
103 | }
104 | ic.commit();
105 |
106 | uint8_t eth[6] = {0, 0, 0, 0, 0, 0};
107 | ic.getHwAddress(eth);
108 | LOG("OK %s %02x:%02x:%02x:%02x:%02x:%02x\n", iflan,
109 | eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
110 |
111 | // associate
112 | do {
113 | DBG("WLEXT assoc\n");
114 | if (!ic.setEssid(essid, strlen(essid)))
115 | break;
116 | // wait for line on stdin before attempting again
117 | fgets(buf, sizeof(buf), stdin);
118 | } while (!feof(stdin));
119 |
120 | } else {
121 | // wpa_supplicant configuration
122 |
123 | FILE *f = fopen("wpa.conf", "w");
124 | if (f) {
125 | fprintf(f, "ctrl_interface=%s\nap_scan=2\n", iflan);
126 | fclose(f);
127 | }
128 | chmod("wpa.conf" , S_IRUSR | S_IWUSR | S_IRGRP| S_IWGRP | S_IROTH);
129 |
130 | atexit(cleanup);
131 | if (!Wifi::init())
132 | return -1;
133 |
134 | int netid = Wifi::addNetwork();
135 | if (netid < 0) {
136 | ERR("Failed to ADD_NETWORK\n");
137 | return -1;
138 | }
139 | // TODO: allow dynamic reconfiguration in the association loop
140 | if (!Wifi::setup(netid, essid, bssid, wep, chan2freq(channel)))
141 | return -1;
142 |
143 | uint8_t eth[6] = {0, 0, 0, 0, 0, 0};
144 | ic.getHwAddress(eth);
145 | LOG("OK %s %02x:%02x:%02x:%02x:%02x:%02x\n", iflan,
146 | eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
147 | do {
148 | DBG("WPASUPP assoc\n");
149 | if (!Wifi::assoc())
150 | break;
151 | // wait for line on stdin before attempting again
152 | fgets(buf, sizeof(buf), stdin);
153 | } while (!feof(stdin));
154 | }
155 | }
156 |
157 | Wifi::shutdown();
158 | return 0;
159 | }
160 |
161 | void die(int) {
162 | Wifi::shutdown();
163 | ERR("killed\n");
164 | exit(1);
165 | }
166 |
167 | int main(int argc, const char * argv[]) {
168 | prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0);
169 | struct sigaction act;
170 | act.sa_handler = die;
171 | sigaction(SIGINT, &act, 0);
172 | sigaction(SIGTERM, &act, 0);
173 |
174 | if (argc == 2) {
175 | if (!strcmp(argv[1], "assoc")) {
176 | return assoc_loop();
177 | } else if (!strcmp(argv[1], "config")) {
178 | return config();
179 | } else if (!strcmp(argv[1], "load")) {
180 | return Wifi::load_driver() ? 0 : -1;
181 | } else if (!strcmp(argv[1], "unload")) {
182 | return Wifi::unload_driver() ? 0 : -1;
183 | }
184 | }
185 | ERR("Usage: %s assoc|load|unload\n", argv[0]);
186 | return -1;
187 | }
188 |
189 |
--------------------------------------------------------------------------------
/external/Makefile:
--------------------------------------------------------------------------------
1 |
2 | CWD = $(shell pwd)
3 | PROJECT_ROOT = $(CWD)/..
4 | EXTERNAL_ROOT = $(PROJECT_ROOT)/external
5 | ASSETS = $(PROJECT_ROOT)/assets
6 |
7 |
8 | # Android SDK setup for shellfork
9 | SDK_BASE ?= /opt/android-sdk
10 | SDK_PLATFORM_LEVEL ?= 9
11 | SDK_PLATFORM=$(SDK_BASE)/platforms/android-$(SDK_PLATFORM_LEVEL)/
12 |
13 |
14 | # Android NDK setup
15 |
16 | # Android now has 64-bit and 32-bit versions of the NDK for GNU/Linux. We
17 | # assume that the build platform uses the appropriate version, otherwise the
18 | # user building this will have to manually set NDK_PROCESSOR or NDK_TOOLCHAIN.
19 | CPU := $(shell uname -m)
20 | ifeq ($(CPU),x86_64)
21 | NDK_PROCESSOR=x86_64
22 | else
23 | NDK_PROCESSOR=x86
24 | endif
25 |
26 | NDK_BASE ?= /opt/android-ndk
27 | NDK_PLATFORM_LEVEL ?= 9
28 | NDK_ABI=arm
29 | NDK_COMPILER_VERSION=4.6
30 |
31 | NDK_SYSROOT=$(NDK_BASE)/platforms/android-$(NDK_PLATFORM_LEVEL)/arch-$(NDK_ABI)
32 | NDK_UNAME := $(shell uname -s | tr '[A-Z]' '[a-z]')
33 | NDK_TOOLCHAIN = $(NDK_ABI)-linux-androideabi-$(NDK_COMPILER_VERSION)
34 | NDK_TOOLCHAIN_BASE=$(NDK_BASE)/toolchains/$(NDK_TOOLCHAIN)/prebuilt/$(NDK_UNAME)-$(NDK_PROCESSOR)
35 |
36 | # to use the real HOST tag, you need the latest libtool files:
37 | # http://stackoverflow.com/questions/4594736/configure-does-not-recognize-androideabi
38 | HOST := arm-linux-androideabi
39 |
40 | # install root for built files
41 | DESTDIR = $(CWD)
42 | # TODO try adding the Android-style /data/app.name here
43 | prefix = /data/data/info.guardianproject.lildebi/app_opt
44 | LOCAL := $(DESTDIR)$(prefix)
45 |
46 | PATH := ${PATH}:$(NDK_TOOLCHAIN_BASE)/bin:$(LOCAL)/bin
47 |
48 | CC := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-gcc --sysroot=$(NDK_SYSROOT)
49 | CXX := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-g++
50 | CPP := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-cpp
51 | LD := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-ld
52 | AR := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-ar
53 | RANLIB := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-ranlib
54 | STRIP := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-strip \
55 | --strip-unneeded -R .note -R .comment
56 |
57 |
58 | # the meaning of NDK_TOOLCHAIN has changed, since it was added as an official
59 | # env var to the Android NDK build system. the olsrd still has the old version,
60 | # which we are not calling NDK_TOOLCHAIN_BASE
61 | ALL_NDK_FLAGS = NDK_BASE="$(NDK_BASE)" \
62 | NDK_ABI="$(NDK_ABI)" \
63 | NDK_PLATFORM_LEVEL="$(NDK_PLATFORM_LEVEL)" \
64 | NDK_COMPILER_VERSION="$(NDK_COMPILER_VERSION)" \
65 | NDK_TOOLCHAIN="$(NDK_TOOLCHAIN_BASE)" \
66 | NDK_SYSROOT="$(NDK_SYSROOT)" \
67 | NDK_UNAME="$(NDK_UNAME)" \
68 | HOST="$(HOST)" \
69 | CC="$(CC)" \
70 | LD="$(LD)" \
71 | AR="$(AR)" \
72 | STRIP="$(STRIP)"
73 |
74 |
75 | ALL_CFLAGS = -DANDROID -I$(LOCAL)/include
76 | ALL_LDFLAGS = -L$(LOCAL)/lib -Wl,--rpath,$(LOCAL)/lib
77 |
78 | # build as small as possible, mostly useful for static binaries
79 | ALL_CFLAGS += -fdata-sections -ffunction-sections -Os
80 | ALL_LDFLAGS += -Wl,--gc-sections
81 |
82 | all: olsrd busybox shell-fork
83 |
84 | clean: olsrd-clean olsrinfo-clean busybox-clean shell-fork-clean
85 |
86 | .PHONY: shell-fork olsrd olsrd-clean olsrinfo olsrinfo-clean busybox busybox-clean shell-fork-clean
87 | .SUFFIXES: .java .class
88 |
89 | #--olsrd-----------------------------------------------------------------------#
90 |
91 | OLSRD_SOURCE := $(wildcard olsrd/[*/*.[ch]) \
92 | $(wildcard olsrd/*/*/*.[ch])
93 |
94 | olsrd: olsrd-build-stamp
95 |
96 | olsrd-build-stamp: $(OLSRD_SOURCE)
97 | make -C olsrd OS=android $(ALL_NDK_FLAGS) DEBUG=0 VERBOSE=1 all
98 | # build only the plugins we are likely to use to keep the build stable
99 | make -C olsrd OS=android $(ALL_NDK_FLAGS) DEBUG=0 arprefresh
100 | make -C olsrd OS=android $(ALL_NDK_FLAGS) DEBUG=0 bmf
101 | make -C olsrd OS=android $(ALL_NDK_FLAGS) DEBUG=0 dot_draw
102 | make -C olsrd OS=android $(ALL_NDK_FLAGS) DEBUG=0 dyn_gw_plain
103 | make -C olsrd OS=android $(ALL_NDK_FLAGS) DEBUG=0 httpinfo
104 | make -C olsrd OS=android $(ALL_NDK_FLAGS) DEBUG=0 jsoninfo
105 | make -C olsrd OS=android $(ALL_NDK_FLAGS) DEBUG=0 nameservice
106 | make -C olsrd OS=android $(ALL_NDK_FLAGS) DEBUG=0 pgraph
107 | make -C olsrd OS=android $(ALL_NDK_FLAGS) DEBUG=0 secure
108 | make -C olsrd OS=android $(ALL_NDK_FLAGS) DEBUG=0 txtinfo
109 | make -C olsrd OS=android $(ALL_NDK_FLAGS) DEBUG=0 watchdog
110 | touch olsrd-build-stamp
111 |
112 | olsrd-clean:
113 | make -C olsrd OS=android clean_all
114 | rm -f olsrd-build-stamp
115 |
116 | #--olsrinfo--------------------------------------------------------------------#
117 |
118 | OLSRINFO_CLASSPATH := src:libs/jackson-mapper-asl-1.9.7.jar:libs/jackson-core-asl-1.9.7.jar
119 | OLSRINFO_SOURCE := \
120 | $(wildcard olsrinfo/src/net/commotionwireless/olsrinfo/*.java) \
121 | $(wildcard olsrinfo/src/net/commotionwireless/olsrinfo/datatypes/*.java)
122 | OLSRINFO_CLASSES := $(OLSRINFO_SOURCE:%.java=%.class)
123 | OLSRINFO_JAR = ../libs/olsrinfo.jar
124 |
125 | olsrinfo: $(OLSRINFO_JAR)
126 |
127 | $(OLSRINFO_JAR): $(OLSRINFO_CLASSES)
128 | jar cvf $(OLSRINFO_JAR) -C olsrinfo/bin .
129 |
130 | $(OLSRINFO_CLASSES): $(OLSRINFO_SOURCE)
131 |
132 | olsrinfo/bin:
133 | install -d olsrinfo/bin
134 |
135 | %.class: %.java olsrinfo/bin
136 | cd olsrinfo && javac -g \
137 | -source 1.6 -target 1.6 \
138 | -d bin \
139 | -classpath $(OLSRINFO_CLASSPATH) \
140 | $(<:olsrinfo/%=%)
141 |
142 |
143 | #--busybox--------------------------------------------------------------------#
144 |
145 | busybox: $(EXTERNAL_ROOT)/busybox/busybox
146 |
147 | $(EXTERNAL_ROOT)/busybox/.config: $(EXTERNAL_ROOT)/busybox_config
148 | sed s/^CONFIG_SYSROOT.*$$/CONFIG_SYSROOT=\"$(subst /,\\/,$(NDK_SYSROOT))\"/ busybox_config > $(EXTERNAL_ROOT)/busybox/.config
149 |
150 | $(EXTERNAL_ROOT)/busybox/busybox: $(EXTERNAL_ROOT)/busybox/.config
151 | make -C $(EXTERNAL_ROOT)/busybox/
152 |
153 | busybox-clean:
154 | rm -f -- $(EXTERNAL_ROOT)/busybox/.config
155 | rm -f -- $(EXTERNAL_ROOT)/busybox/busybox
156 | make -C $(EXTERNAL_ROOT)/busybox/ clean
157 |
158 | FORK_SOURCE := $(wildcard shell-fork/*.[ch])
159 | SHELL_JAVA_SOURCE := $(wildcard shell-fork/src/net/net.commotionwireless.shell/*.java)
160 | shell-fork: fork-timestamp shell-jar-timestamp
161 |
162 | fork-timestamp: $(FORK_SOURCE)
163 | make -C shell-fork/ $(ALL_NDK_FLAGS) OS=android fork
164 |
165 | shell-jar-timestamp: $(SHELL_JAVA_SOURCE)
166 | ant -Dbasedir=$(EXTERNAL_ROOT)/shell-fork -f $(EXTERNAL_ROOT)/shell-fork/build.xml \
167 | -DandroidJarFilePath="$(SDK_PLATFORM)" -DjunitJarFile=/usr/share/java/junit4.jar \
168 | jar
169 |
170 | shell-fork-clean:
171 | make -C shell-fork/ clean
172 | ant -Dbasedir=$(EXTERNAL_ROOT)/shell-fork -f $(EXTERNAL_ROOT)/shell-fork/build.xml clean
173 |
174 |
--------------------------------------------------------------------------------
/src/net/commotionwireless/meshtether/NativeHelper.java:
--------------------------------------------------------------------------------
1 | package net.commotionwireless.meshtether;
2 |
3 | import java.io.BufferedInputStream;
4 | import java.io.BufferedOutputStream;
5 | import java.io.File;
6 | import java.io.FileInputStream;
7 | import java.io.FileNotFoundException;
8 | import java.io.FileOutputStream;
9 | import java.io.IOException;
10 | import java.io.InputStream;
11 | import java.lang.reflect.InvocationTargetException;
12 | import java.lang.reflect.Method;
13 | import java.util.zip.ZipEntry;
14 | import java.util.zip.ZipOutputStream;
15 |
16 | import android.content.Context;
17 | import android.content.res.AssetManager;
18 | import android.os.Environment;
19 | import android.util.Log;
20 |
21 | public class NativeHelper {
22 | public static final String TAG = "NativeHelper";
23 |
24 | public static File publicFiles;
25 | public static File profileDir;
26 | public static File app_bin;
27 | public static File app_log;
28 |
29 | static String SU_C;
30 | static String SU_C_FORK;
31 | static String RUN;
32 | static String STOP_OLSRD;
33 | static String DO_STOP_OLSRD;
34 | static String DEL_ROUTE;
35 | static String OLSRD;
36 | static String WIFI;
37 | static String BUSYBOX;
38 |
39 | public static void setup(Context context) {
40 | app_bin = context.getDir("bin", Context.MODE_PRIVATE).getAbsoluteFile();
41 | app_log = context.getDir("log", Context.MODE_PRIVATE).getAbsoluteFile();
42 | // this is the same as android-8's getExternalFilesDir() but works on android-1
43 | publicFiles = new File(Environment.getExternalStorageDirectory(),
44 | "Android/data/" + context.getPackageName() + "/files/");
45 | publicFiles.mkdirs();
46 | profileDir = new File(Environment.getExternalStorageDirectory(), "MeshTether");
47 | profileDir.mkdirs();
48 | SU_C = new File(app_bin, "su_c").getAbsolutePath();
49 | SU_C_FORK = new File(app_bin, "su_c_fork").getAbsolutePath();
50 | STOP_OLSRD = new File(app_bin, "stop_olsrd").getAbsolutePath();
51 | DO_STOP_OLSRD = new File(app_bin, "do_stop_olsrd").getAbsolutePath();
52 | DEL_ROUTE = new File(app_bin, "del-fake-default-route").getAbsolutePath();
53 | RUN = new File(app_bin, "run").getAbsolutePath();
54 | OLSRD = new File(app_bin, "olsrd").getAbsolutePath();
55 | WIFI = new File(app_bin, "wifi").getAbsolutePath();
56 | BUSYBOX = new File(app_bin, "busybox").getAbsolutePath();
57 | }
58 |
59 | public static boolean unzipAssets(Context context) {
60 | boolean result = true;
61 | try {
62 | AssetManager am = context.getAssets();
63 | final String[] assetList = am.list("");
64 |
65 | // ignore folder added to the assets on various devices
66 | for (String asset : assetList) {
67 | if (asset.equals("images")
68 | || asset.equals("sounds")
69 | || asset.equals("webkit")
70 | || asset.equals("databases") // Motorola
71 | || asset.equals("kioskmode")) // Samsung
72 | continue;
73 |
74 | int BUFFER = 2048;
75 | final File file = new File(NativeHelper.app_bin, asset);
76 | InputStream tmp;
77 | try {
78 | tmp = am.open(asset);
79 | } catch (FileNotFoundException e) {
80 | // if asset is a directory, we'll get this exception
81 | e.printStackTrace();
82 | continue;
83 | }
84 | final InputStream assetIS = tmp;
85 |
86 | if (file.exists()) {
87 | file.delete();
88 | Log.i(MeshTetherApp.TAG, "DebiHelper.unzipDebiFiles() deleting "
89 | + file.getAbsolutePath());
90 | }
91 |
92 | FileOutputStream fos = new FileOutputStream(file);
93 | BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER);
94 |
95 | int count;
96 | byte[] data = new byte[BUFFER];
97 |
98 | while ((count = assetIS.read(data, 0, BUFFER)) != -1) {
99 | dest.write(data, 0, count);
100 | }
101 |
102 | dest.flush();
103 | dest.close();
104 |
105 | assetIS.close();
106 | }
107 | } catch (IOException e) {
108 | result = false;
109 | Log.e(MeshTetherApp.TAG, "Can't unzip", e);
110 | }
111 | chmod("0750", new File(SU_C));
112 | chmod("0750", new File(SU_C_FORK));
113 | chmod("0750", new File(RUN));
114 | chmod("0750", new File(STOP_OLSRD));
115 | chmod("0750", new File(DO_STOP_OLSRD));
116 | chmod("0750", new File(DEL_ROUTE));
117 | chmod("0750", new File(OLSRD));
118 | chmod("0750", new File(WIFI));
119 | chmod("0750", new File(BUSYBOX));
120 | chmod("0750", new File(app_bin, "script_aria"));
121 | chmod("0750", new File(app_bin, "script_hero"));
122 | chmod("0750", new File(app_bin, "script_samsung"));
123 | chmod("0750", new File(app_bin, "fork"));
124 |
125 | return result;
126 | }
127 |
128 | public static boolean installBusyboxSymlinks() {
129 | File testFile = new File(NativeHelper.app_bin, "awk");
130 | if (testFile.exists()) {
131 | Log.v(TAG, "busybox test file exists: " + testFile);
132 | } else {
133 | // setup busybox so we have the utils we need, guaranteed
134 | String command = new File(NativeHelper.app_bin, "busybox").getAbsolutePath()
135 | + " --install -s " + NativeHelper.app_bin.getAbsolutePath();
136 | Log.i(TAG, "Running " + command);
137 | try {
138 | Process sh = Runtime.getRuntime().exec(command);
139 | sh.waitFor();
140 | } catch (Exception e) {
141 | e.printStackTrace();
142 | return false;
143 | }
144 | }
145 | return true;
146 | }
147 |
148 | public static void chmod(String modestr, File path) {
149 | Log.i(TAG, "chmod " + modestr + " " + path.getAbsolutePath());
150 | try {
151 | Class> fileUtils = Class.forName("android.os.FileUtils");
152 | Method setPermissions = fileUtils.getMethod("setPermissions", String.class,
153 | int.class, int.class, int.class);
154 | int mode = Integer.parseInt(modestr, 8);
155 | int a = (Integer) setPermissions.invoke(null, path.getAbsolutePath(), mode,
156 | -1, -1);
157 | if (a != 0) {
158 | Log.i(TAG, "ERROR: android.os.FileUtils.setPermissions() returned " + a
159 | + " for '" + path + "'");
160 | }
161 | } catch (ClassNotFoundException e) {
162 | Log.i(TAG, "android.os.FileUtils.setPermissions() failed:", e);
163 | } catch (IllegalAccessException e) {
164 | Log.i(TAG, "android.os.FileUtils.setPermissions() failed:", e);
165 | } catch (InvocationTargetException e) {
166 | Log.i(TAG, "android.os.FileUtils.setPermissions() failed:", e);
167 | } catch (NoSuchMethodException e) {
168 | Log.i(TAG, "android.os.FileUtils.setPermissions() failed:", e);
169 | }
170 | }
171 |
172 | public static boolean isSdCardPresent() {
173 | return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
174 | }
175 |
176 | public static void zip(File fileToZip, File zip)
177 | throws FileNotFoundException, IOException {
178 | final int BUFFER = 2048;
179 | BufferedInputStream origin = null;
180 | byte data[] = new byte[BUFFER];
181 |
182 | FileInputStream fi = new FileInputStream(fileToZip);
183 | origin = new BufferedInputStream(fi, BUFFER);
184 |
185 | ZipOutputStream out;
186 | out = new ZipOutputStream(new FileOutputStream(zip));
187 | ZipEntry e = new ZipEntry(fileToZip.getName());
188 | out.putNextEntry(e);
189 | int count;
190 | while ((count = origin.read(data, 0, BUFFER)) != -1)
191 | out.write(data, 0, count);
192 | out.closeEntry();
193 | origin.close();
194 | out.close();
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/native/wifi/wifi.hh:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Barnacle Wifi Tether
3 | * Copyright (C) 2010 by Szymon Jakubczak
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #ifndef WIFI_HH_INCLUDED
20 | #define WIFI_HH_INCLUDED
21 |
22 | #include
23 | #include
24 | #include
25 |
26 | #include
27 |
28 | #include "init.hh"
29 |
30 | extern "C" {
31 | #include "hardware_legacy_stub.h"
32 | }
33 |
34 | namespace Wifi {
35 | bool load_driver() {
36 | if (wifi_load_driver() != 0) {
37 | ERR("Failed to load driver: %s\n", strerror(errno));
38 | return false;
39 | }
40 |
41 | LOG("driver loaded\n");
42 | return true;
43 | }
44 |
45 | bool unload_driver() {
46 | return wifi_unload_driver() == 0;
47 | }
48 |
49 | static Init::Service *svc = 0;
50 |
51 | bool start_supplicant() {
52 | // we try to start the supplicant by hand in order to swap the .conf file
53 | if (!svc)
54 | svc = Init::find("wpa_supplicant");
55 | if (svc) {
56 | DBG("Found service: '%s' socket: '%s'\n", svc->command, svc->socket);
57 | // use our config file
58 | int cmdlen = strlen(svc->command);
59 | char cwd[256];
60 | getcwd(cwd, sizeof(cwd));
61 | int newcmdlen = cmdlen + strlen(cwd) + 32;
62 | char *newcommand = (char *)malloc(newcmdlen); // malloc not new[] because Service free()s
63 | snprintf(newcommand, newcmdlen, "%s -c%s/%s", svc->command, cwd, "wpa.conf");
64 | svc->command = newcommand;
65 | if (svc->start()) {
66 | DBG("wpa_supplicant custom-started\n");
67 | return true;
68 | } else {
69 | delete svc;
70 | svc = 0;
71 | }
72 | }
73 | // but if not, we use libhardware_legacy
74 | return false;// ::wifi_start_supplicant() == 0;
75 | }
76 |
77 | void stop_supplicant() {
78 | if (svc)
79 | svc->stop();
80 | else
81 | ::wifi_stop_supplicant();
82 | }
83 |
84 |
85 | // from core/jni/android_net_wifi_Wifi.cpp
86 | bool doCommand(const char *cmd, char *replybuf, int replybuflen) {
87 | size_t len = replybuflen - 1;
88 | if (::wifi_command(cmd, replybuf, &len) != 0) {
89 | return false;
90 | } else {
91 | // Strip off trailing newline
92 | if (len > 0 && replybuf[len-1] == '\n') --len;
93 | replybuf[len] = '\0';
94 | return true;
95 | }
96 | }
97 |
98 | int doIntCommand(const char *cmd) {
99 | char reply[256];
100 | if (doCommand(cmd, reply, sizeof(reply))) {
101 | return atoi(reply);
102 | } else {
103 | return -1;
104 | }
105 | }
106 |
107 | bool doBoolCommand(const char *cmd, const char *expect = "OK") {
108 | char reply[256];
109 | if (doCommand(cmd, reply, sizeof(reply))) {
110 | if (strcmp(reply, expect) != 0)
111 | ERR("received unexpected reply '%s'\n", reply);
112 |
113 | return (strcmp(reply, expect) == 0);
114 | } else {
115 | return false;
116 | }
117 | }
118 |
119 | void shutdown() {
120 | ::wifi_close_supplicant_connection();
121 | stop_supplicant();
122 | }
123 |
124 | bool init() {
125 | if (!start_supplicant()) {
126 | ERR("Failed to start supplicant: %s\n", strerror(errno));
127 | return false;
128 | }
129 | LOG("wpa_supplicant started\n");
130 |
131 | // try to connect to supplicant 3 times
132 | bool connected = false;
133 | for (int i = 0; i < 3; ++i) {
134 | if (::wifi_connect_to_supplicant() == 0) {
135 | connected = true;
136 | break;
137 | }
138 | usleep(100000); // 100ms
139 | }
140 | if (!connected) {
141 | ERR("Failed to connect to supplicant: %s\n", strerror(errno));
142 | return false;
143 | }
144 | LOG("wpa_supplicant connected\n");
145 |
146 | if (!doBoolCommand("PING", "PONG")) {
147 | ERR("Failed to ping supplicant\n");
148 | return false;
149 | }
150 |
151 | doBoolCommand("DRIVER START", "OK"); // ignore response
152 |
153 | if (!doBoolCommand("AP_SCAN 2", "OK")) {
154 | ERR("Failed to set AP_SCAN\n");
155 | return false;
156 | }
157 |
158 | if (!doBoolCommand("DISCONNECT", "OK")) {
159 | ERR("Failed to DISCONNECT\n");
160 | return false;
161 | }
162 |
163 | return true;
164 | }
165 |
166 | // returns < 0 if failed
167 | int addNetwork() {
168 | return doIntCommand("ADD_NETWORK");
169 | }
170 |
171 | bool setup(int netid, const char *essid, const char *bssid, const char *wep, int freq) {
172 | char buf[256];
173 |
174 | #define SET(X...) \
175 | snprintf(buf, sizeof(buf), X); \
176 | if (!doBoolCommand(buf, "OK")) { \
177 | ERR("Failed to %s", buf); \
178 | return false; \
179 | }
180 |
181 | SET("SET_NETWORK %d mode 1", netid);
182 | SET("SET_NETWORK %d key_mgmt NONE", netid);
183 | if (bssid[0])
184 | SET("SET_NETWORK %d bssid %s", netid, bssid);
185 | if (wep[0]) {
186 | SET("SET_NETWORK %d wep_key0 %s", netid, wep);
187 | SET("SET_NETWORK %d wep_tx_keyidx 0", netid);
188 | }
189 | SET("SET_NETWORK %d ssid \"%s\"", netid, essid); // NOTE: ascii must be in ""
190 |
191 | if(freq)
192 | SET("SET_NETWORK %d frequency %d", netid, freq); // this does not work on TIWLAN
193 |
194 | SET("SELECT_NETWORK %d", netid);
195 | return true;
196 | }
197 |
198 | static bool firstAttempt = true;
199 |
200 | bool assoc() {
201 | doBoolCommand("DRIVER POWERMODE 1", "OK"); // 0-AUTO, 1-ACTIVE
202 |
203 | if (!firstAttempt)
204 | doBoolCommand("SCAN"); // this allows to join an existing IBSS
205 |
206 | firstAttempt = false;
207 |
208 | if (doBoolCommand("REASSOCIATE", "OK")) {
209 | #if 0
210 | char buf[256];
211 |
212 | while(false) { // FIXME: actually process events -- but when do these events stop?
213 | int nread = ::wifi_wait_for_event(buf, sizeof(buf));
214 | if (nread < 0) return false; // failed!
215 | // find space
216 | char *p = buf;
217 | for( ; *p && !isspace(*p); ++p);
218 | *p = '\0';
219 | if (strcmp(buf, "CTRL-EVENT-CONNECTED") == 0) {
220 | // connected! -- we're done
221 | return true;
222 | }
223 | if (strcmp(buf, "CTRL-EVENT-DISCONNECTED") == 0) {
224 | // disconnected! -- we're done!
225 | //-- or should we reassociate again?
226 | return true;
227 | }
228 | if (strcmp(buf, "CTRL-EVENT-TERMINATING") == 0) {
229 | // bam, this is not good
230 | return false;
231 | }
232 | }
233 | #endif
234 | return true;
235 | }
236 | ERR("Failed to REASSOCIATE\n");
237 | return true; // FIXME: don't ignore this error
238 | }
239 |
240 | };
241 |
242 | #endif // WIFI_HH_INCLUDED
243 |
--------------------------------------------------------------------------------
/src/net/commotionwireless/meshtether/LinksActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Commotion Mesh Tether
3 | * Copyright (C) 2010 by Szymon Jakubczak
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package net.commotionwireless.meshtether;
20 |
21 | import java.util.ArrayList;
22 |
23 | import net.commotionwireless.meshtether.MeshService.ClientData;
24 | import net.commotionwireless.olsrinfo.datatypes.HNA;
25 | import net.commotionwireless.olsrinfo.datatypes.Link;
26 | import net.commotionwireless.olsrinfo.datatypes.OlsrDataDump;
27 | import android.os.Bundle;
28 | import android.os.Handler;
29 | import android.view.View;
30 | import android.view.ViewGroup;
31 | import android.widget.BaseAdapter;
32 | import android.widget.ImageView;
33 | import android.widget.LinearLayout;
34 | import android.widget.ProgressBar;
35 | import android.widget.TextView;
36 |
37 | public class LinksActivity extends android.app.ListActivity {
38 | private MeshTetherApp app;
39 | private BaseAdapter adapter;
40 | private ArrayList clients = new ArrayList();
41 |
42 | private OlsrInfoThread mOlsrInfoThread;
43 | boolean mPauseOlsrInfoThread = false;
44 | private final Handler mHandler = new Handler();
45 |
46 | private static class ViewHolder {
47 | TextView remoteIP;
48 | ProgressBar lqBar;
49 | ProgressBar nlqBar;
50 | LinearLayout idrow;
51 | ImageView defaultRouteIcon;
52 | ImageView otherRouteIcon;
53 | }
54 |
55 | /** Called when the activity is first created. */
56 | @Override
57 | public void onCreate(Bundle savedInstanceState) {
58 | super.onCreate(savedInstanceState);
59 | app = (MeshTetherApp)getApplication();
60 | app.setLinksActivity(this);
61 |
62 | adapter = new BaseAdapter(){
63 | @Override
64 | public int getCount() { return clients.size(); }
65 | @Override
66 | public Object getItem(int position) { return clients.get(position); }
67 | @Override
68 | public long getItemId(int position) { return position; }
69 |
70 | @Override
71 | public View getView(int position, View convertView, ViewGroup parent) {
72 | final MeshService.ClientData client = clients.get(position);
73 |
74 | ViewHolder holder;
75 |
76 | if (convertView == null) {
77 | View view = getLayoutInflater().inflate(R.layout.linkrow, null);
78 | holder = new ViewHolder();
79 | holder.remoteIP = (TextView) view.findViewById(R.id.remoteip);
80 | holder.lqBar = (ProgressBar) view.findViewById(R.id.linkquality);
81 | holder.nlqBar = (ProgressBar) view.findViewById(R.id.neighborlinkquality);
82 | holder.idrow = (LinearLayout) view.findViewById(R.id.idrow);
83 | holder.defaultRouteIcon = new ImageView(getBaseContext());
84 | holder.defaultRouteIcon.setId(R.drawable.default_route);
85 | holder.defaultRouteIcon.setImageResource(R.drawable.default_route);
86 | holder.otherRouteIcon = new ImageView(getBaseContext());
87 | holder.otherRouteIcon.setId(R.drawable.other_route);
88 | holder.otherRouteIcon.setImageResource(R.drawable.other_route);
89 | view.setTag(holder);
90 | view.setClickable(false);
91 | convertView = view;
92 | } else {
93 | holder = (ViewHolder) convertView.getTag();
94 | }
95 |
96 | holder.remoteIP.setText(client.remoteIP);
97 | holder.lqBar.setProgress((int)(client.linkQuality * 100));
98 | holder.nlqBar.setProgress((int)(client.neighborLinkQuality * 100));
99 |
100 | if (client.hasDefaultRoute) {
101 | if(holder.idrow.findViewById(R.drawable.default_route) == null)
102 | holder.idrow.addView(holder.defaultRouteIcon);
103 | } else {
104 | holder.idrow.removeView(holder.defaultRouteIcon);
105 | }
106 | if (client.hasRouteToOther) {
107 | if(holder.idrow.findViewById(R.drawable.other_route) == null)
108 | holder.idrow.addView(holder.otherRouteIcon);
109 | } else {
110 | holder.idrow.removeView(holder.otherRouteIcon);
111 | }
112 | return convertView;
113 | }
114 | };
115 | setListAdapter(adapter);
116 | setTitle(getString(R.string.clientview));
117 |
118 | mOlsrInfoThread = new OlsrInfoThread();
119 | mOlsrInfoThread.start();
120 | }
121 |
122 | @Override
123 | protected void onDestroy() {
124 | super.onDestroy();
125 | mOlsrInfoThread.interrupt();
126 | mOlsrInfoThread = null;
127 | app.setLinksActivity(null);
128 | }
129 |
130 | @Override
131 | protected void onResume() {
132 | super.onResume();
133 | app.cancelClientNotify();
134 | update();
135 |
136 | if (hasWindowFocus() && clients.isEmpty())
137 | app.updateToast(getString(R.string.noclients), false);
138 | mPauseOlsrInfoThread = false;
139 | }
140 |
141 | @Override
142 | protected void onPause() {
143 | super.onPause();
144 | mPauseOlsrInfoThread = true;
145 | }
146 |
147 | public void update() {
148 | if (app.service != null)
149 | clients = app.service.clients;
150 | adapter.notifyDataSetChanged();
151 | }
152 |
153 | class OlsrInfoThread extends Thread {
154 |
155 | @Override
156 | public void run() {
157 | ArrayList clientsToAdd = new ArrayList();
158 | try {
159 | while(true) {
160 | OlsrDataDump dump = app.mJsonInfo.parseCommand("/links/hna");
161 | for (Link l : dump.links) {
162 | MeshService.ClientData c = new MeshService.ClientData(l.remoteIP, l.linkQuality,
163 | l.neighborLinkQuality, l.linkCost, l.validityTime);
164 | for (HNA h : dump.hna) {
165 | if (l.remoteIP.equals(h.gateway))
166 | if (h.genmask == 0)
167 | c.hasDefaultRoute = true;
168 | else
169 | c.hasRouteToOther = true;
170 | }
171 | clientsToAdd.add(c);
172 | }
173 | final ArrayList updateList = new ArrayList(clientsToAdd);
174 | mHandler.post(new Runnable() {
175 | @Override
176 | public void run() {
177 | for (MeshService.ClientData cd : updateList) {
178 | clientAdded(cd);
179 | }
180 | }
181 | });
182 | while (mPauseOlsrInfoThread)
183 | Thread.sleep(500);
184 | Thread.sleep(5000);
185 | }
186 | } catch (InterruptedException e) {
187 | // fall through
188 | }
189 | }
190 | }
191 |
192 | private void clientAdded(ClientData cd) {
193 |
194 | for (int i = 0; i < clients.size(); ++i) {
195 | ClientData c = clients.get(i);
196 | if (c.remoteIP.equals(cd.remoteIP)) {
197 | if (c.hasRouteToOther == cd.hasRouteToOther
198 | && c.hasDefaultRoute == cd.hasDefaultRoute
199 | && c.linkQuality == cd.linkQuality
200 | && c.neighborLinkQuality == cd.neighborLinkQuality) {
201 | return; // no change
202 | }
203 | clients.remove(i); // we'll add it at the end
204 | break;
205 | }
206 | }
207 | clients.add(cd);
208 | app.clientAdded(cd);
209 | }
210 |
211 | }
212 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 | Mesh Tether
22 | Mesh links
23 | Connecting to the mesh…
24 | Client connected
25 | Error occured
26 | Associate
27 | Please, set your preferences
28 | No clients connected
29 | Starting
30 | Data network is ready
31 | Disabling Wifi Manager…
32 | Wifi Manager is interfering with MeshTether!
33 | Waiting until Wifi is disabled
34 | Running…
35 | Restarting…
36 | beaconing ad-hoc network
37 | Connected to NAT
38 | Could not connect to NAT, will retry later
39 | Updated NAT filter
40 | Connected %s
41 | Stopped
42 | Could not find WAN interface
43 | Mobile data interface found:
44 | Wireless interface found:
45 | Could not start the process!
46 | Unpacking assets…
47 | Could not unpack binaries
48 | Could not unpack %s"
49 | Could not make the binary executable
50 | Enabling wifi…
51 | Could not execute %s
52 | Warning: did not finish cleanly
53 | Stopped unexpectedly!
54 | Exception occured!
55 | Invalid IP address
56 | Invalid MAC address
57 | Current:
58 | Restart for changes to take effect
59 | on/off
60 | waiting for olsrd to start…
61 | (no data yet)
62 |
63 |
64 | Choose a mesh profile
65 | Failed to load profile!
66 | (default)
67 |
68 |
69 | Default Mesh Profile
70 | SSID (Network Name)
71 | BSSID (Network ID)
72 | unique MAC address
73 | Wifi Channel
74 | Mesh Node IP
75 | Mesh Node Netmask
76 | DNS Server
77 | Adhoc Wifi Setup
78 | Invalid Mesh Prefix or IP.
79 |
80 |
81 | Mesh service starting…
82 | Starting olsrd…
83 | Mesh service stopping…
84 |
85 |
86 | Getting info from olsrd…
87 | Writing info to file…
88 | Zipping up file…
89 | olsrd is not running, no status information available!
90 |
91 |
92 | Help
93 | Mesh on the phone is experimental! Please check our wiki, email our mailing list, or find us on IRC.
94 |
95 |
96 | if_wan
97 | if_lan
98 | adhoc_netmask
99 | adhoc_ip
100 | lan_essid
101 | lan_bssid
102 | lan_channel
103 | lan_wext
104 | lan_script
105 | adhoc_dns_server
106 |
107 |
108 | - 1
109 | - 2
110 | - 3
111 | - 4
112 | - 5
113 | - 6
114 | - 7
115 | - 8
116 | - 9
117 | - 10
118 | - 11
119 | - 12
120 | - 13
121 |
122 |
123 |
124 | - 1 – 2412 MHz
125 | - 2 – 2417 MHz
126 | - 3 – 2422 MHz
127 | - 4 – 2427 MHz
128 | - 5 – 2432 MHz
129 | - 6 – 2437 MHz
130 | - 7 – 2442 MHz
131 | - 8 – 2447 MHz
132 | - 9 – 2452 MHz
133 | - 10 – 2457 MHz
134 | - 11 – 2462 MHz
135 | - 12 – 2467 MHz
136 | - 13 – 2472 MHz
137 |
138 |
139 |
140 |
141 | - script_hero
142 | - script_samsung
143 | - script_aria
144 |
145 |
146 | - none
147 | - Hero/Eris
148 | - Samsung
149 | - Aria/Liberty (see blog)
150 |
151 |
152 | http://commotionwireless.net/
153 | http://webchat.freenode.net/?randomnick=1&channels=oti&uio=d4
154 | https://code.commotionwireless.net/projects/commotion/wiki/Android_Troubleshooting
155 | http://szym.net/barnacle/faq/#root
156 | https://code.commotionwireless.net/projects/commotion/wiki
157 |
158 |
--------------------------------------------------------------------------------
/native/wifi/init.hh:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Barnacle Wifi Tether
3 | * Copyright (C) 2010 by Szymon Jakubczak
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | // init.rc parsing routines
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 |
30 | #include
31 |
32 | namespace Init {
33 | const char * skipWhite(const char *s) {
34 | while (isblank(*s)) ++s;
35 | return s;
36 | }
37 |
38 | void chomp(char * s) {
39 | char * end = s + strlen(s);
40 | if (end > s) {
41 | do --end; while (isspace(*end));
42 | *(end+1) = 0;
43 | }
44 | }
45 |
46 | struct Service {
47 | const char *name;
48 | char *command;
49 | char *socket;
50 |
51 | pid_t pid;
52 |
53 | Service(const char *n) : name(n), command(0), socket(0) {}
54 |
55 | // service
56 | // socket
57 | void parseLine(const char* line) {
58 | if (!command) {
59 | if (strncmp(line, "service", 7) != 0)
60 | return;
61 |
62 | line = skipWhite(line + 7);
63 | if (!*line) return;
64 |
65 | int namelen = strlen(name);
66 | if (strncmp(line, name, namelen) == 0) {
67 | command = strdup(skipWhite(line + namelen));
68 | chomp(command);
69 | }
70 | } else if (!socket) {
71 | if (strncmp(line, "socket", 6) == 0) {
72 | socket = strdup(skipWhite(line + 6));
73 | chomp(socket);
74 | }
75 | }
76 | }
77 |
78 | bool parse(FILE *f) {
79 | char buf[1024];
80 | char *p = buf;
81 |
82 | while(!(command && socket)) {
83 | if (fgets(p, buf + sizeof(buf) - p, f) == 0)
84 | return false;
85 | char *b = strchr(p, '#');
86 | if (b) { // trim comment
87 | *b = 0;
88 | } else {
89 | b = strchr(p, '\\');
90 |
91 | if (b && ((b[1] == '\r') || (b[1] =='\n'))) {
92 | p = b;
93 | continue; // stitch next line
94 | }
95 | }
96 | p = buf;
97 | parseLine(skipWhite(buf));
98 | }
99 | return true;
100 | }
101 |
102 | ~Service() {
103 | if (command) { free(command); command = 0; }
104 | if (socket) { free(socket); socket = 0; }
105 | }
106 |
107 | int createSocket() {
108 | // parse the socket params
109 | char *name = strtok(socket, " ");
110 | char *stype = strtok(0, " ");
111 | char *sperm = strtok(0, " ");
112 | char *suid = strtok(0, " ");
113 | char *sgid = strtok(0, " ");
114 |
115 | if (!stype || !sperm) return -1;
116 |
117 | int type = (!strcmp(stype, "dgram")) ? SOCK_DGRAM : SOCK_STREAM;
118 | int perm = strtoul(sperm, 0, 8); // TODO: check errors
119 |
120 | uid_t uid = 0;
121 | gid_t gid = 0;
122 |
123 | if (suid) {
124 | struct passwd * p = getpwnam(suid);
125 | if (!p) return -1;
126 | uid = p->pw_uid;
127 | gid = p->pw_gid;
128 |
129 | if (sgid) {
130 | struct group * g = getgrnam(sgid);
131 | if (!g) return -1;
132 | gid = g->gr_gid;
133 | }
134 | }
135 |
136 | // see system/core/init/util.c:create_socket
137 | struct sockaddr_un addr;
138 | int fd, ret;
139 |
140 | fd = ::socket(PF_UNIX, type, 0);
141 | if (fd < 0) {
142 | DBG("Failed to open socket '%s': %s\n", name, strerror(errno));
143 | return -1;
144 | }
145 |
146 | memset(&addr, 0 , sizeof(addr));
147 | addr.sun_family = AF_UNIX;
148 | snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s", name);
149 |
150 | ret = ::unlink(addr.sun_path);
151 | if (ret != 0 && errno != ENOENT) {
152 | DBG("Failed to unlink old socket '%s': %s\n", name, strerror(errno));
153 | goto out_close;
154 | }
155 |
156 | ret = ::bind(fd, (struct sockaddr *) &addr, sizeof (addr));
157 | if (ret) {
158 | DBG("Failed to bind socket '%s': %s\n", name, strerror(errno));
159 | goto out_unlink;
160 | }
161 |
162 | ::chown(addr.sun_path, uid, gid);
163 | ::chmod(addr.sun_path, perm);
164 |
165 | DBG("Created socket '%s' with mode '%o', user '%d', group '%d'\n",
166 | addr.sun_path, perm, uid, gid);
167 |
168 | return fd;
169 |
170 | out_unlink:
171 | ::unlink(addr.sun_path);
172 | out_close:
173 | ::close(fd);
174 | return -1;
175 | }
176 |
177 | bool start() {
178 | // create socket
179 | int sock = createSocket();
180 | if (sock < 0) return false;
181 |
182 | pid = fork();
183 | if (pid < 0) return false;
184 |
185 | if (pid > 0) {
186 | close(sock); // leave it to the child
187 |
188 | char prop_name[PROP_NAME_MAX];
189 | snprintf(prop_name, PROP_NAME_MAX, "init.svc.%s", name);
190 | if (!property_set(prop_name, "running"))
191 | DBG("Failed to set init.svc. property %s\n", strerror(errno));
192 |
193 | return true;
194 | }
195 |
196 | setpgid(0, getpid());
197 |
198 | close(0); close(1); close(2);
199 |
200 | // publish socket
201 | char env_name[64];
202 | char env_val[64];
203 | snprintf(env_name, sizeof(env_name), ANDROID_SOCKET_ENV_PREFIX"%s", socket);
204 | snprintf(env_val, sizeof(env_val), "%d", sock);
205 | setenv(env_name, env_val, 1);
206 |
207 | // split into argc, argv
208 | int argc;
209 | char * argv[128];
210 | argv[0] = strtok(command, " ");
211 | for(argc = 1; argc < 128; ++argc) {
212 | argv[argc] = strtok(0, " ");
213 | if (!argv[argc]) {
214 | break;
215 | }
216 | }
217 |
218 | // execve
219 | if (execv(argv[0], argv) < 0) {
220 | DBG("Failed to execute %s\n", argv[0]);
221 | }
222 | _exit(127);
223 | return false; // unreachable
224 | }
225 |
226 | void stop() {
227 | if (pid > 0) {
228 | DBG("stopping %s\n", name);
229 | kill(-pid, SIGTERM);
230 | char prop_name[PROP_NAME_MAX];
231 | snprintf(prop_name, PROP_NAME_MAX, "init.svc.%s", name);
232 | property_set(prop_name, "stopping");
233 | pid = -1;
234 | }
235 | }
236 | };
237 |
238 | Service* find(const char * initrcname, const char * name) {
239 | FILE *initrc = fopen(initrcname, "r");
240 | if (!initrc) {
241 | DBG("Could not open %s\n", initrcname);
242 | return 0;
243 | }
244 | Service* s = new Service(name);
245 | if (!s->parse(initrc)) {
246 | DBG("Could not parse %s\n", initrcname);
247 | delete s;
248 | s = 0;
249 | }
250 | fclose(initrc);
251 | return s;
252 | }
253 |
254 | Service* find(const char * name) {
255 | Service *s = find("/init.rc", name);
256 | if (s) return s;
257 |
258 | const char * hardware = getenv("brncl_hardware");
259 | char buf[64];
260 | snprintf(buf, sizeof(buf), "/init.%s.rc", hardware);
261 | return find(buf, name);
262 | }
263 | }
264 |
--------------------------------------------------------------------------------
/src/net/commotionwireless/meshtether/InfoActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Commotion Mesh Tether
3 | * Copyright (C) 2010 by Szymon Jakubczak
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package net.commotionwireless.meshtether;
20 |
21 | import java.lang.reflect.Field;
22 | import java.util.ArrayList;
23 | import java.util.Collection;
24 | import java.util.HashMap;
25 | import java.util.Iterator;
26 | import java.util.List;
27 | import java.util.SortedSet;
28 | import java.util.TreeSet;
29 |
30 | import net.commotionwireless.olsrinfo.datatypes.AddressNetmask;
31 | import net.commotionwireless.olsrinfo.datatypes.Config;
32 | import net.commotionwireless.olsrinfo.datatypes.HNA;
33 | import net.commotionwireless.olsrinfo.datatypes.LinkQualityMultiplier;
34 | import net.commotionwireless.olsrinfo.datatypes.OlsrDataDump;
35 | import net.commotionwireless.olsrinfo.datatypes.Plugin;
36 | import android.net.wifi.WifiInfo;
37 | import android.os.Bundle;
38 | import android.view.View;
39 | import android.view.ViewGroup;
40 | import android.widget.BaseAdapter;
41 | import android.widget.TextView;
42 |
43 | public class InfoActivity extends android.app.ListActivity {
44 | public final static String TAG = "InfoActivity";
45 |
46 | private MeshTetherApp app;
47 | private String[] info = new String[0];
48 | private BaseAdapter adapter;
49 |
50 | private static class ViewHolder {
51 | TextView infoKey;
52 | TextView infoValue;
53 | }
54 |
55 | /** Called when the activity is first created. */
56 | @Override
57 | public void onCreate(Bundle savedInstanceState) {
58 | super.onCreate(savedInstanceState);
59 |
60 | app = (MeshTetherApp) getApplication();
61 | app.setInfoActivity(this);
62 | adapter = new BaseAdapter() {
63 |
64 | @Override
65 | public int getCount() {
66 | return info.length / 2;
67 | }
68 |
69 | @Override
70 | public long getItemId(int position) {
71 | return position;
72 | }
73 |
74 | @Override
75 | public Object getItem(int position) {
76 | String[] ret = new String[2];
77 | int i = position * 2;
78 | ret[0] = info[i];
79 | ret[1] = info[i + 1];
80 | return ret;
81 | }
82 |
83 | @Override
84 | public View getView(int position, View convertView, ViewGroup parent) {
85 | ViewHolder holder;
86 |
87 | if (convertView == null) {
88 | View view = getLayoutInflater().inflate(R.layout.inforow,
89 | null);
90 | holder = new ViewHolder();
91 | holder.infoKey = (TextView) view
92 | .findViewById(R.id.info_key);
93 | holder.infoValue = (TextView) view
94 | .findViewById(R.id.info_value);
95 | view.setTag(holder);
96 | view.setClickable(false);
97 | convertView = view;
98 | } else {
99 | holder = (ViewHolder) convertView.getTag();
100 | }
101 |
102 | int i = position * 2;
103 | holder.infoKey.setText(info[i]);
104 | holder.infoValue.setText(info[i + 1]);
105 | return convertView;
106 | }
107 | };
108 | setListAdapter(adapter);
109 | setTitle(getString(R.string.clientview));
110 | }
111 |
112 | @Override
113 | public void onResume() {
114 | super.onResume();
115 | update();
116 | }
117 |
118 | void update() {
119 | info = generateConfigList();
120 | adapter.notifyDataSetChanged();
121 | }
122 |
123 | private String[] makeStringArray(List l) {
124 | String[] ret = new String[l.size()];
125 | ret = l.toArray(ret);
126 | return ret;
127 | }
128 |
129 | private String[] generateConfigList() {
130 | HashMap data = new HashMap();
131 | List stringList = new ArrayList();
132 |
133 | // add active profile info first
134 | if (app.service != null) {
135 | String[] active = app.service.getActiveMeshProfile();
136 | String profileString = "";
137 | for (int i=0; i < active.length; i++) {
138 | profileString += "\n";
139 | profileString += "" + active[i];
140 | }
141 | stringList.add("active profile"); // key
142 | stringList.add(profileString); // value
143 | }
144 |
145 | // then add wifi info
146 | WifiInfo wi = app.wifiManager.getConnectionInfo();
147 | String wifiInfoString = "\n";
148 | wifiInfoString += "SSID: " + wi.getSSID() + "\n";
149 | wifiInfoString += "BSSID: " + wi.getBSSID() + "\n";
150 | int ipInt = wi.getIpAddress();
151 | String ipString = String.format("%d.%d.%d.%d",
152 | (ipInt & 0xff),
153 | (ipInt >> 8 & 0xff),
154 | (ipInt >> 16 & 0xff),
155 | (ipInt >> 24 & 0xff));
156 | wifiInfoString += "ip: " + ipString + "\n";
157 | wifiInfoString += "MAC: " + wi.getMacAddress() + "\n";
158 | wifiInfoString += "speed: " + wi.getLinkSpeed() + " Mbps\n";
159 | wifiInfoString += "RSSI: " + wi.getRssi() + " dBm";
160 | stringList.add("wifi info"); // key
161 | stringList.add(wifiInfoString);// value
162 |
163 | OlsrDataDump dump = app.mJsonInfo.parseCommand("/config");
164 | if (dump == null || dump.config == null
165 | || dump.config.unicastSourceIpAddress == null) {
166 | stringList.add(getString(R.string.waiting_for_olsrd));
167 | stringList.add(getString(R.string.no_data_yet));
168 | return makeStringArray(stringList);
169 | }
170 |
171 | Config config = dump.config;
172 | data.put("systemTime", dump.systemTime);
173 | data.put("timeSinceStartup", dump.timeSinceStartup);
174 |
175 | try {
176 | for (Field field : config.getClass().getDeclaredFields()) {
177 | String name = field.getName();
178 | String value = "";
179 | if (name.equals("defaultLinkQualityMultipliers")) {
180 | for (LinkQualityMultiplier lqm : config.defaultLinkQualityMultipliers) {
181 | value += lqm.route + " - " + lqm.multiplier + "\n";
182 | }
183 | } else if (name.equals("ipcAllowedAddresses")) {
184 | for (AddressNetmask addr : config.ipcAllowedAddresses) {
185 | value += addr.ipAddress + "/" + addr.netmask + "\n";
186 | }
187 | } else if (name.equals("hna")) {
188 | for (HNA hna : config.hna) {
189 | value += hna.destination + " " + hna.gateway + "\n";
190 | }
191 | } else {
192 | Object o = field.get(config);
193 | if (o != null)
194 | value = o.toString() + "\n";
195 | }
196 | // remove the last, trailing \n
197 | if (value.length() > 0)
198 | data.put(name, value.substring(0, value.length() - 1));
199 | else
200 | data.put(name, "");
201 | }
202 | } catch (IllegalArgumentException e) {
203 | e.printStackTrace();
204 | } catch (IllegalAccessException e) {
205 | e.printStackTrace();
206 | }
207 |
208 | SortedSet sortedKeys = new TreeSet(data.keySet());
209 | Iterator iter = sortedKeys.iterator();
210 | while (iter.hasNext()) {
211 | String key = iter.next();
212 | stringList.add(key);
213 | stringList.add(data.get(key).toString());
214 | }
215 |
216 | Collection plugins = app.mJsonInfo.plugins();
217 | for (Plugin p : plugins) {
218 | String value = "\n";
219 | if (p.port > 0 && p.port < 65536)
220 | value += "port: " + p.port + "\n";
221 | if (p.accept != null && !p.accept.equals(""))
222 | value += "accept: " + p.accept + "\n";
223 | if (p.host != null && !p.host.equals(""))
224 | value += "host: " + p.host + "\n";
225 | if (p.net != null && !p.net.equals(""))
226 | value += "net: " + p.net + "\n";
227 | if (p.ping != null && !p.ping.equals(""))
228 | value += "ping: " + p.ping + "\n";
229 | if (p.hna != null && !p.hna.equals(""))
230 | value += "hna: " + p.hna + "\n";
231 | if (p.uuidfile != null && !p.uuidfile.equals(""))
232 | value += "uuidfile: " + p.uuidfile + "\n";
233 | if (p.keyfile != null && !p.keyfile.equals(""))
234 | value += "keyfile: " + p.keyfile + "\n";
235 |
236 | String key = p.plugin;
237 | // remove the path to the plugin
238 | key = key.substring(key.lastIndexOf("/olsrd_") + 7, key.length());
239 | // remove the lib file name extension
240 | stringList.add(key.replace(".so.", " "));
241 | // remove the last, trailing \n
242 | stringList.add(value.substring(0, value.length() - 1));
243 | }
244 | return makeStringArray(stringList);
245 | }
246 | }
--------------------------------------------------------------------------------
/native/wifi/iwctl.hh:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Barnacle Wifi Tether
3 | * Copyright (C) 2010 by Szymon Jakubczak
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #ifndef INCLUDED_IWCTL_HH
20 | #define INCLUDED_IWCTL_HH
21 |
22 | #include
23 | #include
24 | #include // the most painful header ever
25 | #include // for ETHERTYPE_ and ARPHRD
26 |
27 | #include // for inet_addr
28 |
29 | #include
30 |
31 | const int WepSize104 = 104/8;
32 | const int WepSize40 = 40/8;
33 | // inp = hex string
34 | template
35 | static inline bool wep_parse(const char *inp, uint8_t *var) {
36 | if (strlen(inp) != 2*WepSize)
37 | return false;
38 | for (int i = 0; i < WepSize; ++i) {
39 | // so lazy, we'll use strtoul
40 | char b[3] = { inp[2*i], inp[2*i+1], 0 };
41 | char *p;
42 | var[i] = strtoul(b, &p, 16);
43 | if (p == b) return false;
44 | }
45 | return true;
46 | }
47 |
48 | static inline int chan2freq(int chan) {
49 | return 2407 + chan * 5; // MHz
50 | }
51 |
52 | #ifdef BRNCL_TIWLAN_HACK
53 | namespace TIWLAN {
54 | const unsigned PRIVATE_CMD_SET_FLAG = 0x00000001;
55 | const unsigned PRIVATE_CMD_GET_FLAG = 0x00000002;
56 |
57 | struct ti_private_cmd {
58 | uint32_t cmd; // parameter name
59 | uint32_t flags; // command action type (PRIVATE_CMD_SET_FLAG | PRIVATE_CMD_GET_FLAG)
60 | void* in_buffer; // Pointer to Input Buffer
61 | uint32_t in_buffer_len;
62 | void* out_buffer; // Pointer to Output buffer
63 | uint32_t out_buffer_len;
64 | };
65 |
66 |
67 | bool private_set(int sock, iwreq &iwr, uint32_t ioctl_cmd, uint32_t val) {
68 | ti_private_cmd cmd;
69 | cmd.cmd = ioctl_cmd;
70 | cmd.flags = PRIVATE_CMD_SET_FLAG;
71 | cmd.in_buffer = &val;
72 | cmd.in_buffer_len = sizeof(val);
73 |
74 | iwr.u.data.pointer = &cmd;
75 | iwr.u.data.length = sizeof(cmd);
76 | iwr.u.data.flags = 0;
77 | return (ioctl(sock, SIOCIWFIRSTPRIV, &iwr) == 0);
78 | }
79 |
80 | bool private_get(int sock, iwreq &iwr, uint32_t ioctl_cmd, uint32_t &val) {
81 | ti_private_cmd cmd;
82 | cmd.cmd = ioctl_cmd;
83 | cmd.flags = PRIVATE_CMD_SET_FLAG;
84 | cmd.out_buffer = &val;
85 | cmd.out_buffer_len = sizeof(val);
86 |
87 | iwr.u.data.pointer = &cmd;
88 | iwr.u.data.length = sizeof(cmd);
89 | iwr.u.data.flags = 0;
90 | return (ioctl(sock, SIOCIWFIRSTPRIV, &iwr) == 0);
91 | }
92 |
93 |
94 | const unsigned SET_BIT = 0x08000000;
95 | const unsigned GET_BIT = 0x00800000;
96 | const unsigned RSN_MODULE_PARAM = 0x0800;
97 | const unsigned RSN_ENCRYPTION_STATUS_PARAM = SET_BIT | GET_BIT | RSN_MODULE_PARAM | 0x04;
98 |
99 | bool enable_wep(int sock, iwreq &iwr, bool yes) {
100 | return private_set(sock, iwr, RSN_ENCRYPTION_STATUS_PARAM, yes ? 1 : 0);
101 | }
102 |
103 | bool check_wep(int sock, iwreq &iwr, uint32_t &v) {
104 | return private_get(sock, iwr, RSN_ENCRYPTION_STATUS_PARAM, v);
105 | }
106 | };
107 | #endif // BRNCL_TIWLAN_HACK
108 |
109 | /**
110 | * combines ifconfig and iwconfig
111 | */
112 | class IwCtl : public IfCtl {
113 | protected:
114 | // TODO: add event socket?
115 | iwreq _iwr; // iwconfig
116 |
117 | bool _setChannel(int chan) {
118 | _iwr.u.freq.m = chan;
119 | _iwr.u.freq.i = 0;
120 | _iwr.u.freq.e = 3; // kHz
121 | if (ioctl(_sock, SIOCSIWFREQ, &_iwr)) {
122 | DBG("Could not set freq: %s\n", strerror(errno));
123 | return false;
124 | }
125 | return true;
126 | }
127 |
128 | public:
129 | IwCtl(const char *iface) : IfCtl(iface) {
130 | strncpy(_iwr.ifr_name, iface, IFNAMSIZ);
131 | _iwr.ifr_name[IFNAMSIZ-1] = 0;
132 | }
133 |
134 | bool setMode(int mode = IW_MODE_ADHOC) {
135 | _iwr.u.mode = mode;
136 | if (ioctl(_sock, SIOCSIWMODE, &_iwr)) {
137 | fail("Could not set ad-hoc mode");
138 | return false;
139 | }
140 | return true;
141 | }
142 |
143 | bool setChannel(int chan) {
144 | // TIWLAN is broken and thinks freq is channel idx
145 | return _setChannel(chan) || _setChannel(chan2freq(chan));
146 | }
147 |
148 | bool setBssid(uint8_t *bssid) {
149 | _iwr.u.ap_addr.sa_family = ARPHRD_ETHER;
150 | memcpy(_iwr.u.ap_addr.sa_data, bssid, ETHER_ADDR_LEN);
151 | if (ioctl(_sock, SIOCSIWAP, &_iwr)) {
152 | fail("Could not set bssid");
153 | return false;
154 | }
155 | return true;
156 | }
157 |
158 | bool setEssid(char *essid, int len) {
159 | // --> initiates association
160 | if (len < 0)
161 | len = strlen(essid);
162 | if (len > IW_ESSID_MAX_SIZE) {
163 | len = IW_ESSID_MAX_SIZE;
164 | }
165 | _iwr.u.essid.flags = 1; // not promiscuous
166 | _iwr.u.essid.length = len;
167 | _iwr.u.essid.pointer = (caddr_t) essid;
168 | if (ioctl(_sock, SIOCSIWESSID, &_iwr)) {
169 | fail("Could not set ssid");
170 | return false;
171 | }
172 | return true;
173 | }
174 |
175 | bool commit() {
176 | if (ioctl(_sock, SIOCSIWCOMMIT, &_iwr)) {
177 | return false;
178 | }
179 | return true;
180 | }
181 |
182 | bool setAuthParam(int idx, uint32_t value) {
183 | _iwr.u.param.flags = idx & IW_AUTH_INDEX;
184 | _iwr.u.param.value = value;
185 | if (ioctl(_sock, SIOCSIWAUTH, &_iwr) < 0) {
186 | DBG("Could not set auth param: %s\n", strerror(errno));
187 | return false;
188 | }
189 | return true;
190 | }
191 |
192 | bool setWepKey(int idx, uint8_t *key, int len) {
193 | _iwr.u.encoding.flags = (idx + 1) & IW_ENCODE_INDEX;
194 | if (key) {
195 | _iwr.u.encoding.flags |= IW_ENCODE_OPEN;
196 | _iwr.u.encoding.pointer = (caddr_t) key;
197 | _iwr.u.encoding.length = len;
198 | } else {
199 | _iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
200 | _iwr.u.encoding.pointer = (caddr_t) NULL;
201 | _iwr.u.encoding.length = 0;
202 | }
203 | //_iwr.u.data = _iwr.u.encoding;
204 | if (ioctl(_sock, SIOCSIWENCODE, &_iwr) < 0) {
205 | ERR("Could not set WEP key %d: %s\n", idx, strerror(errno));
206 | return false;
207 | }
208 | return true;
209 | }
210 |
211 | bool setWepTx(int idx) {
212 | _iwr.u.encoding.flags = (idx + 1) & IW_ENCODE_INDEX;
213 | _iwr.u.encoding.pointer = (caddr_t) NULL;
214 | _iwr.u.encoding.length = 0;
215 | //_iwr.u.data = _iwr.u.encoding;
216 | if (ioctl(_sock, SIOCSIWENCODE, &_iwr) < 0) {
217 | ERR("Could not select WEP TX key %d: %s\n", idx, strerror(errno));
218 | return false;
219 | }
220 | return true;
221 | }
222 |
223 | bool disableWPA() {
224 | // disable WPA
225 | setAuthParam(IW_AUTH_WPA_VERSION, IW_AUTH_WPA_VERSION_DISABLED);
226 | setAuthParam(IW_AUTH_WPA_ENABLED, false);
227 | if (!setAuthParam(IW_AUTH_KEY_MGMT, 0)) {
228 | fail("Could not set KEY_MGMT to NONE");
229 | return false;
230 | }
231 | setAuthParam(IW_AUTH_PRIVACY_INVOKED, false);
232 |
233 | // setAuthParam(IW_AUTH_CIPHER_GROUP, IW_AUTH_CIPHER_NONE);
234 | // setAuthParam(IW_AUTH_CIPHER_PAIRWISE, IW_AUTH_CIPHER_NONE);
235 | // setAuthParam(IW_AUTH_RX_UNENCRYPTED_EAPOL, true);
236 | return true;
237 | }
238 |
239 | bool configureWep(const char *wep) {
240 | int len = 0;
241 | uint8_t key[WepSize104];
242 | if (wep_parse(wep, key))
243 | len = WepSize104;
244 | else if (wep_parse(wep, key))
245 | len = WepSize40;
246 | else {
247 | ERR("Failed to parse WEP\n");
248 | return false;
249 | }
250 |
251 | if ( disableWPA()
252 | && setWepKey(0, key, len)
253 | && setWepTx(0) ) {
254 | #ifdef BRNCL_TIWLAN_HACK
255 | if ((_iwr.ifr_name[0] == 't') && (_iwr.ifr_name[1] == 'i')) {
256 | // I think it's a TI device, let's try the priv ioctl:
257 | DBG("attempting private TI ioctl");
258 | if (!TIWLAN::enable_wep(_sock, _iwr, 1)) {
259 | DBG("Private ioctl (set) failed %s\n", strerror(errno));
260 | } else {
261 | uint32_t val = 7777;
262 | if (!TIWLAN::check_wep(_sock, _iwr, val)) {
263 | DBG("Private ioctl (get) failed %s\n", strerror(errno));
264 | } else {
265 | LOG("WEP status %d\n", val);
266 | }
267 | }
268 | }
269 | #endif // BRNCL_TIWLAN_HACK
270 | return true;
271 | }
272 | return false;
273 | }
274 |
275 | // TODO: monitor WLAN events
276 | };
277 |
278 | // find an interface interface in /proc/net/wireless or /proc/net/dev
279 | bool find_if(const char *filename, int nlines, char *ifname) {
280 | FILE *f = fopen(filename, "r");
281 | if (f) {
282 | char buf[512];
283 | for (int i = 0; i < nlines; ++i)
284 | if (!fgets(buf, 512, f)) return false;
285 |
286 | // eat up leading spaces
287 | char *ps = buf;
288 | while(isspace(*ps)) ++ps;
289 | // find delimiter
290 | char *pe = ps;
291 | while(isalnum(*pe)) ++pe;
292 | *pe = '\0';
293 | strncpy(ifname, ps, IFNAMSIZ-1);
294 | fclose(f);
295 | return true;
296 | }
297 | return false;
298 | }
299 |
300 |
301 | #endif // INCLUDED_IWCTL_HH
302 |
--------------------------------------------------------------------------------
/src/net/commotionwireless/meshtether/MeshTetherApp.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Commotion Mesh Tether
3 | * Copyright (C) 2010 by Szymon Jakubczak
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package net.commotionwireless.meshtether;
20 |
21 | import java.util.ArrayList;
22 | import java.util.HashMap;
23 | import java.util.Map;
24 | import java.util.Set;
25 | import java.util.concurrent.CopyOnWriteArraySet;
26 |
27 | import net.commotionwireless.olsrinfo.JsonInfo;
28 | import android.app.Notification;
29 | import android.app.NotificationManager;
30 | import android.app.PendingIntent;
31 | import android.content.Context;
32 | import android.content.Intent;
33 | import android.content.SharedPreferences;
34 | import android.net.Uri;
35 | import android.net.wifi.WifiManager;
36 | import android.preference.PreferenceManager;
37 | import android.util.Log;
38 | import android.widget.Toast;
39 |
40 |
41 | /**
42 | * Manages preferences, activities and prepares the service
43 | */
44 | public class MeshTetherApp extends android.app.Application {
45 | final static String TAG = "MeshTetherApp";
46 |
47 | final static String FILE_INI = "brncl.ini";
48 |
49 | final static String ACTION_CLIENTS = "net.commotionwireless.meshtether.SHOW_CLIENTS";
50 | final static String ACTION_TOGGLE = "net.commotionwireless.meshtether.TOGGLE_STATE";
51 | final static String ACTION_CHECK = "net.commotionwireless.meshtether.CHECK_STATE";
52 | final static String ACTION_CHANGED = "net.commotionwireless.meshtether.STATE_CHANGED";
53 |
54 | final static int ERROR_ROOT = 1;
55 | final static int ERROR_OTHER = 2;
56 | final static int ERROR_SUPPLICANT = 3;
57 |
58 | SharedPreferences prefs;
59 | StatusActivity statusActivity = null;
60 | LinksActivity linksActivity = null;
61 | InfoActivity infoActivity = null;
62 | private Toast toast;
63 |
64 | WifiManager wifiManager;
65 |
66 | // notifications
67 | private NotificationManager notificationManager;
68 | private Notification notification;
69 | private Notification notificationClientAdded;
70 | private Notification notificationError;
71 | final static int NOTIFY_RUNNING = 0;
72 | final static int NOTIFY_CLIENT = 1;
73 | final static int NOTIFY_ERROR = 2;
74 |
75 | JsonInfo mJsonInfo = null;
76 | Set profiles;
77 | Map profileProperties;
78 | String activeProfile;
79 |
80 | public MeshService service = null;
81 | public Util.StyledStringBuilder log = null; // == service.log, unless service is dead
82 |
83 | @Override
84 | public void onCreate() {
85 | super.onCreate();
86 | Log.d(TAG, "onCreate");
87 | NativeHelper.setup(this);
88 |
89 | // initialize default values if not done this in the past
90 | PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
91 | prefs = PreferenceManager.getDefaultSharedPreferences(this);
92 |
93 | // if IP address isn't set, generate one
94 | if (prefs.getString(getString(R.string.adhoc_ip), "").equals("")) {
95 | SharedPreferences.Editor e = prefs.edit();
96 | String myIP = "10." + String.valueOf((int)(Math.random() * 254))
97 | + "." + String.valueOf((int)(Math.random() * 254))
98 | + "." + String.valueOf((int)(Math.random() * 254));
99 | e.putString(getString(R.string.adhoc_ip), myIP);
100 | e.commit();
101 | Log.i(TAG, "Generated IP: " + myIP);
102 | }
103 |
104 | notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
105 | toast = Toast.makeText(this, "", Toast.LENGTH_SHORT);
106 | notification = new Notification(R.drawable.comlogo_sm_on, getString(R.string.notify_running), 0);
107 | notification.flags |= Notification.FLAG_ONGOING_EVENT;
108 | notificationClientAdded = new Notification(android.R.drawable.stat_sys_warning,
109 | getString(R.string.notify_client), 0);
110 | notificationClientAdded.flags = Notification.FLAG_AUTO_CANCEL;
111 | notificationError = new Notification(R.drawable.barnacle_error,
112 | getString(R.string.notify_error), 0);
113 | notificationError.setLatestEventInfo(this,
114 | getString(R.string.app_name),
115 | getString(R.string.notify_error),
116 | PendingIntent.getActivity(this, 0, new Intent(this, StatusActivity.class), 0));
117 | notificationError.flags = Notification.FLAG_AUTO_CANCEL;
118 |
119 | activeProfile = getString(R.string.defaultprofile);
120 |
121 | mJsonInfo = new JsonInfo();
122 | profiles = new CopyOnWriteArraySet();
123 | profiles.add(activeProfile);
124 | profileProperties = new HashMap();
125 |
126 | wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
127 | }
128 |
129 | @Override
130 | public void onTerminate() {
131 | if (service != null) {
132 | Log.e(TAG, "The app is terminated while the service is running!");
133 | service.stopRequest();
134 | }
135 | super.onTerminate();
136 | }
137 |
138 | public void startService() {
139 | if (service == null) {
140 | showProgressMessage(R.string.servicestarting);
141 | startService(new Intent(this, MeshService.class));
142 | }
143 | }
144 |
145 | public void stopService() {
146 | if (service != null)
147 | service.stopRequest();
148 | }
149 |
150 | public int getState() {
151 | if (service != null)
152 | return service.getState();
153 | return MeshService.STATE_STOPPED;
154 | }
155 |
156 | public boolean isChanging() {
157 | return getState() == MeshService.STATE_STARTING;
158 | }
159 |
160 | public boolean isRunning() {
161 | return getState() == MeshService.STATE_RUNNING;
162 | }
163 |
164 | public boolean isStopped() {
165 | return getState() == MeshService.STATE_STOPPED;
166 | }
167 |
168 | void setStatusActivity(StatusActivity a) { // for updates
169 | statusActivity = a;
170 | }
171 |
172 | void setLinksActivity(LinksActivity a) { // for updates
173 | linksActivity = a;
174 | }
175 |
176 | void setInfoActivity(InfoActivity a) { // for updates
177 | infoActivity = a;
178 | }
179 |
180 | void serviceStarted(MeshService s) {
181 | Log.w(TAG, "serviceStarted");
182 | service = s;
183 | log = service.log;
184 | service.startRequest();
185 | if (linksActivity != null)
186 | linksActivity.update();
187 | if (infoActivity != null)
188 | infoActivity.update();
189 | }
190 |
191 | static void broadcastState(Context ctx, int state) {
192 | Intent intent = new Intent(ACTION_CHANGED);
193 | intent.putExtra("state", state);
194 | ctx.sendBroadcast(intent, "net.commotionwireless.meshtether.ACCESS_STATE");
195 | }
196 |
197 | void updateStatus() {
198 | if (statusActivity != null)
199 | statusActivity.update();
200 | // TODO: only broadcast state if changed or stale, using a sticky intent broadcast
201 | broadcastState(this, getState());
202 | }
203 |
204 | void updateToast(String msg, boolean islong) {
205 | toast.setText(msg);
206 | toast.setDuration(islong ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT);
207 | toast.show();
208 | }
209 |
210 | void clientAdded(MeshService.ClientData cd) {
211 | if (prefs.getBoolean("client_notify", false)) {
212 | notificationClientAdded.defaults = 0;
213 | if (prefs.getBoolean("client_light", false)) {
214 | notificationClientAdded.flags |= Notification.FLAG_SHOW_LIGHTS;
215 | notificationClientAdded.ledARGB = 0xffffff00; // yellow
216 | notificationClientAdded.ledOnMS = 500;
217 | notificationClientAdded.ledOffMS = 1000;
218 | } else {
219 | notificationClientAdded.flags &= ~Notification.FLAG_SHOW_LIGHTS;
220 | }
221 | String sound = prefs.getString("client_sound", null);
222 | if (sound == null) {
223 | notificationClientAdded.defaults |= Notification.DEFAULT_SOUND;
224 | // | Notification.DEFAULT_VIBRATE // requires permission
225 | } else {
226 | if (sound.length() > 0)
227 | notificationClientAdded.sound = Uri.parse(sound);
228 | }
229 | Intent notificationIntent = new Intent(this, StatusActivity.class);
230 | notificationIntent.setAction(ACTION_CLIENTS);
231 | PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
232 | notificationClientAdded.setLatestEventInfo(this, getString(R.string.app_name),
233 | getString(R.string.notify_client) + " " + cd.toNiceString(), contentIntent);
234 | notificationManager.notify(NOTIFY_CLIENT, notificationClientAdded);
235 | }
236 |
237 | if (linksActivity != null)
238 | linksActivity.update();
239 | }
240 |
241 | void cancelClientNotify() {
242 | notificationManager.cancel(NOTIFY_CLIENT);
243 | }
244 |
245 | void processStarted() {
246 | Log.w(TAG, "processStarted");
247 | Intent notificationIntent = new Intent(this, StatusActivity.class);
248 | PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
249 | notification.setLatestEventInfo(this, getString(R.string.app_name),
250 | getString(R.string.notify_running), contentIntent);
251 | notificationManager.notify(NOTIFY_RUNNING, notification);
252 | service.startForegroundCompat(NOTIFY_RUNNING, notification);
253 | }
254 |
255 | void processStopped() {
256 | Log.w(TAG, "processStopped");
257 | notificationManager.cancel(NOTIFY_RUNNING);
258 | notificationManager.cancel(NOTIFY_CLIENT);
259 | if (service != null) service.stopSelf();
260 | service = null;
261 | updateStatus();
262 | }
263 |
264 | void failed(int err) {
265 | if (statusActivity != null) {
266 | if (err == ERROR_ROOT) {
267 | statusActivity.showDialog(StatusActivity.DLG_ROOT);
268 | } else if (err == ERROR_SUPPLICANT) {
269 | statusActivity.showDialog(StatusActivity.DLG_SUPPLICANT);
270 | } else if (err == ERROR_OTHER) {
271 | statusActivity.getTabHost().setCurrentTab(0); // show links
272 | statusActivity.showDialog(StatusActivity.DLG_ERROR);
273 | }
274 | }
275 | if ((statusActivity == null) || !statusActivity.hasWindowFocus()) {
276 | Log.d(TAG, "notifying error");
277 | notificationManager.notify(NOTIFY_ERROR, notificationError);
278 | }
279 | }
280 |
281 | /** find default route interface */
282 | protected boolean findIfWan() {
283 | // TODO move to Util.java and actually detect if there is a GSM/CDMA net connection
284 | String if_wan = prefs.getString(getString(R.string.if_wan), "");
285 | if (if_wan.length() != 0) return true;
286 |
287 | // must find mobile data interface
288 | ArrayList routes = Util.readLinesFromFile("/proc/net/route");
289 | for (int i = 1; i < routes.size(); ++i) {
290 | String line = routes.get(i);
291 | String[] tokens = line.split("\\s+");
292 | if (tokens[1].equals("00000000")) {
293 | // this is our default route
294 | if_wan = tokens[0];
295 | break;
296 | }
297 | }
298 | if (if_wan.length() != 0) {
299 | updateToast(getString(R.string.wanok) + if_wan, false);
300 | prefs.edit().putString(getString(R.string.if_wan), if_wan).commit();
301 | return true;
302 | }
303 | // it might be okay in local mode
304 | return prefs.getBoolean("wan_nowait", false);
305 | }
306 |
307 | protected void foundIfLan(String found_if_lan) {
308 | String if_lan = prefs.getString(getString(R.string.if_lan), "");
309 | if (if_lan.length() == 0) {
310 | updateToast(getString(R.string.lanok) + found_if_lan, false);
311 | }
312 | // NOTE: always use the name found by the process
313 | if_lan = found_if_lan;
314 | prefs.edit().putString(getString(R.string.if_lan), if_lan).commit();
315 | }
316 |
317 | void cleanUpNotifications() {
318 | if ((service != null) && (service.getState() == MeshService.STATE_STOPPED))
319 | processStopped(); // clean up notifications
320 | }
321 |
322 | void showProgressMessage(int resId) {
323 | showProgressMessage(getString(resId));
324 | }
325 |
326 | void showProgressMessage(String messageText) {
327 | Log.i(TAG, "MSG_PROGRESSDIALOG");
328 | if (messageText == null) messageText = "(null)";
329 | // TODO remove these null check and fix the actual bug! these should
330 | // always exist when this is called
331 | if (statusActivity == null) {
332 | Log.e(TAG, "statusActivity is null!");
333 | return;
334 | }
335 | if (statusActivity.mProgressDialog == null) {
336 | Log.e(TAG, "statusActivity.mProgressDialog is null!");
337 | return;
338 | }
339 | statusActivity.mProgressDialog.setMessage(messageText);
340 | if ( !statusActivity.mProgressDialog.isShowing())
341 | statusActivity.mProgressDialog.show();
342 | }
343 |
344 | void hideProgressDialog() {
345 | Log.i(TAG, "MSG_PROGRESSDIALOG_DISMISS");
346 | statusActivity.mProgressDialog.dismiss();
347 | }
348 | }
349 |
350 |
--------------------------------------------------------------------------------
/src/net/commotionwireless/meshtether/StatusActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Commotion Mesh Tether
3 | * Copyright (C) 2010 by Szymon Jakubczak
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package net.commotionwireless.meshtether;
20 |
21 | import java.io.File;
22 | import java.io.FileFilter;
23 | import java.io.FileWriter;
24 | import java.io.IOException;
25 | import java.text.NumberFormat;
26 | import java.util.ArrayList;
27 | import java.util.Collection;
28 | import java.util.Collections;
29 |
30 | import net.commotionwireless.olsrinfo.datatypes.OlsrDataDump;
31 | import android.app.AlertDialog;
32 | import android.app.Dialog;
33 | import android.app.ProgressDialog;
34 | import android.content.DialogInterface;
35 | import android.content.Intent;
36 | import android.net.Uri;
37 | import android.os.Bundle;
38 | import android.os.Handler;
39 | import android.os.Message;
40 | import android.util.Log;
41 | import android.view.Menu;
42 | import android.view.MenuItem;
43 | import android.view.View;
44 | import android.view.View.OnClickListener;
45 | import android.view.Window;
46 | import android.widget.Button;
47 | import android.widget.ImageButton;
48 | import android.widget.TabHost;
49 | import android.widget.TabHost.OnTabChangeListener;
50 | import android.widget.TextView;
51 |
52 | public class StatusActivity extends android.app.TabActivity {
53 | private MeshTetherApp app;
54 |
55 | private TabHost tabs;
56 | private ImageButton onoff;
57 | private Button chooseProfile;
58 | private AlertDialog.Builder profileDialogBuilder;
59 |
60 | private boolean paused;
61 |
62 | private TextView textDownloadRate;
63 | private TextView textUploadRate;
64 |
65 | final static int DLG_ABOUT = 0;
66 | final static int DLG_ROOT = 1;
67 | final static int DLG_ERROR = 2;
68 | final static int DLG_SUPPLICANT = 3;
69 |
70 | private final static String LINKS = "links";
71 | private final static String INFO = "info";
72 |
73 | static NumberFormat nf = NumberFormat.getInstance();
74 | static {
75 | nf.setMaximumFractionDigits(2);
76 | nf.setMinimumFractionDigits(2);
77 | nf.setMinimumIntegerDigits(1);
78 | }
79 |
80 | ProgressDialog mProgressDialog;
81 | final Handler mHandler = new Handler() {
82 | @Override
83 | public void handleMessage(Message msg) {
84 | mProgressDialog.setMessage(msg.getData().getString("message"));
85 | }
86 | };
87 |
88 | /** Called when the activity is first created. */
89 | @Override
90 | public void onCreate(Bundle savedInstanceState) {
91 | super.onCreate(savedInstanceState);
92 |
93 | app = (MeshTetherApp)getApplication();
94 |
95 | requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
96 | setProgressBarIndeterminate(true);
97 | setContentView(R.layout.main);
98 |
99 | // control interface
100 | onoff = (ImageButton) findViewById(R.id.onoff);
101 | onoff.setOnClickListener(new OnClickListener() {
102 | @Override
103 | public void onClick(View v) {
104 | int state = app.getState();
105 | if (state == MeshService.STATE_STOPPED) {
106 | chooseProfile.setEnabled(false);
107 | onoff.setImageResource(R.drawable.comlogo_sm_on);
108 | app.startService();
109 | } else {
110 | app.stopService();
111 | onoff.setImageResource(R.drawable.comlogo_sm_off);
112 | chooseProfile.setEnabled(true);
113 | update();
114 | }
115 | }
116 | });
117 |
118 | profileDialogBuilder = new AlertDialog.Builder(this);
119 | profileDialogBuilder.setTitle(R.string.choose_profile);
120 |
121 | chooseProfile = (Button) findViewById(R.id.choose_profile);
122 | chooseProfile.setOnClickListener(new OnClickListener() {
123 | @Override
124 | public void onClick(View v) {
125 | findProfilesOnDisk();
126 | final String[] profilesArray = app.profiles.toArray(new String[0]);
127 | profileDialogBuilder.setItems(profilesArray, new DialogInterface.OnClickListener() {
128 | @Override
129 | public void onClick(DialogInterface dialog, int which) {
130 | app.activeProfile = profilesArray[which];
131 | chooseProfile.setText(app.activeProfile);
132 | }
133 | });
134 | profileDialogBuilder.create().show();
135 | }
136 | });
137 |
138 | tabs = getTabHost();
139 | tabs.addTab(tabs.newTabSpec(LINKS)
140 | .setIndicator(LINKS, getResources().getDrawable(R.drawable.ic_tab_contacts))
141 | .setContent(new Intent(this, LinksActivity.class)));
142 | tabs.addTab(tabs.newTabSpec(INFO)
143 | .setIndicator(INFO, getResources().getDrawable(R.drawable.ic_tab_recent))
144 | .setContent(new Intent(this, InfoActivity.class)));
145 | tabs.setOnTabChangedListener(new OnTabChangeListener() {
146 | @Override
147 | public void onTabChanged(String tabId) {
148 | update();
149 | // force refresh of up/down stats
150 | if (app.service != null)
151 | app.service.statsRequest(0);
152 | if (INFO.equals(tabId))
153 | app.infoActivity.update();
154 | if (app.linksActivity != null)
155 | if (LINKS.equals(tabId))
156 | app.linksActivity.mPauseOlsrInfoThread = false;
157 | else
158 | app.linksActivity.mPauseOlsrInfoThread = true;
159 | }
160 | });
161 |
162 | app.setStatusActivity(this);
163 | paused = false;
164 |
165 | textDownloadRate = ((TextView)findViewById(R.id.download_rate));
166 | textUploadRate = ((TextView)findViewById(R.id.upload_rate));
167 |
168 | mProgressDialog = new ProgressDialog(this);
169 | mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
170 | }
171 | @Override
172 | protected void onDestroy() {
173 | super.onDestroy();
174 | app.setStatusActivity(null);
175 | }
176 | @Override
177 | public boolean onCreateOptionsMenu(Menu menu) {
178 | getMenuInflater().inflate(R.menu.main, menu);
179 | return true;
180 | }
181 | @Override
182 | public boolean onOptionsItemSelected(MenuItem item) {
183 | switch (item.getItemId()) {
184 | case R.id.menu_prefs:
185 | startActivity(new Intent(this, SettingsActivity.class));
186 | return true;
187 | case R.id.menu_about:
188 | showDialog(DLG_ABOUT);
189 | return true;
190 | case R.id.menu_share_debug:
191 | zipAndShareFile(new File(NativeHelper.app_log, "olsrd.log"));
192 | return true;
193 | case R.id.menu_share_status:
194 | getOlsrdStatusAndShare();
195 | return true;
196 | }
197 | return(super.onOptionsItemSelected(item));
198 | }
199 |
200 | private void findProfilesOnDisk() {
201 | FileFilter filter = new FileFilter() {
202 |
203 | @Override
204 | public boolean accept(File pathname) {
205 | if (pathname.getAbsolutePath().endsWith(".properties"))
206 | return true;
207 | return false;
208 | }
209 | };
210 | Collection all = new ArrayList();
211 | Collections.addAll(all, NativeHelper.app_bin.listFiles(filter));
212 | Collections.addAll(all, NativeHelper.profileDir.listFiles(filter));
213 | for (File f : all) {
214 | Log.i(MeshTetherApp.TAG, "Searching for profile: " + f.getAbsolutePath());
215 | String path = f.getAbsolutePath();
216 | String profileName = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf(".properties"));
217 | app.profiles.add(profileName);
218 | app.profileProperties.put(profileName, path);
219 | }
220 | }
221 |
222 | private void getOlsrdStatusAndShare() {
223 | if (app.getState() == MeshService.STATE_RUNNING) {
224 | app.linksActivity.mPauseOlsrInfoThread = true;
225 | mProgressDialog.setMessage("Generating...");
226 | mProgressDialog.show();
227 | new Thread() {
228 |
229 | private void showMessage(int messageId) {
230 | String message = getString(messageId);
231 | Message msg = mHandler.obtainMessage();
232 | Bundle b = new Bundle();
233 | b.putString("message", message);
234 | msg.setData(b);
235 | mHandler.sendMessage(msg);
236 | }
237 |
238 | @Override
239 | public void run() {
240 | try {
241 | showMessage(R.string.gettingolsrinfo);
242 | OlsrDataDump dump = app.mJsonInfo.all();
243 | showMessage(R.string.writingfile);
244 | String filename;
245 | if (dump.uuid == null || dump.uuid.contentEquals(""))
246 | filename = new String("olsrd-status-" + dump.systemTime + ".json");
247 | else
248 | filename = new String("olsrd-status-" + dump.systemTime + "_" + dump.uuid + ".json");
249 | final File f = new File(NativeHelper.app_log, filename);
250 | FileWriter fw = new FileWriter(f);
251 | fw.write(dump.toString());
252 | fw.close();
253 | showMessage(R.string.zippingfile);
254 | zipAndShareFile(f);
255 | } catch (IOException e) {
256 | e.printStackTrace();
257 | }
258 | mProgressDialog.dismiss();
259 | app.linksActivity.mPauseOlsrInfoThread = false;
260 | }
261 | }.start();
262 | } else {
263 | // nothing to do, since we can't talk to olsrd
264 | app.updateToast(getString(R.string.olsrdnotrunning), true);
265 | return;
266 | }
267 | }
268 |
269 | private void zipAndShareFile(File f) {
270 | if (! NativeHelper.isSdCardPresent()) {
271 | app.updateToast("Cannot find SD card, needed for saving the zip file.", true);
272 | return;
273 | }
274 | if (! f.exists()) {
275 | app.updateToast(f.getAbsolutePath() + " does not exist!", true);
276 | return;
277 | }
278 | final File zipFile = new File(NativeHelper.publicFiles, f.getName() + ".zip");
279 | try {
280 | NativeHelper.zip(f, zipFile);
281 | } catch (IOException e) {
282 | e.printStackTrace();
283 | return;
284 | }
285 | Intent i = new Intent(android.content.Intent.ACTION_SEND);
286 | i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
287 | i.setType("application/zip");
288 | i.putExtra(Intent.EXTRA_SUBJECT, "log from Commotion Mesh Tether");
289 | i.putExtra(Intent.EXTRA_TEXT, "Attached is an log sent by Commotion Mesh Tether. For more info, see:\nhttps://code.commotionwireless.net/projects/commotion-android");
290 | i.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(zipFile));
291 | startActivity(Intent.createChooser(i, "How do you want to share?"));
292 | }
293 |
294 | @Override
295 | protected Dialog onCreateDialog(int id) {
296 | // TODO: these should not create and remove dialogs, but restore and dismiss
297 | if (id == DLG_ABOUT) {
298 | return (new AlertDialog.Builder(this))
299 | .setIcon(android.R.drawable.ic_dialog_info)
300 | .setTitle(R.string.help_title)
301 | .setMessage(R.string.help_message)
302 | .setPositiveButton("Live Chat", new DialogInterface.OnClickListener() {
303 | @Override
304 | public void onClick(DialogInterface dialog, int which) {
305 | Uri uri = Uri.parse(getString(R.string.ircUrl));
306 | startActivity(new Intent(Intent.ACTION_VIEW, uri));
307 | }})
308 | .setNeutralButton("Website", new DialogInterface.OnClickListener() {
309 | @Override
310 | public void onClick(DialogInterface dialog, int which) {
311 | Uri uri = Uri.parse(getString(R.string.websiteUrl));
312 | startActivity(new Intent(Intent.ACTION_VIEW, uri));
313 | }})
314 | .setNegativeButton("OK", new DialogInterface.OnClickListener() {
315 | @Override
316 | public void onClick(DialogInterface dialog, int which) { removeDialog(DLG_ABOUT); }})
317 | .create();
318 | }
319 | if (id == DLG_ROOT) {
320 | return (new AlertDialog.Builder(this))
321 | .setIcon(android.R.drawable.ic_dialog_alert)
322 | .setTitle("Root Access")
323 | .setMessage("MeshTether requires 'su' to access the hardware! Please, make sure you have root access.")
324 | .setPositiveButton("Help", new DialogInterface.OnClickListener() {
325 | @Override
326 | public void onClick(DialogInterface dialog, int which) {
327 | Uri uri = Uri.parse(getString(R.string.rootUrl));
328 | startActivity(new Intent(Intent.ACTION_VIEW, uri));
329 | }})
330 | .setNegativeButton("Close", new DialogInterface.OnClickListener() {
331 | @Override
332 | public void onClick(DialogInterface dialog, int which) { removeDialog(DLG_ROOT); }})
333 | .create();
334 | }
335 | if (id == DLG_ERROR) {
336 | return (new AlertDialog.Builder(this))
337 | .setIcon(android.R.drawable.ic_dialog_alert)
338 | .setTitle("Error")
339 | .setMessage("Unexpected error occured! Check the troubleshooting guide for the error printed in the log tab.")
340 | .setPositiveButton("Help", new DialogInterface.OnClickListener() {
341 | @Override
342 | public void onClick(DialogInterface dialog, int which) {
343 | Uri uri = Uri.parse(getString(R.string.fixUrl));
344 | startActivity(new Intent(Intent.ACTION_VIEW, uri));
345 | }})
346 | .setNegativeButton("Close", new DialogInterface.OnClickListener() {
347 | @Override
348 | public void onClick(DialogInterface dialog, int which) { removeDialog(DLG_ERROR); }})
349 | .create();
350 | }
351 | if (id == DLG_SUPPLICANT) {
352 | return (new AlertDialog.Builder(this))
353 | .setIcon(android.R.drawable.ic_dialog_alert)
354 | .setTitle("Supplicant not available")
355 | .setMessage("MeshTether had trouble starting wpa_supplicant. Try again but set 'Skip wpa_supplicant' in settings.")
356 | .setPositiveButton("Do it now!", new DialogInterface.OnClickListener() {
357 | @Override
358 | public void onClick(DialogInterface dialog, int which) {
359 | app.prefs.edit().putBoolean(getString(R.string.lan_wext), true).commit();
360 | app.updateToast("Settings updated, try again...", true);
361 | }})
362 | .setNeutralButton("More info", new DialogInterface.OnClickListener() {
363 | @Override
364 | public void onClick(DialogInterface dialog, int which) {
365 | Uri uri = Uri.parse(getString(R.string.wikiUrl));
366 | startActivity(new Intent(Intent.ACTION_VIEW, uri));
367 | }})
368 | .setNegativeButton("Close", new DialogInterface.OnClickListener() {
369 | @Override
370 | public void onClick(DialogInterface dialog, int which) { removeDialog(DLG_ROOT); }})
371 | .create();
372 | }
373 | return null;
374 | }
375 |
376 | @Override
377 | protected void onPause() {
378 | super.onPause();
379 | paused = true;
380 | }
381 | @Override
382 | protected void onResume() {
383 | super.onResume();
384 | paused = false;
385 | update();
386 | app.cleanUpNotifications();
387 | }
388 | @Override
389 | protected void onNewIntent(Intent intent) {
390 | super.onNewIntent(intent);
391 | if (MeshTetherApp.ACTION_CLIENTS.equals(intent.getAction())) {
392 | getTabHost().setCurrentTab(0); // show links
393 | }
394 | }
395 |
396 | static String formatRate(long v) {
397 | if (v < 1048576)
398 | return nf.format(v / 1024.0f) + " KB";
399 | else
400 | return nf.format(v / 1048576.0f) + " MB";
401 | }
402 |
403 | void update() {
404 | int state = app.getState();
405 |
406 | if (state == MeshService.STATE_STOPPED) {
407 | if (textDownloadRate != null)
408 | textDownloadRate.setText("---");
409 | if (textUploadRate != null)
410 | textUploadRate.setText("---");
411 | return;
412 | }
413 |
414 | MeshService svc = app.service;
415 | if (svc == null) return; // unexpected race condition
416 |
417 | if (state == MeshService.STATE_STARTING) {
418 | setProgressBarIndeterminateVisibility(true);
419 | return;
420 | }
421 |
422 | if (state != MeshService.STATE_RUNNING) {
423 | // this is unexpected, but don't fail
424 | return;
425 | }
426 |
427 | // STATE_RUNNING
428 | setProgressBarIndeterminateVisibility(false);
429 |
430 | Util.TrafficStats stats = svc.stats;
431 | if (textDownloadRate != null)
432 | textDownloadRate.setText(formatRate(stats.rate.tx_bytes)+"/s");
433 | if (textUploadRate != null)
434 | textUploadRate.setText(formatRate(stats.rate.rx_bytes)+"/s");
435 | // only request stats when visible
436 | if (!paused)
437 | svc.statsRequest(1000);
438 | }
439 | }
440 |
--------------------------------------------------------------------------------
/src/net/commotionwireless/meshtether/MeshService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Commotion Mesh Tether
3 | * Copyright (C) 2010 by Szymon Jakubczak
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | package net.commotionwireless.meshtether;
20 |
21 | import java.io.File;
22 | import java.io.FileInputStream;
23 | import java.io.IOException;
24 | import java.lang.reflect.InvocationTargetException;
25 | import java.lang.reflect.Method;
26 | import java.util.ArrayList;
27 | import java.util.Map;
28 | import java.util.Properties;
29 |
30 | import net.commotionwireless.meshtether.Util.MACAddress;
31 | import android.app.Notification;
32 | import android.content.BroadcastReceiver;
33 | import android.content.ContentResolver;
34 | import android.content.Context;
35 | import android.content.Intent;
36 | import android.content.IntentFilter;
37 | import android.content.SharedPreferences;
38 | import android.net.ConnectivityManager;
39 | import android.net.NetworkInfo;
40 | import android.net.wifi.WifiConfiguration;
41 | import android.net.wifi.WifiInfo;
42 | import android.net.wifi.WifiManager;
43 | import android.os.Handler;
44 | import android.os.IBinder;
45 | import android.os.Message;
46 | import android.os.PowerManager;
47 | import android.preference.PreferenceManager;
48 | import android.provider.Settings;
49 | import android.util.Log;
50 |
51 | import net.commotionwireless.shell.*;
52 |
53 | /**
54 | * Manages the running process, client list, and log
55 | */
56 | public class MeshService extends android.app.Service {
57 | final static String TAG = "MeshService";
58 | // messages from the process
59 | final static int MSG_OUTPUT = 1;
60 | final static int MSG_ERROR = 2;
61 | // messages from self
62 | final static int MSG_EXCEPTION = 3;
63 | final static int MSG_NETSCHANGE = 4;
64 | // requests from activities
65 | final static int MSG_START = 5;
66 | final static int MSG_STOP = 6;
67 | final static int MSG_ASSOC = 7;
68 | final static int MSG_STATS = 8;
69 | final static int MSG_STOP_OLSRD_OUTPUT = 10;
70 | // messages for the ProgressDialog
71 | final static int MSG_SHOW_PROGRESSDIALOG = 11;
72 | final static int MSG_HIDE_PROGRESSDIALOG = 12;
73 | // app states
74 | public final static int STATE_STOPPED = 0;
75 | public final static int STATE_STARTING = 1;
76 | public final static int STATE_RUNNING = 2; // process said OK
77 |
78 | // private state
79 | private int state = STATE_STOPPED;
80 | private WifiManager.WifiLock wifiLock;
81 |
82 | private String activeSSID = "";
83 | private String activeBSSID = "";
84 | private String activeIP = "";
85 | private String activeNetmask = "";
86 | private String activeIpGeneration = "";
87 | private String activeDNS = "";
88 | private String activeOlsrdConf = "";
89 |
90 | private Shell mShell;
91 | private ShellProcess WifiShellProcess;
92 |
93 | private PowerManager.WakeLock wakeLock;
94 | private BroadcastReceiver connectivityReceiver = new BroadcastReceiver() {
95 | @Override
96 | public void onReceive(Context context, Intent intent) {
97 | mHandler.sendEmptyMessage(MSG_NETSCHANGE);
98 | }
99 | };
100 |
101 | // public state
102 | public final Util.StyledStringBuilder log = new Util.StyledStringBuilder();
103 |
104 | final static int COLOR_ERROR = 0xffff2222;
105 | final static int COLOR_LOG = 0xff888888;//android.R.color.primary_text_dark;
106 | final static int COLOR_TIME = 0xffffffff;
107 |
108 | public static class ClientData {
109 | final String remoteIP;
110 | final float linkQuality;
111 | final float neighborLinkQuality;
112 | final int linkCost;
113 | final int validityTime;
114 | boolean hasRouteToOther;
115 | boolean hasDefaultRoute;
116 | ClientData(String ip, float lq, float nlq, int lc, int vt) {
117 | remoteIP = ip;
118 | linkQuality = lq;
119 | neighborLinkQuality = nlq;
120 | linkCost = lc;
121 | validityTime = vt;
122 | hasRouteToOther = false;
123 | hasDefaultRoute = false;
124 | }
125 | @Override
126 | public String toString() { return remoteIP + " " + linkQuality + " " + neighborLinkQuality; }
127 | public String toNiceString() { return remoteIP; }
128 | }
129 | public final ArrayList clients = new ArrayList();
130 | public final Util.TrafficStats stats = new Util.TrafficStats();
131 |
132 | // WARNING: this is not entirely safe
133 | public static MeshService singleton = null;
134 |
135 | // cached for convenience
136 | private String if_lan = "";
137 | private Util.MACAddress if_mac = null;
138 | private MeshTetherApp app;
139 | private WifiManager wifiManager;
140 | private int currentNetId = -1;
141 | private ConnectivityManager connManager;
142 | private boolean filteringEnabled = false;
143 | private Method mStartForeground = null;
144 |
145 | /** public service interface */
146 | public void startRequest() {
147 | mHandler.sendEmptyMessage(MSG_START);
148 | }
149 |
150 | public void assocRequest() {
151 | mHandler.sendEmptyMessage(MSG_ASSOC);
152 | }
153 |
154 | public void stopRequest() {
155 | mHandler.sendEmptyMessage(MSG_STOP);
156 | }
157 |
158 | public void statsRequest(long delay) {
159 | Message msg = mHandler.obtainMessage(MSG_STATS);
160 | mHandler.sendMessageDelayed(msg, delay);
161 | }
162 |
163 | public int getState() {
164 | return state;
165 | }
166 |
167 | public boolean hasFiltering() {
168 | return filteringEnabled;
169 | }
170 |
171 | @Override
172 | public void onCreate() {
173 | super.onCreate();
174 | singleton = this;
175 |
176 | mShell = Shell.getInstance();
177 |
178 | wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
179 | connManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
180 |
181 | try {
182 | mStartForeground = getClass().getMethod("startForeground", new Class[] {
183 | int.class, Notification.class});
184 | } catch (NoSuchMethodException e) {
185 | mStartForeground = null;
186 | }
187 |
188 | state = STATE_STOPPED;
189 | filteringEnabled = false;
190 |
191 | app = (MeshTetherApp)getApplication();
192 | app.serviceStarted(this);
193 |
194 | PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
195 | wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MeshService");
196 | wakeLock.acquire();
197 |
198 | wifiLock = wifiManager.createWifiLock (WifiManager.WIFI_MODE_FULL, "MeshService");
199 | // WifiManager.WIFI_MODE_FULL_HIGH_PERF is only available at API level 12
200 |
201 | IntentFilter filter = new IntentFilter();
202 | filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
203 | filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
204 | registerReceiver(connectivityReceiver, filter);
205 |
206 | }
207 |
208 | @Override
209 | public void onDestroy() {
210 | if (state != STATE_STOPPED)
211 | Log.e(TAG, "service destroyed while running!");
212 | // ensure we clean up
213 | stopProcess();
214 | state = STATE_STOPPED;
215 | app.processStopped();
216 | wakeLock.release();
217 |
218 | mShell.stopShell();
219 |
220 | try {
221 | unregisterReceiver(connectivityReceiver);
222 | } catch (Exception e) {
223 | // ignore
224 | }
225 |
226 | singleton = null;
227 | super.onDestroy();
228 | }
229 |
230 | private static String getWifiStateString(int state) {
231 | switch (state) {
232 | case WifiManager.WIFI_STATE_ENABLED:
233 | return "WIFI_STATE_ENABLED";
234 | case WifiManager.WIFI_STATE_ENABLING:
235 | return "WIFI_STATE_ENABLING";
236 | case WifiManager.WIFI_STATE_DISABLED:
237 | return "WIFI_STATE_DISABLED";
238 | case WifiManager.WIFI_STATE_DISABLING:
239 | return "WIFI_STATE_DISABLING";
240 | case WifiManager.WIFI_STATE_UNKNOWN:
241 | return "WIFI_STATE_UNKNOWN";
242 | default:
243 | return "(none)";
244 | }
245 | }
246 |
247 | // our handler
248 | private final Handler mHandler = new Handler() {
249 | @Override
250 | public void handleMessage(Message msg) { handle(msg); }
251 | };
252 | private ShellProcess mDelRouteProcess;
253 |
254 | private void handle(Message msg) {
255 | switch (msg.what) {
256 | case MSG_SHOW_PROGRESSDIALOG:
257 | Log.i(TAG, "handle MSG_SHOW_PROGRESSDIALOG");
258 | app.showProgressMessage((String)msg.obj);
259 | break;
260 | case MSG_HIDE_PROGRESSDIALOG:
261 | Log.i(TAG, "handle MSG_HIDE_PROGRESSDIALOG");
262 | app.hideProgressDialog();
263 | break;
264 | case MSG_EXCEPTION:
265 | Log.i(TAG, "handle MSG_EXCEPTION");
266 | if (state == STATE_STOPPED) return;
267 | Throwable thr = (Throwable)msg.obj;
268 | log(true, getString(R.string.exception) + " " + thr.getMessage());
269 | Log.e(TAG, "Exception " + thr.getMessage() + " " + Log.getStackTraceString(thr));
270 | stopProcess();
271 | mShell.stopShell();
272 | state = STATE_STOPPED;
273 | break;
274 | case MSG_ERROR:
275 | Log.i(TAG, "handle MSG_ERROR");
276 | if (state == STATE_STOPPED) return;
277 | if (WifiShellProcess == null) return; // don't kill it again...
278 | if (msg.obj != null) {
279 | String line = (String)msg.obj;
280 | log(true, line); // just dump it and ignore it
281 | } else {
282 | // no message, means process died
283 | log(true, getString(R.string.unexpected));
284 | stopProcess();
285 | mShell.stopShell();
286 |
287 | if ((state == STATE_STARTING)) {
288 | String err = log.toString();
289 | if (isRootError(err)) {
290 | app.failed(MeshTetherApp.ERROR_ROOT);
291 | } else if (isSupplicantError(err)) {
292 | app.failed(MeshTetherApp.ERROR_SUPPLICANT);
293 | } else {
294 | app.failed(MeshTetherApp.ERROR_OTHER);
295 | }
296 | } else {
297 | app.failed(MeshTetherApp.ERROR_OTHER);
298 | }
299 | state = STATE_STOPPED;
300 | }
301 | break;
302 | case MSG_OUTPUT:
303 | Log.i(TAG, "handle MSG_OUTPUT");
304 | if (state == STATE_STOPPED) return;
305 | if (WifiShellProcess == null) return; // cut the gibberish
306 | String line = (String)msg.obj;
307 | if (line == null) {
308 | // ignore it, wait for MSG_ERROR(null)
309 | break;
310 | }
311 | if (line.startsWith("WIFI: OK")) {
312 | // WIFI: OK
313 | String[] parts = line.split(" +");
314 | if_lan = parts[2];
315 | if_mac = Util.MACAddress.parse(parts[3]);
316 | if (state == STATE_STARTING) {
317 | state = STATE_RUNNING;
318 | log(false, getString(R.string.running));
319 | clients.clear();
320 | stats.init(Util.fetchTrafficData(if_lan));
321 | //app.foundIfLan(if_lan); // this will allow 3G <-> 4G with simple restart
322 | app.processStarted();
323 | mHandler.sendEmptyMessage(MSG_ASSOC);
324 | mHandler.sendEmptyMessage(MSG_HIDE_PROGRESSDIALOG);
325 | }
326 | } else {
327 | log(false, line);
328 | }
329 | break;
330 | case MSG_START:
331 | Log.i(TAG, "handle MSG_START");
332 |
333 | if (state != STATE_STOPPED) return;
334 | log.clear();
335 |
336 | if ( !setMeshProfile())
337 | break;
338 | log(false, getString(R.string.starting) + " " + activeSSID);
339 |
340 | // TODO make this only overwrite on upgrade to new version
341 | log(false, getString(R.string.unpacking));
342 | if (!NativeHelper.unzipAssets(this) || !NativeHelper.installBusyboxSymlinks()) {
343 | log(true, getString(R.string.unpackerr));
344 | state = STATE_STOPPED;
345 | break;
346 | }
347 |
348 | if ( !wifiManager.isWifiEnabled()) {
349 | log(false, getString(R.string.enablingwifi));
350 | wifiManager.setWifiEnabled(true); // this will send MSG_NETSCHANGE
351 | }
352 | if (wifiManager.getConnectionInfo().getIpAddress() != 0) // if connected, disconnect
353 | wifiManager.disconnect(); // this will send MSG_NETSCHANGE
354 |
355 | mShell.setForkCommand(NativeHelper.SU_C_FORK, buildEnvFromPrefs());
356 | mShell.startShell();
357 | Shell.waitForShellToStart(mShell);
358 |
359 | state = STATE_STARTING;
360 | // FALL THROUGH!
361 | case MSG_NETSCHANGE:
362 | Log.i(TAG, "handle MSG_NETSCHANGE");
363 | int wifiState = wifiManager.getWifiState();
364 | String wifiStateString = getWifiStateString(wifiState);
365 | if (wifiState == WifiManager.WIFI_STATE_ENABLED) {
366 | // wifi is good (or lost), we can start now...
367 | if ((state == STATE_STARTING) && (WifiShellProcess == null)) {
368 | if (app.findIfWan()) {
369 | // TODO if WAN found with checkUplink(), then setup Hna4 routing
370 | log(false, "Found active WAN interface");
371 | } else {
372 | ///log(true, getString(R.string.wanerr));
373 | //state = STATE_STOPPED;
374 | //break;
375 | log(false, "No active WAN interface found");
376 | }
377 |
378 | log(false, "Enabling wifi for " + activeSSID);
379 | WifiConfiguration wc = new WifiConfiguration();
380 | wc.priority = 100000;
381 | wc.hiddenSSID = true; // Android won't see Adhoc SSIDs
382 | wc.status = WifiConfiguration.Status.ENABLED;
383 | wc.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
384 | wc.SSID = activeSSID;
385 | wc.BSSID = activeBSSID;
386 | currentNetId = wifiManager.addNetwork(wc);
387 | if(currentNetId < 0) {
388 | System.out.println("Unable to add network configuration for " + activeSSID);
389 | return;
390 | }
391 | wifiManager.enableNetwork(currentNetId, true);
392 |
393 | // set up the static IP settings
394 | // TODO read and store the current settings so they can be restored on stop
395 | log(false, "Setting up IP config");
396 | final ContentResolver cr = getContentResolver();
397 | Settings.System.putInt(cr, Settings.System.WIFI_USE_STATIC_IP, 1);
398 | Settings.System.putString(cr, Settings.System.WIFI_STATIC_IP, activeIP);
399 | Settings.System.putString(cr, Settings.System.WIFI_STATIC_NETMASK, activeNetmask);
400 | Settings.System.putString(cr, Settings.System.WIFI_STATIC_GATEWAY, activeIP);
401 | Settings.System.putString(cr, Settings.System.WIFI_STATIC_DNS1, activeDNS);
402 |
403 | // meshing works very poorly with wifi sleep enabled
404 | // TODO check if this sticks after the app quits, if so
405 | // save the current value and restore it on stopping
406 | Settings.System.putInt(cr, Settings.System.WIFI_SLEEP_POLICY,
407 | Settings.System.WIFI_SLEEP_POLICY_NEVER);
408 |
409 | if (!startProcess()) {
410 | log(true, getString(R.string.starterr));
411 | state = STATE_STOPPED;
412 | break;
413 | }
414 | } // if not checkUpLink then we simply wait...
415 | } else { // not WIFI_STATE_ENABLED
416 | app.updateToast("WIFI: " + wifiStateString, false); log(false, "WIFI: " + wifiStateString);
417 | switch (state) {
418 | case STATE_RUNNING:
419 | app.updateToast("STATE_RUNNING", true); log(false, "STATE_RUNNING");
420 | stopProcess(); // this tears down everything
421 | mShell.stopShell();
422 | state = STATE_STARTING;
423 | break;
424 | case STATE_STARTING:
425 | app.updateToast("STATE_STARTING", false); log(false, "STATE_STARTING");
426 | break;
427 | case STATE_STOPPED:
428 | app.updateToast("STATE_STOPPED", false); log(false, "STATE_STOPPED");
429 | break;
430 | default:
431 | app.updateToast("Something went wrong...", false); log(false, "Something went wrong...");
432 | }
433 | }
434 | break;
435 | case MSG_STOP:
436 | Log.i(TAG, "handle MSG_STOP");
437 | if (state == STATE_STOPPED) return;
438 | stopProcess();
439 | mShell.stopShell();
440 | wifiManager.disableNetwork(currentNetId);
441 | wifiManager.removeNetwork(currentNetId);
442 | final ContentResolver cr = getContentResolver();
443 | Settings.System.putInt(cr, Settings.System.WIFI_USE_STATIC_IP, 0);
444 | log(false, getString(R.string.stopped));
445 | state = STATE_STOPPED;
446 | break;
447 | case MSG_ASSOC:
448 | Log.i(TAG, "handle MSG_ASSOC");
449 | if (state != STATE_RUNNING) return;
450 | if (tellProcess("WLAN")) {
451 | app.updateToast(getString(R.string.beaconing), true);
452 | }
453 | if (clients.isEmpty() && app.prefs.getBoolean("lan_autoassoc", false)) {
454 | mHandler.removeMessages(MSG_ASSOC);
455 | // rebeacon, in 5 seconds
456 | mHandler.sendEmptyMessageDelayed(MSG_ASSOC, 5000);
457 | }
458 | break;
459 | case MSG_STATS:
460 | //Log.i(TAG, "handle MSG_STATS");
461 | mHandler.removeMessages(MSG_STATS);
462 | if (state != STATE_RUNNING || if_lan.length() == 0) return;
463 | stats.update(Util.fetchTrafficData(if_lan));
464 | break;
465 | }
466 | app.updateStatus();
467 | if (state == STATE_STOPPED) {
468 | app.processStopped();
469 | app.hideProgressDialog();
470 | }
471 | }
472 |
473 | protected void log(boolean error, String msg) {
474 | android.text.format.Time time = new android.text.format.Time();
475 | time.setToNow();
476 | Log.i(TAG, "log: " + msg);
477 | log.append(COLOR_TIME, time.format("%H:%M:%S\t"))
478 | .append(error ? COLOR_ERROR : COLOR_LOG, msg)
479 | .append("\n");
480 | Message message = mHandler.obtainMessage();
481 | message.what = MSG_SHOW_PROGRESSDIALOG;
482 | message.obj = msg;
483 | mHandler.sendMessage(message);
484 | }
485 |
486 | /** Worker Threads */
487 | private class OutputMonitor implements Runnable {
488 | private final java.io.BufferedReader br;
489 | private final int msg;
490 | public OutputMonitor(int t, java.io.InputStream is) {
491 | br = Util.toReader(is);
492 | msg = t;
493 | }
494 | @Override
495 | public void run() {
496 | try{
497 | String line;
498 | do {
499 | line = br.readLine();
500 | mHandler.obtainMessage(msg, line).sendToTarget(); // NOTE: the last null is also sent!
501 | } while(line != null);
502 | } catch (Exception e) {
503 | mHandler.obtainMessage(MSG_EXCEPTION, e).sendToTarget();
504 | }
505 | }
506 | }
507 |
508 | private boolean checkUplink() {
509 | if (app.prefs.getBoolean("wan_nowait", false)) {
510 | return true;
511 | }
512 | NetworkInfo mobileInfo = connManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
513 | NetworkInfo wimaxInfo = connManager.getNetworkInfo(6);
514 | return (mobileInfo.isConnected() || ((wimaxInfo != null) && wimaxInfo.isConnected()));
515 | }
516 |
517 | private String getPrefValue(String pref) {
518 |
519 | // initialize default values if not done this in the past
520 | PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
521 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
522 |
523 | final int[] ids = SettingsActivity.prefids;
524 | for (int i = 0; i < ids.length; ++i) {
525 | String k = getString(ids[i]);
526 | String v = prefs.getString(k, null);
527 | if (k.equalsIgnoreCase(pref))
528 | return v;
529 | }
530 | return null;
531 | }
532 | /** Prepare env vars for ./wifi from preferences */
533 | protected String[] buildEnvFromPrefs() {
534 | ArrayList envlist = new ArrayList();
535 |
536 | // get the existing environment first, since many programs like 'su' require
537 | // env vars like LD_LIBRARY_PATH to be set
538 | Map env = System.getenv();
539 | for (String envName : env.keySet()) {
540 | if (envName.equals("LD_LIBRARY_PATH")) {
541 | // set LD_LIBRARY_PATH to load olsrd plugins
542 | envlist.add(envName + "=" + NativeHelper.app_bin.getAbsolutePath() + ":" + env.get(envName));
543 | } else {
544 | envlist.add(envName + "=" + env.get(envName));
545 | }
546 | }
547 |
548 | // initialize default values if not done this in the past
549 | PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
550 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
551 |
552 | final int[] ids = SettingsActivity.prefids;
553 | for (int i = 0; i < ids.length; ++i) {
554 | String k = getString(ids[i]);
555 | String v = prefs.getString(k, null);
556 | if (v != null && v.length() != 0) {
557 | // TODO some chars need to be escaped, but this seems to add "" to the ESSID name
558 | // if (ids[i] == R.string.lan_essid) {
559 | // v = '"'+v+'"';
560 | // }
561 | // Special handling for Mesh Prefix
562 | if (k.equalsIgnoreCase(getString(R.string.adhoc_ip)))
563 | {
564 | if (v.matches("^[0-9]{1,3}$"))
565 | {
566 | // Convert the Mesh Prefix into a Mesh IP.
567 | WifiManager wifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE);
568 | if (wifiManager != null)
569 | {
570 | WifiInfo wifiInfo = wifiManager.getConnectionInfo();
571 | if (wifiInfo != null)
572 | {
573 | Log.d(TAG, "Mac addr: " + wifiInfo.getMacAddress());
574 | MACAddress macAddress = MACAddress.parse(wifiInfo.getMacAddress());
575 | v += "." + macAddress.getOctet(4) + "." + macAddress.getOctet(5) + "." + macAddress.getOctet(6);
576 | }
577 | }
578 | }
579 | }
580 | envlist.add("brncl_" + k + "=" + v);
581 | }
582 | }
583 | // not included in prefids are checkboxes
584 | final int[] checks = SettingsActivity.checks;
585 | for (int i = 0; i < checks.length; ++i) {
586 | String k = getString(checks[i]);
587 | if (prefs.getBoolean(k, false))
588 | envlist.add("brncl_" + k + "=1");
589 | }
590 | envlist.add("brncl_path=" + NativeHelper.app_bin.getAbsolutePath());
591 | envlist.add("olsrd_conf_path=" + activeOlsrdConf);
592 |
593 | String[] ret = envlist.toArray(new String[0]);
594 | for (String s : ret) {
595 | Log.i(TAG, "env var: " + s);
596 | }
597 | return ret;
598 | }
599 |
600 | private String formatSSID(String ssid) {
601 | if (ssid == null)
602 | return null;
603 | return "\"".concat(ssid).concat("\"");
604 | }
605 |
606 | private String generateIP(String base, String netmask) {
607 | String[] netmaskBytes = netmask.split("[.]+");
608 | String[] baseBytes = base.split("[.]+");
609 | // start at byte 1 since a completely random IP would be stupid
610 | String ret = baseBytes[0];
611 | for (int i=1; i= netmaskBytes.length || netmaskBytes[i].equals("0")))
615 | ret += String.valueOf((int)(Math.random() * 254));
616 | else
617 | ret += Byte.parseByte(baseBytes[i]);
618 | }
619 | return ret;
620 | }
621 |
622 | private boolean setMeshProfile() {
623 | activeOlsrdConf = new File(NativeHelper.app_bin, "olsrd.conf").getAbsolutePath();
624 | if (app.activeProfile.equals(getString(R.string.defaultprofile))) {
625 | activeSSID = formatSSID(getPrefValue(getString(R.string.lan_essid)));
626 | activeBSSID = getPrefValue(getString(R.string.lan_bssid));
627 | activeIP = getPrefValue(getString(R.string.adhoc_ip));
628 | activeNetmask = getPrefValue(getString(R.string.adhoc_netmask));
629 | activeDNS = getPrefValue(getString(R.string.adhoc_dns_server));
630 | } else {
631 | // TODO
632 | Properties prop = new Properties();
633 | String propFilename = app.profileProperties.get(app.activeProfile);
634 | String confFilename = propFilename.replace(".properties", ".conf");
635 | if (new File(confFilename).exists())
636 | activeOlsrdConf = confFilename;
637 | try {
638 | prop.load(new FileInputStream(propFilename));
639 | } catch (Exception e) {
640 | e.printStackTrace();
641 | app.updateToast(getString(R.string.profile_load_error) + " " + propFilename, false);
642 | return false;
643 | }
644 | activeSSID = formatSSID(prop.getProperty("ssid"));
645 | activeBSSID = prop.getProperty("bssid");
646 | activeNetmask = prop.getProperty("netmask");
647 | activeIpGeneration = prop.getProperty("ipgenerate");
648 | if (activeIpGeneration != null &&
649 | (activeIpGeneration.equals("true") || activeIpGeneration.equals("1"))) {
650 | activeIP = generateIP(prop.getProperty("ip"), activeNetmask);
651 | activeIpGeneration = "true";
652 | } else {
653 | activeIP = prop.getProperty("ip");
654 | activeIpGeneration = "false";
655 | }
656 | activeDNS = prop.getProperty("dns");
657 | }
658 | return true;
659 | }
660 |
661 | String[] getActiveMeshProfile() {
662 | String[] ret = { activeSSID, activeBSSID, activeIP, activeNetmask, activeIpGeneration, activeDNS, activeOlsrdConf };
663 | return ret;
664 | }
665 |
666 | private boolean startProcess() {
667 | // calling 'su -c' from Java doesn't work so we use a helper script
668 |
669 | log(false, "Aquiring wifi lock");
670 | wifiLock.acquire();
671 | app.showProgressMessage(R.string.startingolsrd);
672 | try {
673 | mDelRouteProcess = new ShellProcess("MSG_STOP_OLSRD_OUTPUT", NativeHelper.DEL_ROUTE, mShell);
674 | mDelRouteProcess.setHandler(mHandler, MSG_STOP_OLSRD_OUTPUT);
675 | mDelRouteProcess.runAsynchronous();
676 |
677 | //DelRouteProcess = new MeshTetherProcess(NativeHelper.DEL_ROUTE, env, NativeHelper.app_bin);
678 | //DelRouteProcess.runUntilExit(mHandler, MSG_STOP_OLSRD_OUTPUT, MSG_STOP_OLSRD_OUTPUT);
679 |
680 | WifiShellProcess = new ShellProcess("MSG_OUTPUT", NativeHelper.SU_C, mShell);
681 | WifiShellProcess.setHandler(mHandler, MSG_OUTPUT);
682 | WifiShellProcess.runAsynchronous();
683 |
684 | //WifiProcess = new MeshTetherProcess(NativeHelper.SU_C, env, NativeHelper.app_bin);
685 | //WifiProcess.run(mHandler, MSG_OUTPUT, MSG_ERROR);
686 | } catch (Exception e) {
687 | log(true, String.format(getString(R.string.execerr), NativeHelper.SU_C));
688 | Log.e(TAG, "start failed " + e.toString());
689 | return false;
690 | }
691 | return true;
692 | }
693 |
694 | private void stopProcess() {
695 | /*
696 | * TODO: UN copy and paste!!
697 | */
698 | if (state != STATE_STOPPED) {
699 | app.showProgressMessage(R.string.servicestopping);
700 | ShellProcess StopOlsrProcess = null;
701 |
702 | StopOlsrProcess = new ShellProcess("MSG_STOP_OLSRD_OUTPUT", NativeHelper.STOP_OLSRD, mShell);
703 | StopOlsrProcess.setHandler(mHandler, MSG_STOP_OLSRD_OUTPUT);
704 | if (!StopOlsrProcess.runSynchronous()) {
705 | Log.w(TAG, "Could not StopOlsrProcess");
706 | }
707 | if (WifiShellProcess != null) {
708 | // first, just close the stream
709 | if (state != STATE_STOPPED) {
710 | try {
711 | WifiShellProcess.stop();
712 | } catch (Exception e) {
713 | Log.w(TAG, "Exception while closing WifiShellProcess: " + e.toString());
714 | }
715 | }
716 | WifiShellProcess = null;
717 | }
718 | log(false, "Disconnecting from " + activeSSID);
719 | wifiManager.disconnect();
720 | log(false, "Releasing wifi lock");
721 | wifiLock.release();
722 | clients.clear();
723 | app.linksActivity.update();
724 | app.hideProgressDialog();
725 | }
726 | }
727 |
728 |
729 | private boolean tellProcess(String msg) {
730 | if (WifiShellProcess != null) {
731 | try {
732 | WifiShellProcess.sendInput(msg);
733 | return true;
734 | } catch (Exception e) {
735 | Log.w(TAG, "tellProcess(): " + e.toString());
736 | }
737 | }
738 | return false;
739 | }
740 |
741 | @Override
742 | public IBinder onBind(Intent intent) {
743 | return null;
744 | }
745 |
746 | /**
747 | * This is a wrapper around the new startForeground method, using the older
748 | * APIs if it is not available.
749 | */
750 | public void startForegroundCompat(int id, Notification notification) {
751 | // If we have the new startForeground API, then use it.
752 | if (mStartForeground != null) {
753 | try {
754 | mStartForeground.invoke(this, new Object[] {Integer.valueOf(id), notification});
755 | } catch (InvocationTargetException e) {
756 | Log.w(TAG, "Unable to invoke startForeground", e);
757 | } catch (IllegalAccessException e) {
758 | Log.w(TAG, "Unable to invoke startForeground", e);
759 | }
760 | return;
761 | }
762 | // Fall back on the old API.
763 | //setForeground(true);
764 | }
765 |
766 | public static boolean isSupplicantError(String msg) {
767 | return msg.contains("supplicant");
768 | }
769 |
770 | public static boolean isRootError(String msg) {
771 | return msg.contains("ermission") || msg.contains("su: not found");
772 | }
773 |
774 | }
775 |
776 |
--------------------------------------------------------------------------------