author | Zhiwei Gong <zhiwei.gong@amlogic.com> | 2015-01-16 08:46:43 (GMT) |
---|---|---|
committer | zhiwei.gong <zhiwei.gong@amlogic.com> | 2015-01-19 02:04:07 (GMT) |
commit | 7abd6089b536b9422e647fe9a13526de72497912 (patch) | |
tree | 7277b8086206579cb28ebda5bd03ab388371d18c | |
parent | 2978d264b0115244dd46de3ca93c00bce6befc7f (diff) | |
download | pppoe-7abd6089b536b9422e647fe9a13526de72497912.zip pppoe-7abd6089b536b9422e647fe9a13526de72497912.tar.gz pppoe-7abd6089b536b9422e647fe9a13526de72497912.tar.bz2 |
add pppoe support
Change-Id: I9b48039d6b6a317010059119be48ce44f3e0a951
-rw-r--r-- | java/Android.mk | 24 | ||||
-rw-r--r-- | java/src/com/droidlogic/pppoe/DhcpInfoInternal.java | 173 | ||||
-rw-r--r-- | java/src/com/droidlogic/pppoe/IPppoeManager.java | 365 | ||||
-rw-r--r-- | java/src/com/droidlogic/pppoe/PppoeDevInfo.java | 109 | ||||
-rw-r--r-- | java/src/com/droidlogic/pppoe/PppoeManager.java | 137 | ||||
-rw-r--r-- | java/src/com/droidlogic/pppoe/PppoeMonitor.java | 119 | ||||
-rw-r--r-- | java/src/com/droidlogic/pppoe/PppoeNative.java | 21 | ||||
-rw-r--r-- | java/src/com/droidlogic/pppoe/PppoeService.java | 274 | ||||
-rw-r--r-- | java/src/com/droidlogic/pppoe/PppoeStateTracker.java | 615 | ||||
-rw-r--r-- | java/src/com/droidlogic/pppoe/package.html | 3 | ||||
-rw-r--r-- | jni/Android.mk | 19 | ||||
-rw-r--r-- | jni/com_droidlogic_common.cpp | 551 | ||||
-rw-r--r-- | jni/com_droidlogic_common.h | 64 | ||||
-rw-r--r-- | jni/com_droidlogic_pppoe.cpp | 302 |
14 files changed, 2776 insertions, 0 deletions
diff --git a/java/Android.mk b/java/Android.mk new file mode 100644 index 0000000..dbd7cc0 --- a/dev/null +++ b/java/Android.mk @@ -0,0 +1,24 @@ +# Copyright (C) 2014 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. +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := droidlogic.frameworks.pppoe + +LOCAL_SRC_FILES := $(call all-java-files-under,src) +LOCAL_MODULE_TAGS := optional + +include $(BUILD_JAVA_LIBRARY) + diff --git a/java/src/com/droidlogic/pppoe/DhcpInfoInternal.java b/java/src/com/droidlogic/pppoe/DhcpInfoInternal.java new file mode 100644 index 0000000..eecaadd --- a/dev/null +++ b/java/src/com/droidlogic/pppoe/DhcpInfoInternal.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2010 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. + */ + +package com.droidlogic.pppoe; + + + +import android.text.TextUtils; +import android.util.Log; +import android.net.RouteInfo; +import android.net.DhcpInfo; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.NetworkUtils; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +/** + * A simple object for retrieving the results of a DHCP request. + * Replaces (internally) the IPv4-only DhcpInfo class. + * @hide + */ +public class DhcpInfoInternal { + private final static String TAG = "DhcpInfoInternal"; + public String ipAddress; + public int prefixLength; + + public String dns1; + public String dns2; + + public String serverAddress; + public int leaseDuration; + + /** + * Vendor specific information (from RFC 2132). + */ + public String vendorInfo; + + private Collection<RouteInfo> mRoutes; + + public DhcpInfoInternal() { + mRoutes = new ArrayList<RouteInfo>(); + } + + public void addRoute(RouteInfo routeInfo) { + mRoutes.add(routeInfo); + } + + public Collection<RouteInfo> getRoutes() { + return Collections.unmodifiableCollection(mRoutes); + } + + private int convertToInt(String addr) { + if (addr != null) { + try { + InetAddress inetAddress = NetworkUtils.numericToInetAddress(addr); + if (inetAddress instanceof Inet4Address) { + return NetworkUtils.inetAddressToInt((Inet4Address)inetAddress); + } + } catch (IllegalArgumentException e) {} + } + return 0; + } + + public DhcpInfo makeDhcpInfo() { + DhcpInfo info = new DhcpInfo(); + info.ipAddress = convertToInt(ipAddress); + for (RouteInfo route : mRoutes) { + if (route.isDefaultRoute()) { + info.gateway = convertToInt(route.getGateway().getHostAddress()); + break; + } + } + try { + InetAddress inetAddress = NetworkUtils.numericToInetAddress(ipAddress); + info.netmask = NetworkUtils.prefixLengthToNetmaskInt(prefixLength); + } catch (IllegalArgumentException e) {} + info.dns1 = convertToInt(dns1); + info.dns2 = convertToInt(dns2); + info.serverAddress = convertToInt(serverAddress); + info.leaseDuration = leaseDuration; + return info; + } + + public LinkAddress makeLinkAddress() { + if (TextUtils.isEmpty(ipAddress)) { + Log.e(TAG, "makeLinkAddress with empty ipAddress"); + return null; + } + return new LinkAddress(NetworkUtils.numericToInetAddress(ipAddress), prefixLength); + } + + public LinkProperties makeLinkProperties() { + LinkProperties p = new LinkProperties(); + p.addLinkAddress(makeLinkAddress()); + for (RouteInfo route : mRoutes) { + p.addRoute(route); + } + //if empty, connectivity configures default DNS + if (TextUtils.isEmpty(dns1) == false) { + p.addDnsServer(NetworkUtils.numericToInetAddress(dns1)); + } else { + Log.d(TAG, "makeLinkProperties with empty dns1!"); + } + if (TextUtils.isEmpty(dns2) == false) { + p.addDnsServer(NetworkUtils.numericToInetAddress(dns2)); + } else { + Log.d(TAG, "makeLinkProperties with empty dns2!"); + } + return p; + } + + /* Updates the DHCP fields that need to be retained from + * original DHCP request if the DHCP renewal shows them as + * being empty + */ + public void updateFromDhcpRequest(DhcpInfoInternal orig) { + if (orig == null) return; + + if (TextUtils.isEmpty(dns1)) { + dns1 = orig.dns1; + } + + if (TextUtils.isEmpty(dns2)) { + dns2 = orig.dns2; + } + + if (mRoutes.size() == 0) { + for (RouteInfo route : orig.getRoutes()) { + addRoute(route); + } + } + } + + /** + * Test if this DHCP lease includes vendor hint that network link is + * metered, and sensitive to heavy data transfers. + */ + public boolean hasMeteredHint() { + if (vendorInfo != null) { + return vendorInfo.contains("ANDROID_METERED"); + } else { + return false; + } + } + + public String toString() { + String routeString = ""; + for (RouteInfo route : mRoutes) routeString += route.toString() + " | "; + return "addr: " + ipAddress + "/" + prefixLength + + " mRoutes: " + routeString + + " dns: " + dns1 + "," + dns2 + + " dhcpServer: " + serverAddress + + " leaseDuration: " + leaseDuration; + } +} diff --git a/java/src/com/droidlogic/pppoe/IPppoeManager.java b/java/src/com/droidlogic/pppoe/IPppoeManager.java new file mode 100644 index 0000000..5b04d04 --- a/dev/null +++ b/java/src/com/droidlogic/pppoe/IPppoeManager.java @@ -0,0 +1,365 @@ +/* + * This file is auto-generated. DO NOT MODIFY. + * Original file: frameworks/base/pppoe/java/android/net/pppoe/IPppoeManager.aidl + */ +package com.droidlogic.pppoe; +public interface IPppoeManager extends android.os.IInterface +{ +/** Local-side IPC implementation stub class. */ +public static abstract class Stub extends android.os.Binder implements com.droidlogic.pppoe.IPppoeManager +{ +private static final java.lang.String DESCRIPTOR = "com.droidlogic.pppoe.IPppoeManager"; +/** Construct the stub at attach it to the interface. */ +public Stub() +{ +this.attachInterface(this, DESCRIPTOR); +} +/** + * Cast an IBinder object into an android.net.pppoe.IPppoeManager interface, + * generating a proxy if needed. + */ +public static com.droidlogic.pppoe.IPppoeManager asInterface(android.os.IBinder obj) +{ +if ((obj == null)) { +return null; +} +android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); +if (((iin != null) && (iin instanceof com.droidlogic.pppoe.IPppoeManager))) { +return ((com.droidlogic.pppoe.IPppoeManager)iin); +} +return new com.droidlogic.pppoe.IPppoeManager.Stub.Proxy(obj); +} +@Override public android.os.IBinder asBinder() +{ +return this; +} +@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException +{ +switch (code) +{ +case INTERFACE_TRANSACTION: +{ +reply.writeString(DESCRIPTOR); +return true; +} +case TRANSACTION_getDeviceNameList: +{ +data.enforceInterface(DESCRIPTOR); +java.lang.String[] _result = this.getDeviceNameList(); +reply.writeNoException(); +reply.writeStringArray(_result); +return true; +} +case TRANSACTION_setPppoeState: +{ +data.enforceInterface(DESCRIPTOR); +int _arg0; +_arg0 = data.readInt(); +this.setPppoeState(_arg0); +reply.writeNoException(); +return true; +} +case TRANSACTION_getPppoeState: +{ +data.enforceInterface(DESCRIPTOR); +int _result = this.getPppoeState(); +reply.writeNoException(); +reply.writeInt(_result); +return true; +} +case TRANSACTION_UpdatePppoeDevInfo: +{ +data.enforceInterface(DESCRIPTOR); +com.droidlogic.pppoe.PppoeDevInfo _arg0; +if ((0 != data.readInt())) { +_arg0 = com.droidlogic.pppoe.PppoeDevInfo.CREATOR.createFromParcel(data); +} +else { +_arg0 = null; +} +this.UpdatePppoeDevInfo(_arg0); +reply.writeNoException(); +return true; +} +case TRANSACTION_isPppoeConfigured: +{ +data.enforceInterface(DESCRIPTOR); +boolean _result = this.isPppoeConfigured(); +reply.writeNoException(); +reply.writeInt(((_result)?(1):(0))); +return true; +} +case TRANSACTION_getSavedPppoeConfig: +{ +data.enforceInterface(DESCRIPTOR); +com.droidlogic.pppoe.PppoeDevInfo _result = this.getSavedPppoeConfig(); +reply.writeNoException(); +if ((_result != null)) { +reply.writeInt(1); +_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); +} +else { +reply.writeInt(0); +} +return true; +} +case TRANSACTION_getTotalInterface: +{ +data.enforceInterface(DESCRIPTOR); +int _result = this.getTotalInterface(); +reply.writeNoException(); +reply.writeInt(_result); +return true; +} +case TRANSACTION_setPppoeMode: +{ +data.enforceInterface(DESCRIPTOR); +java.lang.String _arg0; +_arg0 = data.readString(); +this.setPppoeMode(_arg0); +reply.writeNoException(); +return true; +} +case TRANSACTION_isPppoeDeviceUp: +{ +data.enforceInterface(DESCRIPTOR); +boolean _result = this.isPppoeDeviceUp(); +reply.writeNoException(); +reply.writeInt(((_result)?(1):(0))); +return true; +} +case TRANSACTION_getDhcpInfo: +{ +data.enforceInterface(DESCRIPTOR); +android.net.DhcpInfo _result = this.getDhcpInfo(); +reply.writeNoException(); +if ((_result != null)) { +reply.writeInt(1); +_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); +} +else { +reply.writeInt(0); +} +return true; +} +} +return super.onTransact(code, data, reply, flags); +} +private static class Proxy implements com.droidlogic.pppoe.IPppoeManager +{ +private android.os.IBinder mRemote; +Proxy(android.os.IBinder remote) +{ +mRemote = remote; +} +@Override public android.os.IBinder asBinder() +{ +return mRemote; +} +public java.lang.String getInterfaceDescriptor() +{ +return DESCRIPTOR; +} +@Override public java.lang.String[] getDeviceNameList() throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +java.lang.String[] _result; +try { +_data.writeInterfaceToken(DESCRIPTOR); +mRemote.transact(Stub.TRANSACTION_getDeviceNameList, _data, _reply, 0); +_reply.readException(); +_result = _reply.createStringArray(); +} +finally { +_reply.recycle(); +_data.recycle(); +} +return _result; +} +@Override public void setPppoeState(int state) throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +try { +_data.writeInterfaceToken(DESCRIPTOR); +_data.writeInt(state); +mRemote.transact(Stub.TRANSACTION_setPppoeState, _data, _reply, 0); +_reply.readException(); +} +finally { +_reply.recycle(); +_data.recycle(); +} +} +@Override public int getPppoeState() throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +int _result; +try { +_data.writeInterfaceToken(DESCRIPTOR); +mRemote.transact(Stub.TRANSACTION_getPppoeState, _data, _reply, 0); +_reply.readException(); +_result = _reply.readInt(); +} +finally { +_reply.recycle(); +_data.recycle(); +} +return _result; +} +@Override public void UpdatePppoeDevInfo(com.droidlogic.pppoe.PppoeDevInfo info) throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +try { +_data.writeInterfaceToken(DESCRIPTOR); +if ((info != null)) { +_data.writeInt(1); +info.writeToParcel(_data, 0); +} +else { +_data.writeInt(0); +} +mRemote.transact(Stub.TRANSACTION_UpdatePppoeDevInfo, _data, _reply, 0); +_reply.readException(); +} +finally { +_reply.recycle(); +_data.recycle(); +} +} +@Override public boolean isPppoeConfigured() throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +boolean _result; +try { +_data.writeInterfaceToken(DESCRIPTOR); +mRemote.transact(Stub.TRANSACTION_isPppoeConfigured, _data, _reply, 0); +_reply.readException(); +_result = (0!=_reply.readInt()); +} +finally { +_reply.recycle(); +_data.recycle(); +} +return _result; +} +@Override public com.droidlogic.pppoe.PppoeDevInfo getSavedPppoeConfig() throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +com.droidlogic.pppoe.PppoeDevInfo _result; +try { +_data.writeInterfaceToken(DESCRIPTOR); +mRemote.transact(Stub.TRANSACTION_getSavedPppoeConfig, _data, _reply, 0); +_reply.readException(); +if ((0 != _reply.readInt())) { +_result = com.droidlogic.pppoe.PppoeDevInfo.CREATOR.createFromParcel(_reply); +} +else { +_result = null; +} +} +finally { +_reply.recycle(); +_data.recycle(); +} +return _result; +} +@Override public int getTotalInterface() throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +int _result; +try { +_data.writeInterfaceToken(DESCRIPTOR); +mRemote.transact(Stub.TRANSACTION_getTotalInterface, _data, _reply, 0); +_reply.readException(); +_result = _reply.readInt(); +} +finally { +_reply.recycle(); +_data.recycle(); +} +return _result; +} +@Override public void setPppoeMode(java.lang.String mode) throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +try { +_data.writeInterfaceToken(DESCRIPTOR); +_data.writeString(mode); +mRemote.transact(Stub.TRANSACTION_setPppoeMode, _data, _reply, 0); +_reply.readException(); +} +finally { +_reply.recycle(); +_data.recycle(); +} +} +@Override public boolean isPppoeDeviceUp() throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +boolean _result; +try { +_data.writeInterfaceToken(DESCRIPTOR); +mRemote.transact(Stub.TRANSACTION_isPppoeDeviceUp, _data, _reply, 0); +_reply.readException(); +_result = (0!=_reply.readInt()); +} +finally { +_reply.recycle(); +_data.recycle(); +} +return _result; +} +@Override public android.net.DhcpInfo getDhcpInfo() throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +android.net.DhcpInfo _result; +try { +_data.writeInterfaceToken(DESCRIPTOR); +mRemote.transact(Stub.TRANSACTION_getDhcpInfo, _data, _reply, 0); +_reply.readException(); +if ((0 != _reply.readInt())) { +_result = android.net.DhcpInfo.CREATOR.createFromParcel(_reply); +} +else { +_result = null; +} +} +finally { +_reply.recycle(); +_data.recycle(); +} +return _result; +} +} +static final int TRANSACTION_getDeviceNameList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); +static final int TRANSACTION_setPppoeState = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); +static final int TRANSACTION_getPppoeState = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); +static final int TRANSACTION_UpdatePppoeDevInfo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3); +static final int TRANSACTION_isPppoeConfigured = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4); +static final int TRANSACTION_getSavedPppoeConfig = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5); +static final int TRANSACTION_getTotalInterface = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6); +static final int TRANSACTION_setPppoeMode = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7); +static final int TRANSACTION_isPppoeDeviceUp = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8); +static final int TRANSACTION_getDhcpInfo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 9); +} +public java.lang.String[] getDeviceNameList() throws android.os.RemoteException; +public void setPppoeState(int state) throws android.os.RemoteException; +public int getPppoeState() throws android.os.RemoteException; +public void UpdatePppoeDevInfo(com.droidlogic.pppoe.PppoeDevInfo info) throws android.os.RemoteException; +public boolean isPppoeConfigured() throws android.os.RemoteException; +public com.droidlogic.pppoe.PppoeDevInfo getSavedPppoeConfig() throws android.os.RemoteException; +public int getTotalInterface() throws android.os.RemoteException; +public void setPppoeMode(java.lang.String mode) throws android.os.RemoteException; +public boolean isPppoeDeviceUp() throws android.os.RemoteException; +public android.net.DhcpInfo getDhcpInfo() throws android.os.RemoteException; +} diff --git a/java/src/com/droidlogic/pppoe/PppoeDevInfo.java b/java/src/com/droidlogic/pppoe/PppoeDevInfo.java new file mode 100644 index 0000000..e70d18c --- a/dev/null +++ b/java/src/com/droidlogic/pppoe/PppoeDevInfo.java @@ -0,0 +1,109 @@ +package com.droidlogic.pppoe; + + +import android.os.Parcel; +import android.os.Parcelable; +import android.os.Parcelable.Creator; + +public class PppoeDevInfo implements Parcelable { + private String dev_name; + private String ipaddr; + private String netmask; + private String route; + private String dns; + private String mode; + public static final String PPPOE_CONN_MODE_DHCP= "dhcp"; + public static final String PPPOE_CONN_MODE_MANUAL = "manual"; + + public PppoeDevInfo () { + dev_name = null; + ipaddr = null; + dns = null; + route = null; + netmask = null; + mode = PPPOE_CONN_MODE_DHCP; + } + + public void setIfName(String ifname) { + this.dev_name = ifname; + } + + public String getIfName() { + return this.dev_name; + } + + public void setIpAddress(String ip) { + this.ipaddr = ip; + } + + public String getIpAddress( ) { + return this.ipaddr; + } + public void setNetMask(String ip) { + this.netmask = ip; + } + + public String getNetMask( ) { + return this.netmask; + } + + public void setRouteAddr(String route) { + this.route = route; + } + + public String getRouteAddr() { + return this.route; + } + + public void setDnsAddr(String dns) { + this.dns = dns; + } + + public String getDnsAddr( ) { + return this.dns; + } + + public boolean setConnectMode(String mode) { + if (mode.equals(PPPOE_CONN_MODE_DHCP) || mode.equals(PPPOE_CONN_MODE_MANUAL)) { + this.mode = mode; + return true; + } + return false; + } + + public String getConnectMode() { + return this.mode; + } + + public int describeContents() { + // TODO Auto-generated method stub + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(this.dev_name); + dest.writeString(this.ipaddr); + dest.writeString(this.netmask); + dest.writeString(this.route); + dest.writeString(this.dns); + dest.writeString(this.mode); + } + /** Implement the Parcelable interface {@hide} */ + public static final Creator<PppoeDevInfo> CREATOR = + new Creator<PppoeDevInfo>() { + public PppoeDevInfo createFromParcel(Parcel in) { + PppoeDevInfo info = new PppoeDevInfo(); + info.setIfName(in.readString()); + info.setIpAddress(in.readString()); + info.setNetMask(in.readString()); + info.setRouteAddr(in.readString()); + info.setDnsAddr(in.readString()); + info.setConnectMode(in.readString()); + return info; + } + + public PppoeDevInfo[] newArray(int size) { + return new PppoeDevInfo[size]; + } + }; +} diff --git a/java/src/com/droidlogic/pppoe/PppoeManager.java b/java/src/com/droidlogic/pppoe/PppoeManager.java new file mode 100644 index 0000000..23572c6 --- a/dev/null +++ b/java/src/com/droidlogic/pppoe/PppoeManager.java @@ -0,0 +1,137 @@ +package com.droidlogic.pppoe; + +import java.util.List; + +import android.content.Context; +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.net.wifi.IWifiManager; +import android.os.Handler; +import android.os.RemoteException; +import android.util.Slog; +import android.net.DhcpInfo; +import com.droidlogic.pppoe.PppoeDevInfo; +import com.droidlogic.pppoe.IPppoeManager; +import com.droidlogic.pppoe.PppoeService; + +public class PppoeManager { + public static final String TAG = "PppoeManager"; + public static final int PPPOE_DEVICE_SCAN_RESULT_READY = 0; + public static final String PPPOE_STATE_CHANGED_ACTION = + "com.droidlogic.pppoe.PPPOE_STATE_CHANGED"; + public static final String NETWORK_STATE_CHANGED_ACTION = + "com.droidlogic.pppoe.STATE_CHANGE"; + +// public static final String ACTION_PPPOE_NETWORK = "android.net.pppoe.PPPOE_NET_CHG"; + + + public static final String EXTRA_NETWORK_INFO = "networkInfo"; + public static final String EXTRA_PPPOE_STATE = "pppoe_state"; + public static final String EXTRA_PPPOE_ERRCODE = "pppoe_errcode"; + public static final String PROP_VAL_PPP_NOERR = "0:0"; + public static final String EXTRA_PREVIOUS_PPPOE_STATE = "previous_pppoe_state"; + + public static final int PPPOE_STATE_UNKNOWN = 0; + public static final int PPPOE_STATE_DISABLED = 1; + public static final int PPPOE_STATE_ENABLED = 2; + + IPppoeManager mService; + private final Context mContext; + + + public PppoeManager(IPppoeManager service, Context context) { + Slog.i(TAG, "Init Pppoe Manager"); + mService = service; + mContext = context; + + } + + public boolean isPppoeConfigured() { + try { + return mService.isPppoeConfigured(); + } catch (RemoteException e) { + Slog.i(TAG, "Can not check pppoe config state"); + } + return false; + } + + public PppoeDevInfo getSavedPppoeConfig() { + try { + return mService.getSavedPppoeConfig(); + } catch (RemoteException e) { + Slog.i(TAG, "Can not get pppoe config"); + } + return null; + } + + public void UpdatePppoeDevInfo(PppoeDevInfo info) { + try { + mService.UpdatePppoeDevInfo(info); + } catch (RemoteException e) { + Slog.i(TAG, "Can not update pppoe device info"); + } + } + + public String[] getDeviceNameList() { + try { + return mService.getDeviceNameList(); + } catch (RemoteException e) { + return null; + } + } + + public void setPppoeEnabled(boolean enable) { + try { + mService.setPppoeState(enable ? PPPOE_STATE_ENABLED:PPPOE_STATE_DISABLED); + } catch (RemoteException e) { + Slog.i(TAG,"Can not set new state"); + } + } + + public int getPppoeState( ) { + try { + return mService.getPppoeState(); + } catch (RemoteException e) { + return 0; + } + } + + public boolean pppoeConfigured() { + try { + return mService.isPppoeConfigured(); + } catch (RemoteException e) { + return false; + } + } + + public DhcpInfo getDhcpInfo() { + try { + return mService.getDhcpInfo(); + } catch (RemoteException e) { + return null; + } + } + + public int getTotalInterface() { + try { + return mService.getTotalInterface(); + } catch (RemoteException e) { + return 0; + } + } + + public void pppoeSetDefaultConf() { + try { + mService.setPppoeMode(PppoeDevInfo.PPPOE_CONN_MODE_DHCP); + } catch (RemoteException e) { + } + } + + public boolean isPppoeDeviceUp() { + try { + return mService.isPppoeDeviceUp(); + } catch (RemoteException e) { + return false; + } + } +} diff --git a/java/src/com/droidlogic/pppoe/PppoeMonitor.java b/java/src/com/droidlogic/pppoe/PppoeMonitor.java new file mode 100644 index 0000000..9348701 --- a/dev/null +++ b/java/src/com/droidlogic/pppoe/PppoeMonitor.java @@ -0,0 +1,119 @@ +package com.droidlogic.pppoe; + +import java.util.regex.Matcher; + +import android.os.SystemProperties; +import android.net.NetworkInfo; +import android.util.Config; +import android.util.Slog; +import java.util.StringTokenizer; + +/** + * Listens for events for pppoe, and passes them on + * to the {@link PppoeStateTracker} for handling. Runs in its own thread. + * + * @hide + */ +public class PppoeMonitor { + private static final String TAG = "PppoeMonitor"; + private static final int CONNECTED = 1; + private static final int INTERFACE_DOWN = 2; + private static final int INTERFACE_UP = 3; + private static final int DEV_ADDED = 4; + private static final int DEV_REMOVED = 5; + private static final String connectedEvent = "CONNECTED"; + private static final String disconnectedEvent = "DISCONNECTED"; + + private static final int NEW_LINK = 16; + private static final int DEL_LINK = 17; + private static final boolean DEBUG = false; + private final String pppoe_running_flag = "net.pppoe.running"; + + private PppoeStateTracker mTracker; + + public PppoeMonitor(PppoeStateTracker tracker) { + mTracker = tracker; + } + + public void startMonitoring() { + if (DEBUG) Slog.i(TAG, "Start startMonitoring"); + new MonitorThread().start(); + } + + class MonitorThread extends Thread { + + public MonitorThread() { + super("PppoeMonitor"); + } + + public void run() { + int index; + int i; + if (DEBUG) Slog.i(TAG, "Start run"); + for (;;) { + String eventName = PppoeNative.waitForEvent(); + + String propVal = SystemProperties.get(pppoe_running_flag); + if (DEBUG) Slog.i(TAG, "Start run for "+"eventName"+eventName+"propVal"+propVal); + int n = 0; + if (propVal.length() != 0) { + try { + n = Integer.parseInt(propVal); + } catch (NumberFormatException e) {} + } + + if ( 0 == n) { + continue; + } + + if (eventName == null) { + continue; + } + if (DEBUG) Slog.i(TAG, "EVENT[" + eventName+"]"); + /* + * Map event name into event enum + */ + String [] events = eventName.split(":"); + index = events.length; + if (index < 2) + continue; + i = 0; + while (index != 0 && i < index-1) { + int event = 0; + if ("added".equals(events[i+1]) ) { + event = DEV_ADDED; + } + else if ("removed".equals(events[i+1])) { + event = DEV_REMOVED; + } + else { + int cmd =Integer.parseInt(events[i+1]); + if ( cmd == DEL_LINK) { + event = INTERFACE_DOWN; + handleEvent(events[i],event); + } + else if (cmd == NEW_LINK) { + event = INTERFACE_UP; + handleEvent(events[i],event); + } + } + i = i + 2; + } + } + } + + void handleEvent(String ifname,int event) { + switch (event) { + case INTERFACE_DOWN: + mTracker.notifyStateChange(ifname,NetworkInfo.DetailedState.DISCONNECTED); + break; + case INTERFACE_UP: + mTracker.notifyStateChange(ifname,NetworkInfo.DetailedState.CONNECTED); + break; + default: + mTracker.notifyStateChange(ifname,NetworkInfo.DetailedState.FAILED); + } + } + + } +} diff --git a/java/src/com/droidlogic/pppoe/PppoeNative.java b/java/src/com/droidlogic/pppoe/PppoeNative.java new file mode 100644 index 0000000..030e1a3 --- a/dev/null +++ b/java/src/com/droidlogic/pppoe/PppoeNative.java @@ -0,0 +1,21 @@ +package com.droidlogic.pppoe; + +/** + * Native calls to pppoe interface. + * + * {@hide} + */ + +public class PppoeNative { + static { + System.loadLibrary("pppoe"); + initPppoeNative(); + } + + public native static String getInterfaceName(int i); + public native static int getInterfaceCnt(); + public native static int initPppoeNative(); + public native static String waitForEvent(); + public native static int isInterfaceAdded(String ifname); + +} diff --git a/java/src/com/droidlogic/pppoe/PppoeService.java b/java/src/com/droidlogic/pppoe/PppoeService.java new file mode 100644 index 0000000..c333b56 --- a/dev/null +++ b/java/src/com/droidlogic/pppoe/PppoeService.java @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2009 The Android-x86 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. + * + * Author: Yi Sun <beyounn@gmail.com> + */ + +package com.droidlogic.pppoe; + +import java.net.UnknownHostException; +import com.droidlogic.pppoe.PppoeNative; +import com.droidlogic.pppoe.PppoeManager; +import com.droidlogic.pppoe.PppoeStateTracker; +import com.droidlogic.pppoe.PppoeDevInfo; +import android.provider.Settings; +import android.util.Slog; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import java.io.IOException; +import java.io.FileReader; +import java.io.BufferedReader; +import android.net.DhcpInfo; + +public class PppoeService<syncronized> extends IPppoeManager.Stub{ + + private Context mContext; + private PppoeStateTracker mTracker; + private String[] DevName; + private static final String TAG = "PppoeService"; + private int isPppoeEnabled ; + private int mPppoeState= PppoeManager.PPPOE_STATE_UNKNOWN; + /** {@hide} */ + public static final String PPPOE_ON = "pppoe_on"; + /** {@hide} */ + public static final String PPPOE_IP = "pppoe_ip"; + /** {@hide} */ + public static final String PPPOE_MASK = "pppoe_mask"; + /** {@hide} */ + public static final String PPPOE_DNS = "pppoe_dns"; + /** {@hide} */ + public static final String PPPOE_ROUTE = "pppoe_route"; + /** {@hide} */ + public static final String PPPOE_CONF = "pppoe_conf"; + /** {@hide} */ + public static final String PPPOE_IFNAME = "pppoe_ifname"; + + public PppoeService(Context context, PppoeStateTracker Tracker){ + mTracker = Tracker; + mContext = context; + + isPppoeEnabled = getPersistedState(); + Slog.i(TAG,"Pppoe dev enabled " + isPppoeEnabled ); + getDeviceNameList(); + setPppoeState(isPppoeEnabled); + registerForBroadcasts(); + Slog.i(TAG, "Trigger the pppoe monitor"); + mTracker.StartPolling(); + } + + public boolean isPppoeConfigured() { + + final ContentResolver cr = mContext.getContentResolver(); + int x = Settings.Secure.getInt(cr, PPPOE_CONF,0); + + if (x == 0) { + Settings.Secure.putString(cr, PPPOE_IFNAME, "ppp0"); + Settings.Secure.putString(cr, PPPOE_IP, "0.0.0.0"); + Settings.Secure.putString(cr, PPPOE_DNS, "0.0.0.0"); + Settings.Secure.putString(cr, PPPOE_MASK, "255.255.255.0"); + Settings.Secure.putString(cr, PPPOE_ROUTE, "0.0.0.0"); + + Slog.i(TAG, "@@@@@@NO CONFIG. set default"); + Settings.Secure.putInt(cr, PPPOE_CONF,1); + } + + x = Settings.Secure.getInt(cr, PPPOE_CONF,0); + + if (x == 1) + return true; + return false; + } + + public synchronized PppoeDevInfo getSavedPppoeConfig() { + + if (isPppoeConfigured() ) { + final ContentResolver cr = mContext.getContentResolver(); + PppoeDevInfo info = new PppoeDevInfo(); + info.setIfName(Settings.Secure.getString(cr, PPPOE_IFNAME)); + info.setIpAddress(Settings.Secure.getString(cr, PPPOE_IP)); + info.setDnsAddr(Settings.Secure.getString(cr, PPPOE_DNS)); + info.setNetMask(Settings.Secure.getString(cr, PPPOE_MASK)); + info.setRouteAddr(Settings.Secure.getString(cr, PPPOE_ROUTE)); + + return info; + } + return null; + } + + + public synchronized void setPppoeMode(String mode) { + final ContentResolver cr = mContext.getContentResolver(); + Slog.i(TAG,"Set pppoe mode " + DevName + " mode " + mode); + if (DevName != null) { + Settings.Secure.putString(cr, PPPOE_IFNAME, DevName[0]); + Settings.Secure.putInt(cr, PPPOE_CONF,1); + } + } + + public synchronized void UpdatePppoeDevInfo(PppoeDevInfo info) { + final ContentResolver cr = mContext.getContentResolver(); + Settings.Secure.putInt(cr, PPPOE_CONF,1); + Settings.Secure.putString(cr, PPPOE_IFNAME, info.getIfName()); + Settings.Secure.putString(cr, PPPOE_IP, info.getIpAddress()); + Settings.Secure.putString(cr, PPPOE_DNS, info.getDnsAddr()); + Settings.Secure.putString(cr, PPPOE_ROUTE, info.getRouteAddr()); + Settings.Secure.putString(cr, PPPOE_MASK,info.getNetMask()); + } + private void registerForBroadcasts() { + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(Intent.ACTION_SCREEN_ON); + intentFilter.addAction(Intent.ACTION_SCREEN_OFF); + mContext.registerReceiver(mReceiver, intentFilter); + } + + public int getTotalInterface() { + return PppoeNative.getInterfaceCnt(); + } + + + private int scanPppoeDevice() { + int i = 0,j; + if ((i = PppoeNative.getInterfaceCnt()) != 0) { + Slog.i(TAG, "total found "+i+ " net devices"); + DevName = new String[i]; + } + else + return i; + + for (j = 0; j < i; j++) { + DevName[j] = PppoeNative.getInterfaceName(j); + if (DevName[j] == null) + break; + Slog.i(TAG,"device " + j + " name " + DevName[j]); + } + + return i; + } + + public String[] getDeviceNameList() { + return (scanPppoeDevice() > 0 ) ? DevName : null; + } + + private int getPersistedState() { + final ContentResolver cr = mContext.getContentResolver(); + try { + return Settings.Secure.getInt(cr, PPPOE_ON); + } catch (Settings.SettingNotFoundException e) { + return PppoeManager.PPPOE_STATE_UNKNOWN; + } + } + + private synchronized void persistPppoeEnabled(boolean enabled) { + final ContentResolver cr = mContext.getContentResolver(); + Settings.Secure.putInt(cr, PPPOE_ON, + enabled ? PppoeManager.PPPOE_STATE_ENABLED : PppoeManager.PPPOE_STATE_DISABLED); + } + + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action.equals(Intent.ACTION_SCREEN_ON)) { + Slog.d(TAG, "ACTION_SCREEN_ON"); + try { + mTracker.resetInterface(); + } catch (UnknownHostException e) { + Slog.e(TAG, "Wrong pppoe configuration"); + } + } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { + Slog.d(TAG, "ACTION_SCREEN_OFF"); + mTracker.stopInterface(false); + } + } + }; + + public synchronized void setPppoeState(int state) { + Slog.i(TAG, "setPppoeState from " + mPppoeState + " to "+ state); + + if (mPppoeState != state) { + mPppoeState = state; + if (state == PppoeManager.PPPOE_STATE_DISABLED) { + persistPppoeEnabled(false); +// mTracker.stopInterface(false); + new Thread("stopInterface") { + @Override + public void run() { + mTracker.stopInterface(false); + } + }.start(); + } else { + persistPppoeEnabled(true); + if (!isPppoeConfigured()) { + // If user did not configure any interfaces yet, pick the first one + // and enable it. + setPppoeMode(PppoeDevInfo.PPPOE_CONN_MODE_DHCP); + } +// try { +// mTracker.resetInterface(); +// } catch (UnknownHostException e) { +// Slog.e(TAG, "Wrong pppoe configuration"); +// } + new Thread("resetInterface") { + @Override + public void run() { + try { + mTracker.resetInterface(); + } catch (UnknownHostException e) { + Slog.e(TAG, "Wrong pppoe configuration"); + } + } + }.start(); + + } + } + } + + public int getPppoeState( ) { + return mPppoeState; + } + + public boolean isPppoeDeviceUp( ) { + try { + boolean retval = false; + FileReader fr = new FileReader("/sys/class/net/ppp0/operstate"); + BufferedReader br = new BufferedReader(fr, 32); + String status = br.readLine(); + if (status != null && status.equals("up")) { + Slog.d(TAG, "PppoeDevice status:" + status); + retval = true; + } + else if (status != null && status.equals("down")) { + Slog.d(TAG, "PppoeDevice status:" + status); + retval = false; + } + else { + retval = false; + } + br.close(); + fr.close(); + return retval; + } catch (IOException e) { + Slog.d(TAG, "get PppoeDevice status error"); + return false; + } + } + + public DhcpInfo getDhcpInfo( ) { + return mTracker.getDhcpInfo(); + } +} diff --git a/java/src/com/droidlogic/pppoe/PppoeStateTracker.java b/java/src/com/droidlogic/pppoe/PppoeStateTracker.java new file mode 100644 index 0000000..e7b90b0 --- a/dev/null +++ b/java/src/com/droidlogic/pppoe/PppoeStateTracker.java @@ -0,0 +1,615 @@ +package com.droidlogic.pppoe; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Iterator; +import java.util.concurrent.atomic.AtomicBoolean; + +import android.R; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.bluetooth.BluetoothHeadset; +import android.content.Context; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.DhcpInfo; +import android.net.InterfaceConfiguration; +import android.net.NetworkInfo; +import android.net.NetworkInfo.DetailedState; +import android.net.RouteInfo; +import android.net.LinkAddress; +import android.net.NetworkCapabilities; +import android.net.LinkProperties; +import android.net.LinkQualityInfo; +import android.net.NetworkStateTracker; +import android.net.NetworkUtils; +import android.net.NetworkInfo.DetailedState; +import android.net.NetworkAgent; +import android.net.Network; +import android.net.SamplingDataTracker; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.INetworkManagementService; +import android.os.Looper; +import android.os.Message; +import android.os.Messenger; +import android.os.Parcel; +import android.os.SystemProperties; +import android.os.ServiceManager; +import android.os.INetworkManagementService; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.*; +import android.util.Slog; +/** + * Track the state of Pppoe connectivity. All event handling is done here, + * and all changes in connectivity state are initiated here. + * + * @hide + */ +public class PppoeStateTracker implements NetworkStateTracker { + + private static final String TAG="PppoeStateTracker"; + private static final String PROP_PPP_ADDR = "dhcp.ppp0.ipaddress"; + private static final String PROP_PPP_MASK = "dhcp.ppp0.mask"; + private static final String PROP_PPP_DNS1 = "dhcp.ppp0.dns1"; + private static final String PROP_PPP_DNS2 = "dhcp.ppp0.dns2"; + private static final String PROP_PPP_GW = "dhcp.ppp0.gateway"; + private static final String PROP_PPP_DEF_ROUTE ="net.ppp0.gw"; + + private static final String PROP_VAL_PPP_NOERR = "0:0"; + private static final String PROP_NAME_PPP_ERRCODE = "net.ppp.errcode"; + + public static final int EVENT_CONNECTED = 3; + public static final int EVENT_DISCONNECTED = 4; + public static final int EVENT_CONNECT_FAILED = 5; + public static final int EVENT_DISCONNECT_FAILED = 6; + + public static final String PPPOE_SERVICE = "pppoe"; + + private PppoeManager mEM; + private boolean mServiceStarted; + private boolean mInterfaceStopped; + private String mInterfaceName = "ppp0"; + private DhcpInfoInternal mDhcpInfoInternal; + private PppoeMonitor mMonitor; + + private AtomicBoolean mTeardownRequested = new AtomicBoolean(false); + private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false); + private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false); + private PppoeDevInfo Info; + protected Network mNetwork = new Network(ConnectivityManager.NETID_UNSET); + + private LinkProperties mLinkProperties; + private NetworkCapabilities mNetworkCapabilities; + private NetworkInfo mNetworkInfo; + private final Looper mLooper; + private NetworkAgent mNetworkAgent; + private String mNetworkName; + private Handler mTarget; + private Handler mTrackerTarget; + private Context mContext; + private static DetailedState mLastState = DetailedState.DISCONNECTED; + + public PppoeStateTracker(Looper looper,int netType, String networkName) { + Slog.i(TAG,"Starts ..."); + mNetworkName = networkName; + mNetworkInfo = new NetworkInfo(netType, 0, networkName, ""); + mNetworkInfo.setIsAvailable(false); + setTeardownRequested(false); + mLooper=looper; + mLinkProperties = new LinkProperties(); + mNetworkCapabilities = new NetworkCapabilities(); + + if (PppoeNative.initPppoeNative() != 0 ) { + Slog.e(TAG,"Can not init pppoe device layers"); + return; + } + Slog.i(TAG,"Successed"); + + mServiceStarted = true; + + mMonitor = new PppoeMonitor(this); + + + } + + public boolean stopInterface(boolean suspend) { + if (mEM != null) { + PppoeDevInfo info = mEM.getSavedPppoeConfig(); + if (info != null && mEM.pppoeConfigured()) + { + mInterfaceStopped = true; + Slog.i(TAG, "stop interface"); + String ifname = info.getIfName(); + + NetworkUtils.resetConnections(ifname, NetworkUtils.RESET_ALL_ADDRESSES); + if (!suspend) + NetworkUtils.disableInterface(ifname); + } + } + + return true; + } + + + private boolean configureInterfaceStatic(String ifname, DhcpInfoInternal dhcpInfoInternal) { + IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); + INetworkManagementService netd = INetworkManagementService.Stub.asInterface(b); + InterfaceConfiguration ifcg = new InterfaceConfiguration(); + ifcg.setLinkAddress(dhcpInfoInternal.makeLinkAddress()); + Slog.i(TAG, "configureInterface on dev:" + ifname); + try { + netd.setInterfaceConfig(ifname, ifcg); + //mLinkProperties = dhcpInfoInternal.makeLinkProperties(); + + //return true; + } catch (RemoteException re) { + Slog.i(TAG, "IP configuration failed: " + re); + return false; + } catch (IllegalStateException e) { + Slog.i(TAG, "IP configuration failed: " + e); + return false; + } + // Create our NetworkAgent. + + + final boolean linkChanged = !dhcpInfoInternal.makeLinkProperties().equals(mLinkProperties); + if (linkChanged) { + mLinkProperties = dhcpInfoInternal.makeLinkProperties(); + //mLinkProperties.addLinkAddress(); + mLinkProperties.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(Info.getRouteAddr()))); + //mLinkProperties.addDnsServer(); + mLinkProperties.setInterfaceName(ifname); + Slog.i(TAG,"Link configuration changed for netId: " + + " new: " + mLinkProperties + "info.getRouteAddr():" +Info.getRouteAddr()); + + +// } +// if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties); + return true; + } + return false; + } + + private boolean configureInterface(PppoeDevInfo info) throws UnknownHostException { + mInterfaceStopped = false; + Info=info; + mDhcpInfoInternal = new DhcpInfoInternal(); + mDhcpInfoInternal.ipAddress = info.getIpAddress(); + mDhcpInfoInternal.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(info.getRouteAddr()))); + + + InetAddress ia = NetworkUtils.numericToInetAddress(info.getNetMask()); + mDhcpInfoInternal.prefixLength = NetworkUtils.netmaskIntToPrefixLength( + NetworkUtils.inetAddressToInt((Inet4Address)ia)); + mDhcpInfoInternal.dns1 = info.getDnsAddr(); + + configureInterfaceStatic(info.getIfName(), mDhcpInfoInternal); + return true; + } + + + public boolean resetInterface() throws UnknownHostException{ + /* + * This will guide us to enabled the enabled device + */ + Slog.i(TAG, ">>>resetInterface"); + if (mEM != null) { + Slog.i(TAG, "pppoeConfigured: " + mEM.pppoeConfigured()); + PppoeDevInfo info = mEM.getSavedPppoeConfig(); + + if (info != null && mEM.pppoeConfigured()) { + Slog.i(TAG, "IfName:" + info.getIfName()); + Slog.i(TAG, "IP:" + info.getIpAddress()); + Slog.i(TAG, "Mask:" + info.getNetMask()); + Slog.i(TAG, "DNS:" + info.getDnsAddr()); + Slog.i(TAG, "Route:" + info.getRouteAddr()); + + synchronized(this) { + if (mInterfaceName != null) { + Slog.i(TAG, "reset device " + mInterfaceName); + NetworkUtils.resetConnections(mInterfaceName, NetworkUtils.RESET_ALL_ADDRESSES); + } + + Slog.i(TAG, "Force the connection disconnected before configuration"); + setPppoeState( false, EVENT_DISCONNECTED, PppoeManager.PROP_VAL_PPP_NOERR); + + configureInterface(info); + } + } + } + return true; + } + + + @Override + public String getTcpBufferSizesPropName() { + // TODO Auto-generated method stub + return "net.tcp.buffersize.pppoe"; + } + + public void StartPolling() { + Slog.i(TAG, "start monitoring"); + mMonitor.startMonitoring(); + Slog.i(TAG, "end monitoring"); + } + @Override + public boolean isAvailable() { + // Only say available if we have interfaces and user did not disable us. + return ((mEM.getTotalInterface() != 0) && (mEM.getPppoeState() != PppoeManager.PPPOE_STATE_DISABLED)); + } + + @Override + public boolean reconnect() { + Slog.i(TAG, ">>>reconnect"); + try { + if (mEM.getPppoeState() != PppoeManager.PPPOE_STATE_DISABLED ) { + // maybe this is the first time we run, so set it to enabled + mEM.setPppoeEnabled(true); + if (!mEM.pppoeConfigured()) { + mEM.pppoeSetDefaultConf(); + } + return resetInterface(); + } + } catch (UnknownHostException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return false; + + } + + @Override + public boolean setRadio(boolean turnOn) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void startMonitoring(Context context, Handler target) { + Slog.i(TAG,"start to monitor the pppoe devices"); + if (mServiceStarted) { + mContext = context; + IBinder b = ServiceManager.getService(PPPOE_SERVICE); + IPppoeManager PppoeService = IPppoeManager.Stub.asInterface(b); + mEM = new PppoeManager(PppoeService, context); + mTarget = target; + mTrackerTarget = new Handler(target.getLooper(), mTrackerHandlerCallback); + if (mEM == null) { + Slog.i(TAG,"failed to start startMonitoring"); + return; + } + int state = mEM.getPppoeState(); + if (state != mEM.PPPOE_STATE_DISABLED) { + if (state == mEM.PPPOE_STATE_UNKNOWN) { + // maybe this is the first time we run, so set it to enabled + mEM.setPppoeEnabled(true); + } else { + try { + resetInterface(); + } catch (UnknownHostException e) { + Slog.e(TAG, "Wrong pppoe configuration"); + } + } + } + } + } + + @Override + public void setNetId(int netId) { + mNetwork = new Network(netId); + } + + @Override + public Network getNetwork() { + return mNetwork; + } + + public boolean teardown() { + return (mEM != null) ? stopInterface(false) : false; + } + + public void captivePortalCheckComplete() { + //TODO + } + private void postNotification(int event, String errcode) { + final Intent intent = new Intent(PppoeManager.PPPOE_STATE_CHANGED_ACTION); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + intent.putExtra(PppoeManager.EXTRA_PPPOE_STATE, event); + intent.putExtra(PppoeManager.EXTRA_PPPOE_ERRCODE, errcode); + mContext.sendBroadcast(intent); + + Slog.d(TAG, "Send PPPOE_STATE_CHANGED_ACTION"); + } + + private void setPppoeState(boolean state, int event, String errcode) { + Slog.d(TAG, "PST.setPppoeState()" + mNetworkInfo.isConnected() + " ==> " + state); + if (event == EVENT_CONNECT_FAILED || mNetworkInfo.isConnected() != state) { + mNetworkInfo.setIsAvailable(state); + postNotification(event, errcode); + } + + if (mNetworkInfo.isConnected() != state) { + if (state) { + mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null); + + } else { + mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null); + if ( EVENT_DISCONNECTED == event ) { + Slog.d(TAG, "EVENT_DISCONNECTED: StopInterface"); + stopInterface(true); + } + } + Message msg = mTarget.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo); + msg.sendToTarget(); + + msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo); + msg.sendToTarget(); + } + } + public DhcpInfo getDhcpInfo() { + return mDhcpInfoInternal.makeDhcpInfo(); + } + + private Handler.Callback mTrackerHandlerCallback = new Handler.Callback() { + /** {@inheritDoc} */ + public boolean handleMessage(Message msg) { + synchronized (this) { + boolean newNetworkstate = false; + PppoeDevInfo info = new PppoeDevInfo(); + + switch (msg.what) { + case EVENT_DISCONNECTED: + Slog.i(TAG, "[EVENT: PPP DOWN]"); + Slog.i(TAG, "DO NOT clear IP Config and PPP Property"); + + /* + SystemProperties.set(PROP_PPP_ADDR, "0.0.0.0"); + SystemProperties.set(PROP_PPP_MASK, "0.0.0.0"); + SystemProperties.set(PROP_PPP_DNS1, "0.0.0.0"); + SystemProperties.set(PROP_PPP_DNS2, "0.0.0.0"); + SystemProperties.set(PROP_PPP_GW, "0.0.0.0"); + */ + info.setIfName(mInterfaceName); + info.setIpAddress("0.0.0.0"); + info.setNetMask("0.0.0.0"); + info.setDnsAddr("0.0.0.0"); + info.setRouteAddr("0.0.0.0"); + mEM.UpdatePppoeDevInfo(info); + + try { + configureInterface(info); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + newNetworkstate = false; + + String ppp_err = SystemProperties.get(PROP_NAME_PPP_ERRCODE, PppoeManager.PROP_VAL_PPP_NOERR); + Slog.i(TAG, "ppp_err:" + ppp_err); + if (ppp_err.equals(PROP_VAL_PPP_NOERR)) { + setPppoeState(newNetworkstate, EVENT_DISCONNECTED, PppoeManager.PROP_VAL_PPP_NOERR); + } else { + setPppoeState(newNetworkstate, EVENT_CONNECT_FAILED, ppp_err); + } + break; + + case EVENT_CONNECTED: + Slog.i(TAG, "[EVENT: PPP UP]"); + newNetworkstate = true; + + int i=0; + + info.setIfName(mInterfaceName); + String prop_val = null; + do { + prop_val = SystemProperties.get(PROP_PPP_ADDR, "0.0.0.0"); + info.setIpAddress(prop_val); + Slog.i(TAG, "ip:" + prop_val); + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + // Shut up! + } + i++; + } while(info.getIpAddress().equals("0.0.0.0") && i<10); + + prop_val = SystemProperties.get(PROP_PPP_MASK, "0.0.0.0"); + info.setNetMask(prop_val); + Slog.i(TAG, "mask:" + prop_val); + + prop_val = SystemProperties.get(PROP_PPP_DNS1, "0.0.0.0"); + info.setDnsAddr(prop_val); + Slog.i(TAG, "dns:" + prop_val); + + prop_val = SystemProperties.get(PROP_PPP_GW, "0.0.0.0"); + info.setRouteAddr(prop_val); + Slog.i(TAG, "gw:" + prop_val); + + SystemProperties.set(PROP_PPP_DEF_ROUTE,prop_val); + mEM.UpdatePppoeDevInfo(info); + try { + configureInterface(info); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + + setPppoeState(newNetworkstate, EVENT_CONNECTED, PppoeManager.PROP_VAL_PPP_NOERR); + mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null); + + mNetworkAgent = new NetworkAgent(mLooper, mContext, mNetworkName, + mNetworkInfo, mNetworkCapabilities,mLinkProperties,60) { + @Override + public void unwanted() { + // We are user controlled, not driven by NetworkRequest. + } + }; + if (mNetworkAgent != null) { + mNetworkAgent.sendNetworkInfo(mNetworkInfo); + } +// if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties); + break; + } + } + return true; + } + }; + + public void notifyPppConnected(String ifname) { + Slog.i(TAG, "report interface is up for " + ifname + ", last status: " + mLastState); + mLastState = DetailedState.CONNECTED; + synchronized(this) { + mTrackerTarget.sendEmptyMessage(EVENT_CONNECTED); + } + + } + public void notifyStateChange(String ifname,DetailedState state) { + Slog.i(TAG, "report state change:" + mLastState.toString() + "->" + state.toString() + " on dev " + ifname); + if (ifname.equals(mInterfaceName)) { + mLastState = state; + synchronized(this) { + mTrackerTarget.sendEmptyMessage(state.equals(DetailedState.CONNECTED) + ? EVENT_CONNECTED : EVENT_DISCONNECTED); + } + } + } + + + /** + * Fetch NetworkInfo for the network + */ + public NetworkInfo getNetworkInfo() { + return new NetworkInfo(mNetworkInfo); + } + + + /** + * Fetch LinkProperties for the network + */ + public LinkProperties getLinkProperties() { + return new LinkProperties(mLinkProperties); + } + + /** + * A capability is an Integer/String pair, the capabilities + * are defined in the class LinkSocket#Key. + * + * @return a copy of this connections capabilities, may be empty but never null. + */ + public NetworkCapabilities getNetworkCapabilities() { + return new NetworkCapabilities(mNetworkCapabilities); + } + + + public void setUserDataEnable(boolean enabled) { + Slog.d(TAG, "ignoring setUserDataEnable(" + enabled + ")"); + } + + public void setPolicyDataEnable(boolean enabled) { + Slog.d(TAG, "ignoring setPolicyDataEnable(" + enabled + ")"); + } + + + /** + * Check if private DNS route is set for the network + */ + public boolean isPrivateDnsRouteSet() { + Slog.v(TAG, "isPrivateDnsRouteSet"); + return mPrivateDnsRouteSet.get(); + } + + /** + * Set a flag indicating private DNS route is set + */ + public void privateDnsRouteSet(boolean enabled) { + Slog.v(TAG, "privateDnsRouteSet"); + mPrivateDnsRouteSet.set(enabled); + } + + + /** + * Check if default route is set + */ + public boolean isDefaultRouteSet() { + Slog.v(TAG, "isDefaultRouteSet"); + return mDefaultRouteSet.get(); + } + + + /** + * Set a flag indicating default route is set for the network + */ + public void defaultRouteSet(boolean enabled) { + Slog.v(TAG, "defaultRouteSet"); + mDefaultRouteSet.set(enabled); + } + + public void setTeardownRequested(boolean isRequested) { + Slog.v(TAG, "setTeardownRequested(" + isRequested + ")"); + mTeardownRequested.set(isRequested); + } + + public boolean isTeardownRequested() { + boolean flag = mTeardownRequested.get(); + Slog.v(TAG, "isTeardownRequested: " + flag); + return flag; + } + + public void setDependencyMet(boolean met) { + // not supported on this network + } + + /** + * Informs the state tracker that another interface is stacked on top of it. + **/ + public void addStackedLink(LinkProperties link){ + } + + /** + * Informs the state tracker that a stacked interface has been removed. + **/ + public void removeStackedLink(LinkProperties link){ + } + + /* + * Called once to setup async channel between this and + * the underlying network specific code. + */ + public void supplyMessenger(Messenger messenger){ + } + + /* + * Network interface name that we'll lookup for sampling data + */ + public String getNetworkInterfaceName(){ + return null; + } + + /* + * Save the starting sample + */ + public void startSampling(SamplingDataTracker.SamplingSnapshot s){ + } + + /* + * Save the ending sample + */ + public void stopSampling(SamplingDataTracker.SamplingSnapshot s) { + } + + @Override + public void captivePortalCheckCompleted(boolean isCaptivePortal) { + // not implemented + } + + /** + * Get interesting information about this network link + * @return a copy of link information, null if not available + */ + public LinkQualityInfo getLinkQualityInfo(){ + return null; + } +} diff --git a/java/src/com/droidlogic/pppoe/package.html b/java/src/com/droidlogic/pppoe/package.html new file mode 100644 index 0000000..db6f78b --- a/dev/null +++ b/java/src/com/droidlogic/pppoe/package.html @@ -0,0 +1,3 @@ +<body> +{@hide} +</body>
\ No newline at end of file diff --git a/jni/Android.mk b/jni/Android.mk new file mode 100644 index 0000000..3ce7c94 --- a/dev/null +++ b/jni/Android.mk @@ -0,0 +1,19 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + com_droidlogic_common.cpp \ + com_droidlogic_pppoe.cpp\ + +#LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libcutils \ + libgui \ + libnativehelper + +LOCAL_MODULE := libpppoe + + +include $(BUILD_SHARED_LIBRARY) diff --git a/jni/com_droidlogic_common.cpp b/jni/com_droidlogic_common.cpp new file mode 100644 index 0000000..ce96878 --- a/dev/null +++ b/jni/com_droidlogic_common.cpp @@ -0,0 +1,551 @@ +/* + * Copyright 2009, The Android-x86 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. + * + * Author: kejun.gao <greatgauss@gmail.com> + */ + +#include "jni.h" +#include "com_droidlogic_common.h" + + +//namespace android { + + +/* Same as strlen(x) for constant string literals ONLY */ +#define CONST_STRLEN(x) (sizeof(x)-1) + +/* Convenience macro to call has_prefix with a constant string literal */ +#define HAS_CONST_PREFIX(str,end,prefix) has_prefix((str),(end),prefix,CONST_STRLEN(prefix)) + + + +static char flags_desc[512]; + +static const char * flag_desc_tbl[32] = { + "UP", + "BC", + "DBG", + "LOOPBACK", + + "PPP", + "NT", + "RUNNING", + "NOARP", + + "PROMISC", + "ALLMULTI", + "MASTER", + "SLAVE", + + "MC", + "PORTSEL", + "AUTOMEDIA", + "DYNAMIC", + + "LINK_UP", + "DORMANT", + "UNDEFINED", + "UNDEFINED", + + "UNDEFINED", + "UNDEFINED", + "UNDEFINED", + "UNDEFINED", + + "UNDEFINED", + "UNDEFINED", + "UNDEFINED", + "UNDEFINED", + "UNDEFINED", + "UNDEFINED", + "UNDEFINED", + "UNDEFINED", +}; + +static char* if_flags_desc(int flags, char *desc) { + desc[0] = '\0'; + for (int i = 18; i >= 0; i--) { + if (flags & (1<<i)) { + strcat(desc, " "); + strcat(desc, flag_desc_tbl[i]); + } + } + + return desc; +} + + +/* + * Decode a RTM_NEWADDR or RTM_DELADDR message. + */ +static int parseIfAddrMessage +(int type, struct ifaddrmsg *ifaddr, int rtasize, char *ifname, +pfunc_is_interested_event pfunc_check) +{ + struct rtattr *rta; + struct ifa_cacheinfo *cacheinfo = NULL; + char addrstr[INET6_ADDRSTRLEN] = ""; + + // Sanity check. + if (type != RTM_NEWADDR && type != RTM_DELADDR) { + ALOGE("%s on incorrect message type 0x%x" , __FUNCTION__, type); + return -1; + } + + // For log messages. + const char *msgtype = (type == RTM_NEWADDR) ? "RTM_NEWADDR" : "RTM_DELADDR"; + + for (rta = IFA_RTA(ifaddr); RTA_OK(rta, rtasize); + rta = RTA_NEXT(rta, rtasize)) { + if (rta->rta_type == IFA_ADDRESS) { + // Only look at the first address, because we only support notifying + // one change at a time. + if (*addrstr != '\0') { + ALOGE("Multiple IFA_ADDRESSes in %s, ignoring" , msgtype); + continue; + } + + // Convert the IP address to a string. + if (ifaddr->ifa_family == AF_INET) { + struct in_addr *addr4 = (struct in_addr *) RTA_DATA(rta); + if (RTA_PAYLOAD(rta) < sizeof(*addr4)) { + ALOGE("Short IPv4 address (%d bytes) in %s" , + RTA_PAYLOAD(rta), msgtype); + continue; + } + inet_ntop(AF_INET, addr4, addrstr, sizeof(addrstr)); + } else if (ifaddr->ifa_family == AF_INET6) { + struct in6_addr *addr6 = (struct in6_addr *) RTA_DATA(rta); + if (RTA_PAYLOAD(rta) < sizeof(*addr6)) { + ALOGE("Short IPv6 address (%d bytes) in %s" , + RTA_PAYLOAD(rta), msgtype); + continue; + } + inet_ntop(AF_INET6, addr6, addrstr, sizeof(addrstr)); + } else { + ALOGE("Unknown address family %d" , ifaddr->ifa_family); + continue; + } + + // Find the interface name. + if (!if_indextoname(ifaddr->ifa_index, ifname)) { + ALOGE("Unknown ifindex %d in %s" , ifaddr->ifa_index, msgtype); + return -1; + } + + if (pfunc_check && !pfunc_check(ifname)) { + return -1; + } + ALOGI("Address %s %s/%d %s %u %u" , + (type == RTM_NEWADDR) ? "updated": "removed", + addrstr, ifaddr->ifa_prefixlen, ifname, ifaddr->ifa_flags, ifaddr->ifa_scope ); + } else if (rta->rta_type == IFA_CACHEINFO) { + // Address lifetime information. + if (cacheinfo) { + // We only support one address. + ALOGE("Multiple IFA_CACHEINFOs in %s, ignoring\n" , msgtype); + continue; + } + + if (RTA_PAYLOAD(rta) < sizeof(*cacheinfo)) { + ALOGE("Short IFA_CACHEINFO (%d vs. %d bytes) in %s" , + RTA_PAYLOAD(rta), sizeof(cacheinfo), msgtype); + continue; + } + + cacheinfo = (struct ifa_cacheinfo *) RTA_DATA(rta); + } + } + + if (addrstr[0] == '\0') { + ALOGE("No IFA_ADDRESS in %s" , msgtype); + return -1; + } + + return 0; +} + + +static void parseBinaryNetlinkMessage +(char *buff, int len, char *rbuf, int rbufsize, int *pguard, pfunc_is_interested_event pfunc_check) +{ + char *result = NULL; + unsigned int guard; + int nAttrLen; + struct nlmsghdr *nh; + struct rtattr *pstruAttr; + char *ifname = (char*)"UNKNOWN_NAME"; + + guard = *pguard; + result = rbuf + guard; + + rbuf[0] = '\0'; + for (nh = (struct nlmsghdr *) buff; NLMSG_OK (nh, (unsigned int)len); + nh = NLMSG_NEXT (nh, len)) + { + if (nh->nlmsg_type == NLMSG_DONE) { + ALOGE("Did not find useful eth interface information"); + return; + } + + if (nh->nlmsg_type == NLMSG_ERROR) { + /* Do some error handling. */ + ALOGE("Read device name failed"); + return; + } + + if (nh->nlmsg_type == RTM_DELLINK || + nh->nlmsg_type == RTM_NEWLINK) { + struct ifinfomsg *einfo; + int type = nh->nlmsg_type; + char *desc; + + einfo = (struct ifinfomsg *)NLMSG_DATA(nh); + + pstruAttr = IFLA_RTA(einfo); + nAttrLen = NLMSG_PAYLOAD(nh, sizeof(struct ifinfomsg)); + + while (RTA_OK(pstruAttr, nAttrLen)) + { + switch (pstruAttr->rta_type) + { + case IFLA_IFNAME: + ifname = (char *)RTA_DATA(pstruAttr); + break; + + default: + break; + } + + pstruAttr = RTA_NEXT(pstruAttr, nAttrLen); + } + + if (pfunc_check && !pfunc_check(ifname)) { + continue; + } + + if (type == RTM_NEWLINK && + (!(einfo->ifi_flags & IFF_LOWER_UP))) { + type = RTM_DELLINK; + } + + desc = (char*)((type == RTM_DELLINK) ? "DELLINK" : "NEWLINK"); + + ALOGI("%s: %s(%d), flags=0X%X(%s)", ifname, desc, type, einfo->ifi_flags, if_flags_desc(einfo->ifi_flags, flags_desc)); + + snprintf(result,rbufsize-guard, "%s:%d:",ifname,type); + guard += strlen(result); + result +=guard; + *pguard = guard; + } + else if (nh->nlmsg_type == RTM_DELADDR || nh->nlmsg_type == RTM_NEWADDR) { + int len = nh->nlmsg_len - sizeof(*nh); + struct ifaddrmsg *ifa; + char ifname[IFNAMSIZ + 1] = {0}; + + if (sizeof(*ifa) > (size_t) len) { + ALOGE("Got a short RTM_xxxADDR message\n"); + continue; + } + + ifa = (struct ifaddrmsg *)NLMSG_DATA(nh); + size_t rtasize = IFA_PAYLOAD(nh); + if (0 != parseIfAddrMessage(nh->nlmsg_type, ifa, rtasize, ifname, pfunc_check)) { + continue; + } + snprintf(result,rbufsize-guard, "%s:%d:",ifname,nh->nlmsg_type); + guard += strlen(result); + result +=guard; + *pguard = guard; + } + + } + rbuf[guard] = '\0'; + + if (rbuf[0]) ALOGI("%s",rbuf); +} + + +/* If the string between 'str' and 'end' begins with 'prefixlen' characters + * from the 'prefix' array, then return 'str + prefixlen', otherwise return + * NULL. + */ +static const char* +has_prefix(const char* str, const char* end, const char* prefix, size_t prefixlen) +{ + if ((end-str) >= (ptrdiff_t)prefixlen && !memcmp(str, prefix, prefixlen)) + return str + prefixlen; + else + return NULL; +} + + +/* + * Parse an ASCII-formatted message from a NETLINK_KOBJECT_UEVENT + * netlink socket. + */ +static void parseAsciiNetlinkMessage +(char *buff, int len, char *rbuf, int rbufsize, int *pguard, pfunc_is_interested_event pfunc_check) +{ + int guard; + char *result = NULL; + unsigned int left; + const char *s = buff; + const char *end; + int param_idx = 0; + int i; + int first = 1; + char *path = NULL; + const char *action = NULL; + int seq; + char *subsys = NULL; + char *pch; + char *net_if = NULL; + + if (len == 0) + return; + guard = *pguard; + result = rbuf + guard; + + ALOGV(">>>>>>KOBJECT_UEVENT"); + for (pch = buff; pch < buff + len;) { + ALOGV("%s", pch); + pch = strchr(pch,'\0'); + pch++; + } + ALOGV("<<<<<<KOBJECT_UEVENT"); + + /* Ensure the buff is zero-terminated, the code below depends on this */ + buff[len-1] = '\0'; + + end = s + len; + while (s < end) { + if (first) { + const char *p; + /* buff is 0-terminated, no need to check p < end */ + for (p = s; *p != '@'; p++) { + if (!*p) { /* no '@', should not happen */ + return; + } + } + path = strdup(p+1); + first = 0; + } else { + const char* a; + if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) { + if (!strcmp(a, "add")) + action = "added"; + else if (!strcmp(a, "remove")) + action = "removed"; + else if (!strcmp(a, "change")) + action = "changed"; + } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) { + seq = atoi(a); + } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) { + subsys = strdup(a); + } else if ((a = HAS_CONST_PREFIX(s, end, "INTERFACE=")) != NULL) { + net_if = strdup(a); + } } + s += strlen(s) + 1; + } + + if (subsys && 0 == strcmp(subsys, "net") && net_if && action) { + if (!pfunc_check || pfunc_check(net_if)) { + ALOGI("%s %s", net_if, action); + snprintf(result, rbufsize-guard, "%s:%s:",net_if,action); + guard += strlen(result); + } + } + rbuf[guard] = '\0'; + *pguard = guard; + if (rbuf[0]) ALOGI("%s",rbuf); + return; +} + + +static char* waitForNetInterfaceEvent +(int nl_socket_netlink_route, int nl_socket_kobj_uevent, +char *rbuf, int *pguard, +pfunc_update_interface_list pfunc, +pfunc_is_interested_event pfunc_check) +{ + char *buff; + struct iovec iov; + struct msghdr msg; + int len; + fd_set readable; + int result = -1; + int maxfd; + int old_guard; + + *pguard = 0; + buff = (char *)malloc(NL_POLL_MSG_SZ); + if (!buff) { + ALOGE("Allocate poll buffer failed"); + goto error; + } + + iov.iov_base = buff; + iov.iov_len = NL_POLL_MSG_SZ; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + maxfd = (nl_socket_netlink_route >= nl_socket_kobj_uevent) ? + nl_socket_netlink_route: nl_socket_kobj_uevent; + + FD_ZERO(&readable); + FD_SET(nl_socket_netlink_route, &readable); + FD_SET(nl_socket_kobj_uevent, &readable); + + while (1) { + result = select(maxfd+1, &readable, NULL, NULL, NULL); + if (result >= 0 || errno != EINTR) { + break; + } + } + + if (result < 0) { + goto error; + } + if (result == 0) { + /* Timed out */ + goto error; + } + + if (FD_ISSET(nl_socket_netlink_route, &readable)) { + old_guard = *pguard; + if ((len = recvmsg(nl_socket_netlink_route, &msg, 0))>= 0) { + parseBinaryNetlinkMessage(buff, len, rbuf, RET_STR_SZ, pguard,pfunc_check); + } + + if (old_guard != *pguard) + ALOGE("netlink_route socket readable: [%s]", rbuf); + } + + if (FD_ISSET(nl_socket_kobj_uevent, &readable)) { + old_guard = *pguard; + if ((len = recvmsg(nl_socket_kobj_uevent, &msg, 0))>= 0) { + parseAsciiNetlinkMessage(buff, len, rbuf, RET_STR_SZ, pguard,pfunc_check); + pfunc(); + } + if (old_guard != *pguard) + ALOGE("kobject_event socket readable: [%s]", rbuf); + } + + return rbuf; + +error: + if (buff) + free(buff); + return NULL; +} + + +static int open_NETLINK_socket(int netlinkFamily, int groups) +{ + struct sockaddr_nl nl_addr; + int ret = -1; + int mysocket; + + memset(&nl_addr, 0, sizeof(struct sockaddr_nl)); + nl_addr.nl_family = AF_NETLINK; + nl_addr.nl_pid = 0; + nl_addr.nl_groups = groups; + + /* + *Create connection to netlink socket + */ + mysocket = socket(AF_NETLINK,SOCK_DGRAM,netlinkFamily); + if (mysocket < 0) { + ALOGE("Can not create netlink poll socket" ); + goto error; + } + + errno = 0; + if (bind(mysocket, (struct sockaddr *)(&nl_addr), + sizeof(struct sockaddr_nl))) { + ALOGE("Can not bind to netlink poll socket,%s",strerror(errno)); + + goto error; + } + + return mysocket; +error: + ALOGE("%s failed" ,__FUNCTION__); + if (mysocket >0) + close(mysocket); + return ret; +} + + +static int find_empty_node(interface_info_t *node_table, int nr_nodes) +{ + int i; + for ( i = 0; i <nr_nodes; i++) { + if (node_table[i].if_index == -1) + return i; + } + return -1; +} + + + +static int add_interface_node_to_list(interface_info_t *node_table, int nr_nodes, int if_index, char *if_name) +{ + /* + *Todo: Lock here!!!! + */ + int i; + + i = find_empty_node(node_table, nr_nodes); + if (i < 0) + return -1; + + node_table[i].if_index = if_index; + node_table[i].name = strdup(if_name); + + return 0; +} + + +static int getInterfaceName(interface_info_t *node_table, int nr_nodes, + int index, char *ifname) +{ + int i, j; + interface_info_t *info; + + for ( i = 0, j = -1; i < nr_nodes; i++) { + info= node_table + i; + if (node_table[i].if_index != -1) + j++; + if (j == index) { + ALOGI("Found :%s",info->name); + strcpy(ifname, info->name); + return 0; + } + } + + ifname[0]='\0'; + return -1; +} + + +//}; + diff --git a/jni/com_droidlogic_common.h b/jni/com_droidlogic_common.h new file mode 100644 index 0000000..f6d44cd --- a/dev/null +++ b/jni/com_droidlogic_common.h @@ -0,0 +1,64 @@ +#ifndef ANDROID_NET_COMMON_H +#define ANDROID_NET_COMMON_H + #include <inttypes.h> +#include <utils/misc.h> +#include <android_runtime/AndroidRuntime.h> +#include <utils/Log.h> +#include <asm/types.h> + +/* +The statement + typedef unsigned short sa_family_t; +is removed from bionic/libc/kernel/common/linux/socket.h. +To avoid compile failure, add the statement here. +*/ +typedef unsigned short sa_family_t; + +#include <linux/netlink.h> +#include <linux/rtnetlink.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <poll.h> +#include <net/if_arp.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <dirent.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <linux/rtnetlink.h> //for ifinfomsg +#include <linux/netlink.h> //for nlmsghdr{} + +#define NL_SOCK_INV -1 +#define RET_STR_SZ 4096 +#define NL_POLL_MSG_SZ 8*1024 +#define SYSFS_PATH_MAX 256 + +#define SYSFS_CLASS_NET "/sys/class/net" + +typedef int (*pfunc_update_interface_list)(void); +typedef int (*pfunc_is_interested_event)(char *ifname); + +typedef struct _interface_info_t { + int if_index; + char *name; +} interface_info_t; + +#define NR_ETHER_INTERFACES 16 +#define NR_PPP_INTERFACES 16 + +static int open_NETLINK_socket(int netlinkFamily, int groups); +static void parseAsciiNetlinkMessage +(char *buff, int len, char *rbuf, int rbufsize, int *pguard, pfunc_is_interested_event pfunc_check); +static void parseBinaryNetlinkMessage +(char *buff, int len, char *rbuf, int rbufsize, int *pguard, pfunc_is_interested_event pfunc_check); + +static char* waitForNetInterfaceEvent +(int nl_socket_netlink_route, int nl_socket_kobj_uevent, +char *rbuf, int *pguard, pfunc_update_interface_list pfunc); +static int find_empty_node(interface_info_t *node_table, int nr_nodes); +static int add_interface_node_to_list(interface_info_t *node_table, int nr_nodes, int if_index, char *if_name); +static int getInterfaceName(interface_info_t *node_table, int nr_nodes, int index, char *ifname); + +#endif + diff --git a/jni/com_droidlogic_pppoe.cpp b/jni/com_droidlogic_pppoe.cpp new file mode 100644 index 0000000..80fed3d --- a/dev/null +++ b/jni/com_droidlogic_pppoe.cpp @@ -0,0 +1,302 @@ +/* + * Copyright 2009, The Android-x86 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. + * + * Author: Yi Sun <beyounn@gmail.com> + */ + +#define LOG_TAG "pppoe" + +#include "jni.h" +#include <cutils/properties.h> +#include "com_droidlogic_common.h" +#include "com_droidlogic_common.cpp" + +#include <jni.h> +#include <JNIHelp.h> + +#include <utils/Log.h> +#include <gui/SurfaceComposerClient.h> + + +#define PPPOE_PKG_NAME "com/droidlogic/pppoe/PppoeNative" + +namespace android { +static struct fieldIds { + jclass dhcpInfoClass; + jmethodID constructorId; + jfieldID ipaddress; + jfieldID gateway; + jfieldID netmask; + jfieldID dns1; + jfieldID dns2; + jfieldID serverAddress; + jfieldID leaseDuration; +} dhcpInfoFieldIds; + + +interface_info_t pppoe_if_list[NR_PPP_INTERFACES]; + +static int nr_pppoe_if = 0; +static int nl_socket_netlink_route = -1; +static int nl_socket_kobj_uevent = -1; + +static int netlink_init_pppoe_list(void); + + +static int is_interested_event(char *ifname) +{ + char phy_if_name[PROP_VALUE_MAX] = {0}; + property_get("net.pppoe.phyif", phy_if_name, "UNKNOWN_PHYIF"); + return (0 == strncmp("ppp", ifname, 3) || 0 == strcmp(phy_if_name, ifname)); +} + + +static jstring com_droidlogic_pppoe_PppoeNative_waitForEvent +(JNIEnv *env, jobject clazz) +{ + char rbuf[RET_STR_SZ] = {0}; + int guard = 0; + + waitForNetInterfaceEvent(nl_socket_netlink_route, nl_socket_kobj_uevent, + rbuf, &guard, netlink_init_pppoe_list, is_interested_event); + + return env->NewStringUTF(guard > 0 ? rbuf : NULL); +} + + +static int netlink_init_pppoe_list(void) +{ + int ret = -1; + DIR *netdir; + struct dirent *de; + char path[SYSFS_PATH_MAX]; + interface_info_t *intfinfo; + int index; + FILE *ifidx; + #define MAX_FGETS_LEN 4 + char idx[MAX_FGETS_LEN+1]; + int i; + + for ( i = 0; i < NR_ETHER_INTERFACES; i++) { + pppoe_if_list[i].if_index = -1; + pppoe_if_list[i].name = NULL; + nr_pppoe_if = 0; + } + + if ((netdir = opendir(SYSFS_CLASS_NET)) != NULL) { + while ((de = readdir(netdir)) != NULL) { + if (strcmp(de->d_name,"ppp0")) + continue; + + snprintf(path, SYSFS_PATH_MAX, "%s/%s/type", SYSFS_CLASS_NET, de->d_name); + FILE *typefd; + if ((typefd = fopen(path, "r")) != NULL) { + char typestr[MAX_FGETS_LEN + 1]; + int type = 0; + memset(typestr, 0, MAX_FGETS_LEN + 1); + if (fgets(typestr, MAX_FGETS_LEN, typefd) != NULL) { + type = strtoimax(typestr, NULL, 10); + } + fclose(typefd); + if (type >= ARPHRD_TUNNEL && type < ARPHRD_IEEE802_TR) + continue; + } + + snprintf(path, SYSFS_PATH_MAX,"%s/%s/ifindex",SYSFS_CLASS_NET,de->d_name); + if ((ifidx = fopen(path,"r")) != NULL ) { + memset(idx,0,MAX_FGETS_LEN+1); + if (fgets(idx,MAX_FGETS_LEN,ifidx) != NULL) { + index = strtoimax(idx,NULL,10); + } else { + ALOGE("Can not read %s",path); + fclose(ifidx); + continue; + } + fclose(ifidx); + } else { + ALOGE("Can not open %s for read",path); + continue; + } + + if (0 == add_interface_node_to_list(pppoe_if_list,NR_PPP_INTERFACES,index, (char *) de->d_name)) { + nr_pppoe_if++; + } + } + closedir(netdir); + } + ret = 0; +error: + return ret; +} + + +static jint com_droidlogic_pppoe_PppoeNative_initPppoeNative +(JNIEnv *env, jobject clazz) +{ + int ret = -1; + + ALOGI("==>%s",__FUNCTION__); + + nl_socket_netlink_route = open_NETLINK_socket(NETLINK_ROUTE, RTMGRP_LINK | RTMGRP_IPV4_IFADDR); + if (nl_socket_netlink_route < 0) { + ALOGE("failed to create NETLINK socket"); + goto error; + } + + nl_socket_kobj_uevent = open_NETLINK_socket(NETLINK_KOBJECT_UEVENT, 0xFFFFFFFF); + if (nl_socket_kobj_uevent < 0) { + ALOGE("failed to create NETLINK socket"); + goto error; + } + + if ((ret = netlink_init_pppoe_list()) < 0) { + ALOGE("Can not collect the interface list"); + goto error; + } + return ret; +error: + ALOGE("%s exited with error",__FUNCTION__); + if (nl_socket_netlink_route >0) + close(nl_socket_netlink_route); + if (nl_socket_kobj_uevent >0) + close(nl_socket_kobj_uevent); + return ret; +} + + +static jstring com_droidlogic_pppoe_PppoeNative_getInterfaceName +(JNIEnv *env, jobject clazz, jint index) +{ + int ret; + char ifname[IFNAMSIZ+1]= {0}; + ALOGI("User ask for device name on %d, total:%d",index, nr_pppoe_if); + + if (nr_pppoe_if == 0 || index >= nr_pppoe_if) { + ALOGI("Invalid parameters"); + return env->NewStringUTF(NULL); + } + + ret = getInterfaceName(pppoe_if_list, NR_PPP_INTERFACES, index, ifname); + if (ret != 0) { + ALOGI("No device name found"); + } + + return env->NewStringUTF(ret==0 ? ifname:NULL); +} + + +static jint com_droidlogic_pppoe_PppoeNative_getInterfaceCnt() { + return nr_pppoe_if; +} + +static jint com_droidlogic_pppoe_PppoeNative_isInterfaceAdded +(JNIEnv *env, jobject clazz, jstring ifname) +{ + int retval = 0; + const char * ppp_name = env->GetStringUTFChars(ifname, NULL); + if (ppp_name == NULL) { + ALOGE("Device name NULL!"); + return 0; + } + while (true) { + ALOGE("android_net_pppoe_isInterfaceAdded undefined!"); + } + + env->ReleaseStringUTFChars(ifname, ppp_name); + return retval; +} + +static JNINativeMethod gPppoeMethods[] = { + {"waitForEvent", "()Ljava/lang/String;", + (void *)com_droidlogic_pppoe_PppoeNative_waitForEvent}, + {"getInterfaceName", "(I)Ljava/lang/String;", + (void *)com_droidlogic_pppoe_PppoeNative_getInterfaceName}, + {"initPppoeNative", "()I", + (void *)com_droidlogic_pppoe_PppoeNative_initPppoeNative}, + {"getInterfaceCnt","()I", + (void *)com_droidlogic_pppoe_PppoeNative_getInterfaceCnt}, + {"isInterfaceAdded","(Ljava/lang/String;)I", + (void *)com_droidlogic_pppoe_PppoeNative_isInterfaceAdded} +}; + + + + +int register_com_droidlogic_pppoe_PppoeManager(JNIEnv* env) +{ + jclass pppoe = env->FindClass(PPPOE_PKG_NAME); + ALOGI("Loading pppoe jni class"); + LOG_FATAL_IF( pppoe == NULL, "Unable to find class " PPPOE_PKG_NAME); + + dhcpInfoFieldIds.dhcpInfoClass = + env->FindClass("android/net/DhcpInfo"); + if (dhcpInfoFieldIds.dhcpInfoClass != NULL) { + dhcpInfoFieldIds.constructorId = + env->GetMethodID(dhcpInfoFieldIds.dhcpInfoClass, + "<init>", "()V"); + dhcpInfoFieldIds.ipaddress = + env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, + "ipAddress", "I"); + dhcpInfoFieldIds.gateway = + env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, + "gateway", "I"); + dhcpInfoFieldIds.netmask = + env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, + "netmask", "I"); + dhcpInfoFieldIds.dns1 = + env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "dns1", "I"); + dhcpInfoFieldIds.dns2 = + env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "dns2", "I"); + dhcpInfoFieldIds.serverAddress = + env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, + "serverAddress", "I"); + dhcpInfoFieldIds.leaseDuration = + env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, + "leaseDuration", "I"); + } + + // return AndroidRuntime::registerNativeMethods(env, + // PPPOE_PKG_NAME, + // gPppoeMethods, + // NELEM(gPppoeMethods)); + return jniRegisterNativeMethods(env, PPPOE_PKG_NAME, + gPppoeMethods, NELEM(gPppoeMethods)); +} + +extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved __unused) +{ + + JNIEnv* env = NULL; + jint result = -1; + + if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { + ALOGE("ERROR: GetEnv failed\n"); + goto bail; + } + assert(env != NULL); + + if (register_com_droidlogic_pppoe_PppoeManager(env) < 0) { + ALOGE("ERROR: PppoeManager native registration failed\n"); + goto bail; + } + + /* success -- return valid version number */ + result = JNI_VERSION_1_4; + +bail: + return result; +} + +}; |