Nat464Xlat.java revision f3cab63ef2248aebf2c931cd1e84d5739791fa50
1/* 2 * Copyright (C) 2012 The Android 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 17package com.android.server.connectivity; 18 19import static android.net.ConnectivityManager.TYPE_MOBILE; 20 21import java.net.Inet4Address; 22 23import android.content.Context; 24import android.net.IConnectivityManager; 25import android.net.InterfaceConfiguration; 26import android.net.LinkAddress; 27import android.net.LinkProperties; 28import android.net.NetworkAgent; 29import android.net.NetworkUtils; 30import android.net.RouteInfo; 31import android.os.Handler; 32import android.os.Message; 33import android.os.Messenger; 34import android.os.INetworkManagementService; 35import android.os.RemoteException; 36import android.util.Slog; 37 38import com.android.server.net.BaseNetworkObserver; 39 40/** 41 * @hide 42 * 43 * Class to manage a 464xlat CLAT daemon. 44 */ 45public class Nat464Xlat extends BaseNetworkObserver { 46 private Context mContext; 47 private INetworkManagementService mNMService; 48 private IConnectivityManager mConnService; 49 // Whether we started clatd and expect it to be running. 50 private boolean mIsStarted; 51 // Whether the clatd interface exists (i.e., clatd is running). 52 private boolean mIsRunning; 53 // The LinkProperties of the clat interface. 54 private LinkProperties mLP; 55 // Current LinkProperties of the network. Includes mLP as a stacked link when clat is active. 56 private LinkProperties mBaseLP; 57 // ConnectivityService Handler for LinkProperties updates. 58 private Handler mHandler; 59 // Marker to connote which network we're augmenting. 60 private Messenger mNetworkMessenger; 61 62 // This must match the interface name in clatd.conf. 63 private static final String CLAT_INTERFACE_NAME = "clat4"; 64 65 private static final String TAG = "Nat464Xlat"; 66 67 public Nat464Xlat(Context context, INetworkManagementService nmService, 68 IConnectivityManager connService, Handler handler) { 69 mContext = context; 70 mNMService = nmService; 71 mConnService = connService; 72 mHandler = handler; 73 74 mIsStarted = false; 75 mIsRunning = false; 76 mLP = new LinkProperties(); 77 78 // If this is a runtime restart, it's possible that clatd is already 79 // running, but we don't know about it. If so, stop it. 80 try { 81 if (mNMService.isClatdStarted()) { 82 mNMService.stopClatd(); 83 } 84 } catch(RemoteException e) {} // Well, we tried. 85 } 86 87 /** 88 * Determines whether a network requires clat. 89 * @param network the NetworkAgentInfo corresponding to the network. 90 * @return true if the network requires clat, false otherwise. 91 */ 92 public static boolean requiresClat(NetworkAgentInfo nai) { 93 final int netType = nai.networkInfo.getType(); 94 final boolean connected = nai.networkInfo.isConnected(); 95 final boolean hasIPv4Address = 96 (nai.linkProperties != null) ? nai.linkProperties.hasIPv4Address() : false; 97 Slog.d(TAG, "requiresClat: netType=" + netType + 98 ", connected=" + connected + 99 ", hasIPv4Address=" + hasIPv4Address); 100 // Only support clat on mobile for now. 101 return netType == TYPE_MOBILE && connected && !hasIPv4Address; 102 } 103 104 public boolean isRunningClat(NetworkAgentInfo network) { 105 return mNetworkMessenger == network.messenger; 106 } 107 108 /** 109 * Starts the clat daemon. 110 * @param lp The link properties of the interface to start clatd on. 111 */ 112 public void startClat(NetworkAgentInfo network) { 113 if (mNetworkMessenger != null && mNetworkMessenger != network.messenger) { 114 Slog.e(TAG, "startClat: too many networks requesting clat"); 115 return; 116 } 117 mNetworkMessenger = network.messenger; 118 LinkProperties lp = network.linkProperties; 119 mBaseLP = new LinkProperties(lp); 120 if (mIsStarted) { 121 Slog.e(TAG, "startClat: already started"); 122 return; 123 } 124 String iface = lp.getInterfaceName(); 125 Slog.i(TAG, "Starting clatd on " + iface + ", lp=" + lp); 126 try { 127 mNMService.startClatd(iface); 128 } catch(RemoteException e) { 129 Slog.e(TAG, "Error starting clat daemon: " + e); 130 } 131 mIsStarted = true; 132 } 133 134 /** 135 * Stops the clat daemon. 136 */ 137 public void stopClat() { 138 if (mIsStarted) { 139 Slog.i(TAG, "Stopping clatd"); 140 try { 141 mNMService.stopClatd(); 142 } catch(RemoteException e) { 143 Slog.e(TAG, "Error stopping clat daemon: " + e); 144 } 145 mIsStarted = false; 146 mIsRunning = false; 147 mNetworkMessenger = null; 148 mBaseLP = null; 149 mLP.clear(); 150 } else { 151 Slog.e(TAG, "stopClat: already stopped"); 152 } 153 } 154 155 private void updateConnectivityService() { 156 Message msg = mHandler.obtainMessage( 157 NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED, mBaseLP); 158 msg.replyTo = mNetworkMessenger; 159 Slog.i(TAG, "sending message to ConnectivityService: " + msg); 160 msg.sendToTarget(); 161 } 162 163 // Copies the stacked clat link in oldLp, if any, to the LinkProperties in nai. 164 public void fixupLinkProperties(NetworkAgentInfo nai, LinkProperties oldLp) { 165 if (isRunningClat(nai) && 166 nai.linkProperties != null && 167 !nai.linkProperties.getAllInterfaceNames().contains(CLAT_INTERFACE_NAME)) { 168 Slog.d(TAG, "clatd running, updating NAI for " + nai.linkProperties.getInterfaceName()); 169 for (LinkProperties stacked: oldLp.getStackedLinks()) { 170 if (CLAT_INTERFACE_NAME.equals(stacked.getInterfaceName())) { 171 nai.linkProperties.addStackedLink(stacked); 172 break; 173 } 174 } 175 } 176 } 177 178 @Override 179 public void interfaceAdded(String iface) { 180 if (iface.equals(CLAT_INTERFACE_NAME)) { 181 Slog.i(TAG, "interface " + CLAT_INTERFACE_NAME + 182 " added, mIsRunning = " + mIsRunning + " -> true"); 183 mIsRunning = true; 184 185 // Create the LinkProperties for the clat interface by fetching the 186 // IPv4 address for the interface and adding an IPv4 default route, 187 // then stack the LinkProperties on top of the link it's running on. 188 try { 189 InterfaceConfiguration config = mNMService.getInterfaceConfig(iface); 190 LinkAddress clatAddress = config.getLinkAddress(); 191 mLP.clear(); 192 mLP.setInterfaceName(iface); 193 194 // Although the clat interface is a point-to-point tunnel, we don't 195 // point the route directly at the interface because some apps don't 196 // understand routes without gateways (see, e.g., http://b/9597256 197 // http://b/9597516). Instead, set the next hop of the route to the 198 // clat IPv4 address itself (for those apps, it doesn't matter what 199 // the IP of the gateway is, only that there is one). 200 RouteInfo ipv4Default = new RouteInfo(new LinkAddress(Inet4Address.ANY, 0), 201 clatAddress.getAddress(), iface); 202 mLP.addRoute(ipv4Default); 203 mLP.addLinkAddress(clatAddress); 204 mBaseLP.addStackedLink(mLP); 205 Slog.i(TAG, "Adding stacked link. tracker LP: " + mBaseLP); 206 updateConnectivityService(); 207 } catch(RemoteException e) { 208 Slog.e(TAG, "Error getting link properties: " + e); 209 } 210 } 211 } 212 213 @Override 214 public void interfaceRemoved(String iface) { 215 if (iface == CLAT_INTERFACE_NAME) { 216 if (mIsRunning) { 217 NetworkUtils.resetConnections( 218 CLAT_INTERFACE_NAME, 219 NetworkUtils.RESET_IPV4_ADDRESSES); 220 mBaseLP.removeStackedLink(CLAT_INTERFACE_NAME); 221 updateConnectivityService(); 222 } 223 Slog.i(TAG, "interface " + CLAT_INTERFACE_NAME + 224 " removed, mIsRunning = " + mIsRunning + " -> false"); 225 mIsRunning = false; 226 mLP.clear(); 227 Slog.i(TAG, "mLP = " + mLP); 228 } 229 } 230}; 231