Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 "use strict";
7 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
9 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
10 Cu.import("resource://gre/modules/Services.jsm");
11 Cu.import("resource://gre/modules/FileUtils.jsm");
12 Cu.import("resource://gre/modules/systemlibs.js");
14 const NETWORKMANAGER_CONTRACTID = "@mozilla.org/network/manager;1";
15 const NETWORKMANAGER_CID =
16 Components.ID("{33901e46-33b8-11e1-9869-f46d04d25bcc}");
18 const DEFAULT_PREFERRED_NETWORK_TYPE = Ci.nsINetworkInterface.NETWORK_TYPE_WIFI;
20 XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
21 "@mozilla.org/settingsService;1",
22 "nsISettingsService");
23 XPCOMUtils.defineLazyGetter(this, "ppmm", function() {
24 return Cc["@mozilla.org/parentprocessmessagemanager;1"]
25 .getService(Ci.nsIMessageBroadcaster);
26 });
28 XPCOMUtils.defineLazyServiceGetter(this, "gDNSService",
29 "@mozilla.org/network/dns-service;1",
30 "nsIDNSService");
32 XPCOMUtils.defineLazyServiceGetter(this, "gNetworkService",
33 "@mozilla.org/network/service;1",
34 "nsINetworkService");
36 const TOPIC_INTERFACE_STATE_CHANGED = "network-interface-state-changed";
37 const TOPIC_INTERFACE_REGISTERED = "network-interface-registered";
38 const TOPIC_INTERFACE_UNREGISTERED = "network-interface-unregistered";
39 const TOPIC_ACTIVE_CHANGED = "network-active-changed";
40 const TOPIC_MOZSETTINGS_CHANGED = "mozsettings-changed";
41 const TOPIC_PREF_CHANGED = "nsPref:changed";
42 const TOPIC_XPCOM_SHUTDOWN = "xpcom-shutdown";
43 const TOPIC_CONNECTION_STATE_CHANGED = "network-connection-state-changed";
44 const PREF_MANAGE_OFFLINE_STATUS = "network.gonk.manage-offline-status";
46 const POSSIBLE_USB_INTERFACE_NAME = "rndis0,usb0";
47 const DEFAULT_USB_INTERFACE_NAME = "rndis0";
48 const DEFAULT_3G_INTERFACE_NAME = "rmnet0";
49 const DEFAULT_WIFI_INTERFACE_NAME = "wlan0";
51 // The kernel's proc entry for network lists.
52 const KERNEL_NETWORK_ENTRY = "/sys/class/net";
54 const TETHERING_TYPE_WIFI = "WiFi";
55 const TETHERING_TYPE_USB = "USB";
57 const WIFI_FIRMWARE_AP = "AP";
58 const WIFI_FIRMWARE_STATION = "STA";
59 const WIFI_SECURITY_TYPE_NONE = "open";
60 const WIFI_SECURITY_TYPE_WPA_PSK = "wpa-psk";
61 const WIFI_SECURITY_TYPE_WPA2_PSK = "wpa2-psk";
62 const WIFI_CTRL_INTERFACE = "wl0.1";
64 const NETWORK_INTERFACE_UP = "up";
65 const NETWORK_INTERFACE_DOWN = "down";
67 const TETHERING_STATE_ONGOING = "ongoing";
68 const TETHERING_STATE_IDLE = "idle";
69 const TETHERING_STATE_ACTIVE = "active";
71 // Settings DB path for USB tethering.
72 const SETTINGS_USB_ENABLED = "tethering.usb.enabled";
73 const SETTINGS_USB_IP = "tethering.usb.ip";
74 const SETTINGS_USB_PREFIX = "tethering.usb.prefix";
75 const SETTINGS_USB_DHCPSERVER_STARTIP = "tethering.usb.dhcpserver.startip";
76 const SETTINGS_USB_DHCPSERVER_ENDIP = "tethering.usb.dhcpserver.endip";
77 const SETTINGS_USB_DNS1 = "tethering.usb.dns1";
78 const SETTINGS_USB_DNS2 = "tethering.usb.dns2";
80 // Settings DB path for WIFI tethering.
81 const SETTINGS_WIFI_DHCPSERVER_STARTIP = "tethering.wifi.dhcpserver.startip";
82 const SETTINGS_WIFI_DHCPSERVER_ENDIP = "tethering.wifi.dhcpserver.endip";
84 // Settings DB patch for dun required setting.
85 const SETTINGS_DUN_REQUIRED = "tethering.dun.required";
87 // Default value for USB tethering.
88 const DEFAULT_USB_IP = "192.168.0.1";
89 const DEFAULT_USB_PREFIX = "24";
90 const DEFAULT_USB_DHCPSERVER_STARTIP = "192.168.0.10";
91 const DEFAULT_USB_DHCPSERVER_ENDIP = "192.168.0.30";
93 const DEFAULT_DNS1 = "8.8.8.8";
94 const DEFAULT_DNS2 = "8.8.4.4";
96 const DEFAULT_WIFI_DHCPSERVER_STARTIP = "192.168.1.10";
97 const DEFAULT_WIFI_DHCPSERVER_ENDIP = "192.168.1.30";
99 const IPV4_ADDRESS_ANY = "0.0.0.0";
100 const IPV6_ADDRESS_ANY = "::0";
102 const IPV4_MAX_PREFIX_LENGTH = 32;
103 const IPV6_MAX_PREFIX_LENGTH = 128;
105 const PREF_DATA_DEFAULT_SERVICE_ID = "ril.data.defaultServiceId";
106 const MOBILE_DUN_CONNECT_TIMEOUT = 30000;
107 const MOBILE_DUN_RETRY_INTERVAL = 5000;
108 const MOBILE_DUN_MAX_RETRIES = 5;
110 // Connection Type for Network Information API
111 const CONNECTION_TYPE_CULLULAR = 0;
112 const CONNECTION_TYPE_BLUETOOTH = 1;
113 const CONNECTION_TYPE_ETHERNET = 2;
114 const CONNECTION_TYPE_WIFI = 3;
115 const CONNECTION_TYPE_OTHER = 4;
116 const CONNECTION_TYPE_NONE = 5;
118 let DEBUG = false;
120 // Read debug setting from pref.
121 try {
122 let debugPref = Services.prefs.getBoolPref("network.debugging.enabled");
123 DEBUG = DEBUG || debugPref;
124 } catch (e) {}
126 function defineLazyRegExp(obj, name, pattern) {
127 obj.__defineGetter__(name, function() {
128 delete obj[name];
129 return obj[name] = new RegExp(pattern);
130 });
131 }
133 /**
134 * This component watches for network interfaces changing state and then
135 * adjusts routes etc. accordingly.
136 */
137 function NetworkManager() {
138 this.networkInterfaces = {};
139 Services.obs.addObserver(this, TOPIC_INTERFACE_STATE_CHANGED, true);
140 #ifdef MOZ_B2G_RIL
141 Services.obs.addObserver(this, TOPIC_INTERFACE_REGISTERED, true);
142 Services.obs.addObserver(this, TOPIC_INTERFACE_UNREGISTERED, true);
143 #endif
144 Services.obs.addObserver(this, TOPIC_XPCOM_SHUTDOWN, false);
145 Services.obs.addObserver(this, TOPIC_MOZSETTINGS_CHANGED, false);
147 try {
148 this._manageOfflineStatus =
149 Services.prefs.getBoolPref(PREF_MANAGE_OFFLINE_STATUS);
150 } catch(ex) {
151 // Ignore.
152 }
153 Services.prefs.addObserver(PREF_MANAGE_OFFLINE_STATUS, this, false);
155 // Possible usb tethering interfaces for different gonk platform.
156 this.possibleInterface = POSSIBLE_USB_INTERFACE_NAME.split(",");
158 // Default values for internal and external interfaces.
159 this._tetheringInterface = Object.create(null);
160 this._tetheringInterface[TETHERING_TYPE_USB] = {
161 externalInterface: DEFAULT_3G_INTERFACE_NAME,
162 internalInterface: DEFAULT_USB_INTERFACE_NAME
163 };
164 this._tetheringInterface[TETHERING_TYPE_WIFI] = {
165 externalInterface: DEFAULT_3G_INTERFACE_NAME,
166 internalInterface: DEFAULT_WIFI_INTERFACE_NAME
167 };
169 this.initTetheringSettings();
171 let settingsLock = gSettingsService.createLock();
172 // Read usb tethering data from settings DB.
173 settingsLock.get(SETTINGS_USB_IP, this);
174 settingsLock.get(SETTINGS_USB_PREFIX, this);
175 settingsLock.get(SETTINGS_USB_DHCPSERVER_STARTIP, this);
176 settingsLock.get(SETTINGS_USB_DHCPSERVER_ENDIP, this);
177 settingsLock.get(SETTINGS_USB_DNS1, this);
178 settingsLock.get(SETTINGS_USB_DNS2, this);
179 settingsLock.get(SETTINGS_USB_ENABLED, this);
181 // Read wifi tethering data from settings DB.
182 settingsLock.get(SETTINGS_WIFI_DHCPSERVER_STARTIP, this);
183 settingsLock.get(SETTINGS_WIFI_DHCPSERVER_ENDIP, this);
185 this._usbTetheringSettingsToRead = [SETTINGS_USB_IP,
186 SETTINGS_USB_PREFIX,
187 SETTINGS_USB_DHCPSERVER_STARTIP,
188 SETTINGS_USB_DHCPSERVER_ENDIP,
189 SETTINGS_USB_DNS1,
190 SETTINGS_USB_DNS2,
191 SETTINGS_USB_ENABLED,
192 SETTINGS_WIFI_DHCPSERVER_STARTIP,
193 SETTINGS_WIFI_DHCPSERVER_ENDIP];
195 this.wantConnectionEvent = null;
196 this.setAndConfigureActive();
198 ppmm.addMessageListener('NetworkInterfaceList:ListInterface', this);
200 // Used in resolveHostname().
201 defineLazyRegExp(this, "REGEXP_IPV4", "^\\d{1,3}(?:\\.\\d{1,3}){3}$");
202 defineLazyRegExp(this, "REGEXP_IPV6", "^[\\da-fA-F]{4}(?::[\\da-fA-F]{4}){7}$");
203 }
204 NetworkManager.prototype = {
205 classID: NETWORKMANAGER_CID,
206 classInfo: XPCOMUtils.generateCI({classID: NETWORKMANAGER_CID,
207 contractID: NETWORKMANAGER_CONTRACTID,
208 classDescription: "Network Manager",
209 interfaces: [Ci.nsINetworkManager]}),
210 QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkManager,
211 Ci.nsISupportsWeakReference,
212 Ci.nsIObserver,
213 Ci.nsISettingsServiceCallback]),
215 // nsIObserver
217 observe: function(subject, topic, data) {
218 switch (topic) {
219 case TOPIC_INTERFACE_STATE_CHANGED:
220 let network = subject.QueryInterface(Ci.nsINetworkInterface);
221 debug("Network " + network.name + " changed state to " + network.state);
222 switch (network.state) {
223 case Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED:
224 #ifdef MOZ_B2G_RIL
225 // Add host route for data calls
226 if (this.isNetworkTypeMobile(network.type)) {
227 gNetworkService.removeHostRoutes(network.name);
228 gNetworkService.addHostRoute(network);
229 }
230 // Add extra host route. For example, mms proxy or mmsc.
231 this.setExtraHostRoute(network);
232 // Dun type is a special case where we add the default route to a
233 // secondary table.
234 if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN) {
235 this.setSecondaryDefaultRoute(network);
236 }
237 #endif
238 // Remove pre-created default route and let setAndConfigureActive()
239 // to set default route only on preferred network
240 gNetworkService.removeDefaultRoute(network);
241 this.setAndConfigureActive();
242 #ifdef MOZ_B2G_RIL
243 // Update data connection when Wifi connected/disconnected
244 if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
245 for (let i = 0; i < this.mRil.numRadioInterfaces; i++) {
246 this.mRil.getRadioInterface(i).updateRILNetworkInterface();
247 }
248 }
249 #endif
251 this.onConnectionChanged(network);
253 // Probing the public network accessibility after routing table is ready
254 CaptivePortalDetectionHelper
255 .notify(CaptivePortalDetectionHelper.EVENT_CONNECT, this.active);
256 break;
257 case Ci.nsINetworkInterface.NETWORK_STATE_DISCONNECTED:
258 #ifdef MOZ_B2G_RIL
259 // Remove host route for data calls
260 if (this.isNetworkTypeMobile(network.type)) {
261 gNetworkService.removeHostRoute(network);
262 }
263 // Remove extra host route. For example, mms proxy or mmsc.
264 this.removeExtraHostRoute(network);
265 // Remove secondary default route for dun.
266 if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN) {
267 this.removeSecondaryDefaultRoute(network);
268 }
269 #endif
270 // Remove routing table in /proc/net/route
271 if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
272 gNetworkService.resetRoutingTable(network);
273 #ifdef MOZ_B2G_RIL
274 } else if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE) {
275 gNetworkService.removeDefaultRoute(network);
276 #endif
277 }
279 // Abort ongoing captive portal detection on the wifi interface
280 CaptivePortalDetectionHelper
281 .notify(CaptivePortalDetectionHelper.EVENT_DISCONNECT, network);
282 this.setAndConfigureActive();
283 #ifdef MOZ_B2G_RIL
284 // Update data connection when Wifi connected/disconnected
285 if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
286 for (let i = 0; i < this.mRil.numRadioInterfaces; i++) {
287 this.mRil.getRadioInterface(i).updateRILNetworkInterface();
288 }
289 }
290 #endif
291 break;
292 }
293 #ifdef MOZ_B2G_RIL
294 // Notify outer modules like MmsService to start the transaction after
295 // the configuration of the network interface is done.
296 Services.obs.notifyObservers(network, TOPIC_CONNECTION_STATE_CHANGED,
297 this.convertConnectionType(network));
298 #endif
299 break;
300 #ifdef MOZ_B2G_RIL
301 case TOPIC_INTERFACE_REGISTERED:
302 let regNetwork = subject.QueryInterface(Ci.nsINetworkInterface);
303 // Add extra host route. For example, mms proxy or mmsc.
304 this.setExtraHostRoute(regNetwork);
305 // Dun type is a special case where we add the default route to a
306 // secondary table.
307 if (regNetwork.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN) {
308 this.setSecondaryDefaultRoute(regNetwork);
309 }
310 break;
311 case TOPIC_INTERFACE_UNREGISTERED:
312 let unregNetwork = subject.QueryInterface(Ci.nsINetworkInterface);
313 // Remove extra host route. For example, mms proxy or mmsc.
314 this.removeExtraHostRoute(unregNetwork);
315 // Remove secondary default route for dun.
316 if (unregNetwork.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN) {
317 this.removeSecondaryDefaultRoute(unregNetwork);
318 }
319 break;
320 #endif
321 case TOPIC_MOZSETTINGS_CHANGED:
322 let setting = JSON.parse(data);
323 this.handle(setting.key, setting.value);
324 break;
325 case TOPIC_PREF_CHANGED:
326 this._manageOfflineStatus =
327 Services.prefs.getBoolPref(PREF_MANAGE_OFFLINE_STATUS);
328 debug(PREF_MANAGE_OFFLINE_STATUS + " has changed to " + this._manageOfflineStatus);
329 break;
330 case TOPIC_XPCOM_SHUTDOWN:
331 Services.obs.removeObserver(this, TOPIC_XPCOM_SHUTDOWN);
332 Services.obs.removeObserver(this, TOPIC_MOZSETTINGS_CHANGED);
333 #ifdef MOZ_B2G_RIL
334 Services.obs.removeObserver(this, TOPIC_INTERFACE_REGISTERED);
335 Services.obs.removeObserver(this, TOPIC_INTERFACE_UNREGISTERED);
336 #endif
337 Services.obs.removeObserver(this, TOPIC_INTERFACE_STATE_CHANGED);
338 #ifdef MOZ_B2G_RIL
339 this.dunConnectTimer.cancel();
340 this.dunRetryTimer.cancel();
341 #endif
342 break;
343 }
344 },
346 receiveMessage: function(aMsg) {
347 switch (aMsg.name) {
348 case "NetworkInterfaceList:ListInterface": {
349 #ifdef MOZ_B2G_RIL
350 let excludeMms = aMsg.json.excludeMms;
351 let excludeSupl = aMsg.json.excludeSupl;
352 let excludeIms = aMsg.json.excludeIms;
353 let excludeDun = aMsg.json.excludeDun;
354 #endif
355 let interfaces = [];
357 for each (let i in this.networkInterfaces) {
358 #ifdef MOZ_B2G_RIL
359 if ((i.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS && excludeMms) ||
360 (i.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_SUPL && excludeSupl) ||
361 (i.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_IMS && excludeIms) ||
362 (i.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN && excludeDun)) {
363 continue;
364 }
365 #endif
366 let ips = {};
367 let prefixLengths = {};
368 i.getAddresses(ips, prefixLengths);
370 interfaces.push({
371 state: i.state,
372 type: i.type,
373 name: i.name,
374 ips: ips.value,
375 prefixLengths: prefixLengths.value,
376 gateways: i.getGateways(),
377 dnses: i.getDnses(),
378 httpProxyHost: i.httpProxyHost,
379 httpProxyPort: i.httpProxyPort
380 });
381 }
382 return interfaces;
383 }
384 }
385 },
387 // nsINetworkManager
389 registerNetworkInterface: function(network) {
390 if (!(network instanceof Ci.nsINetworkInterface)) {
391 throw Components.Exception("Argument must be nsINetworkInterface.",
392 Cr.NS_ERROR_INVALID_ARG);
393 }
394 if (network.name in this.networkInterfaces) {
395 throw Components.Exception("Network with that name already registered!",
396 Cr.NS_ERROR_INVALID_ARG);
397 }
398 this.networkInterfaces[network.name] = network;
399 #ifdef MOZ_B2G_RIL
400 // Add host route for data calls
401 if (this.isNetworkTypeMobile(network.type)) {
402 gNetworkService.addHostRoute(network);
403 }
404 #endif
405 // Remove pre-created default route and let setAndConfigureActive()
406 // to set default route only on preferred network
407 gNetworkService.removeDefaultRoute(network);
408 this.setAndConfigureActive();
409 Services.obs.notifyObservers(network, TOPIC_INTERFACE_REGISTERED, null);
410 debug("Network '" + network.name + "' registered.");
411 },
413 unregisterNetworkInterface: function(network) {
414 if (!(network instanceof Ci.nsINetworkInterface)) {
415 throw Components.Exception("Argument must be nsINetworkInterface.",
416 Cr.NS_ERROR_INVALID_ARG);
417 }
418 if (!(network.name in this.networkInterfaces)) {
419 throw Components.Exception("No network with that name registered.",
420 Cr.NS_ERROR_INVALID_ARG);
421 }
422 delete this.networkInterfaces[network.name];
423 #ifdef MOZ_B2G_RIL
424 // Remove host route for data calls
425 if (this.isNetworkTypeMobile(network.type)) {
426 gNetworkService.removeHostRoute(network);
427 }
428 #endif
429 this.setAndConfigureActive();
430 Services.obs.notifyObservers(network, TOPIC_INTERFACE_UNREGISTERED, null);
431 debug("Network '" + network.name + "' unregistered.");
432 },
434 _manageOfflineStatus: true,
436 networkInterfaces: null,
438 _preferredNetworkType: DEFAULT_PREFERRED_NETWORK_TYPE,
439 get preferredNetworkType() {
440 return this._preferredNetworkType;
441 },
442 set preferredNetworkType(val) {
443 #ifdef MOZ_B2G_RIL
444 if ([Ci.nsINetworkInterface.NETWORK_TYPE_WIFI,
445 Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE].indexOf(val) == -1) {
446 #else
447 if (val != Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
448 #endif
449 throw "Invalid network type";
450 }
451 this._preferredNetworkType = val;
452 },
454 active: null,
455 _overriddenActive: null,
457 overrideActive: function(network) {
458 #ifdef MOZ_B2G_RIL
459 if (this.isNetworkTypeSecondaryMobile(network.type)) {
460 throw "Invalid network type";
461 }
462 #endif
463 this._overriddenActive = network;
464 this.setAndConfigureActive();
465 },
467 #ifdef MOZ_B2G_RIL
468 isNetworkTypeSecondaryMobile: function(type) {
469 return (type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS ||
470 type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_SUPL ||
471 type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_IMS ||
472 type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN);
473 },
475 isNetworkTypeMobile: function(type) {
476 return (type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE ||
477 this.isNetworkTypeSecondaryMobile(type));
478 },
480 setExtraHostRoute: function(network) {
481 if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS) {
482 if (!(network instanceof Ci.nsIRilNetworkInterface)) {
483 debug("Network for MMS must be an instance of nsIRilNetworkInterface");
484 return;
485 }
487 network = network.QueryInterface(Ci.nsIRilNetworkInterface);
489 debug("Network '" + network.name + "' registered, " +
490 "adding mmsproxy and/or mmsc route");
492 let hostToResolve = network.mmsProxy;
493 // Workaround an xpconnect issue with undefined string objects.
494 // See bug 808220
495 if (!hostToResolve || hostToResolve === "undefined") {
496 hostToResolve = network.mmsc;
497 }
499 let mmsHosts = this.resolveHostname([hostToResolve]);
500 if (mmsHosts.length == 0) {
501 debug("No valid hostnames can be added. Stop adding host route.");
502 return;
503 }
505 gNetworkService.addHostRouteWithResolve(network, mmsHosts);
506 }
507 },
509 removeExtraHostRoute: function(network) {
510 if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS) {
511 if (!(network instanceof Ci.nsIRilNetworkInterface)) {
512 debug("Network for MMS must be an instance of nsIRilNetworkInterface");
513 return;
514 }
516 network = network.QueryInterface(Ci.nsIRilNetworkInterface);
518 debug("Network '" + network.name + "' unregistered, " +
519 "removing mmsproxy and/or mmsc route");
521 let hostToResolve = network.mmsProxy;
522 // Workaround an xpconnect issue with undefined string objects.
523 // See bug 808220
524 if (!hostToResolve || hostToResolve === "undefined") {
525 hostToResolve = network.mmsc;
526 }
528 let mmsHosts = this.resolveHostname([hostToResolve]);
529 if (mmsHosts.length == 0) {
530 debug("No valid hostnames can be removed. Stop removing host route.");
531 return;
532 }
534 gNetworkService.removeHostRouteWithResolve(network, mmsHosts);
535 }
536 },
538 setSecondaryDefaultRoute: function(network) {
539 let gateways = network.getGateways();
540 for (let i = 0; i < gateways.length; i++) {
541 let isIPv6 = (gateways[i].indexOf(":") != -1) ? true : false;
542 // First, we need to add a host route to the gateway in the secondary
543 // routing table to make the gateway reachable. Host route takes the max
544 // prefix and gateway address 'any'.
545 let route = {
546 ip: gateways[i],
547 prefix: isIPv6 ? IPV6_MAX_PREFIX_LENGTH : IPV4_MAX_PREFIX_LENGTH,
548 gateway: isIPv6 ? IPV6_ADDRESS_ANY : IPV4_ADDRESS_ANY
549 };
550 gNetworkService.addSecondaryRoute(network.name, route);
551 // Now we can add the default route through gateway. Default route takes the
552 // min prefix and destination ip 'any'.
553 route.ip = isIPv6 ? IPV6_ADDRESS_ANY : IPV4_ADDRESS_ANY;
554 route.prefix = 0;
555 route.gateway = gateways[i];
556 gNetworkService.addSecondaryRoute(network.name, route);
557 }
558 },
560 removeSecondaryDefaultRoute: function(network) {
561 let gateways = network.getGateways();
562 for (let i = 0; i < gateways.length; i++) {
563 let isIPv6 = (gateways[i].indexOf(":") != -1) ? true : false;
564 // Remove both default route and host route.
565 let route = {
566 ip: isIPv6 ? IPV6_ADDRESS_ANY : IPV4_ADDRESS_ANY,
567 prefix: 0,
568 gateway: gateways[i]
569 };
570 gNetworkService.removeSecondaryRoute(network.name, route);
572 route.ip = gateways[i];
573 route.prefix = isIPv6 ? IPV6_MAX_PREFIX_LENGTH : IPV4_MAX_PREFIX_LENGTH;
574 route.gateway = isIPv6 ? IPV6_ADDRESS_ANY : IPV4_ADDRESS_ANY;
575 gNetworkService.removeSecondaryRoute(network.name, route);
576 }
577 },
578 #endif // MOZ_B2G_RIL
580 /**
581 * Determine the active interface and configure it.
582 */
583 setAndConfigureActive: function() {
584 debug("Evaluating whether active network needs to be changed.");
585 let oldActive = this.active;
587 if (this._overriddenActive) {
588 debug("We have an override for the active network: " +
589 this._overriddenActive.name);
590 // The override was just set, so reconfigure the network.
591 if (this.active != this._overriddenActive) {
592 this.active = this._overriddenActive;
593 gNetworkService.setDefaultRouteAndDNS(this.active, oldActive);
594 Services.obs.notifyObservers(this.active, TOPIC_ACTIVE_CHANGED, null);
595 }
596 return;
597 }
599 // The active network is already our preferred type.
600 if (this.active &&
601 this.active.state == Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED &&
602 this.active.type == this._preferredNetworkType) {
603 debug("Active network is already our preferred type.");
604 gNetworkService.setDefaultRouteAndDNS(this.active, oldActive);
605 return;
606 }
608 // Find a suitable network interface to activate.
609 this.active = null;
610 #ifdef MOZ_B2G_RIL
611 let defaultDataNetwork;
612 #endif
613 for each (let network in this.networkInterfaces) {
614 if (network.state != Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED) {
615 continue;
616 }
617 #ifdef MOZ_B2G_RIL
618 if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE) {
619 defaultDataNetwork = network;
620 }
621 #endif
622 this.active = network;
623 if (network.type == this.preferredNetworkType) {
624 debug("Found our preferred type of network: " + network.name);
625 break;
626 }
627 }
628 if (this.active) {
629 #ifdef MOZ_B2G_RIL
630 // Give higher priority to default data APN than seconary APN.
631 // If default data APN is not connected, we still set default route
632 // and DNS on seconary APN.
633 if (defaultDataNetwork &&
634 this.isNetworkTypeSecondaryMobile(this.active.type) &&
635 this.active.type != this.preferredNetworkType) {
636 this.active = defaultDataNetwork;
637 }
638 // Don't set default route on secondary APN
639 if (this.isNetworkTypeSecondaryMobile(this.active.type)) {
640 gNetworkService.setDNS(this.active);
641 } else {
642 #endif // MOZ_B2G_RIL
643 gNetworkService.setDefaultRouteAndDNS(this.active, oldActive);
644 #ifdef MOZ_B2G_RIL
645 }
646 #endif
647 }
649 if (this.active != oldActive) {
650 Services.obs.notifyObservers(this.active, TOPIC_ACTIVE_CHANGED, null);
651 }
653 if (this._manageOfflineStatus) {
654 Services.io.offline = !this.active;
655 }
656 },
658 #ifdef MOZ_B2G_RIL
659 resolveHostname: function(hosts) {
660 let retval = [];
662 for (let hostname of hosts) {
663 // Sanity check for null, undefined and empty string... etc.
664 if (!hostname) {
665 continue;
666 }
668 try {
669 let uri = Services.io.newURI(hostname, null, null);
670 hostname = uri.host;
671 } catch (e) {}
673 // An extra check for hostnames that cannot be made by newURI(...).
674 // For example, an IP address like "10.1.1.1".
675 if (hostname.match(this.REGEXP_IPV4) ||
676 hostname.match(this.REGEXP_IPV6)) {
677 retval.push(hostname);
678 continue;
679 }
681 try {
682 let hostnameIps = gDNSService.resolve(hostname, 0);
683 while (hostnameIps.hasMore()) {
684 retval.push(hostnameIps.getNextAddrAsString());
685 debug("Found IP at: " + JSON.stringify(retval));
686 }
687 } catch (e) {}
688 }
690 return retval;
691 },
692 #endif
694 convertConnectionType: function(network) {
695 // If there is internal interface change (e.g., MOBILE_MMS, MOBILE_SUPL),
696 // the function will return null so that it won't trigger type change event
697 // in NetworkInformation API.
698 if (network.type != Ci.nsINetworkInterface.NETWORK_TYPE_WIFI &&
699 network.type != Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE) {
700 return null;
701 }
703 if (network.state == Ci.nsINetworkInterface.NETWORK_STATE_DISCONNECTED) {
704 return CONNECTION_TYPE_NONE;
705 }
707 switch (network.type) {
708 case Ci.nsINetworkInterface.NETWORK_TYPE_WIFI:
709 return CONNECTION_TYPE_WIFI;
710 case Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE:
711 return CONNECTION_TYPE_CULLULAR;
712 }
713 },
715 // nsISettingsServiceCallback
717 tetheringSettings: {},
719 initTetheringSettings: function() {
720 this.tetheringSettings[SETTINGS_USB_ENABLED] = false;
721 this.tetheringSettings[SETTINGS_USB_IP] = DEFAULT_USB_IP;
722 this.tetheringSettings[SETTINGS_USB_PREFIX] = DEFAULT_USB_PREFIX;
723 this.tetheringSettings[SETTINGS_USB_DHCPSERVER_STARTIP] = DEFAULT_USB_DHCPSERVER_STARTIP;
724 this.tetheringSettings[SETTINGS_USB_DHCPSERVER_ENDIP] = DEFAULT_USB_DHCPSERVER_ENDIP;
725 this.tetheringSettings[SETTINGS_USB_DNS1] = DEFAULT_DNS1;
726 this.tetheringSettings[SETTINGS_USB_DNS2] = DEFAULT_DNS2;
728 this.tetheringSettings[SETTINGS_WIFI_DHCPSERVER_STARTIP] = DEFAULT_WIFI_DHCPSERVER_STARTIP;
729 this.tetheringSettings[SETTINGS_WIFI_DHCPSERVER_ENDIP] = DEFAULT_WIFI_DHCPSERVER_ENDIP;
731 #ifdef MOZ_B2G_RIL
732 this.tetheringSettings[SETTINGS_DUN_REQUIRED] =
733 libcutils.property_get("ro.tethering.dun_required") === "1";
734 #endif
735 },
737 _requestCount: 0,
739 handle: function(aName, aResult) {
740 switch(aName) {
741 case SETTINGS_USB_ENABLED:
742 this._oldUsbTetheringEnabledState = this.tetheringSettings[SETTINGS_USB_ENABLED];
743 case SETTINGS_USB_IP:
744 case SETTINGS_USB_PREFIX:
745 case SETTINGS_USB_DHCPSERVER_STARTIP:
746 case SETTINGS_USB_DHCPSERVER_ENDIP:
747 case SETTINGS_USB_DNS1:
748 case SETTINGS_USB_DNS2:
749 case SETTINGS_WIFI_DHCPSERVER_STARTIP:
750 case SETTINGS_WIFI_DHCPSERVER_ENDIP:
751 if (aResult !== null) {
752 this.tetheringSettings[aName] = aResult;
753 }
754 debug("'" + aName + "'" + " is now " + this.tetheringSettings[aName]);
755 let index = this._usbTetheringSettingsToRead.indexOf(aName);
757 if (index != -1) {
758 this._usbTetheringSettingsToRead.splice(index, 1);
759 }
761 if (this._usbTetheringSettingsToRead.length) {
762 debug("We haven't read completely the usb Tethering data from settings db.");
763 break;
764 }
766 if (this._oldUsbTetheringEnabledState === this.tetheringSettings[SETTINGS_USB_ENABLED]) {
767 debug("No changes for SETTINGS_USB_ENABLED flag. Nothing to do.");
768 break;
769 }
771 this._requestCount++;
772 if (this._requestCount === 1) {
773 this.handleUSBTetheringToggle(aResult);
774 }
775 break;
776 };
777 },
779 handleError: function(aErrorMessage) {
780 debug("There was an error while reading Tethering settings.");
781 this.tetheringSettings = {};
782 this.tetheringSettings[SETTINGS_USB_ENABLED] = false;
783 },
785 getNetworkInterface: function(type) {
786 for each (let network in this.networkInterfaces) {
787 if (network.type == type) {
788 return network;
789 }
790 }
791 return null;
792 },
794 _usbTetheringAction: TETHERING_STATE_IDLE,
796 _usbTetheringSettingsToRead: [],
798 _oldUsbTetheringEnabledState: null,
800 // External and internal interface name.
801 _tetheringInterface: null,
803 handleLastRequest: function() {
804 let count = this._requestCount;
805 this._requestCount = 0;
807 if (count === 1) {
808 if (this.wantConnectionEvent) {
809 if (this.tetheringSettings[SETTINGS_USB_ENABLED]) {
810 this.wantConnectionEvent.call(this);
811 }
812 this.wantConnectionEvent = null;
813 }
814 return;
815 }
817 if (count > 1) {
818 this.handleUSBTetheringToggle(this.tetheringSettings[SETTINGS_USB_ENABLED]);
819 this.wantConnectionEvent = null;
820 }
821 },
823 #ifdef MOZ_B2G_RIL
824 dunConnectTimer: Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer),
825 /**
826 * Callback when dun connection fails to connect within timeout.
827 */
828 onDunConnectTimerTimeout: function() {
829 while (this._pendingTetheringRequests.length > 0) {
830 debug("onDunConnectTimerTimeout: callback without network info.");
831 let callback = this._pendingTetheringRequests.shift();
832 if (typeof callback === 'function') {
833 callback();
834 }
835 }
836 },
838 dunRetryTimes: 0,
839 dunRetryTimer: Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer),
840 setupDunConnection: function() {
841 this.dunRetryTimer.cancel();
842 let ril = this.mRil.getRadioInterface(this.gDataDefaultServiceId);
844 if (ril.rilContext && ril.rilContext.data &&
845 ril.rilContext.data.state === "registered") {
846 this.dunRetryTimes = 0;
847 ril.setupDataCallByType("dun");
848 this.dunConnectTimer.cancel();
849 this.dunConnectTimer.
850 initWithCallback(this.onDunConnectTimerTimeout.bind(this),
851 MOBILE_DUN_CONNECT_TIMEOUT, Ci.nsITimer.TYPE_ONE_SHOT);
852 return;
853 }
855 if (this.dunRetryTimes++ >= this.MOBILE_DUN_MAX_RETRIES) {
856 debug("setupDunConnection: max retries reached.");
857 this.dunRetryTimes = 0;
858 // same as dun connect timeout.
859 this.onDunConnectTimerTimeout();
860 return;
861 }
863 debug("Data not ready, retry dun after " + MOBILE_DUN_RETRY_INTERVAL + " ms.");
864 this.dunRetryTimer.
865 initWithCallback(this.setupDunConnection.bind(this),
866 MOBILE_DUN_RETRY_INTERVAL, Ci.nsITimer.TYPE_ONE_SHOT);
867 },
869 _pendingTetheringRequests: [],
870 _dunActiveUsers: 0,
871 handleDunConnection: function(enable, callback) {
872 debug("handleDunConnection: " + enable);
873 let dun = this.getNetworkInterface(
874 Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN);
876 if (!enable) {
877 this._dunActiveUsers--;
878 if (this._dunActiveUsers > 0) {
879 debug("Dun still needed by others, do not disconnect.")
880 return;
881 }
883 this.dunRetryTimes = 0;
884 this.dunRetryTimer.cancel();
885 this.dunConnectTimer.cancel();
886 this._pendingTetheringRequests = [];
888 if (dun && (dun.state == Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED)) {
889 this.mRil.getRadioInterface(this.gDataDefaultServiceId)
890 .deactivateDataCallByType("dun");
891 }
892 return;
893 }
895 this._dunActiveUsers++;
896 if (!dun || (dun.state != Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED)) {
897 debug("DUN data call inactive, setup dun data call!")
898 this._pendingTetheringRequests.push(callback);
899 this.dunRetryTimes = 0;
900 this.setupDunConnection();
902 return;
903 }
904 this._tetheringInterface[TETHERING_TYPE_USB].externalInterface = dun.name;
905 callback(dun);
906 },
907 #endif
909 handleUSBTetheringToggle: function(enable) {
910 debug("handleUSBTetheringToggle: " + enable);
911 if (enable &&
912 (this._usbTetheringAction === TETHERING_STATE_ONGOING ||
913 this._usbTetheringAction === TETHERING_STATE_ACTIVE)) {
914 debug("Usb tethering already connecting/connected.");
915 return;
916 }
918 if (!enable &&
919 this._usbTetheringAction === TETHERING_STATE_IDLE) {
920 debug("Usb tethering already disconnected.");
921 return;
922 }
924 if (!enable) {
925 this.tetheringSettings[SETTINGS_USB_ENABLED] = false;
926 gNetworkService.enableUsbRndis(false, this.enableUsbRndisResult.bind(this));
927 return;
928 }
930 this.tetheringSettings[SETTINGS_USB_ENABLED] = true;
931 this._usbTetheringAction = TETHERING_STATE_ONGOING;
933 #ifdef MOZ_B2G_RIL
934 if (this.tetheringSettings[SETTINGS_DUN_REQUIRED]) {
935 this.handleDunConnection(true, function(network) {
936 if (!network){
937 this.usbTetheringResultReport("Dun connection failed");
938 return;
939 }
940 this._tetheringInterface[TETHERING_TYPE_USB].externalInterface = network.name;
941 gNetworkService.enableUsbRndis(true, this.enableUsbRndisResult.bind(this));
942 }.bind(this));
943 return;
944 }
945 #endif
947 if (this.active) {
948 this._tetheringInterface[TETHERING_TYPE_USB].externalInterface = this.active.name;
949 } else {
950 let mobile = this.getNetworkInterface(Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE);
951 if (mobile) {
952 this._tetheringInterface[TETHERING_TYPE_USB].externalInterface = mobile.name;
953 }
954 }
955 gNetworkService.enableUsbRndis(true, this.enableUsbRndisResult.bind(this));
956 },
958 getUSBTetheringParameters: function(enable, tetheringinterface) {
959 let interfaceIp;
960 let prefix;
961 let wifiDhcpStartIp;
962 let wifiDhcpEndIp;
963 let usbDhcpStartIp;
964 let usbDhcpEndIp;
965 let dns1;
966 let dns2;
967 let internalInterface = tetheringinterface.internalInterface;
968 let externalInterface = tetheringinterface.externalInterface;
970 interfaceIp = this.tetheringSettings[SETTINGS_USB_IP];
971 prefix = this.tetheringSettings[SETTINGS_USB_PREFIX];
972 wifiDhcpStartIp = this.tetheringSettings[SETTINGS_WIFI_DHCPSERVER_STARTIP];
973 wifiDhcpEndIp = this.tetheringSettings[SETTINGS_WIFI_DHCPSERVER_ENDIP];
974 usbDhcpStartIp = this.tetheringSettings[SETTINGS_USB_DHCPSERVER_STARTIP];
975 usbDhcpEndIp = this.tetheringSettings[SETTINGS_USB_DHCPSERVER_ENDIP];
976 dns1 = this.tetheringSettings[SETTINGS_USB_DNS1];
977 dns2 = this.tetheringSettings[SETTINGS_USB_DNS2];
979 // Using the default values here until application support these settings.
980 if (interfaceIp == "" || prefix == "" ||
981 wifiDhcpStartIp == "" || wifiDhcpEndIp == "" ||
982 usbDhcpStartIp == "" || usbDhcpEndIp == "") {
983 debug("Invalid subnet information.");
984 return null;
985 }
987 return {
988 ifname: internalInterface,
989 ip: interfaceIp,
990 prefix: prefix,
991 wifiStartIp: wifiDhcpStartIp,
992 wifiEndIp: wifiDhcpEndIp,
993 usbStartIp: usbDhcpStartIp,
994 usbEndIp: usbDhcpEndIp,
995 dns1: dns1,
996 dns2: dns2,
997 internalIfname: internalInterface,
998 externalIfname: externalInterface,
999 enable: enable,
1000 link: enable ? NETWORK_INTERFACE_UP : NETWORK_INTERFACE_DOWN
1001 };
1002 },
1004 notifyError: function(resetSettings, callback, msg) {
1005 if (resetSettings) {
1006 let settingsLock = gSettingsService.createLock();
1007 // Disable wifi tethering with a useful error message for the user.
1008 settingsLock.set("tethering.wifi.enabled", false, null, msg);
1009 }
1011 debug("setWifiTethering: " + (msg ? msg : "success"));
1013 if (callback) {
1014 callback.wifiTetheringEnabledChange(msg);
1015 }
1016 },
1018 enableWifiTethering: function(enable, config, callback) {
1019 // Fill in config's required fields.
1020 config.ifname = this._tetheringInterface[TETHERING_TYPE_WIFI].internalInterface;
1021 config.internalIfname = this._tetheringInterface[TETHERING_TYPE_WIFI].internalInterface;
1022 config.externalIfname = this._tetheringInterface[TETHERING_TYPE_WIFI].externalInterface;
1024 gNetworkService.setWifiTethering(enable, config, (function(error) {
1025 #ifdef MOZ_B2G_RIL
1026 // Disconnect dun on error or when wifi tethering is disabled.
1027 if (this.tetheringSettings[SETTINGS_DUN_REQUIRED] &&
1028 (!enable || error)) {
1029 this.handleDunConnection(false);
1030 }
1031 #endif
1032 let resetSettings = error;
1033 this.notifyError(resetSettings, callback, error);
1034 }).bind(this));
1035 },
1037 // Enable/disable WiFi tethering by sending commands to netd.
1038 setWifiTethering: function(enable, network, config, callback) {
1039 debug("setWifiTethering: " + enable);
1040 if (!network) {
1041 this.notifyError(true, callback, "invalid network information");
1042 return;
1043 }
1045 if (!config) {
1046 this.notifyError(true, callback, "invalid configuration");
1047 return;
1048 }
1050 if (!enable) {
1051 this.enableWifiTethering(false, config, callback);
1052 return;
1053 }
1055 this._tetheringInterface[TETHERING_TYPE_WIFI].internalInterface = network.name;
1057 #ifdef MOZ_B2G_RIL
1058 if (this.tetheringSettings[SETTINGS_DUN_REQUIRED]) {
1059 this.handleDunConnection(true, function(config, callback, network) {
1060 if (!network) {
1061 this.notifyError(true, callback, "Dun connection failed");
1062 return;
1063 }
1064 this._tetheringInterface[TETHERING_TYPE_WIFI].externalInterface = network.name;
1065 this.enableWifiTethering(true, config, callback);
1066 }.bind(this, config, callback));
1067 return;
1068 }
1069 #endif
1071 let mobile = this.getNetworkInterface(Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE);
1072 // Update the real interface name
1073 if (mobile) {
1074 this._tetheringInterface[TETHERING_TYPE_WIFI].externalInterface = mobile.name;
1075 }
1077 this.enableWifiTethering(true, config, callback);
1078 },
1080 // Enable/disable USB tethering by sending commands to netd.
1081 setUSBTethering: function(enable, tetheringInterface, callback) {
1082 let params = this.getUSBTetheringParameters(enable, tetheringInterface);
1084 if (params === null) {
1085 gNetworkService.enableUsbRndis(false, function() {
1086 this.usbTetheringResultReport("Invalid parameters");
1087 });
1088 return;
1089 }
1091 gNetworkService.setUSBTethering(enable, params, callback);
1092 },
1094 getUsbInterface: function() {
1095 // Find the rndis interface.
1096 for (let i = 0; i < this.possibleInterface.length; i++) {
1097 try {
1098 let file = new FileUtils.File(KERNEL_NETWORK_ENTRY + "/" +
1099 this.possibleInterface[i]);
1100 if (file.exists()) {
1101 return this.possibleInterface[i];
1102 }
1103 } catch (e) {
1104 debug("Not " + this.possibleInterface[i] + " interface.");
1105 }
1106 }
1107 debug("Can't find rndis interface in possible lists.");
1108 return DEFAULT_USB_INTERFACE_NAME;
1109 },
1111 enableUsbRndisResult: function(success, enable) {
1112 if (success) {
1113 // If enable is false, don't find usb interface cause it is already down,
1114 // just use the internal interface in settings.
1115 if (enable) {
1116 this._tetheringInterface[TETHERING_TYPE_USB].internalInterface = this.getUsbInterface();
1117 }
1118 this.setUSBTethering(enable,
1119 this._tetheringInterface[TETHERING_TYPE_USB],
1120 this.usbTetheringResultReport.bind(this));
1121 } else {
1122 this.usbTetheringResultReport("Failed to set usb function");
1123 throw new Error("failed to set USB Function to adb");
1124 }
1125 },
1127 usbTetheringResultReport: function(error) {
1128 let settingsLock = gSettingsService.createLock();
1130 // Disable tethering settings when fail to enable it.
1131 if (error) {
1132 this.tetheringSettings[SETTINGS_USB_ENABLED] = false;
1133 settingsLock.set("tethering.usb.enabled", false, null);
1134 // Skip others request when we found an error.
1135 this._requestCount = 0;
1136 this._usbTetheringAction = TETHERING_STATE_IDLE;
1137 #ifdef MOZ_B2G_RIL
1138 if (this.tetheringSettings[SETTINGS_DUN_REQUIRED]) {
1139 this.handleDunConnection(false);
1140 }
1141 #endif
1142 } else {
1143 if (this.tetheringSettings[SETTINGS_USB_ENABLED]) {
1144 this._usbTetheringAction = TETHERING_STATE_ACTIVE;
1145 } else {
1146 this._usbTetheringAction = TETHERING_STATE_IDLE;
1147 #ifdef MOZ_B2G_RIL
1148 if (this.tetheringSettings[SETTINGS_DUN_REQUIRED]) {
1149 this.handleDunConnection(false);
1150 }
1151 #endif
1152 }
1153 this.handleLastRequest();
1154 }
1155 },
1157 onConnectionChangedReport: function(success, externalIfname) {
1158 debug("onConnectionChangedReport result: success " + success);
1160 if (success) {
1161 // Update the external interface.
1162 this._tetheringInterface[TETHERING_TYPE_USB].externalInterface = externalIfname;
1163 debug("Change the interface name to " + externalIfname);
1164 }
1165 },
1167 onConnectionChanged: function(network) {
1168 if (network.state != Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED) {
1169 debug("We are only interested in CONNECTED event");
1170 return;
1171 }
1173 #ifdef MOZ_B2G_RIL
1174 // We can not use network.type only to check if it's dun, cause if it is
1175 // shared with default, the returned type would always be default, see bug
1176 // 939046. In most cases, if dun is required, it should not be shared with
1177 // default.
1178 if (this.tetheringSettings[SETTINGS_DUN_REQUIRED] &&
1179 (network.type === Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN ||
1180 this.mRil.getRadioInterface(this.gDataDefaultServiceId)
1181 .getDataCallStateByType("dun") ===
1182 Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED)) {
1183 this.dunConnectTimer.cancel();
1184 debug("DUN data call connected, process callbacks.");
1185 while (this._pendingTetheringRequests.length > 0) {
1186 let callback = this._pendingTetheringRequests.shift();
1187 if (typeof callback === 'function') {
1188 callback(network);
1189 }
1190 }
1191 return;
1192 }
1193 #endif
1195 if (!this.tetheringSettings[SETTINGS_USB_ENABLED]) {
1196 debug("Usb tethering settings is not enabled");
1197 return;
1198 }
1200 #ifdef MOZ_B2G_RIL
1201 if (this.tetheringSettings[SETTINGS_DUN_REQUIRED] &&
1202 network.type === Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN &&
1203 this._tetheringInterface[TETHERING_TYPE_USB].externalInterface ===
1204 network.name) {
1205 debug("Dun required and dun interface is the same");
1206 return;
1207 }
1208 #endif
1210 if (this._tetheringInterface[TETHERING_TYPE_USB].externalInterface ===
1211 this.active.name) {
1212 debug("The active interface is the same");
1213 return;
1214 }
1216 let previous = {
1217 internalIfname: this._tetheringInterface[TETHERING_TYPE_USB].internalInterface,
1218 externalIfname: this._tetheringInterface[TETHERING_TYPE_USB].externalInterface
1219 };
1221 let current = {
1222 internalIfname: this._tetheringInterface[TETHERING_TYPE_USB].internalInterface,
1223 externalIfname: network.name
1224 };
1226 let callback = (function() {
1227 // Update external network interface.
1228 debug("Update upstream interface to " + network.name);
1229 gNetworkService.updateUpStream(previous, current, this.onConnectionChangedReport.bind(this));
1230 }).bind(this);
1232 if (this._usbTetheringAction === TETHERING_STATE_ONGOING) {
1233 debug("Postpone the event and handle it when state is idle.");
1234 this.wantConnectionEvent = callback;
1235 return;
1236 }
1237 this.wantConnectionEvent = null;
1239 callback.call(this);
1240 }
1241 };
1243 let CaptivePortalDetectionHelper = (function() {
1245 const EVENT_CONNECT = "Connect";
1246 const EVENT_DISCONNECT = "Disconnect";
1247 let _ongoingInterface = null;
1248 let _available = ("nsICaptivePortalDetector" in Ci);
1249 let getService = function() {
1250 return Cc['@mozilla.org/toolkit/captive-detector;1']
1251 .getService(Ci.nsICaptivePortalDetector);
1252 };
1254 let _performDetection = function(interfaceName, callback) {
1255 let capService = getService();
1256 let capCallback = {
1257 QueryInterface: XPCOMUtils.generateQI([Ci.nsICaptivePortalCallback]),
1258 prepare: function() {
1259 capService.finishPreparation(interfaceName);
1260 },
1261 complete: function(success) {
1262 _ongoingInterface = null;
1263 callback(success);
1264 }
1265 };
1267 // Abort any unfinished captive portal detection.
1268 if (_ongoingInterface != null) {
1269 capService.abort(_ongoingInterface);
1270 _ongoingInterface = null;
1271 }
1272 try {
1273 capService.checkCaptivePortal(interfaceName, capCallback);
1274 _ongoingInterface = interfaceName;
1275 } catch (e) {
1276 debug('Fail to detect captive portal due to: ' + e.message);
1277 }
1278 };
1280 let _abort = function(interfaceName) {
1281 if (_ongoingInterface !== interfaceName) {
1282 return;
1283 }
1285 let capService = getService();
1286 capService.abort(_ongoingInterface);
1287 _ongoingInterface = null;
1288 };
1290 return {
1291 EVENT_CONNECT: EVENT_CONNECT,
1292 EVENT_DISCONNECT: EVENT_DISCONNECT,
1293 notify: function(eventType, network) {
1294 switch (eventType) {
1295 case EVENT_CONNECT:
1296 // perform captive portal detection on wifi interface
1297 if (_available && network &&
1298 network.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
1299 _performDetection(network.name, function() {
1300 // TODO: bug 837600
1301 // We can disconnect wifi in here if user abort the login procedure.
1302 });
1303 }
1305 break;
1306 case EVENT_DISCONNECT:
1307 if (_available &&
1308 network.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
1309 _abort(network.name);
1310 }
1311 break;
1312 }
1313 }
1314 };
1315 }());
1317 #ifdef MOZ_B2G_RIL
1318 XPCOMUtils.defineLazyServiceGetter(NetworkManager.prototype, "mRil",
1319 "@mozilla.org/ril;1",
1320 "nsIRadioInterfaceLayer");
1322 XPCOMUtils.defineLazyGetter(NetworkManager.prototype,
1323 "gDataDefaultServiceId", function() {
1324 try {
1325 return Services.prefs.getIntPref(PREF_DATA_DEFAULT_SERVICE_ID);
1326 } catch(e) {}
1328 return 0;
1329 });
1330 #endif
1332 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkManager]);
1335 let debug;
1336 if (DEBUG) {
1337 debug = function(s) {
1338 dump("-*- NetworkManager: " + s + "\n");
1339 };
1340 } else {
1341 debug = function(s) {};
1342 }