2015年11月3日 星期二

enable_irq_wake是如何起作用的

source:
http://blog.csdn.net/njuitjf/article/details/21475405


enable_irq_wake是如何起作用的
在linux kernel中,调用enable_irq_wake函数,可以将一个irq具有唤醒系统的功能,即把系统从低功耗模式中唤醒,如从suspend to RAM中唤醒。
enable_irq_wake具体如何起作用的呢,今天来学习学习。
先从函数enable_irq_wake开始,实现很简单:

  1. static inline int enable_irq_wake(unsigned int irq)  
  2. {  
  3.  return irq_set_irq_wake(irq, 1);  
  4. }  


函数irq_set_irq_wake的实现也不是很复杂,并且有注释说明,容易理解:

  1. /** 
  2.  * irq_set_irq_wake - control irq power management wakeup 
  3.  * @irq: interrupt to control 
  4.  * @on: enable/disable power management wakeup 
  5.  * 
  6.  * Enable/disable power management wakeup mode, which is 
  7.  * disabled by default.  Enables and disables must match, 
  8.  * just as they match for non-wakeup mode support. 
  9.  * 
  10.  * Wakeup mode lets this IRQ wake the system from sleep 
  11.  * states like "suspend to RAM". 
  12.  */  
  13. int irq_set_irq_wake(unsigned int irq, unsigned int on)  
  14. {  
  15.  unsigned long flags;  
  16.  struct irq_desc *desc = irq_get_desc_buslock(irq, &flags);  
  17.  int ret = 0;  
  18.   
  19.  if (!desc)  
  20.   return -EINVAL;  
  21.   
  22.  /* wakeup-capable irqs can be shared between drivers that 
  23.   * don't need to have the same sleep mode behaviors. 
  24.   */  
  25.  if (on) {  
  26.   if (desc->wake_depth++ == 0) {  
  27.    ret = set_irq_wake_real(irq, on);  
  28.    if (ret)  
  29.     desc->wake_depth = 0;  
  30.    else  
  31.     irqd_set(&desc->irq_data, IRQD_WAKEUP_STATE);  
  32.   }  
  33.  } else {  
  34.   if (desc->wake_depth == 0) {  
  35.    WARN(1"Unbalanced IRQ %d wake disable\n", irq);  
  36.   } else if (--desc->wake_depth == 0) {  
  37.    ret = set_irq_wake_real(irq, on);  
  38.    if (ret)  
  39.     desc->wake_depth = 1;  
  40.    else  
  41.     irqd_clear(&desc->irq_data, IRQD_WAKEUP_STATE);  
  42.   }  
  43.  }  
  44.  irq_put_desc_busunlock(desc, flags);  
  45.  return ret;  
  46. }  


其中关键的代码是计数:desc->wake_depth++, 以及调用函数set_irq_wake_real。
set_irq_wake_real函数调用到了具体cpu相关的代码:

  1. static int set_irq_wake_real(unsigned int irq, unsigned int on)  
  2. {  
  3.  struct irq_desc *desc = irq_to_desc(irq);  
  4.  int ret = -ENXIO;  
  5.   
  6.  if (desc->irq_data.chip->irq_set_wake)  
  7.   ret = desc->irq_data.chip->irq_set_wake(&desc->irq_data, on);  
  8.   
  9.  return ret;  
  10. }  


irq_set_wake为cpu相关代码。
例如,xxx cpu对应的arch\arm\mach-xxx\Irq.c文件中,xxx_init_irq函数中有如下语句:

  1. desc->irq_data.chip->irq_set_wake = xxx_gic_irq_set_wake;  


xxx_gic_irq_set_wake的实现将irq mask,结果保存在一个数组中gpc_wake_irq。
cpu在做power on/off时会使用到该数组。
如mach-xxx\system.c中的函数xxx_cpu_lp_set中有如下代码:

  1. gpc_set_wakeup(gpc_wake_irq);  


