From 742484ce0555b2458d0ac709fc0ce2470e1d6912 Mon Sep 17 00:00:00 2001 From: Jessica Jong Date: Wed, 18 Sep 2013 18:07:14 +0800 Subject: [PATCH] Bug 909688: B2G RIL - handle data connection state changes properly. r=vicamo --- dom/system/gonk/NetworkManager.js | 10 ++++ dom/system/gonk/RadioInterfaceLayer.js | 23 ++++++++ dom/system/gonk/net_worker.js | 7 +++ dom/system/gonk/ril_worker.js | 73 ++++++++++++++++++++++---- 4 files changed, 102 insertions(+), 11 deletions(-) diff --git a/dom/system/gonk/NetworkManager.js b/dom/system/gonk/NetworkManager.js index 4b443dd6ed1b..35071500aca1 100644 --- a/dom/system/gonk/NetworkManager.js +++ b/dom/system/gonk/NetworkManager.js @@ -233,6 +233,7 @@ NetworkManager.prototype = { if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE || network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS || network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_SUPL) { + this.removeHostRoutes(network.name); this.addHostRoute(network); } // Add extra host route. For example, mms proxy or mmsc. @@ -640,6 +641,15 @@ NetworkManager.prototype = { this.worker.postMessage(options); }, + removeHostRoutes: function removeHostRoutes(ifname) { + debug("Going to remove all host routes on " + ifname); + let options = { + cmd: "removeHostRoutes", + ifname: ifname, + }; + this.worker.postMessage(options); + }, + resolveHostname: function resolveHostname(hosts) { let retval = []; diff --git a/dom/system/gonk/RadioInterfaceLayer.js b/dom/system/gonk/RadioInterfaceLayer.js index 4a1c942df290..135e3cc875d4 100644 --- a/dom/system/gonk/RadioInterfaceLayer.js +++ b/dom/system/gonk/RadioInterfaceLayer.js @@ -3242,7 +3242,30 @@ RILNetworkInterface.prototype = { if (this.cid == null) { return; } + if (this.state == datacall.state) { + if (datacall.state != GECKO_NETWORK_STATE_CONNECTED) { + return; + } + // State remains connected, check for minor changes. + let changed = false; + if (this.gateway != datacall.gw) { + this.gateway = datacall.gw; + changed = true; + } + if (datacall.dns && + (this.dns1 != datacall.dns[0] || + this.dns2 != datacall.dns[1])) { + this.dns1 = datacall.dns[0]; + this.dns2 = datacall.dns[1]; + changed = true; + } + if (changed) { + if (DEBUG) this.debug("Notify for data call minor changes."); + Services.obs.notifyObservers(this, + kNetworkInterfaceStateChangedTopic, + null); + } return; } diff --git a/dom/system/gonk/net_worker.js b/dom/system/gonk/net_worker.js index 9b15ecd25628..7c7ad7101bf2 100644 --- a/dom/system/gonk/net_worker.js +++ b/dom/system/gonk/net_worker.js @@ -275,6 +275,13 @@ function removeHostRoute(options) { } } +/** + * Remove the routes associated with the named interface. + */ +function removeHostRoutes(options) { + libnetutils.ifc_remove_host_routes(options.ifname); +} + function removeNetworkRoute(options) { let ipvalue = netHelpers.stringToIP(options.ip); let netmaskvalue = netHelpers.stringToIP(options.netmask); diff --git a/dom/system/gonk/ril_worker.js b/dom/system/gonk/ril_worker.js index ed95a46e4075..30d189501fa8 100644 --- a/dom/system/gonk/ril_worker.js +++ b/dom/system/gonk/ril_worker.js @@ -3677,6 +3677,27 @@ let RIL = { this.sendChromeMessage(message); }, + _compareDataCallLink: function _compareDataCallLink(source, target) { + if (source.ifname != target.ifname || + source.ipaddr != target.ipaddr || + source.gw != target.gw) { + return false; + } + + // Compare .dns. + let sdns = source.dns, tdns = target.dns; + if (sdns.length != tdns.length) { + return false; + } + for (let i = 0; i < sdns.length; i++) { + if (sdns[i] != tdns[i]) { + return false; + } + } + + return true; + }, + _processDataCallList: function _processDataCallList(datacalls, newDataCallOptions) { // Check for possible PDP errors: We check earlier because the datacall // can be removed if is the same as the current one. @@ -3700,6 +3721,7 @@ let RIL = { // If datacalls list is coming from REQUEST_SETUP_DATA_CALL response, // we do not change state for any currentDataCalls not in datacalls list. if (!newDataCallOptions) { + delete this.currentDataCalls[currentDataCall.cid]; currentDataCall.state = GECKO_NETWORK_STATE_DISCONNECTED; currentDataCall.rilMessageType = "datacallstatechange"; this.sendChromeMessage(currentDataCall); @@ -3717,31 +3739,60 @@ let RIL = { this._setDataCallGeckoState(updatedDataCall); if (updatedDataCall.state != currentDataCall.state) { + if (updatedDataCall.state == GECKO_NETWORK_STATE_DISCONNECTED) { + delete this.currentDataCalls[currentDataCall.cid]; + } currentDataCall.status = updatedDataCall.status; currentDataCall.active = updatedDataCall.active; currentDataCall.state = updatedDataCall.state; currentDataCall.rilMessageType = "datacallstatechange"; this.sendChromeMessage(currentDataCall); + continue; } + + // State not changed, now check links. + if (this._compareDataCallLink(updatedDataCall, currentDataCall)) { + if(DEBUG) debug("No changes in data call."); + continue; + } + if ((updatedDataCall.ifname != currentDataCall.ifname) || + (updatedDataCall.ipaddr != currentDataCall.ipaddr)) { + if(DEBUG) debug("Data link changed, cleanup."); + this.deactivateDataCall(currentDataCall); + continue; + } + // Minor change, just update and notify. + if(DEBUG) debug("Data link minor change, just update and notify."); + currentDataCall.gw = updatedDataCall.gw; + if (updatedDataCall.dns) { + currentDataCall.dns[0] = updatedDataCall.dns[0]; + currentDataCall.dns[1] = updatedDataCall.dns[1]; + } + currentDataCall.rilMessageType = "datacallstatechange"; + this.sendChromeMessage(currentDataCall); } for each (let newDataCall in datacalls) { if (!newDataCall.ifname) { continue; } + + if (!newDataCallOptions) { + if (DEBUG) debug("Unexpected new data call: " + JSON.stringify(newDataCall)); + continue; + } + this.currentDataCalls[newDataCall.cid] = newDataCall; this._setDataCallGeckoState(newDataCall); - if (newDataCallOptions) { - newDataCall.radioTech = newDataCallOptions.radioTech; - newDataCall.apn = newDataCallOptions.apn; - newDataCall.user = newDataCallOptions.user; - newDataCall.passwd = newDataCallOptions.passwd; - newDataCall.chappap = newDataCallOptions.chappap; - newDataCall.pdptype = newDataCallOptions.pdptype; - newDataCallOptions = null; - } else if (DEBUG) { - debug("Unexpected new data call: " + JSON.stringify(newDataCall)); - } + + newDataCall.radioTech = newDataCallOptions.radioTech; + newDataCall.apn = newDataCallOptions.apn; + newDataCall.user = newDataCallOptions.user; + newDataCall.passwd = newDataCallOptions.passwd; + newDataCall.chappap = newDataCallOptions.chappap; + newDataCall.pdptype = newDataCallOptions.pdptype; + newDataCallOptions = null; + newDataCall.rilMessageType = "datacallstatechange"; this.sendChromeMessage(newDataCall); }