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工作机制还是有很用的。其中最重要的是下面这几幅图。

Android下实现非启动界面Wifi连接_第1张图片(转自http://hi.baidu.com/anly_jun/blog/item/65e26e117e09ebcda6ef3f56.html)

在想要对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.
* <p/>
* 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 <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include "string.h" #include "hardware_legacy/wifi.h" #include "cutils/log.h" #include "cutils/properties.h" #include <arpa/inet.h> #include <netutils/ifc.h> #include <netutils/dhcp.h> 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;
} From : http://yangyangzhao.blog.163.com/blog/static/175816366201011412949131/

更多相关文章

  1. Android性能测试 一些适用于Android Studio的代码审查和性能测试
  2. Android运行时权限,6.0—9.0多版本,多终端(手机,TV盒子)130行代码一劳
  3. 从零开始--系统深入学习android(实践-让我们开始写代码-Android框
  4. android 使用handler更新ui,使用与原理分析详解(附上代码以及截图)
  5. 1、android源代码下载与跟踪
  6. android经典开源代码集合
  7. ReactNative调用原生封装的代码和控件
  8. Android开发人员不得不收集的代码(持续更新中)
  9. Android清除本地数据缓存代码

随机推荐

  1. android AppWidgetProvider 使用方法
  2. Android检测内存溢出
  3. ArcGIS for Android示例解析之空间查询--
  4. 分享 Android(安卓)手机屏幕录制并制作成
  5. ionic APP生成配置
  6. android跨线程通信eventbus
  7. android与网络(中)socket的陷阱
  8. Android布局中的android:onClick=“...”
  9. Android消息机制学习
  10. Android--About Android(欢迎修改、补充)