函数gpc_set_wakeup的实现:

  1. void gpc_set_wakeup(unsigned int irq[4])  
  2. {  
  3.  /* Mask all wake up source */  
  4.  __raw_writel(~irq[0], gpc_base + 0x8);  
  5.  __raw_writel(~irq[1], gpc_base + 0xc);  
  6.  __raw_writel(~irq[2], gpc_base + 0x10);  
  7.  __raw_writel(~irq[3], gpc_base + 0x14);  
  8.   
  9.  return;  
  10. }  


将irq mask设置到了cpu中。
中cpu的suspend enter函数中,会调用xxx_cpu_lp_set函数。
如xxx_suspend_enter函数中有如下代码:

  1. switch (state) {  
  2. case PM_SUSPEND_MEM:  
  3.  ...  
  4.  mxc_cpu_lp_set(ARM_POWER_OFF);  
  5.  arm_pg = true;  
  6.  break;  
  7. ...  
  8. }  



至此,流程基本清晰了。
enable_irq_wake函数会将irq mask到一个数组。
在进入suspend时,会将irq mask写入到cpu。
也就是告诉cpu哪些irq可以将其从睡眠中唤醒。

2015年7月28日 星期二

ap与sta共存

source:
http://blog.csdn.net/xiaojsj111/article/details/30482001

1:wifi的concurrent mode

所谓wifi的共存模式,有以下几种:
    • station mode + station mode
    • station mode + ap mode
    • station mode + p2p mode
    • p2p mode + ap mode
目前android自从JB version后,就开始支持station + p2p的共存,但其他的共存模式目前在android上都还未支持。现在市面上的wifi驱动主要是支持前三种共存,目前第四种共存模式,暂未见到;而station+ap mode,目前我们有在BXXX项目中使用,使用场景就是:
做Ap供其他的mid或phone来连接,同时自己又做station mode来连接外面可以上网的路由器,这样在mid或phone上,就可以在访问BXXX的同时,还可以上网。BXXX自己当然也可以上网了。

但需要主要的是,以上各模式中的station,ap,p2p在驱动中都需要对应的网络接口的,所以如果要支持concurrent mode,你的驱动insmod后,必须吐出两个网络接口才行,如果只有一个网络接口,那肯定是不支持concurrent mode的,见下图,加载驱动后就会出现wlan0,p2p0两个网络接口。
另外需要注意,这两个网络接口,都是在驱动中虚拟出来的,共享同一个物理硬件,因此他们也共享物理硬件所能达到的throughput,由于他们共同一个物理硬件,所以wlan0和p2p0必须在同一个channel上,因此跟wlan0和p2p0连接的网络都在同一个channel上,这样这个大网络里所有的设备共同参与这个信道的载波侦听/冲突检测,即同一时间只能有一个站在空气中发送无线包。如果刚开始出现ap/p2p跟wlan0的channel不一致的情况,那一般都是ap/p2p断开之前的链接,重新调频到wlan0的信道建立新的链接。

wlan0,p2p0都是在linux下的wifi驱动中创建的,譬如进来一个数据包是根据什么标准来判断,该路由到wlan0还是该路由到p2p0,
这是一个很趣的问题;另外wlan0接口和p2p0接口他们的发送数据包是如何调度和管理的,也是一个值得关注的问题。

2:station mode + ap mode

本节介绍station+ap的concurrent mode是如何建立的。先上一张整体的框架图:
在调试阶段,为了验证ap+sta是否正常工作,我们最好是step by step的先验证sta mode是ok的,然后验证ap
mode是ok的,最后才是sta+ap mode是否ok。

