[picopc] Added ethernet patch based on Yi Sun <beyounn@gmail.com> from android-x86.org
[picopc-android-gingerbread:frameworks-base.git] / ethernet / java / android / net / ethernet / EthernetStateTracker.java
1 /*
2  * Copyright (C) 2010 The Android-X86 Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * Author: Yi Sun <beyounn@gmail.com>
17  */
18
19 package android.net.ethernet;
20
21 import java.net.InetAddress;
22 import java.net.UnknownHostException;
23
24 import android.R;
25 import android.app.Notification;
26 import android.app.NotificationManager;
27 import android.app.PendingIntent;
28 import android.bluetooth.BluetoothHeadset;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.net.ConnectivityManager;
32 import android.net.DhcpInfo;
33 import android.net.NetworkStateTracker;
34 import android.net.NetworkUtils;
35 import android.net.NetworkInfo.DetailedState;
36 import android.net.wifi.WifiManager;
37 import android.os.Handler;
38 import android.os.HandlerThread;
39 import android.os.Looper;
40 import android.os.Message;
41 import android.os.Parcel;
42 import android.os.SystemProperties;
43 import android.util.*;
44
45 /**
46  * Track the state of Ethernet connectivity. All event handling is done here,
47  * and all changes in connectivity state are initiated here.
48  *
49  * @hide
50  */
51
52 public class EthernetStateTracker extends NetworkStateTracker {
53     private static final String TAG                                 = "EthernetStateTracker";
54     public static final int EVENT_DHCP_START                        = 0;
55     public static final int EVENT_INTERFACE_CONFIGURATION_SUCCEEDED = 1;
56     public static final int EVENT_INTERFACE_CONFIGURATION_FAILED    = 2;
57     public static final int EVENT_HW_CONNECTED                      = 3;
58     public static final int EVENT_HW_DISCONNECTED                   = 4;
59     public static final int EVENT_HW_PHYCONNECTED                   = 5;
60     private static final int NOTIFY_ID                              = 6;
61     private static final boolean localLOGV = true;
62
63     private EthernetManager mEM;
64     private boolean mServiceStarted;
65
66     private boolean mStackConnected;
67     private boolean mHWConnected;
68     private boolean mInterfaceStopped;
69     private DhcpHandler mDhcpTarget;
70     private String mInterfaceName ;
71     private DhcpInfo mDhcpInfo;
72     private EthernetMonitor mMonitor;
73     private String[] sDnsPropNames;
74     private boolean mStartingDhcp;
75     private NotificationManager mNotificationManager;
76     private Notification mNotification;
77     private Handler mTrackerTarget;
78
79     public EthernetStateTracker(Context context, Handler target) {
80         super(context, target, ConnectivityManager.TYPE_ETHERNET, 0, "ETH", "");
81         if (localLOGV) Slog.v(TAG, "Starts...");
82
83         if (EthernetNative.initEthernetNative() != 0) {
84             Slog.e(TAG,"Can not init ethernet device layers");
85             return;
86         }
87
88         if (localLOGV) Slog.v(TAG,"Successed");
89         mServiceStarted = true;
90         HandlerThread dhcpThread = new HandlerThread("DHCP Handler Thread");
91         dhcpThread.start();
92         mDhcpTarget = new DhcpHandler(dhcpThread.getLooper(), this);
93         mMonitor = new EthernetMonitor(this);
94         mDhcpInfo = new DhcpInfo();
95     }
96
97     /**
98      * Stop etherent interface
99      * @param suspend {@code false} disable the interface {@code true} only reset the connection without disable the interface
100      * @return true
101      */
102     public boolean stopInterface(boolean suspend) {
103         if (mEM != null) {
104             EthernetDevInfo info = mEM.getSavedConfig();
105             if (info != null && mEM.isConfigured()) {
106                 synchronized (mDhcpTarget) {
107                     mInterfaceStopped = true;
108                     if (localLOGV) Slog.i(TAG, "stop dhcp and interface");
109                     mDhcpTarget.removeMessages(EVENT_DHCP_START);
110                     String ifname = info.getIfName();
111
112                     if (!NetworkUtils.stopDhcp(ifname)) {
113                         if (localLOGV) Slog.w(TAG, "Could not stop DHCP");
114                     }
115                     NetworkUtils.resetConnections(ifname);
116                     if (!suspend)
117                         NetworkUtils.disableInterface(ifname);
118                 }
119             }
120         }
121
122         return true;
123     }
124
125     private boolean configureInterface(EthernetDevInfo info) throws UnknownHostException {
126
127         mStackConnected = false;
128         mHWConnected = false;
129         mInterfaceStopped = false;
130         mStartingDhcp = true;
131         if (info.getConnectMode().equals(EthernetDevInfo.ETHERNET_CONN_MODE_DHCP)) {
132             if (localLOGV) Slog.i(TAG, "trigger dhcp for device " + info.getIfName());
133             sDnsPropNames = new String[] {
134                 "dhcp." + mInterfaceName + ".dns1",
135                 "dhcp." + mInterfaceName + ".dns2"
136              };
137
138             mDhcpTarget.sendEmptyMessage(EVENT_DHCP_START);
139         } else {
140             int event;
141             sDnsPropNames = new String[] {
142                 "net." + mInterfaceName + ".dns1",
143                 "net." + mInterfaceName + ".dns2"
144              };
145             mDhcpInfo.ipAddress = lookupHost(info.getIpAddress());
146             mDhcpInfo.gateway = lookupHost(info.getRouteAddr());
147             mDhcpInfo.netmask = lookupHost(info.getNetMask());
148             mDhcpInfo.dns1 = lookupHost(info.getDnsAddr());
149             mDhcpInfo.dns2 = 0;
150
151             if (localLOGV) Slog.i(TAG, "set ip manually " + mDhcpInfo.toString());
152             NetworkUtils.removeDefaultRoute(info.getIfName());
153             if (NetworkUtils.configureInterface(info.getIfName(), mDhcpInfo)) {
154                 event = EVENT_INTERFACE_CONFIGURATION_SUCCEEDED;
155                 SystemProperties.set("net.dns1", info.getDnsAddr());
156                 SystemProperties.set("net." + info.getIfName() + ".dns1", info.getDnsAddr());
157                 SystemProperties.set("net." + info.getIfName() + ".dns2", "0.0.0.0");
158                 if (localLOGV) Slog.v(TAG, "Static IP configuration succeeded");
159             } else {
160                 event = EVENT_INTERFACE_CONFIGURATION_FAILED;
161                 if (localLOGV) Slog.w(TAG, "Static IP configuration failed");
162             }
163             this.sendEmptyMessage(event);
164         }
165         return true;
166     }
167
168     /**
169      * reset ethernet interface
170      * @return true
171      * @throws UnknownHostException
172      */
173     public boolean resetInterface()  throws UnknownHostException{
174         /*
175          * This will guide us to enabled the enabled device
176          */
177         if (mEM != null) {
178             EthernetDevInfo info = mEM.getSavedConfig();
179             if (info != null && mEM.isConfigured()) {
180                 synchronized (this) {
181                     mInterfaceName = info.getIfName();
182                     if (localLOGV) Slog.i(TAG, "reset device " + mInterfaceName);
183                     NetworkUtils.resetConnections(mInterfaceName);
184                      // Stop DHCP
185                     if (mDhcpTarget != null) {
186                         mDhcpTarget.removeMessages(EVENT_DHCP_START);
187                     }
188                     if (!NetworkUtils.stopDhcp(mInterfaceName)) {
189                         if (localLOGV) Slog.w(TAG, "Could not stop DHCP");
190                     }
191                     configureInterface(info);
192                 }
193             }
194         }
195         return true;
196     }
197
198     @Override
199     public String[] getNameServers() {
200         return getNameServerList(sDnsPropNames);
201     }
202
203     @Override
204     public String getTcpBufferSizesPropName() {
205         return "net.tcp.buffersize.default";
206     }
207
208     public void StartPolling() {
209         mMonitor.startMonitoring();
210     }
211     @Override
212     public boolean isAvailable() {
213         // Only say available if we have interfaces and user did not disable us.
214         return ((mEM.getTotalInterface() != 0) && (mEM.getState() != EthernetManager.ETHERNET_STATE_DISABLED));
215     }
216
217     @Override
218     public boolean reconnect() {
219         try {
220             synchronized (this) {
221                 if (mHWConnected && mStackConnected)
222                     return true;
223             }
224             if (mEM.getState() != EthernetManager.ETHERNET_STATE_DISABLED) {
225                 // maybe this is the first time we run, so set it to enabled
226                 mEM.setEnabled(true);
227                 if (!mEM.isConfigured()) {
228                     mEM.setDefaultConf();
229                 }
230                 return resetInterface();
231             }
232         } catch (UnknownHostException e) {
233             e.printStackTrace();
234         }
235         return false;
236
237     }
238
239     @Override
240     public boolean setRadio(boolean turnOn) {
241         return false;
242     }
243
244     @Override
245     public void startMonitoring() {
246         if (localLOGV) Slog.v(TAG,"start to monitor the ethernet devices");
247         if (mServiceStarted) {
248             mEM = (EthernetManager)mContext.getSystemService(Context.ETHERNET_SERVICE);
249             int state = mEM.getState();
250             if (state != mEM.ETHERNET_STATE_DISABLED) {
251                 if (state == mEM.ETHERNET_STATE_UNKNOWN) {
252                     // maybe this is the first time we run, so set it to enabled
253                     mEM.setEnabled(mEM.getDeviceNameList() != null);
254                 } else {
255                     try {
256                         resetInterface();
257                     } catch (UnknownHostException e) {
258                         Slog.e(TAG, "Wrong ethernet configuration");
259                     }
260                 }
261             }
262         }
263     }
264
265     @Override
266     public int startUsingNetworkFeature(String feature, int callingPid, int callingUid) {
267         return 0;
268     }
269
270     @Override
271     public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid) {
272         return 0;
273     }
274
275     @Override
276     public boolean teardown() {
277         return (mEM != null) ? stopInterface(false) : false;
278     }
279
280     private void postNotification(int event) {
281         String ns = Context.NOTIFICATION_SERVICE;
282         //mNotificationManager = (NotificationManager)mContext.getSystemService(ns);
283         Intent intent = new Intent(EthernetManager.ETHERNET_STATE_CHANGED_ACTION);
284         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
285         intent.putExtra(EthernetManager.EXTRA_ETHERNET_STATE, event);
286         mContext.sendStickyBroadcast(intent);
287     }
288
289     private void setState(boolean state, int event) {
290         if (mNetworkInfo.isConnected() != state) {
291             if (state) {
292                 setDetailedState(DetailedState.CONNECTED);
293                 //mTarget.sendEmptyMessage(EVENT_CONFIGURATION_CHANGED);
294             } else {
295                 setDetailedState(DetailedState.DISCONNECTED);
296                 stopInterface(true);
297             }
298             mNetworkInfo.setIsAvailable(state);
299             postNotification(event);
300         }
301     }
302
303     public void handleMessage(Message msg) {
304
305         synchronized (this) {
306             switch (msg.what) {
307             case EVENT_INTERFACE_CONFIGURATION_SUCCEEDED:
308                 if (localLOGV) Slog.i(TAG, "received configured succeeded, stack=" + mStackConnected + " HW=" + mHWConnected);
309                 mStackConnected = true;
310                 if (mHWConnected)
311                     setState(true, msg.what);
312                 break;
313             case EVENT_INTERFACE_CONFIGURATION_FAILED:
314                 mStackConnected = false;
315                 //start to retry ?
316                 break;
317             case EVENT_HW_CONNECTED:
318                 if (localLOGV) Slog.i(TAG, "received HW connected, stack=" + mStackConnected + " HW=" + mHWConnected);
319                 mHWConnected = true;
320                 if (mStackConnected)
321                     setState(true, msg.what);
322                 break;
323             case EVENT_HW_DISCONNECTED:
324                 if (localLOGV) Slog.i(TAG, "received disconnected events, stack=" + mStackConnected + " HW=" + mHWConnected);
325                 setState(mHWConnected = false, msg.what);
326                 break;
327             case EVENT_HW_PHYCONNECTED:
328                 if (localLOGV) Slog.i(TAG, "interface up event, kick off connection request");
329                 if (!mStartingDhcp) {
330                     int state = mEM.getState();
331                     if (state != mEM.ETHERNET_STATE_DISABLED) {
332                         EthernetDevInfo info = mEM.getSavedConfig();
333                         if (info != null && mEM.isConfigured()) {
334                             try {
335                                 configureInterface(info);
336                             } catch (UnknownHostException e) {
337                                  // TODO Auto-generated catch block
338                                  //e.printStackTrace();
339                                  Slog.e(TAG, "Cannot configure interface");
340                             }
341                         }
342                     }
343                 }
344                 break;
345             }
346         }
347     }
348
349     private class DhcpHandler extends Handler {
350          public DhcpHandler(Looper looper, Handler target) {
351              super(looper);
352              mTrackerTarget = target;
353          }
354
355          public void handleMessage(Message msg) {
356              int event;
357
358              switch (msg.what) {
359                  case EVENT_DHCP_START:
360                      synchronized (mDhcpTarget) {
361                          if (!mInterfaceStopped) {
362                              if (localLOGV) Slog.d(TAG, "DhcpHandler: DHCP request started");
363                              if (NetworkUtils.runDhcp(mInterfaceName, mDhcpInfo)) {
364                                  event = EVENT_INTERFACE_CONFIGURATION_SUCCEEDED;
365                                  if (localLOGV) Slog.d(TAG, "DhcpHandler: DHCP request succeeded: " + mDhcpInfo.toString());
366                              } else {
367                                  event = EVENT_INTERFACE_CONFIGURATION_FAILED;
368                                  Slog.e(TAG, "DhcpHandler: DHCP request failed: " + NetworkUtils.getDhcpError());
369                              }
370                              mTrackerTarget.sendEmptyMessage(event);
371                          } else {
372                              mInterfaceStopped = false;
373                          }
374                          mStartingDhcp = false;
375                      }
376                      break;
377              }
378          }
379     }
380
381     public void notifyPhyConnected(String ifname) {
382         if (localLOGV) Slog.v(TAG, "report interface is up for " + ifname);
383         synchronized(this) {
384             this.sendEmptyMessage(EVENT_HW_PHYCONNECTED);
385         }
386
387     }
388
389     public void notifyStateChange(String ifname,DetailedState state) {
390         if (localLOGV) Slog.i(TAG, "report new state " + state.toString() + " on dev " + ifname);
391         if (ifname.equals(mInterfaceName)) {
392             if (localLOGV) Slog.v(TAG, "update network state tracker");
393             synchronized(this) {
394                 this.sendEmptyMessage(state.equals(DetailedState.CONNECTED)
395                     ? EVENT_HW_CONNECTED : EVENT_HW_DISCONNECTED);
396             }
397         }
398     }
399
400     private static int lookupHost(String hostname) {
401         InetAddress inetAddress;
402         try {
403             inetAddress = InetAddress.getByName(hostname);
404         } catch (UnknownHostException e) {
405             return -1;
406         }
407         byte[] addrBytes;
408         int addr;
409         addrBytes = inetAddress.getAddress();
410         addr = ((addrBytes[3] & 0xff) << 24)
411                 | ((addrBytes[2] & 0xff) << 16)
412                 | ((addrBytes[1] & 0xff) << 8)
413                 |  (addrBytes[0] & 0xff);
414         return addr;
415     }
416 }