Bug 1104664 - Replace ifc_* functions with corresponding netd commands. r=echen

This commit is contained in:
Henry Chang 2015-01-09 14:45:53 +08:00
parent 7b25078737
commit 8e4dd5da02
8 changed files with 854 additions and 101 deletions

View File

@ -0,0 +1,68 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "NetIdManager.h"
NetIdManager::NetIdManager()
: mNextNetId(MIN_NET_ID)
{
}
int NetIdManager::getNextNetId()
{
// Modified from
// http://androidxref.com/5.0.0_r2/xref/frameworks/base/services/
// core/java/com/android/server/ConnectivityService.java#764
int netId = mNextNetId;
if (++mNextNetId > MAX_NET_ID) {
mNextNetId = MIN_NET_ID;
}
return netId;
}
void NetIdManager::acquire(const nsString& aInterfaceName,
NetIdInfo* aNetIdInfo)
{
// Lookup or create one.
if (!mInterfaceToNetIdHash.Get(aInterfaceName, aNetIdInfo)) {
aNetIdInfo->mNetId = getNextNetId();
aNetIdInfo->mRefCnt = 1;
} else {
aNetIdInfo->mRefCnt++;
}
// Update hash and return.
mInterfaceToNetIdHash.Put(aInterfaceName, *aNetIdInfo);
return;
}
bool NetIdManager::lookup(const nsString& aInterfaceName,
NetIdInfo* aNetIdInfo)
{
return mInterfaceToNetIdHash.Get(aInterfaceName, aNetIdInfo);
}
bool NetIdManager::release(const nsString& aInterfaceName,
NetIdInfo* aNetIdInfo)
{
if (!mInterfaceToNetIdHash.Get(aInterfaceName, aNetIdInfo)) {
return false; // No such key.
}
aNetIdInfo->mRefCnt--;
// Update the hash if still be referenced.
if (aNetIdInfo->mRefCnt > 0) {
mInterfaceToNetIdHash.Put(aInterfaceName, *aNetIdInfo);
return true;
}
// No longer be referenced. Remove the entry.
mInterfaceToNetIdHash.Remove(aInterfaceName);
return true;
}

View File

@ -0,0 +1,45 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef NetIdManager_h
#define NetIdManager_h
#include "nsString.h"
#include "nsDataHashtable.h"
// NetId is a logical network identifier defined by netd.
// A network is typically a physical one (i.e. PhysicalNetwork.cpp)
// for netd but it could be a virtual network as well.
// We currently use physical network only and use one-to-one
// network-interface mapping.
class NetIdManager {
public:
// keep in sync with system/netd/NetworkController.cpp
enum {
MIN_NET_ID = 100,
MAX_NET_ID = 65535,
};
// We need to count the number of references since different
// application like data and mms may use the same interface.
struct NetIdInfo {
int mNetId;
int mRefCnt;
};
public:
NetIdManager();
bool lookup(const nsString& aInterfaceName, NetIdInfo* aNetIdInfo);
void acquire(const nsString& aInterfaceName, NetIdInfo* aNetIdInfo);
bool release(const nsString& aInterfaceName, NetIdInfo* aNetIdInfo);
private:
int getNextNetId();
int mNextNetId;
nsDataHashtable<nsStringHashKey, NetIdInfo> mInterfaceToNetIdHash;
};
#endif

View File