2.1:station的启动方式

    • inmod wifi drivers modules  //加载wifi驱动模块,在这里可以指定各个网络接口的名字,正常会出wlan0和p2p0两个网络接口。
    • ifconfig wlan0 up //打开station mode对应的wlan0网络接口
    • 如下设置wpa_supplicant.conf,这样让station mode一起来就自动去链接指定的ap
  1. / # cat /data/misc/wifi/wpa_supplicant.conf  
  2. ctrl_interface=wlan0  
  3. update_config=1  
  4.   
  5. network={  
  6.         ssid="ASUS_BEN_NEW"  
  7.         psk="33333333"  
  8.         priority=1  
  9. }  
    • /system/bin/wpa_supplicant -iwlan0 -Dnl80211 -c/data/misc/wifi/wpa_supplicant.conf //启动wpa_supplicant后台服务
    • 执行wpa_cli,就可以查看这个时候station 是否已经跟路由器连接上了,在确认已经跟路由器连接上后,这个时候只是关联,鉴权完成,data port打开,但还未分配ip地址。
  1. / # wpa_cli   
  2. wpa_cli v2.0-devel-4.2.1  
  3. Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> and contributors  
  4.   
  5. This software may be distributed under the terms of the BSD license.  
  6. See README for more details.  
  7.   
  8.   
  9. Using interface 'wlan0'  
  10.   
  11. Interactive mode  
  12.   
  13. <3>CTRL-EVENT-SCAN-RESULTS   
  14. sta sta_autoconnect status  
  15. > status   
  16. bssid=50:46:5d:00:68:e8  
  17. ssid=ASUS_BEN_NEW  
  18. id=0  
  19. mode=station  
  20. pairwise_cipher=CCMP  
  21. group_cipher=CCMP  
  22. key_mgmt=WPA2-PSK  
  23. wpa_state=COMPLETED  
  24. ip_address=192.168.1.136  
  25. p2p_device_address=00:92:cc:0c:e0:89  
  26. address=00:92:cc:0c:e0:89  
  27. <3>CTRL-EVENT-STATE-CHANGE id=0 state=9 BSSID=50:46:5d:00:68:e8 SSID=ASUS_BEN_NEW  
  28. <3>CTRL-EVENT-CONNECTED - connection to 50:46:5d:00:68:e8 completed (reauth) [id=0 id_str=]  
  29. > p2p0: STA a0:f4:59:45:fc:d5 WPA: group key handshake completed (RSN)  
    • 设置/system/etc/dhcpcd/dhcpcd.conf文件
  1. / # cat /system/etc/dhcpcd/dhcpcd.conf  
  2. # dhcpcd configuration for Android Wi-Fi interface  
  3. # See dhcpcd.conf(5) for details.  
  4.   
  5. # Disable solicitation of IPv6 Router Advertisements  
  6. noipv6rs  
  7.   
  8. interface wlan0  
  9. # dhcpcd-run-hooks uses these options.  
  10. option subnet_mask, routers, domain_name_servers  
    • system/bin/dhcpcd -aABKL      -f/system/etc/dhcpcd/dhcpcd.conf -handroid-e4cf57339578c6dc wlan0//开始申请ip地址
    • ifconfig -a  //通过这个命令,可以看到这个时候wlan0已经被分配了ip地址。这个时候如果可以ping通路由器的ip地址,说明station mode的启动已经ok。

2.2: ap的启动方式

    • 设定/data/misc/wifi/hostapd.conf内容,由于上面已经加载了wifi驱动,所以这里不需要再加载
  1. / # cat /proc/1261/cmdline   
  2. hostapd/data/misc/wifi/hostapd.conf/ #   
  3. / #   
  4. / # cat /data/misc/wifi/hostapd.conf  
  5. interface=p2p0  
  6. ssid=CAST-0CE089  
  7. channel=1  
  8. auth_algs=1  
  9. wpa=2  
  10. wpa_passphrase=198d02d6  
  11. wpa_key_mgmt=WPA-PSK  
  12. rsn_pairwise=TKIP CCMP  
  13.   
  14. ctrl_interface=/data/misc/wifi/hostapd  
  15. beacon_int=100  
  16. hw_mode=g  
  17. ieee80211n=1  
  18. wme_enabled=1  
  19. max_num_sta=8  
