wifinative.java_Android下实现非启动界面Wifi连接

Android下实现非启动界面Wifi连接

http://yangyangzhao.blog.163.com/blog/static/175816366201011412949131/

Android的网络功能和一般的linux并无太大的区别,我原来以为在Android上连接网络和普通的linux连接网络没有很大区别,事实上区别还是有一些的。

由于项目的需要,我的目标是在Android的界面没有启动之前连接wifi,于是本来的期待是直接在init.rc中加入一些脚本调用即可,但研究了一会儿发现没有那么简单。

首先要感谢anly_jun@baidu贴吧的几篇博文,从http://hi.baidu.com/anly_jun/blog/item/8ecb92d593d144cf50da4b6e.html开始,一共有七篇关于Android Wifi模块分析,其中有大量博主自己使用UML工具画的调用讲解,对于理解Android Wifi工作机制还是有很用的。其中最重要的是下面这几幅图。

想要对wifi硬件动作之前,需要做两件事情,一是要load

wifi的driver,而是要打开wpa_supplicant,其实如果是连接没有加密的wifi,没有必要打开wpa_supplicant,但是

为了讲问题化为熟知的问题,此处还是先按照提示调用wifi_load_driver()和wifi_start_supplicant()

按照上面的提示写出来的初始化代码如下:

int init_stage() {

// load the wifi driver: insmod .ko

int ret = wifi_load_driver();

if(ret < 0) {

LOGE("Failed to load Wi-Fi driver. %s",strerror(errno));

return -1;

}

// start wpa_supplicant

ret =  wifi_start_supplicant();

if(ret < 0) {

LOGE("Failed to start supplicant daemon. %s",strerror(errno));

return -1;

}

return 0;

}

下来,便是连接的过程了,经过上面的步骤,wifi的driver已经载入,wpa_supplicant也已经打开,那咱们就可以开始连接无线了吧。后

来证实这是错误的,因为anly_jun的这篇Android

wifi分析的粒度只在Java层面的函数级别,因此有一些细节并没有提到。在下面我会提到这些细节。

按照一般的linux中连接

wifi的步骤,这时候就可以直接调用一个程序来连接某个ssid的无线网络,然后调用dhcpd来分配ip了,我之前在eeepc上连接wifi就非常

简单,调用iwconfig [ssid],再调用dhcpd就可以了。但很遗憾,Android上并没有iwconfig这样方便的工具。

这下线索似乎就断了,天无绝人之路,既然在Android的Java code中都可以添加一个无线网络并且连接,那我们就去Android的Java源代码中找一找。在Android中,程序员是使用WifiManager这个类来进行Wifi操作的,其中关于添加一个网络的代码如下:

/**

* Add a new network description to the set of configured networks.

* The {@code networkId} field of the supplied configuration object

* is ignored.

*

* The new network will be marked DISABLED by default. To enable it,

* called {@link #enableNetwork}.

*

* @param config the set of variables that describe the configuration,

*            contained in a {@link WifiConfiguration} object.

* @return the ID of the newly created network description. This is used in

*         other operations to specified the network to be acted upon.

*         Returns {@code -1} on failure.

*/

public int addNetwork(WifiConfiguration config) {

if (config == null) {

return -1;

}

config.networkId = -1;

return addOrUpdateNetwork(config);

}

/**

* Internal method for doing the RPC that creates a new network description

* or updates an existing one.

*

* @param config The possibly sparse object containing the variables that

*         are to set or updated in the network description.

* @return the ID of the network on success, {@code -1} on failure.

*/

private int addOrUpdateNetwork(WifiConfiguration config) {

try {

return mService.addOrUpdateNetwork(config);

} catch (RemoteException e) {

return -1;

}

}

看其中确实是调用了service的函数,于是又在frameworks/base/services/java/com/android/server/WifiService.java中找到了有关增加一个网络配置的相关代码

/**

* see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}

* @return the supplicant-assigned identifier for the new or updated

* network if the operation succeeds, or {@code -1} if it fails

*/