@ -308,6 +308,17 @@ NetworkManager.prototype = {
debug("Network '" + networkId + "' registered.");
},
_addSubnetRoutes: function(network) {
let ips = {};
let prefixLengths = {};
let length = network.getAddresses(ips, prefixLengths);
for (let i = 0; i < length; i++) {
debug('Adding subnet routes: ' + ips.value[i] + '/' + prefixLengths.value[i]);
gNetworkService.modifyRoute(Ci.nsINetworkService.MODIFY_ROUTE_ADD,
network.name, ips.value[i], prefixLengths.value[i]);
}
},
updateNetworkInterface: function(network) {
if (!(network instanceof Ci.nsINetworkInterface)) {
throw Components.Exception("Argument must be nsINetworkInterface.",
@ -320,35 +331,50 @@ NetworkManager.prototype = {
}
debug("Network " + network.type + "/" + network.name +
" changed state to " + network.state);
// Note that since Lollipop we need to allocate and initialize
// something through netd, so we add createNetwork/destroyNetwork
// to deal with that explicitly.
switch (network.state) {
case Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED:
// Add host route for data calls
if (this.isNetworkTypeMobile(network.type)) {
gNetworkService.removeHostRoutes(network.name);
this.setHostRoutes(network);
}
// Dun type is a special case where we add the default route to a
// secondary table.
if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN) {
this.setSecondaryDefaultRoute(network);
}
// Remove pre-created default route and let setAndConfigureActive()
// to set default route only on preferred network
gNetworkService.removeDefaultRoute(network);
this.setAndConfigureActive();
// Update data connection when Wifi connected/disconnected
if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI && this.mRil) {
for (let i = 0; i < this.mRil.numRadioInterfaces; i++) {
this.mRil.getRadioInterface(i).updateRILNetworkInterface();
gNetworkService.createNetwork(network.name, () => {
// Add host route for data calls
if (this.isNetworkTypeMobile(network.type)) {
gNetworkService.removeHostRoutes(network.name);
this.setHostRoutes(network);
}
}
// Dun type is a special case where we add the default route to a
// secondary table.
if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN) {
this.setSecondaryDefaultRoute(network);
}
// Remove pre-created default route and let setAndConfigureActive()
// to set default route only on preferred network
gNetworkService.removeDefaultRoute(network);
this.onConnectionChanged(network);
this._addSubnetRoutes(network);
this.setAndConfigureActive();
// Update data connection when Wifi connected/disconnected
if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI && this.mRil) {
for (let i = 0; i < this.mRil.numRadioInterfaces; i++) {
this.mRil.getRadioInterface(i).updateRILNetworkInterface();
}
}
this.onConnectionChanged(network);
// Probing the public network accessibility after routing table is ready
CaptivePortalDetectionHelper
.notify(CaptivePortalDetectionHelper.EVENT_CONNECT, this.active);
// Notify outer modules like MmsService to start the transaction after
// the configuration of the network interface is done.
Services.obs.notifyObservers(network, TOPIC_CONNECTION_STATE_CHANGED,
this.convertConnectionType(network));
});
// Probing the public network accessibility after routing table is ready
CaptivePortalDetectionHelper
.notify(CaptivePortalDetectionHelper.EVENT_CONNECT, this.active);
break;
case Ci.nsINetworkInterface.NETWORK_STATE_DISCONNECTED:
// Remove host route for data calls
@ -378,13 +404,14 @@ NetworkManager.prototype = {
}
}
gNetworkService.destroyNetwork(network.name, () => {
// Notify outer modules like MmsService to start the transaction after
// the configuration of the network interface is done.
Services.obs.notifyObservers(network, TOPIC_CONNECTION_STATE_CHANGED,
this.convertConnectionType(network));
});
break;
}
// Notify outer modules like MmsService to start the transaction after
// the configuration of the network interface is done.
Services.obs.notifyObservers(network, TOPIC_CONNECTION_STATE_CHANGED,
this.convertConnectionType(network));
},
unregisterNetworkInterface: function(network) {
@ -435,14 +462,22 @@ NetworkManager.prototype = {
},
_updateRoutes: function(doAdd, ipAddresses, networkName, gateways) {
let getMaxPrefixLength = (aIp) => {
return aIp.match(this.REGEXP_IPV4) ? IPV4_MAX_PREFIX_LENGTH : IPV6_MAX_PREFIX_LENGTH;
}
let promises = [];
ipAddresses.forEach((aIpAddress) => {
let gateway = this.selectGateway(gateways, aIpAddress);
if (gateway) {
promises.push((doAdd)
? gNetworkService.addHostRoute(networkName, gateway, aIpAddress)
: gNetworkService.removeHostRoute(networkName, gateway, aIpAddress));
? gNetworkService.modifyRoute(Ci.nsINetworkService.MODIFY_ROUTE_ADD,
networkName, aIpAddress,
getMaxPrefixLength(aIpAddress), gateway)
: gNetworkService.modifyRoute(Ci.nsINetworkService.MODIFY_ROUTE_REMOVE,
networkName, aIpAddress,
getMaxPrefixLength(aIpAddress), gateway));
}
});
@ -1271,6 +1306,10 @@ NetworkManager.prototype = {
_setDefaultRouteAndDNS: function(network, oldInterface) {
gNetworkService.setDefaultRoute(network, oldInterface, function(success) {
if (!success) {
gNetworkService.destroyNetwork(network, function() {});
return;
}
gNetworkService.setDNS(network, function(result) {
gNetworkService.setNetworkProxy(network);
});

View File

@ -255,22 +255,12 @@ NetworkService.prototype = {
},
resetRoutingTable: function(network) {
let ips = {};
let prefixLengths = {};
let length = network.getAddresses(ips, prefixLengths);
let options = {
cmd: "removeNetworkRoute",
ifname: network.name
};
for (let i = 0; i < length; i++) {
let ip = ips.value[i];
let prefixLength = prefixLengths.value[i];
let options = {
cmd: "removeNetworkRoute",
ifname: network.name,
ip: ip,
prefixLength: prefixLength
};
this.controlMessage(options);
}
this.controlMessage(options);
},
setDNS: function(networkInterface, callback) {
@ -312,8 +302,20 @@ NetworkService.prototype = {
this.controlMessage(options);
},
_setHostRoute: function(doAdd, interfaceName, gateway, host) {
let command = doAdd ? "addHostRoute" : "removeHostRoute";
modifyRoute: function(action, interfaceName, host, prefixLength, gateway) {
let command;
switch (action) {
case Ci.nsINetworkService.MODIFY_ROUTE_ADD:
command = 'addHostRoute';
break;
case Ci.nsINetworkService.MODIFY_ROUTE_REMOVE:
command = 'removeHostRoute';
break;
default:
if (DEBUG) debug('Unknown action: ' + action);
return Promise.reject();
}
if (DEBUG) debug(command + " " + host + " on " + interfaceName);
let deferred = Promise.defer();
@ -321,6 +323,7 @@ NetworkService.prototype = {
cmd: command,
ifname: interfaceName,
gateway: gateway,
prefixLength: prefixLength,
ip: host
};
this.controlMessage(options, function(data) {
@ -333,14 +336,6 @@ NetworkService.prototype = {
return deferred.promise;
},
addHostRoute: function(interfaceName, gateway, host) {
return this._setHostRoute(true, interfaceName, gateway, host);
},
removeHostRoute: function(interfaceName, gateway, host) {
return this._setHostRoute(false, interfaceName, gateway, host);
},
removeHostRoutes: function(ifname) {
if(DEBUG) debug("Going to remove all host routes on " + ifname);
let options = {
@ -567,6 +562,28 @@ NetworkService.prototype = {
});
},
createNetwork: function(interfaceName, callback) {
let params = {
cmd: "createNetwork",
ifname: interfaceName
};
this.controlMessage(params, function(result) {
callback.nativeCommandResult(!result.error);
});
},
destroyNetwork: function(interfaceName, callback) {
let params = {
cmd: "destroyNetwork",
ifname: interfaceName
};
this.controlMessage(params, function(result) {
callback.nativeCommandResult(!result.error);
});
},
shutdown: false,
observe: function observe(aSubject, aTopic, aData) {

View File

@ -248,12 +248,6 @@ const CommandFunc NetworkUtils::sNetworkInterfaceSetAlarmChain[] = {
NetworkUtils::networkInterfaceAlarmSuccess
};
const CommandFunc NetworkUtils::sSetDnsChain[] = {
NetworkUtils::setDefaultInterface,
NetworkUtils::setInterfaceDns,
NetworkUtils::setDnsSuccess,
};
/**
* Helper function to get the mask from given prefix length.
*/
@ -918,13 +912,34 @@ void NetworkUtils::setDefaultInterface(CommandChain* aChain,
doCommand(command, aChain, aCallback);
}
void NetworkUtils::removeDefaultRoute(CommandChain* aChain,
CommandCallback aCallback,
NetworkResultOptions& aResult)
{
char command[MAX_COMMAND_SIZE];
// FIXME: (Bug 1121795) We only remove the first gateway to the default route.
// For dual stack (ipv4/ipv6) device, one of the gateway would
// not be added to the default route.
snprintf(command, MAX_COMMAND_SIZE - 1, "network route remove %d %s 0.0.0.0/0 %s",
GET_FIELD(mNetId), GET_CHAR(mIfname), GET_CHAR(mGateways[0]));
doCommand(command, aChain, aCallback);
}
void NetworkUtils::setInterfaceDns(CommandChain* aChain,
CommandCallback aCallback,
NetworkResultOptions& aResult)
{
char command[MAX_COMMAND_SIZE];
int written = snprintf(command, sizeof command, "resolver setifdns %s %s",
GET_CHAR(mIfname), GET_CHAR(mDomain));
int written;
if (SDK_VERSION >= 20) {
written = snprintf(command, sizeof command, "resolver setnetdns %d %s",
GET_FIELD(mNetId), GET_CHAR(mDomain));
} else {
written = snprintf(command, sizeof command, "resolver setifdns %s %s",
GET_CHAR(mIfname), GET_CHAR(mDomain));
}
nsTArray<nsString>& dnses = GET_FIELD(mDnses);
uint32_t length = dnses.Length();
@ -949,6 +964,188 @@ void NetworkUtils::setInterfaceDns(CommandChain* aChain,
doCommand(command, aChain, aCallback);
}
void NetworkUtils::clearAddrForInterface(CommandChain* aChain,
CommandCallback aCallback,
NetworkResultOptions& aResult)
{
char command[MAX_COMMAND_SIZE];
snprintf(command, MAX_COMMAND_SIZE - 1, "interface clearaddrs %s", GET_CHAR(mIfname));
doCommand(command, aChain, aCallback);
}
void NetworkUtils::createNetwork(CommandChain* aChain,
CommandCallback aCallback,
NetworkResultOptions& aResult)
{
char command[MAX_COMMAND_SIZE];
snprintf(command, MAX_COMMAND_SIZE - 1, "network create %d", GET_FIELD(mNetId));
doCommand(command, aChain, aCallback);
}
void NetworkUtils::destroyNetwork(CommandChain* aChain,
CommandCallback aCallback,
NetworkResultOptions& aResult)
{
char command[MAX_COMMAND_SIZE];
snprintf(command, MAX_COMMAND_SIZE - 1, "network destroy %d", GET_FIELD(mNetId));
doCommand(command, aChain, aCallback);
}
void NetworkUtils::addInterfaceToNetwork(CommandChain* aChain,
CommandCallback aCallback,
NetworkResultOptions& aResult)
{
char command[MAX_COMMAND_SIZE];
snprintf(command, MAX_COMMAND_SIZE - 1, "network interface add %d %s",
GET_FIELD(mNetId), GET_CHAR(mIfname));
doCommand(command, aChain, aCallback);
}
void NetworkUtils::addRouteToInterface(CommandChain* aChain,
CommandCallback aCallback,
NetworkResultOptions& aResult)
{
struct MyCallback {
static void callback(CommandCallback::CallbackType aOriginalCallback,
CommandChain* aChain,
bool aError,
mozilla::dom::NetworkResultOptions& aResult)
{
NS_ConvertUTF16toUTF8 reason(aResult.mResultReason);
NU_DBG("addRouteToInterface's reason: %s", reason.get());
if (aError && reason.EqualsASCII("addRoute() failed (File exists)")) {
NU_DBG("Ignore \"File exists\" error when adding host route.");
return aOriginalCallback(aChain, false, aResult);
}
aOriginalCallback(aChain, aError, aResult);
}
};
CommandCallback wrappedCallback(MyCallback::callback, aCallback);
modifyRouteOnInterface(aChain, wrappedCallback, aResult, true);
}
void NetworkUtils::removeRouteFromInterface(CommandChain* aChain,
CommandCallback aCallback,
NetworkResultOptions& aResult)
{
modifyRouteOnInterface(aChain, aCallback, aResult, false);
}
void NetworkUtils::modifyRouteOnInterface(CommandChain* aChain,
CommandCallback aCallback,
NetworkResultOptions& aResult,
bool aDoAdd)
{
char command[MAX_COMMAND_SIZE];
// AOSP adds host route to its interface table but it doesn't work for
// B2G because we cannot set fwmark per application. So, we add
// all host routes to legacy_system table except scope link route.
nsCString ipOrSubnetIp = NS_ConvertUTF16toUTF8(GET_FIELD(mIp));
nsCString gatewayOrEmpty;
const char* legacyOrEmpty = "legacy 0 "; // Add to legacy by default.
if (GET_FIELD(mGateway).IsEmpty()) {
ipOrSubnetIp = getSubnetIp(ipOrSubnetIp, GET_FIELD(mPrefixLength));
legacyOrEmpty = ""; // Add to interface table for scope link route.
} else {
gatewayOrEmpty = nsCString(" ") + NS_ConvertUTF16toUTF8(GET_FIELD(mGateway));
}
const char* action = aDoAdd ? "add" : "remove";
snprintf(command, MAX_COMMAND_SIZE - 1, "network route %s%s %d %s %s/%d%s",
legacyOrEmpty, action,
GET_FIELD(mNetId), GET_CHAR(mIfname), ipOrSubnetIp.get(),
GET_FIELD(mPrefixLength), gatewayOrEmpty.get());
doCommand(command, aChain, aCallback);
}
void NetworkUtils::addDefaultRouteToNetwork(CommandChain* aChain,
CommandCallback aCallback,
NetworkResultOptions& aResult)
{
char command[MAX_COMMAND_SIZE];
// FIXME: (Bug 1121795) We only add the first gateway to the default route.
// For dual stack (ipv4/ipv6) device, one of the gateway would
// not be added to the default route.
snprintf(command, MAX_COMMAND_SIZE - 1, "network route add %d %s 0.0.0.0/0 %s",
GET_FIELD(mNetId), GET_CHAR(mIfname), GET_CHAR(mGateways[0]));
struct MyCallback {
static void callback(CommandCallback::CallbackType aOriginalCallback,
CommandChain* aChain,
bool aError,
mozilla::dom::NetworkResultOptions& aResult)
{
NS_ConvertUTF16toUTF8 reason(aResult.mResultReason);
NU_DBG("addDefaultRouteToNetwork's reason: %s", reason.get());
if (aError && reason.EqualsASCII("addRoute() failed (File exists)")) {
NU_DBG("Ignore \"File exists\" error when adding host route.");
return aOriginalCallback(aChain, false, aResult);
}
aOriginalCallback(aChain, aError, aResult);
}
};
CommandCallback wrappedCallback(MyCallback::callback, aCallback);
doCommand(command, aChain, wrappedCallback);
}
void NetworkUtils::setDefaultNetwork(CommandChain* aChain,
CommandCallback aCallback,
NetworkResultOptions& aResult)
{
char command[MAX_COMMAND_SIZE];
snprintf(command, MAX_COMMAND_SIZE - 1, "network default set %d", GET_FIELD(mNetId));
doCommand(command, aChain, aCallback);
}
void NetworkUtils::setIpv6Enabled(CommandChain* aChain,
CommandCallback aCallback,
NetworkResultOptions& aResult,
bool aEnabled)
{
char command[MAX_COMMAND_SIZE];
snprintf(command, MAX_COMMAND_SIZE - 1, "interface ipv6 %s %s",
GET_CHAR(mIfname), aEnabled ? "enable" : "disable");
struct MyCallback {
static void callback(CommandCallback::CallbackType aOriginalCallback,
CommandChain* aChain,
bool aError,
mozilla::dom::NetworkResultOptions& aResult)
{
aOriginalCallback(aChain, false, aResult);
}
};
CommandCallback wrappedCallback(MyCallback::callback, aCallback);
doCommand(command, aChain, wrappedCallback);
}
void NetworkUtils::enableIpv6(CommandChain* aChain,
CommandCallback aCallback,
NetworkResultOptions& aResult)
{
setIpv6Enabled(aChain, aCallback, aResult, true);
}
void NetworkUtils::disableIpv6(CommandChain* aChain,
CommandCallback aCallback,
NetworkResultOptions& aResult)
{
setIpv6Enabled(aChain, aCallback, aResult, false);
}
#undef GET_CHAR
#undef GET_FIELD
@ -1053,14 +1250,6 @@ void NetworkUtils::networkInterfaceAlarmSuccess(CommandChain* aChain,
finalizeSuccess(aChain, aResult);
}
void NetworkUtils::setDnsSuccess(CommandChain* aChain,
CommandCallback aCallback,
NetworkResultOptions& aResult)
{
postMessage(aChain->getParams(), aResult);
finalizeSuccess(aChain, aResult);
}
void NetworkUtils::updateUpStreamFail(NetworkParams& aOptions, NetworkResultOptions& aResult)
{
postMessage(aOptions, aResult);
@ -1107,6 +1296,22 @@ void NetworkUtils::setDnsFail(NetworkParams& aOptions, NetworkResultOptions& aRe
postMessage(aOptions, aResult);
}
void NetworkUtils::defaultAsyncSuccessHandler(CommandChain* aChain,
CommandCallback aCallback,
NetworkResultOptions& aResult)
{
NU_DBG("defaultAsyncSuccessHandler");
aResult.mRet = true;
postMessage(aChain->getParams(), aResult);
finalizeSuccess(aChain, aResult);
}
void NetworkUtils::defaultAsyncFailureHandler(NetworkParams& aOptions, NetworkResultOptions& aResult)
{
aResult.mRet = false;
postMessage(aOptions, aResult);
}
#undef ASSIGN_FIELD
#undef ASSIGN_FIELD_VALUE
@ -1170,6 +1375,8 @@ void NetworkUtils::ExecuteCommand(NetworkParams aOptions)
BUILD_ENTRY(enableInterface),
BUILD_ENTRY(disableInterface),
BUILD_ENTRY(resetConnections),
BUILD_ENTRY(createNetwork),
BUILD_ENTRY(destroyNetwork),
#undef BUILD_ENTRY
};
@ -1266,14 +1473,14 @@ void NetworkUtils::onNetdMessage(NetdCommand* aCommand)
gPending = false;
}
if (gCurrentCommand.callback) {
{
char buf[BUF_SIZE];
join(gReason, INTERFACE_DELIMIT, BUF_SIZE, buf);
NetworkResultOptions result;
result.mResultCode = code;
result.mResultReason = NS_ConvertUTF8toUTF16(buf);
(*gCurrentCommand.callback)(gCurrentCommand.chain, isError(code), result);
(gCurrentCommand.callback)(gCurrentCommand.chain, isError(code), result);
gReason.Clear();
}
@ -1335,8 +1542,28 @@ CommandResult NetworkUtils::setDNS(NetworkParams& aOptions)
property_set("net.dnschange", num);
// DNS needs to be set through netd since JellyBean (4.3).
if (SDK_VERSION >= 20) {
// Lollipop.
static CommandFunc COMMAND_CHAIN[] = {
setInterfaceDns,
defaultAsyncSuccessHandler
};
NetIdManager::NetIdInfo netIdInfo;
if (!mNetIdManager.lookup(aOptions.mIfname, &netIdInfo)) {
return -1;
}
aOptions.mNetId = netIdInfo.mNetId;
runChain(aOptions, COMMAND_CHAIN, setDnsFail);
return CommandResult::Pending();
}
if (SDK_VERSION >= 18) {
runChain(aOptions, sSetDnsChain, setDnsFail);
// JB, KK.
static CommandFunc COMMAND_CHAIN[] = {
setDefaultInterface,
setInterfaceDns,
defaultAsyncSuccessHandler
};
runChain(aOptions, COMMAND_CHAIN, setDnsFail);
return CommandResult::Pending();
}
@ -1439,6 +1666,33 @@ CommandResult NetworkUtils::resetConnections(NetworkParams& aOptions) {
* Set default route and DNS servers for given network interface.
*/
CommandResult NetworkUtils::setDefaultRoute(NetworkParams& aOptions)
{
if (SDK_VERSION < 20) {
return setDefaultRouteLegacy(aOptions);
}
static CommandFunc COMMAND_CHAIN[] = {
addDefaultRouteToNetwork,
setDefaultNetwork,
defaultAsyncSuccessHandler,
};
NetIdManager::NetIdInfo netIdInfo;
if (!mNetIdManager.lookup(GET_FIELD(mIfname), &netIdInfo)) {
ERROR("No such interface");
return -1;
}
aOptions.mNetId = netIdInfo.mNetId;
runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler);
return CommandResult::Pending();
}
/**
* Set default route and DNS servers for given network interface by obsoleted libnetutils.
*/
CommandResult NetworkUtils::setDefaultRouteLegacy(NetworkParams& aOptions)
{
NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname);
@ -1493,6 +1747,37 @@ CommandResult NetworkUtils::setDefaultRoute(NetworkParams& aOptions)
*/
CommandResult NetworkUtils::removeDefaultRoute(NetworkParams& aOptions)
{
NU_DBG("Calling NetworkUtils::removeDefaultRoute");
if (SDK_VERSION < 20) {
return removeDefaultRouteLegacy(aOptions);
}
static CommandFunc COMMAND_CHAIN[] = {
removeDefaultRoute,
defaultAsyncSuccessHandler,
};
NetIdManager::NetIdInfo netIdInfo;
if (!mNetIdManager.lookup(GET_FIELD(mIfname), &netIdInfo)) {
ERROR("No such interface: %s", GET_CHAR(mIfname));
return -1;
}
NU_DBG("Obtained netid %d for interface %s", netIdInfo.mNetId, GET_CHAR(mIfname));
aOptions.mNetId = netIdInfo.mNetId;
runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler);
return CommandResult::Pending();
}
/**
* Remove default route for given network interface by obsoleted libnetutils.
*/
CommandResult NetworkUtils::removeDefaultRouteLegacy(NetworkParams& aOptions)
{
// Legacy libnetutils calls before Lollipop.
uint32_t length = aOptions.mGateways.Length();
for (uint32_t i = 0; i < length; i++) {
NS_ConvertUTF16toUTF8 autoGateway(aOptions.mGateways[i]);
@ -1514,6 +1799,34 @@ CommandResult NetworkUtils::removeDefaultRoute(NetworkParams& aOptions)
* Add host route for given network interface.
*/
CommandResult NetworkUtils::addHostRoute(NetworkParams& aOptions)
{
if (SDK_VERSION < 20) {
return addHostRouteLegacy(aOptions);
}
static CommandFunc COMMAND_CHAIN[] = {
addRouteToInterface,
defaultAsyncSuccessHandler,
};
NetIdManager::NetIdInfo netIdInfo;
if (!mNetIdManager.lookup(GET_FIELD(mIfname), &netIdInfo)) {
ERROR("No such interface: %s", GET_CHAR(mIfname));
return -1;
}
NU_DBG("Obtained netid %d for interface %s", netIdInfo.mNetId, GET_CHAR(mIfname));
aOptions.mNetId = netIdInfo.mNetId;
runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler);
return CommandResult::Pending();
}
/**
* Add host route for given network interface.
*/
CommandResult NetworkUtils::addHostRouteLegacy(NetworkParams& aOptions)
{
NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname);
NS_ConvertUTF16toUTF8 autoHostname(aOptions.mIp);
@ -1538,6 +1851,34 @@ CommandResult NetworkUtils::addHostRoute(NetworkParams& aOptions)
* Remove host route for given network interface.
*/
CommandResult NetworkUtils::removeHostRoute(NetworkParams& aOptions)
{
if (SDK_VERSION < 20) {
return removeHostRouteLegacy(aOptions);
}
static CommandFunc COMMAND_CHAIN[] = {
removeRouteFromInterface,
defaultAsyncSuccessHandler,
};
NetIdManager::NetIdInfo netIdInfo;
if (!mNetIdManager.lookup(GET_FIELD(mIfname), &netIdInfo)) {
ERROR("No such interface: %s", GET_CHAR(mIfname));
return -1;
}
NU_DBG("Obtained netid %d for interface %s", netIdInfo.mNetId, GET_CHAR(mIfname));
aOptions.mNetId = netIdInfo.mNetId;
runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler);
return CommandResult::Pending();
}
/**
* Remove host route for given network interface.
*/
CommandResult NetworkUtils::removeHostRouteLegacy(NetworkParams& aOptions)
{
NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname);
NS_ConvertUTF16toUTF8 autoHostname(aOptions.mIp);
@ -1562,11 +1903,89 @@ CommandResult NetworkUtils::removeHostRoute(NetworkParams& aOptions)
* Remove the routes associated with the named interface.
*/
CommandResult NetworkUtils::removeHostRoutes(NetworkParams& aOptions)
{
if (SDK_VERSION < 20) {
return removeHostRoutesLegacy(aOptions);
}
NU_DBG("Don't know how to remove host routes on a interface");
return SUCCESS;
}
/**
* Remove the routes associated with the named interface.
*/
CommandResult NetworkUtils::removeHostRoutesLegacy(NetworkParams& aOptions)
{
return mNetUtils->do_ifc_remove_host_routes(GET_CHAR(mIfname));
}
CommandResult NetworkUtils::removeNetworkRoute(NetworkParams& aOptions)
{
if (SDK_VERSION < 20) {
return removeNetworkRouteLegacy(aOptions);
}
static CommandFunc COMMAND_CHAIN[] = {
clearAddrForInterface,
defaultAsyncSuccessHandler,
};
NetIdManager::NetIdInfo netIdInfo;
if (!mNetIdManager.lookup(GET_FIELD(mIfname), &netIdInfo)) {
ERROR("interface %s is not present in any network", GET_CHAR(mIfname));
return -1;
}
NU_DBG("Obtained netid %d for interface %s", netIdInfo.mNetId, GET_CHAR(mIfname));
aOptions.mNetId = netIdInfo.mNetId;
runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler);
return CommandResult::Pending();
}
nsCString NetworkUtils::getSubnetIp(const nsCString& aIp, int aPrefixLength)
{
int type = getIpType(aIp.get());
if (AF_INET6 == type) {
struct in6_addr in6;
if (inet_pton(AF_INET6, aIp.get(), &in6) != 1) {
return nsCString();
}
uint32_t p, i, p1, mask;
p = aPrefixLength;
i = 0;
while (i < 4) {
p1 = p > 32 ? 32 : p;
p -= p1;
mask = p1 ? ~0x0 << (32 - p1) : 0;
in6.s6_addr32[i++] &= htonl(mask);
}
char subnetStr[INET6_ADDRSTRLEN];
if (!inet_ntop(AF_INET6, &in6, subnetStr, sizeof subnetStr)) {
return nsCString();
}
return nsCString(subnetStr);
}
if (AF_INET == type) {
uint32_t ip = inet_addr(aIp.get());
uint32_t netmask = makeMask(aPrefixLength);
uint32_t subnet = ip & netmask;
struct in_addr addr;
addr.s_addr = subnet;
return nsCString(inet_ntoa(addr));
}
return nsCString();
}
CommandResult NetworkUtils::removeNetworkRouteLegacy(NetworkParams& aOptions)
{
NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname);
NS_ConvertUTF16toUTF8 autoIp(aOptions.mIp);
@ -1857,6 +2276,74 @@ CommandResult NetworkUtils::updateUpStream(NetworkParams& aOptions)
return CommandResult::Pending();
}
/**
* handling upstream interface change event.
*/
CommandResult NetworkUtils::createNetwork(NetworkParams& aOptions)
{
if (SDK_VERSION < 20) {
return SUCCESS;
}
static CommandFunc COMMAND_CHAIN[] = {
createNetwork,
enableIpv6,
addInterfaceToNetwork,
defaultAsyncSuccessHandler,
};
NetIdManager::NetIdInfo netIdInfo;
mNetIdManager.acquire(GET_FIELD(mIfname), &netIdInfo);
if (netIdInfo.mRefCnt > 1) {
// Already created. Just return.
NU_DBG("Interface %s (%d) has been created.", GET_CHAR(mIfname),
netIdInfo.mNetId);
return SUCCESS;
}
NU_DBG("Request netd to create a network with netid %d", netIdInfo.mNetId);
// Newly created netid. Ask netd to create network.
aOptions.mNetId = netIdInfo.mNetId;
runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler);
return CommandResult::Pending();
}
/**
* handling upstream interface change event.
*/
CommandResult NetworkUtils::destroyNetwork(NetworkParams& aOptions)
{
if (SDK_VERSION < 20) {
return SUCCESS;
}
static CommandFunc COMMAND_CHAIN[] = {
disableIpv6,
destroyNetwork,
defaultAsyncSuccessHandler,
};
NetIdManager::NetIdInfo netIdInfo;
if (!mNetIdManager.release(GET_FIELD(mIfname), &netIdInfo)) {
ERROR("No existing netid for %s", GET_CHAR(mIfname));
return -1;
}
if (netIdInfo.mRefCnt > 0) {
// Still be referenced. Just return.
NU_DBG("Someone is still using this interface.");
return SUCCESS;
}
NU_DBG("Interface %s (%d) is no longer used. Tell netd to destroy.",
GET_CHAR(mIfname), netIdInfo.mNetId);
aOptions.mNetId = netIdInfo.mNetId;
runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler);
return CommandResult::Pending();
}
void NetworkUtils::sendBroadcastMessage(uint32_t code, char* reason)
{
NetworkResultOptions result;

View File

@ -10,12 +10,55 @@
#include "mozilla/dom/network/NetUtils.h"
#include "mozilla/ipc/Netd.h"
#include "nsTArray.h"
#include "NetIdManager.h"
class NetworkParams;
class CommandChain;
typedef void (*CommandCallback)(CommandChain*, bool,
mozilla::dom::NetworkResultOptions& aResult);
class CommandCallback {
public:
typedef void (*CallbackType)(CommandChain*, bool,
mozilla::dom::NetworkResultOptions& aResult);
typedef void (*CallbackWrapperType)(CallbackType aOriginalCallback,
CommandChain*, bool,
mozilla::dom::NetworkResultOptions& aResult);
CommandCallback()
: mCallback(nullptr)
, mCallbackWrapper(nullptr)
{
}
CommandCallback(CallbackType aCallback)
: mCallback(aCallback)
, mCallbackWrapper(nullptr)
{
}
CommandCallback(CallbackWrapperType aCallbackWrapper,
CommandCallback aOriginalCallback)
: mCallback(aOriginalCallback.mCallback)
, mCallbackWrapper(aCallbackWrapper)
{
}
void operator()(CommandChain* aChain, bool aError,
mozilla::dom::NetworkResultOptions& aResult)
{
if (mCallbackWrapper) {
return mCallbackWrapper(mCallback, aChain, aError, aResult);
}
if (mCallback) {
return mCallback(aChain, aError, aResult);
}
}
private:
CallbackType mCallback;
CallbackWrapperType mCallbackWrapper;
};
typedef void (*CommandFunc)(CommandChain*, CommandCallback,
mozilla::dom::NetworkResultOptions& aResult);
typedef void (*MessageCallback)(mozilla::dom::NetworkResultOptions& aResult);
@ -109,6 +152,7 @@ public:
#undef COPY_FIELD
}
// Followings attributes are 1-to-1 mapping to NetworkCommandOptions.
int32_t mId;
nsString mCmd;
nsString mDomain;
@ -152,6 +196,9 @@ public:
long mGateway_long;
long mDns1_long;
long mDns2_long;
// Auxiliary information required to carry accros command chain.
int mNetId; // A locally defined id per interface.
};
// CommandChain store the necessary information to execute command one by one.
@ -258,6 +305,16 @@ private:
CommandResult setUSBTethering(NetworkParams& aOptions);
CommandResult enableUsbRndis(NetworkParams& aOptions);
CommandResult updateUpStream(NetworkParams& aOptions);
CommandResult createNetwork(NetworkParams& aOptions);
CommandResult destroyNetwork(NetworkParams& aOptions);
CommandResult addHostRouteLegacy(NetworkParams& aOptions);
CommandResult removeHostRouteLegacy(NetworkParams& aOptions);
CommandResult removeHostRoutesLegacy(NetworkParams& aOptions);
CommandResult setDefaultRouteLegacy(NetworkParams& aOptions);
CommandResult removeDefaultRouteLegacy(NetworkParams& aOptions);
CommandResult removeNetworkRouteLegacy(NetworkParams& aOptions);
/**
* function pointer array holds all netd commands should be executed
@ -277,7 +334,6 @@ private:
static const CommandFunc sNetworkInterfaceEnableAlarmChain[];
static const CommandFunc sNetworkInterfaceDisableAlarmChain[];
static const CommandFunc sNetworkInterfaceSetAlarmChain[];
static const CommandFunc sSetDnsChain[];
/**
* Individual netd command stored in command chain.
@ -318,7 +374,23 @@ private:
static void updateUpStreamSuccess(PARAMS);
static void setDhcpServerSuccess(PARAMS);
static void wifiOperationModeSuccess(PARAMS);
static void setDnsSuccess(PARAMS);
static void clearAddrForInterface(PARAMS);
static void createNetwork(PARAMS);
static void destroyNetwork(PARAMS);
static void addInterfaceToNetwork(PARAMS);
static void addDefaultRouteToNetwork(PARAMS);
static void setDefaultNetwork(PARAMS);
static void removeDefaultRoute(PARAMS);
static void removeNetworkRouteSuccess(PARAMS);
static void removeNetworkRoute(PARAMS);
static void addRouteToInterface(PARAMS);
static void removeRouteFromInterface(PARAMS);
static void modifyRouteOnInterface(PARAMS, bool aDoAdd);
static void enableIpv6(PARAMS);
static void disableIpv6(PARAMS);
static void setIpv6Enabled(PARAMS, bool aEnabled);
static void defaultAsyncSuccessHandler(PARAMS);
#undef PARAMS
/**
@ -333,6 +405,7 @@ private:
static void setDhcpServerFail(PARAMS);
static void networkInterfaceAlarmFail(PARAMS);
static void setDnsFail(PARAMS);
static void defaultAsyncFailureHandler(PARAMS);
#undef PARAMS
/**
@ -370,6 +443,8 @@ private:
const CommandFunc (&aCmds)[N],
ErrorCallback aError);
static nsCString getSubnetIp(const nsCString& aIp, int aPrefixLength);
/**
* Callback function to send netd result to main thread.
*/
@ -379,6 +454,8 @@ private:
* Utility class to access libnetutils.
*/
nsAutoPtr<NetUtils> mNetUtils;
NetIdManager mNetIdManager;
};
#endif

View File

@ -44,6 +44,7 @@ UNIFIED_SOURCES += [
'MozMtpDatabase.cpp',
'MozMtpServer.cpp',
'MozMtpStorage.cpp',
'NetIdManager.cpp',
'NetworkUtils.cpp',
'NetworkWorker.cpp',
'nsVolume.cpp',

View File

@ -159,9 +159,12 @@ interface nsIDhcpRequestCallback : nsISupports
/**
* Provide network services.
*/
[scriptable, uuid(9f1d78e0-1314-11e4-9191-0800200c9a66)]
[scriptable, uuid(f7e23599-176a-435b-9ecf-7e5274bdfa76)]
interface nsINetworkService : nsISupports
{
const long MODIFY_ROUTE_ADD = 0;
const long MODIFY_ROUTE_REMOVE = 1;
/**
* Enable or disable Wifi Tethering
*
@ -314,36 +317,28 @@ interface nsINetworkService : nsISupports
void removeDefaultRoute(in nsINetworkInterface networkInterface);
/**
* Add host route.
* Modify route.
*
* @param action
* nsINetworkService.MODIFY_ROUTE_ADD to add route and
* nsINetworkService.MODIFY_ROUTE_REMOVE to remove.
* @param interfaceName
* Network interface name for the output of the host route.
* @param gateway
* Gateway ip for the output of the host route.
* @param host
* Host ip we want to add route for.
*
* @return A deferred promise that resolves on success or rejects with a
* specified reason otherwise.
*/
jsval addHostRoute(in DOMString interfaceName, in DOMString gateway,
in DOMString host);
/**
* Remove host route.
*
* @param interfaceName
* Network interface name for the output of the host route.
* @param gateway
* Gateway ip for the output of the host route.
* @param host
* Host ip we want to remove route for.
* @param prefixLength
* The prefix length of the route we'd like to modify.
* @param [optional] gateway
* Gateway ip for the output of the host route.
*
* @return A deferred promise that resolves on success or rejects with a
* specified reason otherwise.
*/
jsval removeHostRoute(in DOMString interfaceName, in DOMString gateway,
in DOMString host);
jsval modifyRoute(in long action,
in DOMString interfaceName,
in DOMString host,
in long prefixLength,
[optional] in DOMString gateway);
/**
* Remove all host routes.
@ -470,4 +465,28 @@ interface nsINetworkService : nsISupports
*/
void resetConnections(in DOMString interfaceName,
in nsINativeCommandCallback callback);
/**
* Create network (required to call prior to any networking operation)
*
* @param networkInterface
* The network interface name which we want to reset.
*
* @param callback
* Callback to notify the result of resetting connections.
*/
void createNetwork(in DOMString interfaceName,
in nsINativeCommandCallback callback);
/**
* Destroy network (required to call prior to any networking operation)
*
* @param networkInterface
* The network interface name which we want to reset.
*
* @param callback
* Callback to notify the result of resetting connections.
*/
void destroyNetwork(in DOMString interfaceName,
in nsINativeCommandCallback callback);
};