上面的配置文件中:interface关键字指定ap mode使用的网络接口名字;ssid字段指定了ap的ssid名字;wpa*相关字段设定了ap的加密鉴权方式及密码;ctrl_interface设定控制接口,一般用于hostap_cli来跟他连接。
    • ifconfig p2p0 up  //打开p2p0网络接口
    • ifconfig p2p0 192.168.5.1 //配置p2p0网络接口的ip地址
    • hostapd /data/misc/wifi/hostapd.conf & // 启动hostapd后台,至此ap应该可以被其他wifi设备搜索到,说明启动成功,这个时候应该可以关联,鉴权成功,但由于ap端还未启动dhcp service,所以最终未能分配到ip地址而连接失败
    • /system/bin/dnsmasq --no-daemon --no-resolv      --no-poll --address=/b.tv/192.168.5.1      --dhcp-range=192.168.5.2,192.168.5.254,24h //dnsmasq有两个作用:一个是可以起到dhcp service的作用,另一个可以实现dns的forward;上面的--address指定了域名和ip地址的对应关系,--dhcp-range指定了dhcp的地址分配范围
    • 设定dnsmasq的dns转发,通常设定为8.8.8.8或8.8.4.4//不设定的话,mid或phone后面虽然可以通过ip地址ping通百度,但却不能够通过浏览器来浏览网页,原因就是dnsmasq的dns没有设置好
    • 这个时候,其他wifi设备如果能够扫描到它,并且还能连上它,分配的ip地址也是在192.168.5.2到192.168.5.254之间,并且能够ping通路由器的ip(在这里是192.168.5.1),说明ap mode的启动是成功。

2.3:station 与 ap之间的路由

至此,station mode和ap mode都已经启动成功,并且wlan0和p2p0都有ip地址,但这个时候,你在BXXX或mid上却不能ping通百度的ip地址(ping 180.76.3.151),但是在BXXX上可以ping 通route,在mid上可以ping通BXXX(见上面的框架图),为什么呢,因为你没有设置默认路由的关系。
    • route add 192.168.1.1 wlan0 //在BastCast上,为wlan0接口添加路由
    • route add 192.168.5.1 p2p0//在BastCast上,为p2p0接口添加路由
    • route add default gw 192.168.1.1 ////在BastCast上,添加默认路由
    • iptables -t nat -A natctrl_nat_POSTROUTING -o wlan0      -j MASQUERADE //设定nat,这样内网才能给外网通讯
    • echo 1 > /proc/sys/net/ipv4/ip_forward //是能内核的ip转发功能,默认是禁止的。
    • ping 180.76.3.151 //这个时候在BXXX上应该就可以ping通百度的ip地址了
    • 如果正确设置了dnsmasque的dns转发功能,应该可以通过浏览器上网了

2.4:

3:参考资料

关于realteck wifi的参考文件:
Realtek_WiFi_concurrent_mode_Introduction.pdf
Quick_Start_Guide_for_Station_Mode.pdf
Quick_Start_Guide_for_SoftAP.pdf
wpa_cli_with_wpa_supplicant.pdf

wlan0 + p2p0 啟動方式

source:
http://blog.csdn.net/roger__wong/article/details/8603275

准备工作
    在porting wifi之前你有一些东西需要准备,具体清单如下:
    (1):android source(没有这个你怎么移植wifi网卡到自己的平台上?)
    (2):kernel source(这个是android所依赖的kernel,主要用途是后续用来build driver使用)
    (3):driver source(这个是需要加载driver的source,realtek和ralink一般能拿到源码,atheros是美国公司,版权看的比较重,基本拿不到driver的source)
    (4):tool chain(build driver所使用的交叉编译链,必须要有)
    有了上述4样你才可以开始着手后续的porting,本文主要讲解porting的flow,具体上述东西怎么使用以后再统一介绍。

正文
    首先讲解一下porting wifi的大致流程,具体如下:
    (1):load wifi driver(网卡启用的先决条件)
    (2):起supplicant(这里面带参数很重要)
    (3):给supplicant下指定的命令(这个是wifi framework与driver之间的通讯方式)