public int addOrUpdateNetwork(WifiConfiguration config) {

enforceChangePermission();

/*

* If the supplied networkId is -1, we create a new empty

* network configuration. Otherwise, the networkId should

* refer to an existing configuration.

*/

int netId = config.networkId;

boolean newNetwork = netId == -1;

boolean doReconfig = false;

// networkId of -1 means we want to create a new network

synchronized (mWifiStateTracker) {

if (newNetwork) {

netId = mWifiStateTracker.addNetwork();

if (netId < 0) {

if (DBG) {

Slog.d(TAG, "Failed to add a network!");

}

return -1;

}

doReconfig = true;

}

mNeedReconfig = mNeedReconfig || doReconfig;

}

setVariables: {

/*

* Note that if a networkId for a non-existent network

* was supplied, then the first setNetworkVariable()

* will fail, so we don't bother to make a separate check

* for the validity of the ID up front.

*/

if (config.SSID != null &&

!mWifiStateTracker.setNetworkVariable(

netId,

WifiConfiguration.ssidVarName,

config.SSID)) {

if (DBG) {

Slog.d(TAG, "failed to set SSID: "+config.SSID);

}

break setVariables;

}

if (config.BSSID != null &&

!mWifiStateTracker.setNetworkVariable(

netId,

WifiConfiguration.bssidVarName,

config.BSSID)) {

if (DBG) {

Slog.d(TAG, "failed to set BSSID: "+config.BSSID);

}

break setVariables;

}

我们来到frameworks/base/wifi/java/android/net/wifi/WifiStateTracker.java中,看看addNetwork和setNetworkVariable函数都是什么样的。

/**

* Add a network

*

* @return network id of the new network

*/

public synchronized int addNetwork() {

if (mWifiState.get() != WIFI_STATE_ENABLED) {

return -1;

}

return WifiNative.addNetworkCommand();

}

/**

* Set network setting by name

*

* @param netId network id of the network

* @param name network variable key

* @param value network variable value

* @return {@code true} if the operation succeeds, {@code false} otherwise

*/

public synchronized boolean setNetworkVariable(int netId, String name, String value) {

if (mWifiState.get() != WIFI_STATE_ENABLED) {

return false;

}

return WifiNative.setNetworkVariableCommand(netId, name, value);

}

似乎WifiNative就应该是最终boss了,于是来到frameworks/base/wifi/java/android/net/wifi/WifiNative.java中一看,这两个函数都是这么定义的。

public native static int addNetworkCommand();

public native static boolean setNetworkVariableCommand(int netId, String name, String value);

熟悉Android NDK开发的朋友都应该知道,这里的函数都是通过jni链接到c/c++代码中,于是我们稍微花了一点时间,找到了这个函数所对应的frameworks/base/core/jni/android_net_wifi_Wifi.cpp

static int doCommand(const char *cmd, char *replybuf, int replybuflen)

{

size_t reply_len = replybuflen - 1;

if (::wifi_command(cmd, replybuf, &reply_len) != 0)

return -1;

else {

// Strip off trailing newline

if (reply_len > 0 && replybuf[reply_len-1] == '\n')

replybuf[reply_len-1] = '\0';

else

replybuf[reply_len] = '\0';

return 0;

}

}

static jint doIntCommand(const char *cmd)

{

char reply[256];

if (doCommand(cmd, reply, sizeof(reply)) != 0) {

return (jint)-1;

} else {

return (jint)atoi(reply);

}

}

static jboolean doBooleanCommand(const char *cmd, const char *expect)

{

char reply[256];

if (doCommand(cmd, reply, sizeof(reply)) != 0) {

return (jboolean)JNI_FALSE;

} else {

return (jboolean)(strcmp(reply, expect) == 0);

}

}

……

static jint android_net_wifi_addNetworkCommand(JNIEnv* env, jobject clazz)

{

return doIntCommand("ADD_NETWORK");

}

static jboolean android_net_wifi_setNetworkVariableCommand(JNIEnv* env,

jobject clazz,

jint netId,

jstring name,

jstring value)

{

char cmdstr[256];

jboolean isCopy;

const char *nameStr = env->GetStringUTFChars(name, &isCopy);

const char *valueStr = env->GetStringUTFChars(value, &isCopy);

if (nameStr == NULL || valueStr == NULL)

return JNI_FALSE;

int cmdTooLong = snprintf(cmdstr, sizeof(cmdstr), "SET_NETWORK %d %s %s",

netId, nameStr, valueStr) >= (int)sizeof(cmdstr);

env->ReleaseStringUTFChars(name, nameStr);

env->ReleaseStringUTFChars(value, valueStr);

return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");

}

……

// ----------------------------------------------------------------------------

/*

* JNI registration.

*/

static JNINativeMethod gWifiMethods[] = {

/* name, signature, funcPtr */

{ "loadDriver", "()Z",  (void *)android_net_wifi_loadDriver },

{ "unloadDriver", "()Z",  (void *)android_net_wifi_unloadDriver },

{ "startSupplicant", "()Z",  (void *)android_net_wifi_startSupplicant },

{ "stopSupplicant", "()Z",  (void *)android_net_wifi_stopSupplicant },

{ "connectToSupplicant", "()Z",  (void *)android_net_wifi_connectToSupplicant },

{ "closeSupplicantConnection", "()V",  (void *)android_net_wifi_closeSupplicantConnection },

{ "listNetworksCommand", "()Ljava/lang/String;",

(void*) android_net_wifi_listNetworksCommand },

{ "addNetworkCommand", "()I", (void*) android_net_wifi_addNetworkCommand },

{ "setNetworkVariableCommand", "(ILjava/lang/String;Ljava/lang/String;)Z",

(void*) android_net_wifi_setNetworkVariableCommand },

{ "getNetworkVariableCommand", "(ILjava/lang/String;)Ljava/lang/String;",

(void*) android_net_wifi_getNetworkVariableCommand },

……

来这下终于找到干活儿的函数了,可喜可贺,于是我们得出结论:在Android中,要连上一个无线网络,首先需要添加一个网络,然后设置这个网络的配置,

而这些步骤实际上都是通过向wpa_supplicant发送命令实现的。命令的格式例外的很简单,比如添加一个网络配置是ADD_NETWORK,设置

一个网络配置是SET_NETWORK [netId] [varName] [var]。于是根据Java代码我写出了配置环节的代码。

int config_stage(){

// Add a network config to supplicant mode

int networkId = doIntCommand("ADD_NETWORK"); // Add a new network id

if(networkId < 0) {

LOGE("Failed to add a network configuration. %s",strerror(errno));

return -1;

}

LOGE("Add a network %d",networkId);

// set the ssid of the destination wifi adhoc

char cmdstr[256];

snprintf(cmdstr, sizeof(cmdstr), "SET_NETWORK %d %s %s",networkId, SSID_NAME, SSID);

if(!doBooleanCommand(cmdstr,"OK")) {

LOGE("Failed to set network %d configuration ssid. %s", networkId, strerror(errno));

return -1;

}

return networkId;

}

加了一个配置的网络之后,选择某个网络配置的命令是SELECT_NETWORK

[netId]。在SELECT_NETWORK之后,wpa_supplicant就尝试和该ssid的AP进行associate操作,在

associate之后便调用dhcpd获取ip。SELECT_NETWORK是立即返回的函数,那么何以得知已经和无线AP连接上了

呢?Android的界面里面连接/断开Wifi都是可以被接受到的事件,在WifiStateTracker中我们看到是由WifiMonitor来监

听由wpa_supplicant发过来的消息的,于是我们来到framework/base/wifi/java/android/net/wifi

/WifiMonitor.java,看到其中接受消息的Monitor线程

class MonitorThread extends Thread {

public MonitorThread() {

super("WifiMonitor");

}

public void run() {

if (connectToSupplicant()) {

// Send a message indicating that it is now possible to send commands

// to the supplicant

mWifiStateTracker.notifySupplicantConnection();

} else {

mWifiStateTracker.notifySupplicantLost();

return;

}

//noinspection InfiniteLoopStatement

for (;;) {

String eventStr = WifiNative.waitForEvent();

// Skip logging the common but mostly uninteresting scan-results event

if (Config.LOGD && eventStr.indexOf(scanResultsEvent) == -1) {

Log.v(TAG, "Event [" + eventStr + "]");

}

if (!eventStr.startsWith(eventPrefix)) {

if (eventStr.startsWith(wpaEventPrefix) &&

0 < eventStr.indexOf(passwordKeyMayBeIncorrectEvent)) {

handlePasswordKeyMayBeIncorrect();

}

continue;

}

String eventName = eventStr.substring(eventPrefixLen);

int nameEnd = eventName.indexOf(' ');

if (nameEnd != -1)

eventName = eventName.substring(0, nameEnd);

if (eventName.length() == 0) {

if (Config.LOGD) Log.i(TAG, "Received wpa_supplicant event with empty event name");

WifiNative.wairForEvent

在wifi.c中对应的函数是wifi_wait_event(),用来阻塞的等待wpa_supplicant发来的消息。当

wpa_supplicant连接上之后,便会发出一个CONTROL-EVENT-CONNECTED的消息,只要截获这个消息,我们便可以进行

dhcp的操作了。

基于以上的考虑,我写了connect阶段的代码。这里我偷了一下懒,没有仔细的去分析过来的命令,只是匹配到有CONNECTED的命令,就当已经连接上了。

#define CONNECTED "CONNECTED"

int connect_stage(int networkId) {

char cmdstr[256];

// enable the network

snprintf(cmdstr, sizeof(cmdstr), "SELECT_NETWORK %d",networkId);

if(!doBooleanCommand(cmdstr,"OK")) {

LOGE("Failed to select network %d. %s", networkId, strerror(errno));

return -1;

}

// wait for connect

char buf[256];

while(1) {

int nread = wifi_wait_for_event(buf, sizeof(buf));

if(nread > 0) {

LOGE("receive buf:\n%s\n",buf);

if(strstr(buf,CONNECTED) > 0) {

break;

}

// XXX danger of not going out of the loop!!!

}

continue;

}

return 0;

}

在WifiStateTracer中我还找到了负责dhcp的DhcpHandler,按照其中的函数写了dhcp阶段的代码

int dhcp_stage(){

int result;

in_addr_t ipaddr, gateway, mask, dns1, dns2, server;

uint32_t lease;

char ifname[256];

char mDns1Name[256];

char mDns2Name[256];

property_get("wifi.interface", ifname ,"eth0");

snprintf(mDns1Name, sizeof(mDns1Name), "net.%s.dns1",ifname);

snprintf(mDns2Name, sizeof(mDns2Name), "net.%s.dns2",ifname);

result = dhcp_do_request(ifname, &ipaddr, &gateway, &mask, &dns1, &dns2, &server, &lease);

if(result != 0) {

LOGE("Failed to dhcp on interface %s. %s", ifname, strerror(errno));

return -1;

}

struct in_addr dns_struct1, dns_struct2;

dns_struct1.s_addr = dns1;

dns_struct2.s_addr = dns2;

property_set(mDns1Name,inet_ntoa(dns_struct1));

property_set(mDns2Name,inet_ntoa(dns_struct2));

return 0;

}

是我用无线路由器建立了一个最简单的无线网络,ssid=TSever,没有密码,按照上面步骤进行联网。结果在ADD_NETWORK的步骤就出错了,

无法获得网络id,这是怎么一回事呢?看到dhcp时的代码要对特定的Network

Interface做操作,突然想起来之前在代码中似乎看到有对Interface做使能操作的代码——WifiService在调用

mWifiStateTracker.enableNetwork之前,还调用了String ifname =

mWifiStateTracker.getInterfaceName();

NetworkUtils.enableInterface(ifname);这两句。于是在init阶段,加上了下面这段。

char ifname[256];

property_get("wifi.interface", ifname ,"eth0");

ret = ifc_enable(ifname);

if(ret < 0) {

LOGE("Failed to enable wifi interface %s. %s", ifname ,strerror(errno));

return -1;

}

是运行起来还是出同样的错误,不过这次busybox ifconfig之后可以发现eth0的端口了

,至少没有做无用功。倒回去看在WifiMonitor的MonitorThread中有connectToSupplicant()的调用,本以为此调

用不是非常关键,然后去hardware/libhardware_legacy/wifi/wifi.c文件里面看到全局有一个static

struct wpa_ctrl

*ctrl_conn;并且在wifi_command中需要用到这个ctrl_conn,那么如果这个ctrl_conn是NULL的话,所有的

wifi_command命令自然都无法完成了,于是又加上了

ret = wifi_connect_to_supplicant();

if(ret < 0) {

LOGE("Failed to connect supplicant daemon. %s",strerror(errno));

return -1;

}

这样编译完运行之后,果然顺利的分配到id了。运行一下程序,还是出现了错误,输出的log如下。

I/wpa_supplicant(  618): CTRL-EVENT-SCAN-RESULTS  Ready

I/wpa_supplicant(  618): Trying to associate with 00:24:b2:c1:16:b6 (SSID='TServer' freq=2462 MHz)

I/wpa_supplicant(  618): CTRL-EVENT-STATE-CHANGE id=-1 state=3

E/        (  612): Finished init stage.

E/        (  612): Add a network 2

E/        (  612): Finished config stage.

I/wpa_supplicant(  618): CTRL-EVENT-STATE-CHANGE id=1 state=0

E/        (  612): receive buf:

E/        (  612):  CTRL-EVENT-STATE-CHANGE id=1 state=0

I/wpa_supplicant(  618): CTRL-EVENT-STATE-CHANGE id=-1 state=2

E/        (  612): receive buf:

E/        (  612):  CTRL-EVENT-STATE-CHANGE id=-1 state=2

I/wpa_supplicant(  618): CTRL-EVENT-SCAN-RESULTS  Ready

E/        (  612): receive buf:

E/        (  612):  CTRL-EVENT-SCAN-RESULTS  Ready

I/wpa_supplicant(  618): CTRL-EVENT-STATE-CHANGE id=-1 state=4

E/        (  612): receive buf:

E/        (  612):  CTRL-EVENT-STATE-CHANGE id=-1 state=4

I/wpa_supplicant(  618): Associated with 00:24:b2:c1:16:b6

E/        (  612): receive buf:

E/        (  612):  Associated with 00:24:b2:c1:16:b6

I/wpa_supplicant(  618): CTRL-EVENT-SCAN-RESULTS  Ready

E/        (  612): receive buf:

E/        (  612):  CTRL-EVENT-SCAN-RESULTS  Ready

D/NetworkLocationProvider(  127): onCellLocationChanged [4517,30785]

I/wpa_supplicant(  618): Authentication with 00:24:b2:c1:16:b6 timed out.

E/        (  612): receive buf:

E/        (  612):  Authentication with 00:24:b2:c1:16:b6 timed out.

注意到红色的那句log,我的wifi并没有设置密码,为什么还需要Authentication呢?想一想是不是wpa_supplicant的限制,于是去网上搜了到了这篇wpa_supplicant 工具使用,发现没有密码的情况下应该是这样的配置

# 明文连接方式(不使用WPA和IEEE802.1X)

network={

ssid="plaintext-test"

key_mgmt=NONE

}

于是在config阶段加上了对key_mgmt的设置,这下就连上了Wifi了,正确的log如下

bash-4.1# wificonnect

I/wpa_supplicant(  871): CTRL-EVENT-SCAN-RESULTS  Ready

I/wpa_supplicant(  871): Trying to associate with 00:24:b2:c1:16:b6 (SSID='TServer' freq=2462 MHz)

I/wpa_supplicant(  871): CTRL-EVENT-STATE-CHANGE id=-1 state=3

E/        (  865): Finished init stage.

E/        (  865): Add a network 2

E/        (  865): Finished config stage.

I/wpa_supplicant(  871): CTRL-EVENT-STATE-CHANGE id=1 state=0

E/        (  865): receive buf:

E/        (  865):  CTRL-EVENT-STATE-CHANGE id=1 state=0

I/wpa_supplicant(  871): CTRL-EVENT-STATE-CHANGE id=-1 state=2

E/        (  865): receive buf:

E/        (  865):  CTRL-EVENT-STATE-CHANGE id=-1 state=2

I/wpa_supplicant(  871): CTRL-EVENT-SCAN-RESULTS  Ready

E/        (  865): receive buf:

E/        (  865):  CTRL-EVENT-SCAN-RESULTS  Ready

I/wpa_supplicant(  871): Trying to associate with 00:24:b2:c1:16:b6 (SSID='TServer' freq=2462 MHz)

E/        (  865): receive buf:

E/        (  865):  Trying to associate with 00:24:b2:c1:16:b6 (SSID='TServer' freq=2462 MHz)

I/wpa_supplicant(  871): CTRL-EVENT-STATE-CHANGE id=-1 state=3

E/        (  865): receive buf:

E/        (  865):  CTRL-EVENT-STATE-CHANGE id=-1 state=3

I/wpa_supplicant(  871): CTRL-EVENT-STATE-CHANGE id=2 state=4

E/        (  865): receive buf:

E/        (  865):  CTRL-EVENT-STATE-CHANGE id=2 state=4

I/wpa_supplicant(  871): Associated with 00:24:b2:c1:16:b6

I/wpa_supplicant(  871): CTRL-EVENT-STATE-CHANGE id=2 state=7

I/wpa_supplicant(  871): CTRL-EVENT-CONNECTED - Connection to 00:24:b2:c1:16:b6 completed (auth) [id=2 id_str=]

E/        (  865): receive buf:

E/        (  865):  Associated with 00:24:b2:c1:16:b6

E/        (  865): receive buf:

E/        (  865):  CTRL-EVENT-STATE-CHANGE id=2 state=7

E/        (  865): receive buf:

E/        (  865):  CTRL-EVENT-CONNECTED - Connection to 00:24:b2:c1:16:b6 completed (auth) [id=2 id_str=]

E/        (  865): Finished dhcp stage.

Android下实现非启动界面Wifi连接就算是完成了,以上工作是在界面启动并且Wifi设置关闭的情况下进行的,但和在没有界面的时候应该差别不大,下面是程序的源代码

/* ** ** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** **     http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ #include #include #include #include #include "string.h" #include "hardware_legacy/wifi.h" #include "cutils/log.h" #include "cutils/properties.h" #include #include #include static int doCommand(const char *cmd, char *replybuf, int replybuflen) {     size_t reply_len = replybuflen - 1;

if (wifi_command(cmd, replybuf, &reply_len) != 0)

return -1;

else {         // Strip off trailing newline         if (reply_len > 0 && replybuf[reply_len-1] == '\n')

replybuf[reply_len-1] = '\0';

else             replybuf[reply_len] = '\0';

return 0;

} } static int doIntCommand(const char *cmd) {     char reply[256];     if (doCommand(cmd, reply, sizeof(reply)) != 0) {         return -1;

} else {         return atoi(reply);

} } static int doBooleanCommand(const char *cmd, const char *expect) {     char reply[256];     if (doCommand(cmd, reply, sizeof(reply)) != 0) {         return 0;

} else {         return (strcmp(reply, expect) == 0);

} } // Send a command to the supplicant, and return the reply as a String static char* doStringCommand(const char *cmd) {     char reply[4096];     if (doCommand(cmd, reply, sizeof(reply)) != 0) {         return NULL;

} else {         return reply;

} } int init_stage() {     // load the wifi driver: insmod .ko     int ret = wifi_load_driver();

if(ret < 0) {         LOGE("Failed to load Wi-Fi driver. %s",strerror(errno));

return -1;

}     // start wpa_supplicant     ret =  wifi_start_supplicant();

if(ret < 0) {         LOGE("Failed to start supplicant daemon. %s",strerror(errno));

return -1;

}     ret = wifi_connect_to_supplicant();

if(ret < 0) {         LOGE("Failed to connect supplicant daemon. %s",strerror(errno));

return -1;

}     char ifname[256];     property_get("wifi.interface", ifname ,"eth0");

ret = ifc_enable(ifname);

if(ret < 0) {         LOGE("Failed to enable wifi interface %s. %s", ifname ,strerror(errno));

return -1;

}     return 0; } int scan_stage(){     // XXX we don't need to really scan the wifi     return 0; } #define SSID_NAME "ssid" #define KEY_MGMT "key_mgmt" #define SSID "\"xxxxx\"" #define PASS "NONE" int config_stage(){

// Add a network config to supplicant mode     int networkId = doIntCommand("ADD_NETWORK"); // Add a new network id     if(networkId < 0) {         LOGE("Failed to add a network configuration. %s",strerror(errno));

return -1;

}     LOGE("Add a network %d",networkId);

// set the ssid of the destination wifi adhoc     char cmdstr[256];     snprintf(cmdstr, sizeof(cmdstr), "SET_NETWORK %d %s %s",networkId, SSID_NAME, SSID);

if(!doBooleanCommand(cmdstr,"OK")) {         LOGE("Failed to set network %d configuration ssid. %s", networkId, strerror(errno));

return -1;

}

snprintf(cmdstr, sizeof(cmdstr), "SET_NETWORK %d %s %s", networkId, KEY_MGMT ,PASS);

if(!doBooleanCommand(cmdstr,"OK")) {

LOGE("Failed to set network %d configuration key_mgmr. %s", networkId, strerror(errno));

return -1;

}

return networkId;

}

#define CONNECTED "CONNECTED"

int connect_stage(int networkId) {

char cmdstr[256];

// enable the network

snprintf(cmdstr, sizeof(cmdstr), "SELECT_NETWORK %d",networkId);

if(!doBooleanCommand(cmdstr,"OK")) {

LOGE("Failed to select network %d. %s", networkId, strerror(errno));

return -1;

}

// wait for connect

char buf[256];

while(1) {

int nread = wifi_wait_for_event(buf, sizeof(buf));

if(nread > 0) {

LOGE("receive buf:\n%s\n",buf);

if(strstr(buf,CONNECTED) > 0) {

break;

}

// XXX danger of not going out of the loop!!!

}

continue;

}

return 0;

}

int dhcp_stage(){

int result;

in_addr_t ipaddr, gateway, mask, dns1, dns2, server;

uint32_t lease;

char ifname[256];

char mDns1Name[256];

char mDns2Name[256];

property_get("wifi.interface", ifname ,"eth0");

snprintf(mDns1Name, sizeof(mDns1Name), "net.%s.dns1",ifname);

snprintf(mDns2Name, sizeof(mDns2Name), "net.%s.dns2",ifname);

result = dhcp_do_request(ifname, &ipaddr, &gateway, &mask, &dns1, &dns2, &server, &lease);

if(result != 0) {

LOGE("Failed to dhcp on interface %s. %s", ifname, strerror(errno));

return -1;

}

struct in_addr dns_struct1, dns_struct2;

dns_struct1.s_addr = dns1;

dns_struct2.s_addr = dns2;

property_set(mDns1Name,inet_ntoa(dns_struct1));

property_set(mDns2Name,inet_ntoa(dns_struct2));

return 0;

}

int main(int argc, char *argv[])

{

int ret = init_stage();

if(ret < 0) {

LOGE("Failed init stage. %s",strerror(errno));

exit(-1);

}

LOGE("Finished init stage.");

ret = config_stage();

if(ret < 0) {

LOGE("Failed config stage. %s",strerror(errno));

exit(-1);

}

LOGE("Finished config stage.");

ret = connect_stage(ret);

if(ret < 0) {

LOGE("Failed connect stage. %s",strerror(errno));

exit(-1);

}

LOGV("Finished connect stage.");

ret = dhcp_stage();

if(ret < 0) {

LOGE("Failed dhcp stage. %s",strerror(errno));

exit(-1);

}

LOGE("Finished dhcp stage.");

return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值