基于Android5.1双APN的实现---接上篇

双APN问题解决,两个核心调用:

mCm.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
                            Phone.FEATURE_ENABLE_MMS);

—建立mms类型的dcac(dc)。
此命令对应的command如下:

08-29 17:25:27.336 D/CommandListener(  230): [run Route CMD]: route add ccmni2 secondary 10.130.128.1 32 0.0.0.0
08-29 17:25:27.336 D/CommandListener(  230): [run Route CMD]: route add ccmni2 secondary 10.130.128.1 32 0.0.0.0
08-29 17:25:27.366 D/CommandListener(  230): [run Route CMD]: route add ccmni2 secondary 0.0.0.0 0 10.130.128.1
08-29 17:25:27.366 D/CommandListener(  230): [run Route CMD]: route add ccmni2 secondary 0.0.0.0 0 10.130.128.1
08-29 17:25:27.395 D/CommandListener(  230): [run Route CMD]: route remove ccmni2 default 0.0.0.0 0 10.130.128.1
08-29 17:25:27.395 D/CommandListener(  230): [run Route CMD]: route remove ccmni2 default 0.0.0.0 0 10.130.128.1

secondary为另一张路由表。若没有配合其他操作,此处不会对路由有实际的影响。

mCm.requestRouteToHostAddress(ConnectivityManager.TYPE_MOBILE_MMS, netAddr);

—使用mms类型的dcac去访问指定的netAddr地址(双通路,未指定的依然走默认。如果MMS通路不存在,则走默认通路)

requestRouteToHostAddress()函数,通过socket与Netd通信,将command发送:

08-29 12:00:06.742 D/CommandListener(  230): [run Route CMD]: route add ccmni2 default 10.130.0.1 32 0.0 .0.0
08-29 12:00:06.747 D/CommandListener(  230): [run Route CMD]: route add ccmni2 default 61.135.169.125 32 10.130.0.1

其中倒数第二个参数分别为32和0:

    if (prefix_length == 32) {
        rt.rt_flags |= RTF_HOST;
    }

倒数第三个参数为destIP。
倒数第一个参数来源: //route来源于bestRoute

        if (route.getGateway() == null) {
            if (la.getAddress() instanceof Inet4Address) {
                cmd.appendArg("0.0.0.0");
            } else {
                cmd.appendArg("::0");
            }
        } else {
            cmd.appendArg(route.getGateway().getHostAddress());
        }

即gateway。

以上最终实现在libnetutils/ifc_utils.c中,通过
ifc_init()—建立与net驱动的socket连接
result = ioctl(ifc_ctl_sock, action, &rt)—通过ioctl将操作发送到net驱动,最终建立一个新的route规则:

root@m4g009:/ # ip route show
ip route show
default via 10.18.163.254 dev ccmni0  scope link
10.18.163.254 dev ccmni0  scope link
10.130.0.1 dev ccmni2  scope link
61.135.169.125 via 10.130.0.1 dev ccmni2  scope link

default via 10.18.163.254 dev ccmni0 scope link—默认通路。
61.135.169.125 via 10.130.0.1 dev ccmni2 scope link从函数传递下来的IP地址。设定default对应的是0.0.0.0/0这个目的地址。—从何而来?如何设定/切换?

接下来,确认多路由下的route设定/framework bestroute。

核心log:

08-31 14:44:10.425 D/ConnectivityService(  732): handleConnectivityChange: changed linkProperty[0]: doReset=false resetMask=0
08-31 14:44:10.425 D/ConnectivityService(  732):    curLp=null
08-31 14:44:10.425 D/ConnectivityService(  732):    newLp={InterfaceName: ccmni0 LinkAddresses: [10.130.0.1/32,]  Routes: [0.0.0.0/0 -> 10.130.0.1,] DnsAddresses: [58.240.57.33,221.6.4.66,] Domains: n
08-31 14:44:10.426 D/ConnectivityService(  732): Adding 10.130.0.1/32 -> 0.0.0.0 for interface ccmni0
08-31 14:44:10.431 D/ConnectivityService(  732): Adding 0.0.0.0/0 -> 10.130.0.1 for interface ccmni0

Routes: [0.0.0.0/0 -> 10.130.0.1,]是最后设置到main table中。其来源DataCallResponse::setLinkProperties()。

ConnectivityService中
private NetworkStateTracker mNetTrackers[]
用于跟踪所有网络的状态。其中MobileDataStateTracker对应手机网络,WifiStateTracker对应wifi网络。如下描述,此两种网络有各自独立的default route(基于config.xml)。
同时存在优先级,wifi > mobile.两者默认无法共存,当wifi开启时,mobile网络会被关闭,最终对应改变main table。

private void handleConnect(NetworkInfo info){
        // if this is a default net and other default is running
        // kill the one not preferred
        if (mNetConfigs[newNetType].isDefault()) {
          }
}

查看打开wifi时,handleConnectivityChange()的调用处理流程

    /**
     * The Mobile data connection.  When active, all data traffic
     * will use this network type's interface by default
     * (it has a default route)
     */
    public static final int TYPE_MOBILE      = 0;
    /**
     * The WIFI data connection.  When active, all data traffic
     * will use this network type's interface by default
     * (it has a default route).
     */
    public static final int TYPE_WIFI        = 1;

VPN建立时log,此时操作是非main table,但添加了 route rule

D/ConnectivityService(  732): getActiveNetworkInfo:NetworkInfo: type: mobile[LTE], state: CONNECTED/CONNECTED, reason: connected, extra: UNIM2M.NJM2MAPN, roaming: false, failover: true, isAvailable: true, isConnectedToProvisioningNetwork: false, simId: 0/10068
D/ConnectivityService(  732): getActiveNetworkInfo:NetworkInfo: type: mobile[LTE], state: CONNECTED/CONNECTED, reason: connected, extra: UNIM2M.NJM2MAPN, roaming: false, failover: true, isAvailable: true, isConnectedToProvisioningNetwork: false, simId: 0/10068
D/ConnectivityService(  732): getActiveNetworkInfo:NetworkInfo: type: mobile[LTE], state: CONNECTED/CONNECTED, reason: connected, extra: UNIM2M.NJM2MAPN, roaming: false, failover: true, isAvailable: true, isConnectedToProvisioningNetwork: false, simId: 0/10068
D/ConnectivityService(  732): getActiveNetworkInfo:NetworkInfo: type: mobile[LTE], state: CONNECTED/CONNECTED, reason: connected, extra: UNIM2M.NJM2MAPN, roaming: false, failover: true, isAvailable: true, isConnectedToProvisioningNetwork: false, simId: 0/10068
D/NetworkManagementService(  732): onEvent:600 Iface added tun0:4
D/NetworkManagementService(  732): onEvent:600 Iface added tun0:4
D/NetworkManagementService(  732): onEvent:600 Iface linkstate tun0 down:5
D/NetworkManagementService(  732): onEvent:600 Iface linkstate tun0 up:5
D/NetworkManagementService(  732): onEvent:600 Iface linkstate tun0 down:5
D/NetworkManagementService(  732): onEvent:600 Iface linkstate tun0 up:5
D/NetworkManagementService(  732): onEvent:614 Address updated 10.20.30.1/32 tun0 128 0:7
D/NetworkManagementService(  732): onEvent:614 Address updated 10.20.30.1/32 tun0 128 0:7
D/NetworkManagementService(  732): onEvent:614 Address removed 10.20.30.1/32 tun0 128 0:7
D/NetworkManagementService(  732): onEvent:614 Address removed 10.20.30.1/32 tun0 128 0:7
E/SecondaryTablController(  231): runCmd : cmd : /system/bin/ip route add default dev tun0 table 60
E/SecondaryTablController(  231): runCmd : cmd : /system/bin/ip route add default dev tun0 table 60
E/SecondaryTablController(  231): runCmd : cmd : /system/bin/ip route add default dev tun0 table 60
D/NetworkManagementService(  732): onEvent:614 Address updated 10.20.30.1/24 tun0 128 0:7
D/NetworkManagementService(  732): onEvent:614 Address updated 10.20.30.1/24 tun0 128 0:7
E/SecondaryTablController(  231): runCmd : cmd : /system/bin/ip -6 route add default dev tun0 table 60
E/SecondaryTablController(  231): runCmd : cmd : /system/bin/ip -6 route add default dev tun0 table 60
E/SecondaryTablController(  231): runCmd : cmd : /system/bin/ip -6 route add default dev tun0 table 60
E/SecondaryTablController(  231): runCmd : cmd : /system/bin/ip -6 route replace unreachable default table 60
E/SecondaryTablController(  231): runCmd : cmd : /system/bin/ip -6 route replace unreachable default table 60
E/SecondaryTablController(  231): runCmd : cmd : /system/bin/ip -6 route replace unreachable default table 60
E/SecondaryTablController(  231): runCmd : cmd : /system/bin/ip -4 rule add prio 100 to 1.0.0.0/8 fwmark 60 table 60
E/SecondaryTablController(  231): runCmd : cmd : /system/bin/ip -4 rule add prio 100 to 1.0.0.0/8 fwmark 60 table 60
E/SecondaryTablController(  231): runCmd : cmd : /system/bin/ip -4 rule add prio 100 to 1.0.0.0/8 fwmark 60 table 60
E/SecondaryTablController(  231): runCmd : cmd : /system/bin/ip -4 rule add prio 100 to 2.0.0.0/8 fwmark 60 table 60
# ip rule add fwmark 3  table 3 

fwmark 3是标记,table 3 是路由表3 上边。 意思为凡是标记了 3 的数据使用table3 路由表

之后使用iptables给相应的数据打上标记:

# iptables -A PREROUTING -t mangle -i eth0 -s 192.168.0.1 -192.168.0.100 -j MARK --set-mark 3

因为mangle的处理是优先于 nat 和fiter表的,所以相应数据包到达之后先打上标记,之后再通过ip rule规则。对应的数据包使用相应的路由表进行路由,最后读取路由表信息,将数据包送出网关。

startUsingNetworkFeature调用建立mms的dcac,对应的状态:

E/SecondaryTablController(  232): runCmd : /system/bin/ip route add 10.130.0.2/32 via 0.0.0.0 dev ccmni2 table 60
E/SecondaryTablController(  232): runCmd : /system/bin/ip route add 0.0.0.0/0 via 10.130.0.2 dev ccmni2 table 60

开启wifi热点对应的log,其操作的是main table

D/NetworkManagementService(  732): onEvent:600 Iface linkstate wlan%d down:5
D/NetworkManagementService(  732): onEvent:600 Iface added wlan0:4
D/NetworkManagementService(  732): onEvent:600 Iface linkstate wlan0 down:5
D/NetworkManagementService(  732): onEvent:600 Iface added ap0:4
D/NetworkManagementService(  732): onEvent:600 Iface linkstate ap0 down:5
D/ConnectivityService(  732): received intent ==> android.net.conn.TETHER_STATE_CHANGED
D/ConnectivityService(  732): getMobileDataEnabled returning true
D/NetworkManagementService(  732): onEvent:600 Iface linkstate ap0 up:5
D/NetworkManagementService(  732): onEvent:600 Iface linkstate ap0 up:5
D/ConnectivityService(  732): received intent ==> android.net.conn.TETHER_STATE_CHANGED
D/ConnectivityService(  732): getMobileDataEnabled returning true
D/NetworkManagementService(  732): onEvent:600 Iface linkstate ap0 up:5
D/NetworkManagementService(  732): Enter setInterfaceConfig, iface=ap0
D/CommandListener(  231): Setting iface cfg
D/CommandListener(  231): Trying to bring up ap0
D/NetworkManagementService(  732): onEvent:614 Address updated 192.168.43.1/24 ap0 128 0:7
I/CommandListener_(  231): DumpRoute ++
I/CommandListener_(  231): Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
I/CommandListener_(  231): 0.0.0.0         10.13.28.50     0.0.0.0         UG    0      0        0 ccmni0
I/CommandListener_(  231): 10.13.28.50     0.0.0.0         255.255.255.255 UH    0      0        0 ccmni0
I/CommandListener_(  231): 192.168.43.0    0.0.0.0         255.255.255.0   U     0      0        0 ap0
I/CommandListener_(  231): DumpRoute --
D/ConnectivityService(  732): received intent ==> android.net.conn.TETHER_STATE_CHANGED
D/ConnectivityService(  732): received intent ==> android.net.conn.TETHER_STATE_CHANGED
D/ConnectivityService(  732): getMobileDataEnabled returning true
D/ConnectivityService(  732): getMobileDataEnabled returning true
D/NetworkManagementService(  732): onEvent:614 Address updated fe80::8:22ff:fe6c:e008/64 ap0 128 253:7

目前问题的疑问点:热点和VPN,都会在main table更新规则,并且VPN有通过命令建立新的指向性rule。

100:    from all to 219.0.0.0/8 fwmark 0x3c lookup 60
100:    from all to 220.0.0.0/8 fwmark 0x3c lookup 60
100:    from all to 221.0.0.0/8 fwmark 0x3c lookup 60
100:    from all to 222.0.0.0/8 fwmark 0x3c lookup 60
100:    from all to 223.0.0.0/8 fwmark 0x3c lookup 60
100:    from all to 8.8.0.0/16 fwmark 0x3c lookup 60
32766:  from all lookup main
32767:  from all lookup default

10.20.30.0/24 dev tun0 proto kernel scope link src 10.20.30.1
如何进行的跳转???
—Vpn实则代理机制,本机去代理IP通信,代理再进行了一次route(VPN时,并没有新建dcac,同时貌似VPN和HostAP无法同时开启)
—Wifi热点,本机是一个网关,如何让STA机器通过网关时,由网关指定的通路出去???—NAT!!!Chain natctrl_tether_counters

Vpn开启时log:

D/ConnectivityService(  782): Setting TCP values: [4094,87380,524288,4096,16384,524288] which comes from [net.tcp.buffersize.hspa]
D/ConnectivityService(  782): getMobileDataEnabled returning true
D/ConnectivityService(  782): getMobileDataEnabled returning true
D/ConnectivityService(  782): getMobileDataEnabled returning true
D/ConnectivityService(  782): getActiveNetworkInfo:NetworkInfo: type: mobile[HSPA], state: CONNECTED/CONNECTED, reason: nwTypeChanged, extra: UNIM2M.NJM2MAPN, roaming: false, failover: false, isAvailable: true, isConnectedToProvisioningNetwork: false, simId: 0/10068
D/ConnectivityService(  782): Setting TCP values: [4094,87380,1220608,4096,16384,1220608] which comes from [net.tcp.buffersize.hspap]
D/ConnectivityService(  782): getMobileDataEnabled returning true
D/ConnectivityService(  782): getMobileDataEnabled returning true
D/ConnectivityService(  782): getMobileDataEnabled returning true
D/ConnectivityService(  782): getActiveNetworkInfo:NetworkInfo: type: mobile[HSPA+], state: CONNECTED/CONNECTED, reason: nwTypeChanged, extra: UNIM2M.NJM2MAPN, roaming: false, failover: false, isAvailable: true, isConnectedToProvisioningNetwork: false, simId: 0/10068
D/NetworkManagementService(  782): onEvent:600 Iface added tun0:4
D/NetworkManagementService(  782): onEvent:600 Iface linkstate tun0 down:5
D/NetworkManagementService(  782): onEvent:600 Iface linkstate tun0 up:5
D/NetworkManagementService(  782): onEvent:614 Address updated 10.20.30.1/32 tun0 128 0:7
D/NetworkManagementService(  782): onEvent:614 Address removed 10.20.30.1/32 tun0 128 0:7
D/NetworkManagementService(  782): onEvent:614 Address updated 10.20.30.1/24 tun0 128 0:7

本机使用双APN,同时还要控制当本机为AP模式时,STA的数据通路是怎样的状态?进行实验:
1.del route default ccmni0—STA无法访问网络
2.add route default ccmni0—-STA可以访问网络
3.add route default ccmni2(mms)—-STA无法访问网络

看上去ccmni0与Hostap之间存在一种绑定关系(iptables -v -L,Chain natctrl_tether_counters。iptables -t mangle -L -n查看fwmark),或者是framework的状态位的问题。
—可在framework中添加判断调用,在ccmni2有效的情况下,从framework的调用开始直接改变,排除状态位的影响
—Chain natctrl_tether_counters 这个规则导致的,所以从framework下手需要确认此规则从何时设定。
—上面的规则通过NatController::enableNat()函数来设定,其确实是framework而来。

调用类似route,其由Tethering.java共享网络发起调用。
Tethering.java:

                        for (Integer netType : mUpstreamIfaceTypes) {
                            NetworkInfo info = null;
                            try {
                                info = mConnService.getNetworkInfo(netType.intValue());
                            } catch (RemoteException e) { }
                            if ((info != null) && info.isConnected()) {
                                upType = netType.intValue();
                                break;
                            }
                        }

mUpstreamIfaceTypes数组
通过读取config.xml的配置config_tether_upstream_types数组而来:


    

指定了哪些网络类型可以支持AP模式,即可开启NAT。

另,通过上面的代码发现,当多网口同时工作时,以数组排列顺序为优先级。log如下:

7-06 18:00:12.586 D/Tethering(  696): startListeningForSimChanges
7-06 18:00:12.586 D/Tethering(  696): isGeminiSupport: false
7-06 18:00:12.586 I/Tethering(  696): ifaceTypes = null, use default
7-06 18:00:12.586 I/Tethering(  696): upstreamIfaceTypes.add:0
7-06 18:00:12.586 I/Tethering(  696): upstreamIfaceTypes.add:1
7-06 18:00:12.586 I/Tethering(  696): upstreamIfaceTypes.add:2
7-06 18:00:12.586 I/Tethering(  696): upstreamIfaceTypes.add:5
7-06 18:00:12.586 I/Tethering(  696): upstreamIfaceTypes.add:7
7-06 18:00:12.586 I/Tethering(  696): upstreamIfaceTypes.add:9
7-06 18:00:12.586 I/Tethering(  696): upstreamIfaceTypes.add:49
7-06 18:00:12.586 D/Tethering(  696): simchange mGenerationNumber=5, current generationNumber=5
7-06 18:00:12.586 D/Tethering(  696): got Sim changed to state LOADED, mSimAbsentSeen=false
7-06 18:00:12.589 I/Tethering(  696): checkDunRequired:2
7-06 18:00:12.589 D/Tethering(  696): mPreferredUpstreamMobileApn = 5
7-06 18:00:12.589 D/Tethering(  696): isTetheringIpv6Support: true
7-06 18:00:12.589 D/Tethering(  696): getIpv6FeatureEnable:0
7-06 18:00:12.589 D/Tethering(  696): [TetherMaster]chooseUpstreamType has upstream iface types:
7-06 18:00:12.589 D/Tethering(  696):  0
7-06 18:00:12.589 D/Tethering(  696):  1
7-06 18:00:12.589 D/Tethering(  696):  2
7-06 18:00:12.589 D/Tethering(  696):  5
7-06 18:00:12.589 D/Tethering(  696):  7
7-06 18:00:12.589 D/Tethering(  696):  9
7-06 18:00:12.589 D/Tethering(  696):  49
18:00:12.589 D/Tethering(  696): [TetherMaster]chooseUpstreamType(true), preferredApn =5, got type=0
18:00:12.592 I/Tethering(  696): checkDataEnabled:true
18:00:12.592 D/Tethering(  696): pre-checkDataEnabled + true
18:00:12.592 I/Tethering(  696): [MSM_TetherModeAlive][TetherMaster] mMobileApnReserved:-1
18:00:12.592 D/Tethering(  696): isTetheringIpv6Support: true
18:00:12.592 D/Tethering(  696): isTetheringIpv6Support: true
18:00:12.592 I/Tethering(  696): Finding IPv4 upstream interface on: {InterfaceName: ccmni0 LinkAddresses: [10.20.108.135/32,]  Routes: [0.0.0.
18:00:12.592 I/Tethering(  696): Found interface ccmni0
18:00:12.592 E/Tethering(  696): v4 and v6 Dnses: [/221.6.4.66, /58.240.57.33]
18:00:12.592 D/Tethering(  696): Setting DNS forwarders: Network=102, dnsServers=[221.6.4.66, 58.240.57.33]
18:00:12.596 I/Tethering(  696): [MSM_TetherModeAlive][TetherMaster] notifying tethered with iface =ccmni0
18:00:12.596 D/Tethering(  696): isTetheringIpv6Support: true
18:00:12.596 I/Tethering(  696): [ISM_Tethered] ap0 processMessage what=12
18:00:12.596 D/Tethering(  696): isTetheringIpv6Support: true
18:00:12.596 I/Tethering(  696): [ISM_Tethered:null] CMD_TETHER_CONNECTION_CHANGED mMyUpstreamIfaceName: null, mMyUpstreamIfaceNameIpv6:null, n
18:00:12.596 D/Tethering(  696): isTetheringIpv6Support: true
18:00:12.596 D/Tethering(  696): isTetheringIpv6Support: true
18:00:12.645 I/Tethering(  696): [ISM_Tethered] CMD_TETHER_CONNECTION_CHANGED enableNat for:null(ap0, ccmni0)
18:00:12.645 D/Tethering(  696): isTetheringIpv6Support: true
18:00:12.645 I/Tethering(  696): [ISM_Tethered] CMD_TETHER_CONNECTION_CHANGED finished!null
18:00:12.645 D/Tethering(  696): isTetheringIpv6Support: true
18:00:12.708 I/Tethering(  696): addressUpdated ap0, fe80::8:22ff:feba:5720/64

另,多次映射后,下面的Chain会一直保留,是否会引起问题???

Chain natctrl_tether_counters (2 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 RETURN     all  --  ap0    ccmni2  anywhere             anywhere
    0     0 RETURN     all  --  ccmni2 ap0     anywhere             anywhere
    0     0 RETURN     all  --  ap0    ccmni0  anywhere             anywhere
    0     0 RETURN     all  --  ccmni0 ap0     anywhere             anywhere

Android使用了多个Linux内核的高级包过滤和路由特性来实现per-user VPN。
这些特性(通过netfilter内核框架实现)包含了Linux的iptables工具的owner模块,能够使用数据包生成进程的UID、GID或者PID对数据包进行匹配。

此外,netfilter的另外一个重要特性是能够为特定数据包打上特定的数字标签(mark)。例如,的规则将所有目标端口为80(通常是网站服务器)的数据包标记上0x1。之后这个标记可以被用来进行过滤和路由。
比如,通过添加将标记的包发送给预定义的路由表的路由规则,将标记的包通过特定的接口进行发送。最后添加一条路由,将匹配web路由表的数据包发送到em3接口。

调用流程:

DcTracker::onDataSetupComplete()---A SETUP (aka bringUp) has completed,创建一个dcac后会回调此方法
DcTracker::notifyDefaultData()
PhoneBase::notifyDataConnection()
DefaultPhoneNotifier::doNotifyDataConnection()---其中linkProperties = sender.getLinkProperties(apnType)>>>DcAsyncChannel::getLinkPropertiesSync()>>>DataConnection::getCopyLinkProperties()>>>DataCallResponse.SetupResult setLinkProperties()>>>DataCallResponse linkProperties.addRoute(new RouteInfo(ia))最终的route只存在ia网关,其他都为0

TelephonyRegistry::notifyDataConnection()
MobileDataStateTracker::onDataStateChanged()
MobileDataStateTracker::updateLinkProperitesAndCapatilities()---从intent中获取mLinkProperties
MobileDataStateTracker::setDetailedState()---发送EVENT_STATE_CHANGED到CS服务中的消息队列中
ConnectivityService::handleConnect()---        // if this is a default net and other default is running  kill the one not preferred
ConnectivityService::handleConnectivityChange()
ConnectivityService::updateRoutes()
ConnectivityService::addRoute()
ConnectivityService::modifyRoute()---mNetd.addRoute(ifaceName, r)
NetworkManagementService::modifyRoute()---mConnector.execute(cmd); final Command cmd = new Command("interface", "route", action, interfaceName, type);
CommandListener::InterfaceCmd::runCommand()---default类型ioctl(ifc_ctl_sock, action, &rt)通过socket直接与驱动通信更新route规则;secondary类型sSecondaryTableCtrl->addRoute(),直接用runCmd调用/system/bin/ip route更新规则

总结:
需求:双APN通路,其中APN1是普通apn,可访问所有网络。APN2是特殊apn,只能访问指定网络。默认双通路同时工作,APN1为主通路(AP模式),APN2只提供给特殊app使用。当APN1的流量使用达到阀值,将主通路设置为APN2。
思路:遵循上面的两句调用。

方案一:
“当APN1的流量使用达到阀值,将主通路设置为APN2”
—此处可使用类似VPN的处理,达到阀值时候,修改ip ru和对应table规则,使所有连接访问走APN2通路对应的网口。需要注意Chain natctrl_tether_counters,其默认只支持部分网络类型(APN2基于Mms类型的话,需要修改framework配合)。

方案二:
当以Mms网络类型建立dcac后,其对应操作的是非main table。修改framework,使其直接修改main table,然后上层应用判定阀值,进行切换。同样要注意Chain natctrl_tether_counters。
framework简单修改:

diff --git a/base/services/java/com/android/server/ConnectivityService.java b/base/services/java/com/android/server/ConnectivityService.java
old mode 100644
new mode 100755
index be19c1a..b40e410
--- a/base/services/java/com/android/server/ConnectivityService.java
+++ b/base/services/java/com/android/server/ConnectivityService.java
@@ -3091,7 +3091,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
             }
         }
         mCurrentLinkProperties[netType] = newLp;
-        boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault(), exempt);
+        boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault(), exempt, netType==2);

         if (resetMask != 0 || resetDns) {
             if (VDBG) log("handleConnectivityChange: resetting");
@@ -3173,7 +3173,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
      * returns a boolean indicating the routes changed
      */
     private boolean updateRoutes(LinkProperties newLp, LinkProperties curLp,
-            boolean isLinkDefault, boolean exempt) {
+            boolean isLinkDefault, boolean exempt, boolean isSpecial) {
         Collection routesToAdd = null;
         CompareResult dnsDiff = new CompareResult();
         CompareResult routeDiff = new CompareResult();
@@ -3189,7 +3189,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
         boolean routesChanged = (routeDiff.removed.size() != 0 || routeDiff.added.size() != 0);

         for (RouteInfo r : routeDiff.removed) {
-            if (isLinkDefault || ! r.isDefaultRoute()) {
+            if (isLinkDefault || ! r.isDefaultRoute() || isSpecial) {
                 if (VDBG) log("updateRoutes: default remove route r=" + r);
                 removeRoute(curLp, r, TO_DEFAULT_TABLE);
             }
@@ -3245,7 +3245,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
         }

         for (RouteInfo r :  routeDiff.added) {
-            if (isLinkDefault || ! r.isDefaultRoute()) {
+            if (isLinkDefault || ! r.isDefaultRoute() || isSpecial) {
                 addRoute(newLp, r, TO_DEFAULT_TABLE, exempt);
             } else {
                 // add to a secondary route table

此处还需要注意Tethering的配合!!!

方案三:
上层应用直接通过root shell的方式,操作route table以及ru。注意Tethering的情况。

注意:以Mms类型,需要修改config.xml中网络类型超时设定。

使用到的命令:
netcfg
ip rule
ip route
ip route list table 0/254
iptables -v -L
iptables -t mangle -L -n

摘抄部分:

* 關於路由的相關設定: ip route

這個項目當然就是路由的觀察與設定囉!事實上, ip route 的功能幾乎與 route 這個指令差不多,但是,他還可以進行額外的參數設計,例如 MTU 的規劃等等,相當的強悍啊!
[root@www ~]# ip route show <==單純的顯示出路由的設定而已
[root@www ~]# ip route [add|del] [IP或網域] [via gateway] [dev 裝置]選項與參數:
show :單純的顯示出路由表,也可以使用 list ;
add|del :增加 (add) 或刪除 (del) 路由的意思。
IP或網域:可使用 192.168.50.0/24 之類的網域或者是單純的 IP ;
via :從那個 gateway 出去,不一定需要;
dev :由那個裝置連出去,這就需要了!
mtu :可以額外的設定 MTU 的數值喔!

範例一:顯示出目前的路由資料

[root@www ~]# ip route show
192.168.1.0/24 dev eth0  proto kernel  scope link  src 192.168.1.100
169.254.0.0/16 dev eth0  scope link  metric 1002
default via 192.168.1.254 dev eth0

如上表所示,最簡單的功能就是顯示出目前的路由資訊,其實跟 route 這個指令相同啦! 指示必須要注意幾個小東西:

* proto:此路由的路由協定,主要有 redirect, kernel, boot, static, ra 等, 其中 kernel 指的是直接由核心判斷自動設定。
* scope:路由的範圍,主要是 link ,亦即是與本裝置有關的直接連線。

再來看一下如何進行路由的增加與刪除吧!

範例二:增加路由,主要是本機直接可溝通的網域

[root@www ~]# ip route add 192.168.5.0/24 dev eth0# 針對本機直接溝通的網域設定好路由,不需要透過外部的路由器
[root@www ~]# ip route show
192.168.5.0/24 dev eth0  scope link

….(以下省略)….

範例三:增加可以通往外部的路由,需透過 router 喔!

[root@www ~]# ip route add 192.168.10.0/24 via 192.168.5.100 dev eth0
[root@www ~]# ip route show
192.168.5.0/24 dev eth0  scope link
....(其他省略)....
192.168.10.0/24 via 192.168.5.100 dev eth0

仔細看喔,因為我有 192.168.5.0/24 的路由存在 (我的網卡直接聯繫),
所以才可以將 192.168.10.0/24 的路由丟給 192.168.5.100
那部主機來幫忙傳遞喔!與之前提到的 route 指令是一樣的限制!

範例四:增加預設路由

[root@www ~]# ip route add default via 192.168.1.254 dev eth0

那個 192.168.1.254 就是我的預設路由器 (gateway) 的意思啊! ^_^
真的記得,只要一個預設路由就 OK !

範例五:刪除路由

[root@www ~]# ip route del 192.168.10.0/24
[root@www ~]# ip route del 192.168.5.0/24

示例:
1.APN配置

APN1:UNIM2M.NJM2MAPN(default)
APN2:BJKKJL01.XFDZ.NJM2MAPN(mms)

2.pad启动后,APN1(ccmni0)自动开启。
1)主路由表main规则如下(保持主路由表main规则不变):

ip ro sh ta main
default via 10.7.144.79 dev ccmni0  scope link
10.7.144.79 dev ccmni0  scope link
192.168.43.0/24 dev ap0  proto kernel  scope link  src 192.168.43.1

2)添加对应APN2的路由表(202)及规则,添加前先开启APN2(ccmni2开启)。

ip ro add default dev ccmni2 ta 202
ip ro add 192.168.43.0/24 dev ap0
ip ro sh ta 202
default dev ccmni2  scope link

3)清空rule

ip ru flush
ip ru
0:      from all lookup local

4)添加指向main的路由规则、指向202的路由规则

ip ru add from 192.168.43.0/24 lookup main
ip ru add from all lookup 202
ip ru
0:      from all lookup local
0:      from 192.168.43.0/24 lookup main
0:      from all lookup 202

你可能感兴趣的:(基于Android5.1双APN的实现---接上篇)