(1)load wifi driver    
    首先需要讲解一下,在android4.0之后,wifi的工作方式基本都采用的是比较标准的nl80211方式,以前的wext方式现在使用的已经很少了,关于nl80211和wext的区别,小弟由于接触的少,所以简单的说两句(有错误的请各位大大指正啊,万谢!)
    wext:supplicant通过wext直接给wifi driver下命令,即不通过kernel,所以一般以wext工作的driver是不需要load cfg80211.ko的,这个cfg80211.ko就是kernel里面的wireless部分,主要对接supplicant和driver的。
    nl80211:supplicant的命令以nl80211的方式下给kernel,经过kernel再发送给driver,这样子做的好处是supplicant和driver之间的通讯方式更加标准话,是以后的主流方式,我后面讲的driver都是以这种方式工作的。

    既然是nl80211,那么首先需要build kernel,得到cfg80211.ko,然后用build过的kernel来build driver,得到具体的driver ko,这里面为了区分具体型号的ko,我把名字假设为8192cu.ko,这个是realtek的一款网卡8192cu,市面上比较常见的单频双天线网卡。
    拿到两个ko之后load driver的准备工作就做完了,现在把两个ko copy到平台的/system/lib/modules/路径下,这个是android ko的存放路径,记得修改权限为644,不然可能会有权限问题,然后可以用命令把driver load到系统了,具体如下:
    (1)#insmod cfg80211.ko
    (2)#insmod 8192cu.ko ifname=wlan0 if2name=p2p0
    第一步是加载kernel部分的module,这个是nl80211的前提,另一步是加载对应driver的module,这个是网卡使能的前提,之所在insmod 819cu.ko的时候要带后面的两个参数,主要原因是因为标准android所使用的interface是wlan0和p2p0,如果不带上的话可能带起来的interface不是这两个。
    如果没有异常的话,load driver部分就完毕了,检验load driver是否正确,可以在/sys/class/net/路径下看有没有wlan0和p2p0两个interface,也可以用netcfg命令来查看是否多了wlan0和p2p0两个interface,如果有的话就说明load driver正确,如果没有的话可以看下网卡是否有插上,如果有插上的话可能就是driver有问题来,没有把卡带起来,这个问题一般要找厂家debug了,小弟接触的少,就帮不上什么忙了。

(2)起supplicant
    标准的android系统framework是无法直接与driver进行通讯的,必须通过wpa_supplicant这个deamon来中转才行,这个主要是为了统一不同厂家和不同型号的wifi driver的接口,所以load 完driver之后要做的就是起supplicant,也有少许厂家在debug driver阶段可以不用起supplicant,例如ralink就可以使用iwpriv这个工具直接给driver下命令来作网络操作,由于小弟对driver不熟悉,所以也不在此扩展开来,另外这个不是android的标准流程,仅仅用作driver的debug。
    起supplicant比较常见的方式如下:
    #wpa_supplicant -Dnl80211 -iwlan0 -c/data/misc/wifi/wpa_supplicant.conf -N -Dnl80211 -ip2p0 -c/data/misc/wifi/p2p_supplicant.conf &
    这个命名有点繁琐,我下面给大家详细的解释一下:
    (1)wpa_supplicant:这个是android里面supplicant bin档的官方命名,这个可以自己去修改,路径在平台的/system/bin/下,属于环境变量,所以在启动的时候不用带上绝对路径。
    (2)-Dnl80211:这个说明supplicant与driver的通讯方式采用的是nl80211,这个根据厂家提供的driver来具体设定,也可以是wext方式,以driver为准。
    (3)-iwlan0和-ip2p0:说明会带起两个interface来作supplicant与driver之间的通讯interface,这个可以用netcfg看到这两个interface的状态是UP状态的,也可以用ifconfig来看到新增加的两个使能interface wlan0和p2p0
     (4)-c/data/misc/wifi/wpa_supplicant.conf和-c/data/misc/wifi/p2p_supplicant.conf:这两个是android标准的supplicant配置文件,路径如上所述,如果p2p_supplicant.conf不存在的话,可以把wpa_supplicant.conf copy一份出来用作p2p_supplicant.conf,android的原生flow就是这么做的。
    (5)-N:说明是在wlan0的基础上再加上一个interface,也就是new的意思 ,以前android4.0的时候只能起一个interface,所以也就没有这个参数了。
    (6)&:后台运行符(linux基础,你懂的)
     
    如果一切ok,就可以用ps命令在后台看到wpa_supplicant在后台跑了,这个时候需要验证一下supplicant是否运行正常,主要方法是看/data/system/wpa_supplicant/路径下是否有wlan0和p2p0两个socket,这个是wifi framework和supplicant之间的通讯socket,这里面的这个路径是在supplicant的config文件里面配置的,如果有的话就说明是ok的,如果没有的话就说明有问题,这个问题具体怎么定位后续再说。

(3)给supplicant下指定的命令
    从android4.0之后,wifi就增加了wifi direct功能,这个也就是我们通常说的wifi p2p,具体功能跟蓝牙类似,但是能提供更大的带宽,所以使无线传屏功能成为了可能,可以丢掉HDMI无线传输1080p的视频,这个是以后要说的widi和miracast功能,目前android端主要使用的是miracast,例如三星的All Share Cast和小米的WLAN Display,nexus4的无线显示等等都是基于miracast功能,pc端则是WIDI的天下,这个主要是因为WIDI是intel开发出来的技术,在pc上intel的地位你懂的。
   废话说多了,现在来看怎么通过supplicant来实现wifi sta连线和p2p连线,这里要说的是sta连线就是我们平时连接路由器的功能,p2p连线就是wifi direct功能,下面分别简单实现sta和p2p连线:
1:sta连线
#wpa_cli -iwlan0                                     (使用wpa_cli给supplicant下命令,这个是supplicant的client端)
>scan                                                        (让driver做扫描动作)
>scan_results                                         (让driver反馈扫描结果给supplicant)
>add_network                                         (添加一个网络,这里面会给一个号码,一般开机的第一次添加就是0)
>set_network 0 ssid "cheny"                (选择一个名叫cheny的路由器,这个是前面scan_result反馈回来的名字)
>set_network 0 psk "12345678"          (输入名叫cheny的路由器的密码12345678,加密方式是wpa-psk)
>enable_network 0                                 (使能cheny路由器,也就是建立连接)
>save                                                          (保存)
>status                                                        (查看supplicant的当前状态,一般结果是compeleted)
>quit                                                            (退出wpa_cli命令行)
#dhcpcd -iwlan0                                       (给wlan0这个interface分配ip)
#ifconfig wlan0                                          (查看wlan0的信息,一般会有ip,mac,gateway,netmask,dns等等信息)
    如果一切ok,而且cheny这个路由器能够联通外网,那么此时你就可以ping通外网,平台与路由器之间的连线就建立起来了。

2:p2p连线
#wpa_cli -ip2p0
>p2p_find                                                     (搜索附近的p2p设备)
>p2p_connect 5e:0a:5b:1c:fd:a5 pbc      (根据反馈回来的scan list选择想要连线的p2p设备,第一个参数是将要连线p2p设备的mac,另外一个是连线的方式pbc)
>status                                                            (查询supplicant的状态)
>quit                                                                (退出wpa_cli命令行)
    如果一切ok,那么你就可以用ping来ping通另一个p2p设备来哈,不用通过路由器的中转,目前已经有一些厂家针对这个p2p协议有开发一些高速传输软件,例如android上比较有名的快牙,广告介绍的神乎其神,其实底层的实现就是这么简单。

总结

    如果上述功能都ok,那么就说明driver和supplicant在该平台是ok的,这个是driver的移植第一步,一般这个是由wifi厂家来确保的,我们学习这个flow的主要作用是检验我们拿到的driver和supplicant是否ok,不然冒然开始做移植,后续出问题来难以定位到具体是什么原因,具体android部分的修改,我们下次再介绍,写的不好请大家指正,小弟也是刚学习android的菜鸟,谢谢!

Android下同时使用WIFI与3G网络

source:

http://blog.csdn.net/roger__wong/article/details/8603275


Android下同时使用WIFI与3G网络

分类: LINUX与ANDROID编程 14095人阅读 评论(41) 收藏 举报
编程时候发现当打开WIFI网络的时候系统默认就会把3G网络给关闭,估计是出于省电的原因才如此做的,但目前我需要同时使用这两个网络接口,经过一番研究找到了方法,故写成日志记录下来。
1、android网络机制。
wifi的开启关闭首先由应用程序触发的事件开始(比如用户点击开启图标),然后传入framework层,framework层启动wpa_supplicant,同时建立socket连接与wpa_supplicant进行通信,包括对wpa_supplicant的控制与得到wpa_supplicant的回传结果。若连接上了一个无线网络,则调用dhcp服务申请ip地址(或者使用预先设置好的ip,不过大部分情况下是dhcp的)。若这一切正常则断开3g网络连接并关闭3g接口。
因此从这个角度分析,若要同时启动3g和wifi则必须绕过framework层,手动完成上述所有操作。
因此我找到的方法是在3g网络不断的情况下,手动启动wifi网络,连接指定ap并申请ip。
2、操作步骤。
 (1) 准备工作
因为牵扯到底层操作,所以root必不可少,在root的情况下进入adb shell,若adb daemon没有root使用adb root命令进而使adb shell获得root权限。
原则上使用android里的终端软件也是可以的,但我没有测试。
(2)加载wifi驱动。
不加载驱动在netcfg里面根本看不到wlan0网卡,因此首先要加载驱动。
一般情况下,驱动放在/system/lib/modules下,我的驱动模块是wlan.ko。
insmod /system/lib/modules/wlan.ko。
加载前:
加载后:
发现多出来了wlan0也就是wifi网卡

(3)开启wifi网卡
使用netcfg wlan0 up开启wifi网卡,使用ifconfig wlan0 up也同样可以。
开启后:

(4)连接ap
启动wpa_supplicant并使之连接ap,在使用android系统时,如果开启wifi后范围内有一个之前连接过的wifi(而且这个wifi的ssid和密码还没改的话),那么我们的系统就会自动连接到这个wifi。因此手机里肯定是在某处记录者各个曾经连接过的wifi的ssid和密码。
我的手机(小米2,miui开发版3.xxx)这个默认位置是/data/misc/wifi/wpa_supplicant.conf。当把这个配置文件传给wpa_supplicant启动的时候,就会自动尝试连接其中记录的wifi网络。
使用命令wpa_supplicant -iwlan0 -c/data/misc/wifi/wpa_supplicant.conf -B 启动wpa_supplicant,-B代表后台运行,-i指定无线网卡。
此时若一切正常就会连接上无线ap,使用dmesg查看信息得到:
可以看到有连接成功的信息。

(5)使用dhcp获取ip信息
连接上了暂时还不能用,因为没有配置ip,使用dhcpcd wlan0配置ip信息,使用netcfg wlan0 dhcp也可以。
若出现类似以下信息则说明成功。

此时我们就在android下同时启用了wifi和3g。
此时使用netcfg可以看到两个接口都有ip,说明我们的方法有效。

当然最重要的是以上操作都可以在android用简单的程序来实现。
使用Runtime.getRuntime().exec(new String[] { "su","your command" });来执行命令,之后拿到相应输出流可以得到执行的结果,根据结果再执行下一步命令即可。

(6)更改路由表
到此为止手机已经连接上了无线AP,但本机数据包还无法通过WiFi接口走,原因是没有配置路由导致OS并不知道什么数据包该从WiFi走,什么数据包该从3G走,所以最后一步就是配置路由,告诉OS若IP包的源地址是3G接口的IP,则从3G端口走,否则从WiFi端口走。配置过程及命令如下,主要是使用了了ip命令:
ip route add table 5 via 192.168.1.1 dev wlan0 //添加一个路由表,若通过该路由表路由,则通过设备wlan0路由到地址192.168.1.1,也就是无线AP
ip route add from 192.168.1.140 table 5 prio 30000 //添加路由项,若源地址是192.168.1.140,则通过路由表5进行路由,优先级为30000
类似的,给3G接口也添加路由条目,优先级稍微低一点
然后设置dns,因为WiFi接口没法使用3G接口的默认DNS
setprop net.dns1 8.8.8.8
接着删除默认路由表项
ip route del default via 172.18.206.76 dev rmnet_usb0
重新添加指向wifi的默认路由表
ip route add default via 192.168.1.140 dev wlan0