// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/chromeos/cros/network_library.h" #include <algorithm> #include <map> #include "base/i18n/icu_encoding_detection.h" #include "base/i18n/icu_string_conversions.h" #include "base/i18n/time_formatting.h" #include "base/metrics/histogram.h" #include "base/stl_util-inl.h" #include "base/string_number_conversions.h" #include "base/string_util.h" #include "base/stringprintf.h" #include "base/utf_string_conversions.h" #include "base/utf_string_conversion_utils.h" #include "base/values.h" #include "chrome/browser/chromeos/cros/cros_library.h" #include "chrome/browser/chromeos/login/user_manager.h" #include "chrome/browser/chromeos/network_login_observer.h" #include "chrome/browser/chromeos/user_cros_settings_provider.h" #include "chrome/common/time_format.h" #include "content/browser/browser_thread.h" #include "grit/generated_resources.h" #include "ui/base/l10n/l10n_util.h" //////////////////////////////////////////////////////////////////////////////// // Implementation notes. // NetworkLibraryImpl manages a series of classes that describe network devices // and services: // // NetworkDevice: e.g. ethernet, wifi modem, cellular modem // device_map_: canonical map<path,NetworkDevice*> for devices // // Network: a network service ("network"). // network_map_: canonical map<path,Network*> for all visible networks. // EthernetNetwork // ethernet_: EthernetNetwork* to the active ethernet network in network_map_. // WirelessNetwork: a Wifi or Cellular Network. // WifiNetwork // active_wifi_: WifiNetwork* to the active wifi network in network_map_. // wifi_networks_: ordered vector of WifiNetwork* entries in network_map_, // in descending order of importance. // CellularNetwork // active_cellular_: Cellular version of wifi_. // cellular_networks_: Cellular version of wifi_. // network_unique_id_map_: map<unique_id,Network*> for visible networks. // remembered_network_map_: a canonical map<path,Network*> for all networks // remembered in the active Profile ("favorites"). // remembered_wifi_networks_: ordered vector of WifiNetwork* entries in // remembered_network_map_, in descending order of preference. // // network_manager_monitor_: a handle to the libcros network Manager handler. // NetworkManagerStatusChanged: This handles all messages from the Manager. // Messages are parsed here and the appropriate updates are then requested. // // UpdateNetworkServiceList: This is the primary Manager handler. It handles // the "Services" message which list all visible networks. The handler // rebuilds the network lists without destroying existing Network structures, // then requests neccessary updates to be fetched asynchronously from // libcros (RequestNetworkServiceInfo). // // TODO(stevenjb): Document cellular data plan handlers. // // AddNetworkObserver: Adds an observer for a specific network. // NetworkObserverList: A monitor and list of observers of a network. // network_monitor_: a handle to the libcros network Service handler. // UpdateNetworkStatus: This handles changes to a monitored service, typically // changes to transient states like Strength. (Note: also updates State). // // AddNetworkDeviceObserver: Adds an observer for a specific device. // Will be called on any device property change. // NetworkDeviceObserverList: A monitor and list of observers of a device. // UpdateNetworkDeviceStatus: Handles changes to a monitored device, like // SIM lock state and updates device state. // // All *Pin(...) methods use internal callback that would update cellular // device state once async call is completed and notify all device observers. // //////////////////////////////////////////////////////////////////////////////// namespace chromeos { // Local constants. namespace { // Only send network change notifications to observers once every 50ms. const int kNetworkNotifyDelayMs = 50; // How long we should remember that cellular plan payment was received. const int kRecentPlanPaymentHours = 6; // Default value of the SIM unlock retries count. It is updated to the real // retries count once cellular device with SIM card is initialized. // If cellular device doesn't have SIM card, then retries are never used. const int kDefaultSimUnlockRetriesCount = 999; // Format of the Carrier ID: <carrier name> (<carrier country>). const char* kCarrierIdFormat = "%s (%s)"; // Type of a pending SIM operation. enum SimOperationType { SIM_OPERATION_NONE = 0, SIM_OPERATION_CHANGE_PIN = 1, SIM_OPERATION_CHANGE_REQUIRE_PIN = 2, SIM_OPERATION_ENTER_PIN = 3, SIM_OPERATION_UNBLOCK_PIN = 4, }; // D-Bus interface string constants. // Flimflam property names. const char* kSecurityProperty = "Security"; const char* kPassphraseProperty = "Passphrase"; const char* kIdentityProperty = "Identity"; const char* kCertPathProperty = "CertPath"; const char* kPassphraseRequiredProperty = "PassphraseRequired"; const char* kSaveCredentialsProperty = "SaveCredentials"; const char* kProfilesProperty = "Profiles"; const char* kServicesProperty = "Services"; const char* kServiceWatchListProperty = "ServiceWatchList"; const char* kAvailableTechnologiesProperty = "AvailableTechnologies"; const char* kEnabledTechnologiesProperty = "EnabledTechnologies"; const char* kConnectedTechnologiesProperty = "ConnectedTechnologies"; const char* kDefaultTechnologyProperty = "DefaultTechnology"; const char* kOfflineModeProperty = "OfflineMode"; const char* kSignalStrengthProperty = "Strength"; const char* kNameProperty = "Name"; const char* kStateProperty = "State"; const char* kConnectivityStateProperty = "ConnectivityState"; const char* kTypeProperty = "Type"; const char* kDeviceProperty = "Device"; const char* kActivationStateProperty = "Cellular.ActivationState"; const char* kNetworkTechnologyProperty = "Cellular.NetworkTechnology"; const char* kRoamingStateProperty = "Cellular.RoamingState"; const char* kOperatorNameProperty = "Cellular.OperatorName"; const char* kOperatorCodeProperty = "Cellular.OperatorCode"; const char* kServingOperatorProperty = "Cellular.ServingOperator"; const char* kPaymentURLProperty = "Cellular.OlpUrl"; const char* kUsageURLProperty = "Cellular.UsageUrl"; const char* kCellularApnProperty = "Cellular.APN"; const char* kCellularLastGoodApnProperty = "Cellular.LastGoodAPN"; const char* kWifiHexSsid = "WiFi.HexSSID"; const char* kWifiFrequency = "WiFi.Frequency"; const char* kWifiHiddenSsid = "WiFi.HiddenSSID"; const char* kWifiPhyMode = "WiFi.PhyMode"; const char* kFavoriteProperty = "Favorite"; const char* kConnectableProperty = "Connectable"; const char* kAutoConnectProperty = "AutoConnect"; const char* kIsActiveProperty = "IsActive"; const char* kModeProperty = "Mode"; const char* kErrorProperty = "Error"; const char* kActiveProfileProperty = "ActiveProfile"; const char* kEntriesProperty = "Entries"; const char* kDevicesProperty = "Devices"; const char* kProviderProperty = "Provider"; const char* kHostProperty = "Host"; // Flimflam property names for SIMLock status. const char* kSIMLockStatusProperty = "Cellular.SIMLockStatus"; const char* kSIMLockTypeProperty = "LockType"; const char* kSIMLockRetriesLeftProperty = "RetriesLeft"; // Flimflam property names for Cellular.FoundNetworks. const char* kLongNameProperty = "long_name"; const char* kStatusProperty = "status"; const char* kShortNameProperty = "short_name"; const char* kTechnologyProperty = "technology"; // Flimflam SIMLock status types. const char* kSIMLockPin = "sim-pin"; const char* kSIMLockPuk = "sim-puk"; // APN info property names. const char* kApnProperty = "apn"; const char* kNetworkIdProperty = "network_id"; const char* kUsernameProperty = "username"; const char* kPasswordProperty = "password"; // Operator info property names. const char* kOperatorNameKey = "name"; const char* kOperatorCodeKey = "code"; const char* kOperatorCountryKey = "country"; // Flimflam device info property names. const char* kScanningProperty = "Scanning"; const char* kCarrierProperty = "Cellular.Carrier"; const char* kCellularAllowRoamingProperty = "Cellular.AllowRoaming"; const char* kHomeProviderProperty = "Cellular.HomeProvider"; const char* kMeidProperty = "Cellular.MEID"; const char* kImeiProperty = "Cellular.IMEI"; const char* kImsiProperty = "Cellular.IMSI"; const char* kEsnProperty = "Cellular.ESN"; const char* kMdnProperty = "Cellular.MDN"; const char* kMinProperty = "Cellular.MIN"; const char* kModelIDProperty = "Cellular.ModelID"; const char* kManufacturerProperty = "Cellular.Manufacturer"; const char* kFirmwareRevisionProperty = "Cellular.FirmwareRevision"; const char* kHardwareRevisionProperty = "Cellular.HardwareRevision"; const char* kPoweredProperty = "Powered"; const char* kPRLVersionProperty = "Cellular.PRLVersion"; // (INT16) const char* kSelectedNetworkProperty = "Cellular.SelectedNetwork"; const char* kSupportNetworkScanProperty = "Cellular.SupportNetworkScan"; const char* kFoundNetworksProperty = "Cellular.FoundNetworks"; // Flimflam type options. const char* kTypeEthernet = "ethernet"; const char* kTypeWifi = "wifi"; const char* kTypeWimax = "wimax"; const char* kTypeBluetooth = "bluetooth"; const char* kTypeCellular = "cellular"; const char* kTypeVPN = "vpn"; // Flimflam mode options. const char* kModeManaged = "managed"; const char* kModeAdhoc = "adhoc"; // Flimflam security options. const char* kSecurityWpa = "wpa"; const char* kSecurityWep = "wep"; const char* kSecurityRsn = "rsn"; const char* kSecurity8021x = "802_1x"; const char* kSecurityPsk = "psk"; const char* kSecurityNone = "none"; // Flimflam L2TPIPsec property names. const char* kL2TPIPSecCACertProperty = "L2TPIPsec.CACert"; const char* kL2TPIPSecCertProperty = "L2TPIPsec.Cert"; const char* kL2TPIPSecKeyProperty = "L2TPIPsec.Key"; const char* kL2TPIPSecPSKProperty = "L2TPIPsec.PSK"; const char* kL2TPIPSecUserProperty = "L2TPIPsec.User"; const char* kL2TPIPSecPasswordProperty = "L2TPIPsec.Password"; // Flimflam EAP property names. // See src/third_party/flimflam/doc/service-api.txt. const char* kEapIdentityProperty = "EAP.Identity"; const char* kEapMethodProperty = "EAP.EAP"; const char* kEapPhase2AuthProperty = "EAP.InnerEAP"; const char* kEapAnonymousIdentityProperty = "EAP.AnonymousIdentity"; const char* kEapClientCertProperty = "EAP.ClientCert"; // path const char* kEapCertIDProperty = "EAP.CertID"; // PKCS#11 ID const char* kEapClientCertNssProperty = "EAP.ClientCertNSS"; // NSS nickname const char* kEapPrivateKeyProperty = "EAP.PrivateKey"; const char* kEapPrivateKeyPasswordProperty = "EAP.PrivateKeyPassword"; const char* kEapKeyIDProperty = "EAP.KeyID"; const char* kEapCaCertProperty = "EAP.CACert"; // server CA cert path const char* kEapCaCertIDProperty = "EAP.CACertID"; // server CA PKCS#11 ID const char* kEapCaCertNssProperty = "EAP.CACertNSS"; // server CA NSS nickname const char* kEapUseSystemCAsProperty = "EAP.UseSystemCAs"; const char* kEapPinProperty = "EAP.PIN"; const char* kEapPasswordProperty = "EAP.Password"; const char* kEapKeyMgmtProperty = "EAP.KeyMgmt"; // Flimflam EAP method options. const std::string& kEapMethodPEAP = "PEAP"; const std::string& kEapMethodTLS = "TLS"; const std::string& kEapMethodTTLS = "TTLS"; const std::string& kEapMethodLEAP = "LEAP"; // Flimflam EAP phase 2 auth options. const std::string& kEapPhase2AuthPEAPMD5 = "auth=MD5"; const std::string& kEapPhase2AuthPEAPMSCHAPV2 = "auth=MSCHAPV2"; const std::string& kEapPhase2AuthTTLSMD5 = "autheap=MD5"; const std::string& kEapPhase2AuthTTLSMSCHAPV2 = "autheap=MSCHAPV2"; const std::string& kEapPhase2AuthTTLSMSCHAP = "autheap=MSCHAP"; const std::string& kEapPhase2AuthTTLSPAP = "autheap=PAP"; const std::string& kEapPhase2AuthTTLSCHAP = "autheap=CHAP"; // Flimflam VPN provider types. const char* kProviderL2tpIpsec = "l2tpipsec"; const char* kProviderOpenVpn = "openvpn"; // Flimflam state options. const char* kStateIdle = "idle"; const char* kStateCarrier = "carrier"; const char* kStateAssociation = "association"; const char* kStateConfiguration = "configuration"; const char* kStateReady = "ready"; const char* kStateDisconnect = "disconnect"; const char* kStateFailure = "failure"; const char* kStateActivationFailure = "activation-failure"; // Flimflam connectivity state options. const char* kConnStateUnrestricted = "unrestricted"; const char* kConnStateRestricted = "restricted"; const char* kConnStateNone = "none"; // Flimflam network technology options. const char* kNetworkTechnology1Xrtt = "1xRTT"; const char* kNetworkTechnologyEvdo = "EVDO"; const char* kNetworkTechnologyGprs = "GPRS"; const char* kNetworkTechnologyEdge = "EDGE"; const char* kNetworkTechnologyUmts = "UMTS"; const char* kNetworkTechnologyHspa = "HSPA"; const char* kNetworkTechnologyHspaPlus = "HSPA+"; const char* kNetworkTechnologyLte = "LTE"; const char* kNetworkTechnologyLteAdvanced = "LTE Advanced"; // Flimflam roaming state options const char* kRoamingStateHome = "home"; const char* kRoamingStateRoaming = "roaming"; const char* kRoamingStateUnknown = "unknown"; // Flimflam activation state options const char* kActivationStateActivated = "activated"; const char* kActivationStateActivating = "activating"; const char* kActivationStateNotActivated = "not-activated"; const char* kActivationStatePartiallyActivated = "partially-activated"; const char* kActivationStateUnknown = "unknown"; // Flimflam error options. const char* kErrorOutOfRange = "out-of-range"; const char* kErrorPinMissing = "pin-missing"; const char* kErrorDhcpFailed = "dhcp-failed"; const char* kErrorConnectFailed = "connect-failed"; const char* kErrorBadPassphrase = "bad-passphrase"; const char* kErrorBadWEPKey = "bad-wepkey"; const char* kErrorActivationFailed = "activation-failed"; const char* kErrorNeedEvdo = "need-evdo"; const char* kErrorNeedHomeNetwork = "need-home-network"; const char* kErrorOtaspFailed = "otasp-failed"; const char* kErrorAaaFailed = "aaa-failed"; // Flimflam error messages. const char* kErrorPassphraseRequiredMsg = "Passphrase required"; const char* kErrorIncorrectPinMsg = "org.chromium.flimflam.Error.IncorrectPin"; const char* kErrorPinBlockedMsg = "org.chromium.flimflam.Error.PinBlocked"; const char* kErrorPinRequiredMsg = "org.chromium.flimflam.Error.PinRequired"; const char* kUnknownString = "UNKNOWN"; //////////////////////////////////////////////////////////////////////////// static const char* ConnectionTypeToString(ConnectionType type) { switch (type) { case TYPE_UNKNOWN: break; case TYPE_ETHERNET: return kTypeEthernet; case TYPE_WIFI: return kTypeWifi; case TYPE_WIMAX: return kTypeWimax; case TYPE_BLUETOOTH: return kTypeBluetooth; case TYPE_CELLULAR: return kTypeCellular; case TYPE_VPN: return kTypeVPN; } LOG(ERROR) << "ConnectionTypeToString called with unknown type: " << type; return kUnknownString; } // TODO(stevenjb/njw): Deprecate in favor of setting EAP properties. static const char* SecurityToString(ConnectionSecurity security) { switch (security) { case SECURITY_NONE: return kSecurityNone; case SECURITY_WEP: return kSecurityWep; case SECURITY_WPA: return kSecurityWpa; case SECURITY_RSN: return kSecurityRsn; case SECURITY_8021X: return kSecurity8021x; case SECURITY_PSK: return kSecurityPsk; case SECURITY_UNKNOWN: break; } LOG(ERROR) << "SecurityToString called with unknown type: " << security; return kUnknownString; } static const char* ProviderTypeToString(VirtualNetwork::ProviderType type) { switch (type) { case VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_PSK: case VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_USER_CERT: return kProviderL2tpIpsec; case VirtualNetwork::PROVIDER_TYPE_OPEN_VPN: return kProviderOpenVpn; case VirtualNetwork::PROVIDER_TYPE_MAX: break; } LOG(ERROR) << "ProviderTypeToString called with unknown type: " << type; return kUnknownString; } //////////////////////////////////////////////////////////////////////////// // Helper class to cache maps of strings to enums. template <typename Type> class StringToEnum { public: struct Pair { const char* key; const Type value; }; explicit StringToEnum(const Pair* list, size_t num_entries, Type unknown) : unknown_value_(unknown) { for (size_t i = 0; i < num_entries; ++i, ++list) enum_map_[list->key] = list->value; } Type Get(const std::string& type) const { EnumMapConstIter iter = enum_map_.find(type); if (iter != enum_map_.end()) return iter->second; return unknown_value_; } private: typedef typename std::map<std::string, Type> EnumMap; typedef typename std::map<std::string, Type>::const_iterator EnumMapConstIter; EnumMap enum_map_; Type unknown_value_; DISALLOW_COPY_AND_ASSIGN(StringToEnum); }; //////////////////////////////////////////////////////////////////////////// enum PropertyIndex { PROPERTY_INDEX_ACTIVATION_STATE, PROPERTY_INDEX_ACTIVE_PROFILE, PROPERTY_INDEX_AUTO_CONNECT, PROPERTY_INDEX_AVAILABLE_TECHNOLOGIES, PROPERTY_INDEX_CARRIER, PROPERTY_INDEX_CELLULAR_ALLOW_ROAMING, PROPERTY_INDEX_CELLULAR_APN, PROPERTY_INDEX_CELLULAR_LAST_GOOD_APN, PROPERTY_INDEX_CERT_PATH, PROPERTY_INDEX_CONNECTABLE, PROPERTY_INDEX_CONNECTED_TECHNOLOGIES, PROPERTY_INDEX_CONNECTIVITY_STATE, PROPERTY_INDEX_DEFAULT_TECHNOLOGY, PROPERTY_INDEX_DEVICE, PROPERTY_INDEX_DEVICES, PROPERTY_INDEX_EAP_IDENTITY, PROPERTY_INDEX_EAP_METHOD, PROPERTY_INDEX_EAP_PHASE_2_AUTH, PROPERTY_INDEX_EAP_ANONYMOUS_IDENTITY, PROPERTY_INDEX_EAP_CLIENT_CERT, PROPERTY_INDEX_EAP_CERT_ID, PROPERTY_INDEX_EAP_CLIENT_CERT_NSS, PROPERTY_INDEX_EAP_PRIVATE_KEY, PROPERTY_INDEX_EAP_PRIVATE_KEY_PASSWORD, PROPERTY_INDEX_EAP_KEY_ID, PROPERTY_INDEX_EAP_CA_CERT, PROPERTY_INDEX_EAP_CA_CERT_ID, PROPERTY_INDEX_EAP_CA_CERT_NSS, PROPERTY_INDEX_EAP_USE_SYSTEM_CAS, PROPERTY_INDEX_EAP_PIN, PROPERTY_INDEX_EAP_PASSWORD, PROPERTY_INDEX_EAP_KEY_MGMT, PROPERTY_INDEX_ENABLED_TECHNOLOGIES, PROPERTY_INDEX_ERROR, PROPERTY_INDEX_ESN, PROPERTY_INDEX_FAVORITE, PROPERTY_INDEX_FIRMWARE_REVISION, PROPERTY_INDEX_FOUND_NETWORKS, PROPERTY_INDEX_HARDWARE_REVISION, PROPERTY_INDEX_HOME_PROVIDER, PROPERTY_INDEX_HOST, PROPERTY_INDEX_IDENTITY, PROPERTY_INDEX_IMEI, PROPERTY_INDEX_IMSI, PROPERTY_INDEX_IS_ACTIVE, PROPERTY_INDEX_L2TPIPSEC_CA_CERT, PROPERTY_INDEX_L2TPIPSEC_CERT, PROPERTY_INDEX_L2TPIPSEC_KEY, PROPERTY_INDEX_L2TPIPSEC_PASSWORD, PROPERTY_INDEX_L2TPIPSEC_PSK, PROPERTY_INDEX_L2TPIPSEC_USER, PROPERTY_INDEX_MANUFACTURER, PROPERTY_INDEX_MDN, PROPERTY_INDEX_MEID, PROPERTY_INDEX_MIN, PROPERTY_INDEX_MODE, PROPERTY_INDEX_MODEL_ID, PROPERTY_INDEX_NAME, PROPERTY_INDEX_NETWORK_TECHNOLOGY, PROPERTY_INDEX_OFFLINE_MODE, PROPERTY_INDEX_OPERATOR_CODE, PROPERTY_INDEX_OPERATOR_NAME, PROPERTY_INDEX_PASSPHRASE, PROPERTY_INDEX_PASSPHRASE_REQUIRED, PROPERTY_INDEX_PAYMENT_URL, PROPERTY_INDEX_POWERED, PROPERTY_INDEX_PRL_VERSION, PROPERTY_INDEX_PROFILES, PROPERTY_INDEX_PROVIDER, PROPERTY_INDEX_ROAMING_STATE, PROPERTY_INDEX_SAVE_CREDENTIALS, PROPERTY_INDEX_SCANNING, PROPERTY_INDEX_SECURITY, PROPERTY_INDEX_SELECTED_NETWORK, PROPERTY_INDEX_SERVICES, PROPERTY_INDEX_SERVICE_WATCH_LIST, PROPERTY_INDEX_SERVING_OPERATOR, PROPERTY_INDEX_SIGNAL_STRENGTH, PROPERTY_INDEX_SIM_LOCK, PROPERTY_INDEX_STATE, PROPERTY_INDEX_SUPPORT_NETWORK_SCAN, PROPERTY_INDEX_TYPE, PROPERTY_INDEX_UNKNOWN, PROPERTY_INDEX_USAGE_URL, PROPERTY_INDEX_WIFI_FREQUENCY, PROPERTY_INDEX_WIFI_HEX_SSID, PROPERTY_INDEX_WIFI_HIDDEN_SSID, PROPERTY_INDEX_WIFI_PHY_MODE, }; StringToEnum<PropertyIndex>::Pair property_index_table[] = { { kActivationStateProperty, PROPERTY_INDEX_ACTIVATION_STATE }, { kActiveProfileProperty, PROPERTY_INDEX_ACTIVE_PROFILE }, { kAutoConnectProperty, PROPERTY_INDEX_AUTO_CONNECT }, { kAvailableTechnologiesProperty, PROPERTY_INDEX_AVAILABLE_TECHNOLOGIES }, { kCellularAllowRoamingProperty, PROPERTY_INDEX_CELLULAR_ALLOW_ROAMING }, { kCellularApnProperty, PROPERTY_INDEX_CELLULAR_APN }, { kCellularLastGoodApnProperty, PROPERTY_INDEX_CELLULAR_LAST_GOOD_APN }, { kCarrierProperty, PROPERTY_INDEX_CARRIER }, { kCertPathProperty, PROPERTY_INDEX_CERT_PATH }, { kConnectableProperty, PROPERTY_INDEX_CONNECTABLE }, { kConnectedTechnologiesProperty, PROPERTY_INDEX_CONNECTED_TECHNOLOGIES }, { kConnectivityStateProperty, PROPERTY_INDEX_CONNECTIVITY_STATE }, { kDefaultTechnologyProperty, PROPERTY_INDEX_DEFAULT_TECHNOLOGY }, { kDeviceProperty, PROPERTY_INDEX_DEVICE }, { kDevicesProperty, PROPERTY_INDEX_DEVICES }, { kEapIdentityProperty, PROPERTY_INDEX_EAP_IDENTITY }, { kEapMethodProperty, PROPERTY_INDEX_EAP_METHOD }, { kEapPhase2AuthProperty, PROPERTY_INDEX_EAP_PHASE_2_AUTH }, { kEapAnonymousIdentityProperty, PROPERTY_INDEX_EAP_ANONYMOUS_IDENTITY }, { kEapClientCertProperty, PROPERTY_INDEX_EAP_CLIENT_CERT }, { kEapCertIDProperty, PROPERTY_INDEX_EAP_CERT_ID }, { kEapClientCertNssProperty, PROPERTY_INDEX_EAP_CLIENT_CERT_NSS }, { kEapPrivateKeyProperty, PROPERTY_INDEX_EAP_PRIVATE_KEY }, { kEapPrivateKeyPasswordProperty, PROPERTY_INDEX_EAP_PRIVATE_KEY_PASSWORD }, { kEapKeyIDProperty, PROPERTY_INDEX_EAP_KEY_ID }, { kEapCaCertProperty, PROPERTY_INDEX_EAP_CA_CERT }, { kEapCaCertIDProperty, PROPERTY_INDEX_EAP_CA_CERT_ID }, { kEapCaCertNssProperty, PROPERTY_INDEX_EAP_CA_CERT_NSS }, { kEapUseSystemCAsProperty, PROPERTY_INDEX_EAP_USE_SYSTEM_CAS }, { kEapPinProperty, PROPERTY_INDEX_EAP_PIN }, { kEapPasswordProperty, PROPERTY_INDEX_EAP_PASSWORD }, { kEapKeyMgmtProperty, PROPERTY_INDEX_EAP_KEY_MGMT }, { kEnabledTechnologiesProperty, PROPERTY_INDEX_ENABLED_TECHNOLOGIES }, { kErrorProperty, PROPERTY_INDEX_ERROR }, { kEsnProperty, PROPERTY_INDEX_ESN }, { kFavoriteProperty, PROPERTY_INDEX_FAVORITE }, { kFirmwareRevisionProperty, PROPERTY_INDEX_FIRMWARE_REVISION }, { kFoundNetworksProperty, PROPERTY_INDEX_FOUND_NETWORKS }, { kHardwareRevisionProperty, PROPERTY_INDEX_HARDWARE_REVISION }, { kHomeProviderProperty, PROPERTY_INDEX_HOME_PROVIDER }, { kHostProperty, PROPERTY_INDEX_HOST }, { kIdentityProperty, PROPERTY_INDEX_IDENTITY }, { kImeiProperty, PROPERTY_INDEX_IMEI }, { kImsiProperty, PROPERTY_INDEX_IMSI }, { kIsActiveProperty, PROPERTY_INDEX_IS_ACTIVE }, { kL2TPIPSecCACertProperty, PROPERTY_INDEX_L2TPIPSEC_CA_CERT }, { kL2TPIPSecCertProperty, PROPERTY_INDEX_L2TPIPSEC_CERT }, { kL2TPIPSecKeyProperty, PROPERTY_INDEX_L2TPIPSEC_KEY }, { kL2TPIPSecPasswordProperty, PROPERTY_INDEX_L2TPIPSEC_PASSWORD }, { kL2TPIPSecPSKProperty, PROPERTY_INDEX_L2TPIPSEC_PSK }, { kL2TPIPSecUserProperty, PROPERTY_INDEX_L2TPIPSEC_USER }, { kManufacturerProperty, PROPERTY_INDEX_MANUFACTURER }, { kMdnProperty, PROPERTY_INDEX_MDN }, { kMeidProperty, PROPERTY_INDEX_MEID }, { kMinProperty, PROPERTY_INDEX_MIN }, { kModeProperty, PROPERTY_INDEX_MODE }, { kModelIDProperty, PROPERTY_INDEX_MODEL_ID }, { kNameProperty, PROPERTY_INDEX_NAME }, { kNetworkTechnologyProperty, PROPERTY_INDEX_NETWORK_TECHNOLOGY }, { kOfflineModeProperty, PROPERTY_INDEX_OFFLINE_MODE }, { kOperatorCodeProperty, PROPERTY_INDEX_OPERATOR_CODE }, { kOperatorNameProperty, PROPERTY_INDEX_OPERATOR_NAME }, { kPRLVersionProperty, PROPERTY_INDEX_PRL_VERSION }, { kPassphraseProperty, PROPERTY_INDEX_PASSPHRASE }, { kPassphraseRequiredProperty, PROPERTY_INDEX_PASSPHRASE_REQUIRED }, { kPaymentURLProperty, PROPERTY_INDEX_PAYMENT_URL }, { kPoweredProperty, PROPERTY_INDEX_POWERED }, { kProfilesProperty, PROPERTY_INDEX_PROFILES }, { kProviderProperty, PROPERTY_INDEX_PROVIDER }, { kRoamingStateProperty, PROPERTY_INDEX_ROAMING_STATE }, { kSaveCredentialsProperty, PROPERTY_INDEX_SAVE_CREDENTIALS }, { kScanningProperty, PROPERTY_INDEX_SCANNING }, { kSecurityProperty, PROPERTY_INDEX_SECURITY }, { kSelectedNetworkProperty, PROPERTY_INDEX_SELECTED_NETWORK }, { kServiceWatchListProperty, PROPERTY_INDEX_SERVICE_WATCH_LIST }, { kServicesProperty, PROPERTY_INDEX_SERVICES }, { kServingOperatorProperty, PROPERTY_INDEX_SERVING_OPERATOR }, { kSignalStrengthProperty, PROPERTY_INDEX_SIGNAL_STRENGTH }, { kSIMLockStatusProperty, PROPERTY_INDEX_SIM_LOCK }, { kStateProperty, PROPERTY_INDEX_STATE }, { kSupportNetworkScanProperty, PROPERTY_INDEX_SUPPORT_NETWORK_SCAN }, { kTypeProperty, PROPERTY_INDEX_TYPE }, { kUsageURLProperty, PROPERTY_INDEX_USAGE_URL }, { kWifiFrequency, PROPERTY_INDEX_WIFI_FREQUENCY }, { kWifiHexSsid, PROPERTY_INDEX_WIFI_HEX_SSID }, { kWifiHiddenSsid, PROPERTY_INDEX_WIFI_HIDDEN_SSID }, { kWifiPhyMode, PROPERTY_INDEX_WIFI_PHY_MODE }, }; StringToEnum<PropertyIndex>& property_index_parser() { static StringToEnum<PropertyIndex> parser(property_index_table, arraysize(property_index_table), PROPERTY_INDEX_UNKNOWN); return parser; } //////////////////////////////////////////////////////////////////////////// // Parse strings from libcros. // Network. static ConnectionType ParseType(const std::string& type) { static StringToEnum<ConnectionType>::Pair table[] = { { kTypeEthernet, TYPE_ETHERNET }, { kTypeWifi, TYPE_WIFI }, { kTypeWimax, TYPE_WIMAX }, { kTypeBluetooth, TYPE_BLUETOOTH }, { kTypeCellular, TYPE_CELLULAR }, { kTypeVPN, TYPE_VPN }, }; static StringToEnum<ConnectionType> parser( table, arraysize(table), TYPE_UNKNOWN); return parser.Get(type); } ConnectionType ParseTypeFromDictionary(const DictionaryValue* info) { std::string type_string; info->GetString(kTypeProperty, &type_string); return ParseType(type_string); } static ConnectionMode ParseMode(const std::string& mode) { static StringToEnum<ConnectionMode>::Pair table[] = { { kModeManaged, MODE_MANAGED }, { kModeAdhoc, MODE_ADHOC }, }; static StringToEnum<ConnectionMode> parser( table, arraysize(table), MODE_UNKNOWN); return parser.Get(mode); } static ConnectionState ParseState(const std::string& state) { static StringToEnum<ConnectionState>::Pair table[] = { { kStateIdle, STATE_IDLE }, { kStateCarrier, STATE_CARRIER }, { kStateAssociation, STATE_ASSOCIATION }, { kStateConfiguration, STATE_CONFIGURATION }, { kStateReady, STATE_READY }, { kStateDisconnect, STATE_DISCONNECT }, { kStateFailure, STATE_FAILURE }, { kStateActivationFailure, STATE_ACTIVATION_FAILURE }, }; static StringToEnum<ConnectionState> parser( table, arraysize(table), STATE_UNKNOWN); return parser.Get(state); } static ConnectionError ParseError(const std::string& error) { static StringToEnum<ConnectionError>::Pair table[] = { { kErrorOutOfRange, ERROR_OUT_OF_RANGE }, { kErrorPinMissing, ERROR_PIN_MISSING }, { kErrorDhcpFailed, ERROR_DHCP_FAILED }, { kErrorConnectFailed, ERROR_CONNECT_FAILED }, { kErrorBadPassphrase, ERROR_BAD_PASSPHRASE }, { kErrorBadWEPKey, ERROR_BAD_WEPKEY }, { kErrorActivationFailed, ERROR_ACTIVATION_FAILED }, { kErrorNeedEvdo, ERROR_NEED_EVDO }, { kErrorNeedHomeNetwork, ERROR_NEED_HOME_NETWORK }, { kErrorOtaspFailed, ERROR_OTASP_FAILED }, { kErrorAaaFailed, ERROR_AAA_FAILED }, }; static StringToEnum<ConnectionError> parser( table, arraysize(table), ERROR_NO_ERROR); return parser.Get(error); } // VirtualNetwork static VirtualNetwork::ProviderType ParseProviderType(const std::string& mode) { static StringToEnum<VirtualNetwork::ProviderType>::Pair table[] = { { kProviderL2tpIpsec, VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_PSK }, { kProviderOpenVpn, VirtualNetwork::PROVIDER_TYPE_OPEN_VPN }, }; static StringToEnum<VirtualNetwork::ProviderType> parser( table, arraysize(table), VirtualNetwork::PROVIDER_TYPE_MAX); return parser.Get(mode); } // CellularNetwork. static ActivationState ParseActivationState(const std::string& state) { static StringToEnum<ActivationState>::Pair table[] = { { kActivationStateActivated, ACTIVATION_STATE_ACTIVATED }, { kActivationStateActivating, ACTIVATION_STATE_ACTIVATING }, { kActivationStateNotActivated, ACTIVATION_STATE_NOT_ACTIVATED }, { kActivationStatePartiallyActivated, ACTIVATION_STATE_PARTIALLY_ACTIVATED}, { kActivationStateUnknown, ACTIVATION_STATE_UNKNOWN}, }; static StringToEnum<ActivationState> parser( table, arraysize(table), ACTIVATION_STATE_UNKNOWN); return parser.Get(state); } static ConnectivityState ParseConnectivityState(const std::string& state) { static StringToEnum<ConnectivityState>::Pair table[] = { { kConnStateUnrestricted, CONN_STATE_UNRESTRICTED }, { kConnStateRestricted, CONN_STATE_RESTRICTED }, { kConnStateNone, CONN_STATE_NONE }, }; static StringToEnum<ConnectivityState> parser( table, arraysize(table), CONN_STATE_UNKNOWN); return parser.Get(state); } static NetworkTechnology ParseNetworkTechnology(const std::string& technology) { static StringToEnum<NetworkTechnology>::Pair table[] = { { kNetworkTechnology1Xrtt, NETWORK_TECHNOLOGY_1XRTT }, { kNetworkTechnologyEvdo, NETWORK_TECHNOLOGY_EVDO }, { kNetworkTechnologyGprs, NETWORK_TECHNOLOGY_GPRS }, { kNetworkTechnologyEdge, NETWORK_TECHNOLOGY_EDGE }, { kNetworkTechnologyUmts, NETWORK_TECHNOLOGY_UMTS }, { kNetworkTechnologyHspa, NETWORK_TECHNOLOGY_HSPA }, { kNetworkTechnologyHspaPlus, NETWORK_TECHNOLOGY_HSPA_PLUS }, { kNetworkTechnologyLte, NETWORK_TECHNOLOGY_LTE }, { kNetworkTechnologyLteAdvanced, NETWORK_TECHNOLOGY_LTE_ADVANCED }, }; static StringToEnum<NetworkTechnology> parser( table, arraysize(table), NETWORK_TECHNOLOGY_UNKNOWN); return parser.Get(technology); } static SIMLockState ParseSimLockState(const std::string& state) { static StringToEnum<SIMLockState>::Pair table[] = { { "", SIM_UNLOCKED }, { kSIMLockPin, SIM_LOCKED_PIN }, { kSIMLockPuk, SIM_LOCKED_PUK }, }; static StringToEnum<SIMLockState> parser( table, arraysize(table), SIM_UNKNOWN); SIMLockState parsed_state = parser.Get(state); DCHECK(parsed_state != SIM_UNKNOWN) << "Unknown SIMLock state encountered"; return parsed_state; } static bool ParseSimLockStateFromDictionary(const DictionaryValue* info, SIMLockState* out_state, int* out_retries) { std::string state_string; if (!info->GetString(kSIMLockTypeProperty, &state_string) || !info->GetInteger(kSIMLockRetriesLeftProperty, out_retries)) { LOG(ERROR) << "Error parsing SIMLock state"; return false; } *out_state = ParseSimLockState(state_string); return true; } static bool ParseFoundNetworksFromList(const ListValue* list, CellularNetworkList* found_networks_) { found_networks_->clear(); found_networks_->reserve(list->GetSize()); for (ListValue::const_iterator it = list->begin(); it != list->end(); ++it) { if ((*it)->IsType(Value::TYPE_DICTIONARY)) { found_networks_->resize(found_networks_->size() + 1); DictionaryValue* dict = static_cast<const DictionaryValue*>(*it); dict->GetStringWithoutPathExpansion( kStatusProperty, &found_networks_->back().status); dict->GetStringWithoutPathExpansion( kNetworkIdProperty, &found_networks_->back().network_id); dict->GetStringWithoutPathExpansion( kShortNameProperty, &found_networks_->back().short_name); dict->GetStringWithoutPathExpansion( kLongNameProperty, &found_networks_->back().long_name); dict->GetStringWithoutPathExpansion( kTechnologyProperty, &found_networks_->back().technology); } else { return false; } } return true; } static NetworkRoamingState ParseRoamingState(const std::string& roaming_state) { static StringToEnum<NetworkRoamingState>::Pair table[] = { { kRoamingStateHome, ROAMING_STATE_HOME }, { kRoamingStateRoaming, ROAMING_STATE_ROAMING }, { kRoamingStateUnknown, ROAMING_STATE_UNKNOWN }, }; static StringToEnum<NetworkRoamingState> parser( table, arraysize(table), ROAMING_STATE_UNKNOWN); return parser.Get(roaming_state); } // WifiNetwork static ConnectionSecurity ParseSecurity(const std::string& security) { static StringToEnum<ConnectionSecurity>::Pair table[] = { { kSecurityNone, SECURITY_NONE }, { kSecurityWep, SECURITY_WEP }, { kSecurityWpa, SECURITY_WPA }, { kSecurityRsn, SECURITY_RSN }, { kSecurityPsk, SECURITY_PSK }, { kSecurity8021x, SECURITY_8021X }, }; static StringToEnum<ConnectionSecurity> parser( table, arraysize(table), SECURITY_UNKNOWN); return parser.Get(security); } static EAPMethod ParseEAPMethod(const std::string& method) { static StringToEnum<EAPMethod>::Pair table[] = { { kEapMethodPEAP.c_str(), EAP_METHOD_PEAP }, { kEapMethodTLS.c_str(), EAP_METHOD_TLS }, { kEapMethodTTLS.c_str(), EAP_METHOD_TTLS }, { kEapMethodLEAP.c_str(), EAP_METHOD_LEAP }, }; static StringToEnum<EAPMethod> parser( table, arraysize(table), EAP_METHOD_UNKNOWN); return parser.Get(method); } static EAPPhase2Auth ParseEAPPhase2Auth(const std::string& auth) { static StringToEnum<EAPPhase2Auth>::Pair table[] = { { kEapPhase2AuthPEAPMD5.c_str(), EAP_PHASE_2_AUTH_MD5 }, { kEapPhase2AuthPEAPMSCHAPV2.c_str(), EAP_PHASE_2_AUTH_MSCHAPV2 }, { kEapPhase2AuthTTLSMD5.c_str(), EAP_PHASE_2_AUTH_MD5 }, { kEapPhase2AuthTTLSMSCHAPV2.c_str(), EAP_PHASE_2_AUTH_MSCHAPV2 }, { kEapPhase2AuthTTLSMSCHAP.c_str(), EAP_PHASE_2_AUTH_MSCHAP }, { kEapPhase2AuthTTLSPAP.c_str(), EAP_PHASE_2_AUTH_PAP }, { kEapPhase2AuthTTLSCHAP.c_str(), EAP_PHASE_2_AUTH_CHAP }, }; static StringToEnum<EAPPhase2Auth> parser( table, arraysize(table), EAP_PHASE_2_AUTH_AUTO); return parser.Get(auth); } //////////////////////////////////////////////////////////////////////////////// // Misc. // Safe string constructor since we can't rely on non NULL pointers // for string values from libcros. static std::string SafeString(const char* s) { return s ? std::string(s) : std::string(); } // Erase the memory used by a string, then clear it. static void WipeString(std::string* str) { str->assign(str->size(), '\0'); str->clear(); } static bool EnsureCrosLoaded() { if (!CrosLibrary::Get()->EnsureLoaded()) { return false; } else { if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { LOG(ERROR) << "chromeos_library calls made from non UI thread!"; NOTREACHED(); } return true; } } static void ValidateUTF8(const std::string& str, std::string* output) { output->clear(); for (int32 index = 0; index < static_cast<int32>(str.size()); ++index) { uint32 code_point_out; bool is_unicode_char = base::ReadUnicodeCharacter(str.c_str(), str.size(), &index, &code_point_out); if (is_unicode_char && (code_point_out >= 0x20)) base::WriteUnicodeCharacter(code_point_out, output); else // Puts REPLACEMENT CHARACTER (U+FFFD) if character is not readable UTF-8 base::WriteUnicodeCharacter(0xFFFD, output); } } } // namespace //////////////////////////////////////////////////////////////////////////////// // NetworkDevice NetworkDevice::NetworkDevice(const std::string& device_path) : device_path_(device_path), type_(TYPE_UNKNOWN), scanning_(false), sim_lock_state_(SIM_UNKNOWN), sim_retries_left_(kDefaultSimUnlockRetriesCount), sim_pin_required_(SIM_PIN_REQUIRE_UNKNOWN), PRL_version_(0), data_roaming_allowed_(false), support_network_scan_(false) { } bool NetworkDevice::ParseValue(int index, const Value* value) { switch (index) { case PROPERTY_INDEX_TYPE: { std::string type_string; if (value->GetAsString(&type_string)) { type_ = ParseType(type_string); return true; } break; } case PROPERTY_INDEX_NAME: return value->GetAsString(&name_); case PROPERTY_INDEX_CARRIER: return value->GetAsString(&carrier_); case PROPERTY_INDEX_SCANNING: return value->GetAsBoolean(&scanning_); case PROPERTY_INDEX_CELLULAR_ALLOW_ROAMING: return value->GetAsBoolean(&data_roaming_allowed_); case PROPERTY_INDEX_FOUND_NETWORKS: if (value->IsType(Value::TYPE_LIST)) { return ParseFoundNetworksFromList( static_cast<const ListValue*>(value), &found_cellular_networks_); } break; case PROPERTY_INDEX_HOME_PROVIDER: { if (value->IsType(Value::TYPE_DICTIONARY)) { const DictionaryValue *dict = static_cast<const DictionaryValue*>(value); home_provider_code_.clear(); home_provider_country_.clear(); home_provider_name_.clear(); dict->GetStringWithoutPathExpansion(kOperatorCodeKey, &home_provider_code_); dict->GetStringWithoutPathExpansion(kOperatorCountryKey, &home_provider_country_); dict->GetStringWithoutPathExpansion(kOperatorNameKey, &home_provider_name_); if (!home_provider_name_.empty() && !home_provider_country_.empty()) { home_provider_id_ = base::StringPrintf( kCarrierIdFormat, home_provider_name_.c_str(), home_provider_country_.c_str()); } else { home_provider_id_ = home_provider_code_; LOG(WARNING) << "Carrier ID not defined, using code instead: " << home_provider_id_; } return true; } break; } case PROPERTY_INDEX_MEID: return value->GetAsString(&MEID_); case PROPERTY_INDEX_IMEI: return value->GetAsString(&IMEI_); case PROPERTY_INDEX_IMSI: return value->GetAsString(&IMSI_); case PROPERTY_INDEX_ESN: return value->GetAsString(&ESN_); case PROPERTY_INDEX_MDN: return value->GetAsString(&MDN_); case PROPERTY_INDEX_MIN: return value->GetAsString(&MIN_); case PROPERTY_INDEX_MODEL_ID: return value->GetAsString(&model_id_); case PROPERTY_INDEX_MANUFACTURER: return value->GetAsString(&manufacturer_); case PROPERTY_INDEX_SIM_LOCK: if (value->IsType(Value::TYPE_DICTIONARY)) { bool result = ParseSimLockStateFromDictionary( static_cast<const DictionaryValue*>(value), &sim_lock_state_, &sim_retries_left_); // Initialize PinRequired value only once. // See SIMPinRequire enum comments. if (sim_pin_required_ == SIM_PIN_REQUIRE_UNKNOWN) { if (sim_lock_state_ == SIM_UNLOCKED) { sim_pin_required_ = SIM_PIN_NOT_REQUIRED; } else if (sim_lock_state_ == SIM_LOCKED_PIN || sim_lock_state_ == SIM_LOCKED_PUK) { sim_pin_required_ = SIM_PIN_REQUIRED; } } return result; } break; case PROPERTY_INDEX_FIRMWARE_REVISION: return value->GetAsString(&firmware_revision_); case PROPERTY_INDEX_HARDWARE_REVISION: return value->GetAsString(&hardware_revision_); case PROPERTY_INDEX_POWERED: // we don't care about the value, just the fact that it changed return true; case PROPERTY_INDEX_PRL_VERSION: return value->GetAsInteger(&PRL_version_); case PROPERTY_INDEX_SELECTED_NETWORK: return value->GetAsString(&selected_cellular_network_); case PROPERTY_INDEX_SUPPORT_NETWORK_SCAN: return value->GetAsBoolean(&support_network_scan_); default: break; } return false; } void NetworkDevice::ParseInfo(const DictionaryValue* info) { for (DictionaryValue::key_iterator iter = info->begin_keys(); iter != info->end_keys(); ++iter) { const std::string& key = *iter; Value* value; bool res = info->GetWithoutPathExpansion(key, &value); DCHECK(res); if (res) { int index = property_index_parser().Get(key); if (!ParseValue(index, value)) VLOG(1) << "NetworkDevice: Unhandled key: " << key; } } } //////////////////////////////////////////////////////////////////////////////// // Network void Network::SetName(const std::string& name) { std::string name_utf8; ValidateUTF8(name, &name_utf8); set_name(name_utf8); } bool Network::ParseValue(int index, const Value* value) { switch (index) { case PROPERTY_INDEX_TYPE: { std::string type_string; if (value->GetAsString(&type_string)) { ConnectionType type = ParseType(type_string); LOG_IF(ERROR, type != type_) << "Network with mismatched type: " << service_path_ << " " << type << " != " << type_; return true; } break; } case PROPERTY_INDEX_DEVICE: return value->GetAsString(&device_path_); case PROPERTY_INDEX_NAME: { std::string name; if (value->GetAsString(&name)) { SetName(name); return true; } break; } case PROPERTY_INDEX_STATE: { std::string state_string; if (value->GetAsString(&state_string)) { ConnectionState prev_state = state_; state_ = ParseState(state_string); if (state_ != prev_state) { // State changed, so refresh IP address. // Note: blocking DBus call. TODO(stevenjb): refactor this. InitIPAddress(); } return true; } break; } case PROPERTY_INDEX_MODE: { std::string mode_string; if (value->GetAsString(&mode_string)) { mode_ = ParseMode(mode_string); return true; } break; } case PROPERTY_INDEX_ERROR: { std::string error_string; if (value->GetAsString(&error_string)) { error_ = ParseError(error_string); return true; } break; } case PROPERTY_INDEX_CONNECTABLE: return value->GetAsBoolean(&connectable_); case PROPERTY_INDEX_IS_ACTIVE: return value->GetAsBoolean(&is_active_); case PROPERTY_INDEX_FAVORITE: return value->GetAsBoolean(&favorite_); case PROPERTY_INDEX_AUTO_CONNECT: return value->GetAsBoolean(&auto_connect_); case PROPERTY_INDEX_CONNECTIVITY_STATE: { std::string connectivity_state_string; if (value->GetAsString(&connectivity_state_string)) { connectivity_state_ = ParseConnectivityState(connectivity_state_string); return true; } break; } default: break; } return false; } void Network::ParseInfo(const DictionaryValue* info) { for (DictionaryValue::key_iterator iter = info->begin_keys(); iter != info->end_keys(); ++iter) { const std::string& key = *iter; Value* value; bool res = info->GetWithoutPathExpansion(key, &value); DCHECK(res); if (res) { int index = property_index_parser().Get(key); if (!ParseValue(index, value)) // virtual. VLOG(1) << "Network: " << name() << " Type: " << ConnectionTypeToString(type()) << " Unhandled key: " << key; } } } void Network::SetValueProperty(const char* prop, Value* val) { DCHECK(prop); DCHECK(val); if (!EnsureCrosLoaded()) return; SetNetworkServiceProperty(service_path_.c_str(), prop, val); } void Network::ClearProperty(const char* prop) { DCHECK(prop); if (!EnsureCrosLoaded()) return; ClearNetworkServiceProperty(service_path_.c_str(), prop); } void Network::SetStringProperty( const char* prop, const std::string& str, std::string* dest) { if (dest) *dest = str; scoped_ptr<Value> value(Value::CreateStringValue(str)); SetValueProperty(prop, value.get()); } void Network::SetOrClearStringProperty(const char* prop, const std::string& str, std::string* dest) { if (str.empty()) { ClearProperty(prop); if (dest) dest->clear(); } else { SetStringProperty(prop, str, dest); } } void Network::SetBooleanProperty(const char* prop, bool b, bool* dest) { if (dest) *dest = b; scoped_ptr<Value> value(Value::CreateBooleanValue(b)); SetValueProperty(prop, value.get()); } void Network::SetIntegerProperty(const char* prop, int i, int* dest) { if (dest) *dest = i; scoped_ptr<Value> value(Value::CreateIntegerValue(i)); SetValueProperty(prop, value.get()); } void Network::SetAutoConnect(bool auto_connect) { SetBooleanProperty(kAutoConnectProperty, auto_connect, &auto_connect_); } std::string Network::GetStateString() const { switch (state_) { case STATE_UNKNOWN: return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_STATE_UNKNOWN); case STATE_IDLE: return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_STATE_IDLE); case STATE_CARRIER: return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_STATE_CARRIER); case STATE_ASSOCIATION: return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_STATE_ASSOCIATION); case STATE_CONFIGURATION: return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_STATE_CONFIGURATION); case STATE_READY: return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_STATE_READY); case STATE_DISCONNECT: return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_STATE_DISCONNECT); case STATE_FAILURE: return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_STATE_FAILURE); case STATE_ACTIVATION_FAILURE: return l10n_util::GetStringUTF8( IDS_CHROMEOS_NETWORK_STATE_ACTIVATION_FAILURE); } return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_STATE_UNRECOGNIZED); } std::string Network::GetErrorString() const { switch (error_) { case ERROR_NO_ERROR: // TODO(nkostylev): Introduce new error message "None" instead. return std::string(); case ERROR_OUT_OF_RANGE: return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_ERROR_OUT_OF_RANGE); case ERROR_PIN_MISSING: return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_ERROR_PIN_MISSING); case ERROR_DHCP_FAILED: return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_ERROR_DHCP_FAILED); case ERROR_CONNECT_FAILED: return l10n_util::GetStringUTF8( IDS_CHROMEOS_NETWORK_ERROR_CONNECT_FAILED); case ERROR_BAD_PASSPHRASE: return l10n_util::GetStringUTF8( IDS_CHROMEOS_NETWORK_ERROR_BAD_PASSPHRASE); case ERROR_BAD_WEPKEY: return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_ERROR_BAD_WEPKEY); case ERROR_ACTIVATION_FAILED: return l10n_util::GetStringUTF8( IDS_CHROMEOS_NETWORK_ERROR_ACTIVATION_FAILED); case ERROR_NEED_EVDO: return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_ERROR_NEED_EVDO); case ERROR_NEED_HOME_NETWORK: return l10n_util::GetStringUTF8( IDS_CHROMEOS_NETWORK_ERROR_NEED_HOME_NETWORK); case ERROR_OTASP_FAILED: return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_ERROR_OTASP_FAILED); case ERROR_AAA_FAILED: return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_ERROR_AAA_FAILED); } return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_STATE_UNRECOGNIZED); } void Network::InitIPAddress() { ip_address_.clear(); // If connected, get ip config. if (EnsureCrosLoaded() && connected() && !device_path_.empty()) { IPConfigStatus* ipconfig_status = ListIPConfigs(device_path_.c_str()); if (ipconfig_status) { for (int i = 0; i < ipconfig_status->size; i++) { IPConfig ipconfig = ipconfig_status->ips[i]; if (strlen(ipconfig.address) > 0) { ip_address_ = ipconfig.address; break; } } FreeIPConfigStatus(ipconfig_status); } } } //////////////////////////////////////////////////////////////////////////////// // VirtualNetwork bool VirtualNetwork::ParseProviderValue(int index, const Value* value) { switch (index) { case PROPERTY_INDEX_HOST: return value->GetAsString(&server_hostname_); case PROPERTY_INDEX_NAME: // Note: shadows Network::name_ property. return value->GetAsString(&name_); case PROPERTY_INDEX_TYPE: { std::string provider_type_string; if (value->GetAsString(&provider_type_string)) { provider_type_ = ParseProviderType(provider_type_string); return true; } break; } default: break; } return false; } bool VirtualNetwork::ParseValue(int index, const Value* value) { switch (index) { case PROPERTY_INDEX_PROVIDER: { DCHECK_EQ(value->GetType(), Value::TYPE_DICTIONARY); const DictionaryValue* dict = static_cast<const DictionaryValue*>(value); for (DictionaryValue::key_iterator iter = dict->begin_keys(); iter != dict->end_keys(); ++iter) { const std::string& key = *iter; Value* v; bool res = dict->GetWithoutPathExpansion(key, &v); DCHECK(res); if (res) { int index = property_index_parser().Get(key); if (!ParseProviderValue(index, v)) VLOG(1) << name() << ": Provider unhandled key: " << key << " Type: " << v->GetType(); } } return true; } case PROPERTY_INDEX_L2TPIPSEC_CA_CERT: return value->GetAsString(&ca_cert_); case PROPERTY_INDEX_L2TPIPSEC_PSK: return value->GetAsString(&psk_passphrase_); case PROPERTY_INDEX_L2TPIPSEC_CERT: return value->GetAsString(&user_cert_); case PROPERTY_INDEX_L2TPIPSEC_KEY: return value->GetAsString(&user_cert_key_); case PROPERTY_INDEX_L2TPIPSEC_USER: return value->GetAsString(&username_); case PROPERTY_INDEX_L2TPIPSEC_PASSWORD: return value->GetAsString(&user_passphrase_); default: return Network::ParseValue(index, value); break; } return false; } void VirtualNetwork::ParseInfo(const DictionaryValue* info) { Network::ParseInfo(info); VLOG(1) << "VPN: " << name() << " Type: " << ProviderTypeToString(provider_type()); if (provider_type_ == PROVIDER_TYPE_L2TP_IPSEC_PSK) { if (!user_cert_.empty()) provider_type_ = PROVIDER_TYPE_L2TP_IPSEC_USER_CERT; } } bool VirtualNetwork::NeedMoreInfoToConnect() const { if (server_hostname_.empty() || username_.empty() || user_passphrase_.empty()) return true; switch (provider_type_) { case PROVIDER_TYPE_L2TP_IPSEC_PSK: if (psk_passphrase_.empty()) return true; break; case PROVIDER_TYPE_L2TP_IPSEC_USER_CERT: case PROVIDER_TYPE_OPEN_VPN: if (user_cert_.empty()) return true; break; case PROVIDER_TYPE_MAX: break; } return false; } void VirtualNetwork::SetCACert(const std::string& ca_cert) { SetStringProperty(kL2TPIPSecCACertProperty, ca_cert, &ca_cert_); } void VirtualNetwork::SetPSKPassphrase(const std::string& psk_passphrase) { SetStringProperty(kL2TPIPSecPSKProperty, psk_passphrase, &psk_passphrase_); } void VirtualNetwork::SetUserCert(const std::string& user_cert) { SetStringProperty(kL2TPIPSecCertProperty, user_cert, &user_cert_); } void VirtualNetwork::SetUserCertKey(const std::string& key) { SetStringProperty(kL2TPIPSecKeyProperty, key, &user_cert_key_); } void VirtualNetwork::SetUsername(const std::string& username) { SetStringProperty(kL2TPIPSecUserProperty, username, &username_); } void VirtualNetwork::SetUserPassphrase(const std::string& user_passphrase) { SetStringProperty(kL2TPIPSecPasswordProperty, user_passphrase, &user_passphrase_); } std::string VirtualNetwork::GetProviderTypeString() const { switch (this->provider_type_) { case PROVIDER_TYPE_L2TP_IPSEC_PSK: return l10n_util::GetStringUTF8( IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_L2TP_IPSEC_PSK); break; case PROVIDER_TYPE_L2TP_IPSEC_USER_CERT: return l10n_util::GetStringUTF8( IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_L2TP_IPSEC_USER_CERT); break; case PROVIDER_TYPE_OPEN_VPN: return l10n_util::GetStringUTF8( IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_OPEN_VPN); break; default: return l10n_util::GetStringUTF8( IDS_CHROMEOS_NETWORK_ERROR_UNKNOWN); break; } } //////////////////////////////////////////////////////////////////////////////// // WirelessNetwork bool WirelessNetwork::ParseValue(int index, const Value* value) { switch (index) { case PROPERTY_INDEX_SIGNAL_STRENGTH: return value->GetAsInteger(&strength_); default: return Network::ParseValue(index, value); break; } return false; } //////////////////////////////////////////////////////////////////////////////// // CellularDataPlan string16 CellularDataPlan::GetPlanDesciption() const { switch (plan_type) { case chromeos::CELLULAR_DATA_PLAN_UNLIMITED: { return l10n_util::GetStringFUTF16( IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PURCHASE_UNLIMITED_DATA, base::TimeFormatFriendlyDate(plan_start_time)); break; } case chromeos::CELLULAR_DATA_PLAN_METERED_PAID: { return l10n_util::GetStringFUTF16( IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PURCHASE_DATA, FormatBytes(plan_data_bytes, GetByteDisplayUnits(plan_data_bytes), true), base::TimeFormatFriendlyDate(plan_start_time)); } case chromeos::CELLULAR_DATA_PLAN_METERED_BASE: { return l10n_util::GetStringFUTF16( IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_RECEIVED_FREE_DATA, FormatBytes(plan_data_bytes, GetByteDisplayUnits(plan_data_bytes), true), base::TimeFormatFriendlyDate(plan_start_time)); default: break; } } return string16(); } string16 CellularDataPlan::GetRemainingWarning() const { if (plan_type == chromeos::CELLULAR_DATA_PLAN_UNLIMITED) { // Time based plan. Show nearing expiration and data expiration. if (remaining_time().InSeconds() <= chromeos::kCellularDataVeryLowSecs) { return GetPlanExpiration(); } } else if (plan_type == chromeos::CELLULAR_DATA_PLAN_METERED_PAID || plan_type == chromeos::CELLULAR_DATA_PLAN_METERED_BASE) { // Metered plan. Show low data and out of data. if (remaining_data() <= chromeos::kCellularDataVeryLowBytes) { int64 remaining_mbytes = remaining_data() / (1024 * 1024); return l10n_util::GetStringFUTF16( IDS_NETWORK_DATA_REMAINING_MESSAGE, UTF8ToUTF16(base::Int64ToString(remaining_mbytes))); } } return string16(); } string16 CellularDataPlan::GetDataRemainingDesciption() const { int64 remaining_bytes = remaining_data(); switch (plan_type) { case chromeos::CELLULAR_DATA_PLAN_UNLIMITED: { return l10n_util::GetStringUTF16( IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_UNLIMITED); } case chromeos::CELLULAR_DATA_PLAN_METERED_PAID: { return FormatBytes(remaining_bytes, GetByteDisplayUnits(remaining_bytes), true); } case chromeos::CELLULAR_DATA_PLAN_METERED_BASE: { return FormatBytes(remaining_bytes, GetByteDisplayUnits(remaining_bytes), true); } default: break; } return string16(); } string16 CellularDataPlan::GetUsageInfo() const { if (plan_type == chromeos::CELLULAR_DATA_PLAN_UNLIMITED) { // Time based plan. Show nearing expiration and data expiration. return GetPlanExpiration(); } else if (plan_type == chromeos::CELLULAR_DATA_PLAN_METERED_PAID || plan_type == chromeos::CELLULAR_DATA_PLAN_METERED_BASE) { // Metered plan. Show low data and out of data. int64 remaining_bytes = remaining_data(); if (remaining_bytes == 0) { return l10n_util::GetStringUTF16( IDS_NETWORK_DATA_NONE_AVAILABLE_MESSAGE); } else if (remaining_bytes < 1024 * 1024) { return l10n_util::GetStringUTF16( IDS_NETWORK_DATA_LESS_THAN_ONE_MB_AVAILABLE_MESSAGE); } else { int64 remaining_mb = remaining_bytes / (1024 * 1024); return l10n_util::GetStringFUTF16( IDS_NETWORK_DATA_MB_AVAILABLE_MESSAGE, UTF8ToUTF16(base::Int64ToString(remaining_mb))); } } return string16(); } std::string CellularDataPlan::GetUniqueIdentifier() const { // A cellular plan is uniquely described by the union of name, type, // start time, end time, and max bytes. // So we just return a union of all these variables. return plan_name + "|" + base::Int64ToString(plan_type) + "|" + base::Int64ToString(plan_start_time.ToInternalValue()) + "|" + base::Int64ToString(plan_end_time.ToInternalValue()) + "|" + base::Int64ToString(plan_data_bytes); } base::TimeDelta CellularDataPlan::remaining_time() const { base::TimeDelta time = plan_end_time - base::Time::Now(); return time.InMicroseconds() < 0 ? base::TimeDelta() : time; } int64 CellularDataPlan::remaining_minutes() const { return remaining_time().InMinutes(); } int64 CellularDataPlan::remaining_data() const { int64 data = plan_data_bytes - data_bytes_used; return data < 0 ? 0 : data; } string16 CellularDataPlan::GetPlanExpiration() const { return TimeFormat::TimeRemaining(remaining_time()); } //////////////////////////////////////////////////////////////////////////////// // CellularNetwork::Apn void CellularNetwork::Apn::Set(const DictionaryValue& dict) { if (!dict.GetStringWithoutPathExpansion(kApnProperty, &apn)) apn.clear(); if (!dict.GetStringWithoutPathExpansion(kNetworkIdProperty, &network_id)) network_id.clear(); if (!dict.GetStringWithoutPathExpansion(kUsernameProperty, &username)) username.clear(); if (!dict.GetStringWithoutPathExpansion(kPasswordProperty, &password)) password.clear(); } //////////////////////////////////////////////////////////////////////////////// // CellularNetwork CellularNetwork::~CellularNetwork() { } bool CellularNetwork::ParseValue(int index, const Value* value) { switch (index) { case PROPERTY_INDEX_ACTIVATION_STATE: { std::string activation_state_string; if (value->GetAsString(&activation_state_string)) { ActivationState prev_state = activation_state_; activation_state_ = ParseActivationState(activation_state_string); if (activation_state_ != prev_state) RefreshDataPlansIfNeeded(); return true; } break; } case PROPERTY_INDEX_CELLULAR_APN: { if (value->IsType(Value::TYPE_DICTIONARY)) { apn_.Set(*static_cast<const DictionaryValue*>(value)); return true; } break; } case PROPERTY_INDEX_CELLULAR_LAST_GOOD_APN: { if (value->IsType(Value::TYPE_DICTIONARY)) { last_good_apn_.Set(*static_cast<const DictionaryValue*>(value)); return true; } break; } case PROPERTY_INDEX_NETWORK_TECHNOLOGY: { std::string network_technology_string; if (value->GetAsString(&network_technology_string)) { network_technology_ = ParseNetworkTechnology(network_technology_string); return true; } break; } case PROPERTY_INDEX_ROAMING_STATE: { std::string roaming_state_string; if (value->GetAsString(&roaming_state_string)) { roaming_state_ = ParseRoamingState(roaming_state_string); return true; } break; } case PROPERTY_INDEX_OPERATOR_NAME: return value->GetAsString(&operator_name_); case PROPERTY_INDEX_OPERATOR_CODE: return value->GetAsString(&operator_code_); case PROPERTY_INDEX_SERVING_OPERATOR: { if (value->IsType(Value::TYPE_DICTIONARY)) { const DictionaryValue *dict = static_cast<const DictionaryValue*>(value); operator_code_.clear(); operator_country_.clear(); operator_name_.clear(); dict->GetStringWithoutPathExpansion(kOperatorNameKey, &operator_name_); dict->GetStringWithoutPathExpansion(kOperatorCodeKey, &operator_code_); dict->GetStringWithoutPathExpansion(kOperatorCountryKey, &operator_country_); return true; } break; } case PROPERTY_INDEX_PAYMENT_URL: return value->GetAsString(&payment_url_); case PROPERTY_INDEX_USAGE_URL: return value->GetAsString(&usage_url_); case PROPERTY_INDEX_STATE: { // Save previous state before calling WirelessNetwork::ParseValue. ConnectionState prev_state = state_; if (WirelessNetwork::ParseValue(index, value)) { if (state_ != prev_state) RefreshDataPlansIfNeeded(); return true; } break; } case PROPERTY_INDEX_CONNECTIVITY_STATE: { // Save previous state before calling WirelessNetwork::ParseValue. ConnectivityState prev_state = connectivity_state_; if (WirelessNetwork::ParseValue(index, value)) { if (connectivity_state_ != prev_state) RefreshDataPlansIfNeeded(); return true; } break; } default: return WirelessNetwork::ParseValue(index, value); } return false; } bool CellularNetwork::StartActivation() const { if (!EnsureCrosLoaded()) return false; return ActivateCellularModem(service_path().c_str(), NULL); } void CellularNetwork::RefreshDataPlansIfNeeded() const { if (!EnsureCrosLoaded()) return; if (connected() && activated()) RequestCellularDataPlanUpdate(service_path().c_str()); } void CellularNetwork::SetApn(const Apn& apn) { if (!EnsureCrosLoaded()) return; if (!apn.apn.empty()) { DictionaryValue value; value.SetString(kApnProperty, apn.apn); value.SetString(kNetworkIdProperty, apn.network_id); value.SetString(kUsernameProperty, apn.username); value.SetString(kPasswordProperty, apn.password); SetValueProperty(kCellularApnProperty, &value); } else { ClearProperty(kCellularApnProperty); } } bool CellularNetwork::SupportsDataPlan() const { // TODO(nkostylev): Are there cases when only one of this is defined? return !usage_url().empty() || !payment_url().empty(); } std::string CellularNetwork::GetNetworkTechnologyString() const { // No need to localize these cellular technology abbreviations. switch (network_technology_) { case NETWORK_TECHNOLOGY_1XRTT: return "1xRTT"; break; case NETWORK_TECHNOLOGY_EVDO: return "EVDO"; break; case NETWORK_TECHNOLOGY_GPRS: return "GPRS"; break; case NETWORK_TECHNOLOGY_EDGE: return "EDGE"; break; case NETWORK_TECHNOLOGY_UMTS: return "UMTS"; break; case NETWORK_TECHNOLOGY_HSPA: return "HSPA"; break; case NETWORK_TECHNOLOGY_HSPA_PLUS: return "HSPA Plus"; break; case NETWORK_TECHNOLOGY_LTE: return "LTE"; break; case NETWORK_TECHNOLOGY_LTE_ADVANCED: return "LTE Advanced"; break; default: return l10n_util::GetStringUTF8( IDS_CHROMEOS_NETWORK_CELLULAR_TECHNOLOGY_UNKNOWN); break; } } std::string CellularNetwork::GetConnectivityStateString() const { // These strings do not appear in the UI, so no need to localize them switch (connectivity_state_) { case CONN_STATE_UNRESTRICTED: return "unrestricted"; break; case CONN_STATE_RESTRICTED: return "restricted"; break; case CONN_STATE_NONE: return "none"; break; case CONN_STATE_UNKNOWN: default: return "unknown"; } } std::string CellularNetwork::ActivationStateToString( ActivationState activation_state) { switch (activation_state) { case ACTIVATION_STATE_ACTIVATED: return l10n_util::GetStringUTF8( IDS_CHROMEOS_NETWORK_ACTIVATION_STATE_ACTIVATED); break; case ACTIVATION_STATE_ACTIVATING: return l10n_util::GetStringUTF8( IDS_CHROMEOS_NETWORK_ACTIVATION_STATE_ACTIVATING); break; case ACTIVATION_STATE_NOT_ACTIVATED: return l10n_util::GetStringUTF8( IDS_CHROMEOS_NETWORK_ACTIVATION_STATE_NOT_ACTIVATED); break; case ACTIVATION_STATE_PARTIALLY_ACTIVATED: return l10n_util::GetStringUTF8( IDS_CHROMEOS_NETWORK_ACTIVATION_STATE_PARTIALLY_ACTIVATED); break; default: return l10n_util::GetStringUTF8( IDS_CHROMEOS_NETWORK_ACTIVATION_STATE_UNKNOWN); break; } } std::string CellularNetwork::GetActivationStateString() const { return ActivationStateToString(this->activation_state_); } std::string CellularNetwork::GetRoamingStateString() const { switch (this->roaming_state_) { case ROAMING_STATE_HOME: return l10n_util::GetStringUTF8( IDS_CHROMEOS_NETWORK_ROAMING_STATE_HOME); break; case ROAMING_STATE_ROAMING: return l10n_util::GetStringUTF8( IDS_CHROMEOS_NETWORK_ROAMING_STATE_ROAMING); break; default: return l10n_util::GetStringUTF8( IDS_CHROMEOS_NETWORK_ROAMING_STATE_UNKNOWN); break; } } //////////////////////////////////////////////////////////////////////////////// // WifiNetwork // Called from ParseNetwork after calling ParseInfo. void WifiNetwork::CalculateUniqueId() { ConnectionSecurity encryption = encryption_; // Flimflam treats wpa and rsn as psk internally, so convert those types // to psk for unique naming. if (encryption == SECURITY_WPA || encryption == SECURITY_RSN) encryption = SECURITY_PSK; std::string security = std::string(SecurityToString(encryption)); unique_id_ = security + "|" + name_; } bool WifiNetwork::SetSsid(const std::string& ssid) { // Detects encoding and convert to UTF-8. std::string ssid_utf8; if (!IsStringUTF8(ssid)) { std::string encoding; if (base::DetectEncoding(ssid, &encoding)) { if (!base::ConvertToUtf8AndNormalize(ssid, encoding, &ssid_utf8)) { ssid_utf8.clear(); } } } if (ssid_utf8.empty()) SetName(ssid); else SetName(ssid_utf8); return true; } bool WifiNetwork::SetHexSsid(const std::string& ssid_hex) { // Converts ascii hex dump (eg. "49656c6c6f") to string (eg. "Hello"). std::vector<uint8> ssid_raw; if (!base::HexStringToBytes(ssid_hex, &ssid_raw)) { LOG(ERROR) << "Iligal hex char is found in WiFi.HexSSID."; ssid_raw.clear(); return false; } return SetSsid(std::string(ssid_raw.begin(), ssid_raw.end())); } bool WifiNetwork::ParseValue(int index, const Value* value) { switch (index) { case PROPERTY_INDEX_WIFI_HEX_SSID: { std::string ssid_hex; if (!value->GetAsString(&ssid_hex)) return false; SetHexSsid(ssid_hex); return true; } case PROPERTY_INDEX_NAME: { // Does not change network name when it was already set by WiFi.HexSSID. if (!name().empty()) return true; else return WirelessNetwork::ParseValue(index, value); } case PROPERTY_INDEX_SECURITY: { std::string security_string; if (value->GetAsString(&security_string)) { encryption_ = ParseSecurity(security_string); return true; } break; } case PROPERTY_INDEX_PASSPHRASE: { std::string passphrase; if (value->GetAsString(&passphrase)) { // Only store the passphrase if we are the owner. // TODO(stevenjb): Remove this when chromium-os:12948 is resolved. if (chromeos::UserManager::Get()->current_user_is_owner()) passphrase_ = passphrase; return true; } break; } case PROPERTY_INDEX_PASSPHRASE_REQUIRED: return value->GetAsBoolean(&passphrase_required_); case PROPERTY_INDEX_SAVE_CREDENTIALS: return value->GetAsBoolean(&save_credentials_); case PROPERTY_INDEX_IDENTITY: return value->GetAsString(&identity_); case PROPERTY_INDEX_CERT_PATH: return value->GetAsString(&cert_path_); case PROPERTY_INDEX_EAP_IDENTITY: return value->GetAsString(&eap_identity_); case PROPERTY_INDEX_EAP_METHOD: { std::string method; if (value->GetAsString(&method)) { eap_method_ = ParseEAPMethod(method); return true; } break; } case PROPERTY_INDEX_EAP_PHASE_2_AUTH: { std::string auth; if (value->GetAsString(&auth)) { eap_phase_2_auth_ = ParseEAPPhase2Auth(auth); return true; } break; } case PROPERTY_INDEX_EAP_ANONYMOUS_IDENTITY: return value->GetAsString(&eap_anonymous_identity_); case PROPERTY_INDEX_EAP_CERT_ID: return value->GetAsString(&eap_client_cert_pkcs11_id_); case PROPERTY_INDEX_EAP_CA_CERT_NSS: return value->GetAsString(&eap_server_ca_cert_nss_nickname_); case PROPERTY_INDEX_EAP_USE_SYSTEM_CAS: return value->GetAsBoolean(&eap_use_system_cas_); case PROPERTY_INDEX_EAP_PASSWORD: return value->GetAsString(&eap_passphrase_); case PROPERTY_INDEX_EAP_CLIENT_CERT: case PROPERTY_INDEX_EAP_CLIENT_CERT_NSS: case PROPERTY_INDEX_EAP_PRIVATE_KEY: case PROPERTY_INDEX_EAP_PRIVATE_KEY_PASSWORD: case PROPERTY_INDEX_EAP_KEY_ID: case PROPERTY_INDEX_EAP_CA_CERT: case PROPERTY_INDEX_EAP_CA_CERT_ID: case PROPERTY_INDEX_EAP_PIN: case PROPERTY_INDEX_EAP_KEY_MGMT: // These properties are currently not used in the UI. return true; default: return WirelessNetwork::ParseValue(index, value); } return false; } void WifiNetwork::ParseInfo(const DictionaryValue* info) { Network::ParseInfo(info); CalculateUniqueId(); } const std::string& WifiNetwork::GetPassphrase() const { if (!user_passphrase_.empty()) return user_passphrase_; return passphrase_; } void WifiNetwork::SetPassphrase(const std::string& passphrase) { // Set the user_passphrase_ only; passphrase_ stores the flimflam value. // If the user sets an empty passphrase, restore it to the passphrase // remembered by flimflam. if (!passphrase.empty()) { user_passphrase_ = passphrase; passphrase_ = passphrase; } else { user_passphrase_ = passphrase_; } // Send the change to flimflam. If the format is valid, it will propagate to // passphrase_ with a service update. SetOrClearStringProperty(kPassphraseProperty, passphrase, NULL); } void WifiNetwork::SetSaveCredentials(bool save_credentials) { SetBooleanProperty(kSaveCredentialsProperty, save_credentials, &save_credentials_); } // See src/third_party/flimflam/doc/service-api.txt for properties that // flimflam will forget when SaveCredentials is false. void WifiNetwork::EraseCredentials() { WipeString(&passphrase_); WipeString(&user_passphrase_); WipeString(&eap_client_cert_pkcs11_id_); WipeString(&eap_identity_); WipeString(&eap_anonymous_identity_); WipeString(&eap_passphrase_); } void WifiNetwork::SetIdentity(const std::string& identity) { SetStringProperty(kIdentityProperty, identity, &identity_); } void WifiNetwork::SetCertPath(const std::string& cert_path) { SetStringProperty(kCertPathProperty, cert_path, &cert_path_); } void WifiNetwork::SetEAPMethod(EAPMethod method) { eap_method_ = method; switch (method) { case EAP_METHOD_PEAP: SetStringProperty(kEapMethodProperty, kEapMethodPEAP, NULL); break; case EAP_METHOD_TLS: SetStringProperty(kEapMethodProperty, kEapMethodTLS, NULL); break; case EAP_METHOD_TTLS: SetStringProperty(kEapMethodProperty, kEapMethodTTLS, NULL); break; case EAP_METHOD_LEAP: SetStringProperty(kEapMethodProperty, kEapMethodLEAP, NULL); break; default: ClearProperty(kEapMethodProperty); break; } } void WifiNetwork::SetEAPPhase2Auth(EAPPhase2Auth auth) { eap_phase_2_auth_ = auth; bool is_peap = (eap_method_ == EAP_METHOD_PEAP); switch (auth) { case EAP_PHASE_2_AUTH_AUTO: ClearProperty(kEapPhase2AuthProperty); break; case EAP_PHASE_2_AUTH_MD5: SetStringProperty(kEapPhase2AuthProperty, is_peap ? kEapPhase2AuthPEAPMD5 : kEapPhase2AuthTTLSMD5, NULL); break; case EAP_PHASE_2_AUTH_MSCHAPV2: SetStringProperty(kEapPhase2AuthProperty, is_peap ? kEapPhase2AuthPEAPMSCHAPV2 : kEapPhase2AuthTTLSMSCHAPV2, NULL); break; case EAP_PHASE_2_AUTH_MSCHAP: SetStringProperty(kEapPhase2AuthProperty, kEapPhase2AuthTTLSMSCHAP, NULL); break; case EAP_PHASE_2_AUTH_PAP: SetStringProperty(kEapPhase2AuthProperty, kEapPhase2AuthTTLSPAP, NULL); break; case EAP_PHASE_2_AUTH_CHAP: SetStringProperty(kEapPhase2AuthProperty, kEapPhase2AuthTTLSCHAP, NULL); break; } } void WifiNetwork::SetEAPServerCaCertNssNickname( const std::string& nss_nickname) { VLOG(1) << "SetEAPServerCaCertNssNickname " << nss_nickname; SetOrClearStringProperty(kEapCaCertNssProperty, nss_nickname, &eap_server_ca_cert_nss_nickname_); } void WifiNetwork::SetEAPClientCertPkcs11Id(const std::string& pkcs11_id) { VLOG(1) << "SetEAPClientCertPkcs11Id " << pkcs11_id; SetOrClearStringProperty(kEapCertIDProperty, pkcs11_id, &eap_client_cert_pkcs11_id_); } void WifiNetwork::SetEAPUseSystemCAs(bool use_system_cas) { SetBooleanProperty(kEapUseSystemCAsProperty, use_system_cas, &eap_use_system_cas_); } void WifiNetwork::SetEAPIdentity(const std::string& identity) { SetOrClearStringProperty(kEapIdentityProperty, identity, &eap_identity_); } void WifiNetwork::SetEAPAnonymousIdentity(const std::string& identity) { SetOrClearStringProperty(kEapAnonymousIdentityProperty, identity, &eap_anonymous_identity_); } void WifiNetwork::SetEAPPassphrase(const std::string& passphrase) { SetOrClearStringProperty(kEapPasswordProperty, passphrase, &eap_passphrase_); } std::string WifiNetwork::GetEncryptionString() const { switch (encryption_) { case SECURITY_UNKNOWN: break; case SECURITY_NONE: return ""; case SECURITY_WEP: return "WEP"; case SECURITY_WPA: return "WPA"; case SECURITY_RSN: return "RSN"; case SECURITY_8021X: return "8021X"; case SECURITY_PSK: return "PSK"; } return "Unknown"; } bool WifiNetwork::IsPassphraseRequired() const { // TODO(stevenjb): Remove error_ tests when fixed in flimflam // (http://crosbug.com/10135). if (error_ == ERROR_BAD_PASSPHRASE || error_ == ERROR_BAD_WEPKEY) return true; // For 802.1x networks, configuration is required if connectable is false. if (encryption_ == SECURITY_8021X) return !connectable_; return passphrase_required_; } // Parse 'path' to determine if the certificate is stored in a pkcs#11 device. // flimflam recognizes the string "SETTINGS:" to specify authentication // parameters. 'key_id=' indicates that the certificate is stored in a pkcs#11 // device. See src/third_party/flimflam/files/doc/service-api.txt. bool WifiNetwork::IsCertificateLoaded() const { static const std::string settings_string("SETTINGS:"); static const std::string pkcs11_key("key_id"); if (cert_path_.find(settings_string) == 0) { std::string::size_type idx = cert_path_.find(pkcs11_key); if (idx != std::string::npos) idx = cert_path_.find_first_not_of(kWhitespaceASCII, idx + pkcs11_key.length()); if (idx != std::string::npos && cert_path_[idx] == '=') return true; } return false; } //////////////////////////////////////////////////////////////////////////////// // NetworkLibrary class NetworkLibraryImpl : public NetworkLibrary { public: NetworkLibraryImpl() : network_manager_monitor_(NULL), data_plan_monitor_(NULL), ethernet_(NULL), active_wifi_(NULL), active_cellular_(NULL), active_virtual_(NULL), available_devices_(0), enabled_devices_(0), connected_devices_(0), wifi_scanning_(false), offline_mode_(false), is_locked_(false), sim_operation_(SIM_OPERATION_NONE), notify_task_(NULL) { if (EnsureCrosLoaded()) { Init(); network_manager_monitor_ = MonitorNetworkManager(&NetworkManagerStatusChangedHandler, this); data_plan_monitor_ = MonitorCellularDataPlan(&DataPlanUpdateHandler, this); network_login_observer_.reset(new NetworkLoginObserver(this)); } else { InitTestData(); } } virtual ~NetworkLibraryImpl() { network_manager_observers_.Clear(); if (network_manager_monitor_) DisconnectPropertyChangeMonitor(network_manager_monitor_); data_plan_observers_.Clear(); pin_operation_observers_.Clear(); user_action_observers_.Clear(); if (data_plan_monitor_) DisconnectDataPlanUpdateMonitor(data_plan_monitor_); STLDeleteValues(&network_observers_); STLDeleteValues(&network_device_observers_); ClearNetworks(true /*delete networks*/); ClearRememberedNetworks(true /*delete networks*/); STLDeleteValues(&data_plan_map_); } virtual void AddNetworkManagerObserver(NetworkManagerObserver* observer) { if (!network_manager_observers_.HasObserver(observer)) network_manager_observers_.AddObserver(observer); } virtual void RemoveNetworkManagerObserver(NetworkManagerObserver* observer) { network_manager_observers_.RemoveObserver(observer); } virtual void AddNetworkObserver(const std::string& service_path, NetworkObserver* observer) { DCHECK(observer); if (!EnsureCrosLoaded()) return; // First, add the observer to the callback map. NetworkObserverMap::iterator iter = network_observers_.find(service_path); NetworkObserverList* oblist; if (iter != network_observers_.end()) { oblist = iter->second; } else { oblist = new NetworkObserverList(this, service_path); network_observers_[service_path] = oblist; } if (!oblist->HasObserver(observer)) oblist->AddObserver(observer); } virtual void RemoveNetworkObserver(const std::string& service_path, NetworkObserver* observer) { DCHECK(observer); DCHECK(service_path.size()); NetworkObserverMap::iterator map_iter = network_observers_.find(service_path); if (map_iter != network_observers_.end()) { map_iter->second->RemoveObserver(observer); if (!map_iter->second->size()) { delete map_iter->second; network_observers_.erase(map_iter); } } } virtual void AddNetworkDeviceObserver(const std::string& device_path, NetworkDeviceObserver* observer) { DCHECK(observer); if (!EnsureCrosLoaded()) return; // First, add the observer to the callback map. NetworkDeviceObserverMap::iterator iter = network_device_observers_.find(device_path); NetworkDeviceObserverList* oblist; if (iter != network_device_observers_.end()) { oblist = iter->second; if (!oblist->HasObserver(observer)) oblist->AddObserver(observer); } else { LOG(WARNING) << "No NetworkDeviceObserverList found for " << device_path; } } virtual void RemoveNetworkDeviceObserver(const std::string& device_path, NetworkDeviceObserver* observer) { DCHECK(observer); DCHECK(device_path.size()); NetworkDeviceObserverMap::iterator map_iter = network_device_observers_.find(device_path); if (map_iter != network_device_observers_.end()) { map_iter->second->RemoveObserver(observer); } } virtual void RemoveObserverForAllNetworks(NetworkObserver* observer) { DCHECK(observer); NetworkObserverMap::iterator map_iter = network_observers_.begin(); while (map_iter != network_observers_.end()) { map_iter->second->RemoveObserver(observer); if (!map_iter->second->size()) { delete map_iter->second; network_observers_.erase(map_iter++); } else { ++map_iter; } } } virtual void Lock() { if (is_locked_) return; is_locked_ = true; NotifyNetworkManagerChanged(true); // Forced update. } virtual void Unlock() { DCHECK(is_locked_); if (!is_locked_) return; is_locked_ = false; NotifyNetworkManagerChanged(true); // Forced update. } virtual bool IsLocked() { return is_locked_; } virtual void AddCellularDataPlanObserver(CellularDataPlanObserver* observer) { if (!data_plan_observers_.HasObserver(observer)) data_plan_observers_.AddObserver(observer); } virtual void RemoveCellularDataPlanObserver( CellularDataPlanObserver* observer) { data_plan_observers_.RemoveObserver(observer); } virtual void AddPinOperationObserver(PinOperationObserver* observer) { if (!pin_operation_observers_.HasObserver(observer)) pin_operation_observers_.AddObserver(observer); } virtual void RemovePinOperationObserver(PinOperationObserver* observer) { pin_operation_observers_.RemoveObserver(observer); } virtual void AddUserActionObserver(UserActionObserver* observer) { if (!user_action_observers_.HasObserver(observer)) user_action_observers_.AddObserver(observer); } virtual void RemoveUserActionObserver(UserActionObserver* observer) { user_action_observers_.RemoveObserver(observer); } virtual const EthernetNetwork* ethernet_network() const { return ethernet_; } virtual bool ethernet_connecting() const { return ethernet_ ? ethernet_->connecting() : false; } virtual bool ethernet_connected() const { return ethernet_ ? ethernet_->connected() : false; } virtual const WifiNetwork* wifi_network() const { return active_wifi_; } virtual bool wifi_connecting() const { return active_wifi_ ? active_wifi_->connecting() : false; } virtual bool wifi_connected() const { return active_wifi_ ? active_wifi_->connected() : false; } virtual const CellularNetwork* cellular_network() const { return active_cellular_; } virtual bool cellular_connecting() const { return active_cellular_ ? active_cellular_->connecting() : false; } virtual bool cellular_connected() const { return active_cellular_ ? active_cellular_->connected() : false; } virtual const VirtualNetwork* virtual_network() const { return active_virtual_; } virtual bool virtual_network_connecting() const { return active_virtual_ ? active_virtual_->connecting() : false; } virtual bool virtual_network_connected() const { return active_virtual_ ? active_virtual_->connected() : false; } bool Connected() const { return ethernet_connected() || wifi_connected() || cellular_connected(); } bool Connecting() const { return ethernet_connecting() || wifi_connecting() || cellular_connecting(); } const std::string& IPAddress() const { // Returns IP address for the active network. // TODO(stevenjb): Fix this for VPNs. See chromium-os:13972. const Network* result = active_network(); if (!result) result = connected_network(); // happens if we are connected to a VPN. if (!result) result = ethernet_; // Use non active ethernet addr if no active network. if (result) return result->ip_address(); static std::string null_address("0.0.0.0"); return null_address; } virtual const WifiNetworkVector& wifi_networks() const { return wifi_networks_; } virtual const WifiNetworkVector& remembered_wifi_networks() const { return remembered_wifi_networks_; } virtual const CellularNetworkVector& cellular_networks() const { return cellular_networks_; } virtual const VirtualNetworkVector& virtual_networks() const { return virtual_networks_; } ///////////////////////////////////////////////////////////////////////////// virtual const NetworkDevice* FindNetworkDeviceByPath( const std::string& path) const { NetworkDeviceMap::const_iterator iter = device_map_.find(path); if (iter != device_map_.end()) return iter->second; LOG(WARNING) << "Device path not found: " << path; return NULL; } virtual const NetworkDevice* FindCellularDevice() const { for (NetworkDeviceMap::const_iterator iter = device_map_.begin(); iter != device_map_.end(); ++iter) { if (iter->second->type() == TYPE_CELLULAR) return iter->second; } return NULL; } virtual const NetworkDevice* FindEthernetDevice() const { for (NetworkDeviceMap::const_iterator iter = device_map_.begin(); iter != device_map_.end(); ++iter) { if (iter->second->type() == TYPE_ETHERNET) return iter->second; } return NULL; } virtual const NetworkDevice* FindWifiDevice() const { for (NetworkDeviceMap::const_iterator iter = device_map_.begin(); iter != device_map_.end(); ++iter) { if (iter->second->type() == TYPE_WIFI) return iter->second; } return NULL; } virtual Network* FindNetworkByPath(const std::string& path) const { NetworkMap::const_iterator iter = network_map_.find(path); if (iter != network_map_.end()) return iter->second; return NULL; } WirelessNetwork* FindWirelessNetworkByPath(const std::string& path) const { Network* network = FindNetworkByPath(path); if (network && (network->type() == TYPE_WIFI || network->type() == TYPE_CELLULAR)) return static_cast<WirelessNetwork*>(network); return NULL; } virtual WifiNetwork* FindWifiNetworkByPath(const std::string& path) const { Network* network = FindNetworkByPath(path); if (network && network->type() == TYPE_WIFI) return static_cast<WifiNetwork*>(network); return NULL; } virtual CellularNetwork* FindCellularNetworkByPath( const std::string& path) const { Network* network = FindNetworkByPath(path); if (network && network->type() == TYPE_CELLULAR) return static_cast<CellularNetwork*>(network); return NULL; } virtual VirtualNetwork* FindVirtualNetworkByPath( const std::string& path) const { Network* network = FindNetworkByPath(path); if (network && network->type() == TYPE_VPN) return static_cast<VirtualNetwork*>(network); return NULL; } virtual Network* FindNetworkFromRemembered( const Network* remembered) const { NetworkMap::const_iterator found = network_unique_id_map_.find(remembered->unique_id()); if (found != network_unique_id_map_.end()) return found->second; return NULL; } virtual const CellularDataPlanVector* GetDataPlans( const std::string& path) const { CellularDataPlanMap::const_iterator iter = data_plan_map_.find(path); if (iter == data_plan_map_.end()) return NULL; // If we need a new plan, then ignore any data plans we have. CellularNetwork* cellular = FindCellularNetworkByPath(path); if (cellular && cellular->needs_new_plan()) return NULL; return iter->second; } virtual const CellularDataPlan* GetSignificantDataPlan( const std::string& path) const { const CellularDataPlanVector* plans = GetDataPlans(path); if (plans) return GetSignificantDataPlanFromVector(plans); return NULL; } ///////////////////////////////////////////////////////////////////////////// virtual void ChangePin(const std::string& old_pin, const std::string& new_pin) { const NetworkDevice* cellular = FindCellularDevice(); if (!cellular) { NOTREACHED() << "Calling ChangePin method w/o cellular device."; return; } sim_operation_ = SIM_OPERATION_CHANGE_PIN; chromeos::RequestChangePin(cellular->device_path().c_str(), old_pin.c_str(), new_pin.c_str(), PinOperationCallback, this); } virtual void ChangeRequirePin(bool require_pin, const std::string& pin) { VLOG(1) << "ChangeRequirePin require_pin: " << require_pin << " pin: " << pin; const NetworkDevice* cellular = FindCellularDevice(); if (!cellular) { NOTREACHED() << "Calling ChangeRequirePin method w/o cellular device."; return; } sim_operation_ = SIM_OPERATION_CHANGE_REQUIRE_PIN; chromeos::RequestRequirePin(cellular->device_path().c_str(), pin.c_str(), require_pin, PinOperationCallback, this); } virtual void EnterPin(const std::string& pin) { const NetworkDevice* cellular = FindCellularDevice(); if (!cellular) { NOTREACHED() << "Calling EnterPin method w/o cellular device."; return; } sim_operation_ = SIM_OPERATION_ENTER_PIN; chromeos::RequestEnterPin(cellular->device_path().c_str(), pin.c_str(), PinOperationCallback, this); } virtual void UnblockPin(const std::string& puk, const std::string& new_pin) { const NetworkDevice* cellular = FindCellularDevice(); if (!cellular) { NOTREACHED() << "Calling UnblockPin method w/o cellular device."; return; } sim_operation_ = SIM_OPERATION_UNBLOCK_PIN; chromeos::RequestUnblockPin(cellular->device_path().c_str(), puk.c_str(), new_pin.c_str(), PinOperationCallback, this); } static void PinOperationCallback(void* object, const char* path, NetworkMethodErrorType error, const char* error_message) { NetworkLibraryImpl* networklib = static_cast<NetworkLibraryImpl*>(object); DCHECK(networklib); PinOperationError pin_error; VLOG(1) << "PinOperationCallback, error: " << error << " error_msg: " << error_message; if (error == chromeos::NETWORK_METHOD_ERROR_NONE) { pin_error = PIN_ERROR_NONE; VLOG(1) << "Pin operation completed successfuly"; // TODO(nkostylev): Might be cleaned up and exposed in flimflam API. // http://crosbug.com/14253 // Since this option state is not exposed we have to update it manually. networklib->FlipSimPinRequiredStateIfNeeded(); } else { if (error_message && (strcmp(error_message, kErrorIncorrectPinMsg) == 0 || strcmp(error_message, kErrorPinRequiredMsg) == 0)) { pin_error = PIN_ERROR_INCORRECT_CODE; } else if (error_message && strcmp(error_message, kErrorPinBlockedMsg) == 0) { pin_error = PIN_ERROR_BLOCKED; } else { pin_error = PIN_ERROR_UNKNOWN; NOTREACHED() << "Unknown PIN error: " << error_message; } } networklib->NotifyPinOperationCompleted(pin_error); } virtual void RequestCellularScan() { const NetworkDevice* cellular = FindCellularDevice(); if (!cellular) { NOTREACHED() << "Calling RequestCellularScan method w/o cellular device."; return; } chromeos::ProposeScan(cellular->device_path().c_str()); } virtual void RequestCellularRegister(const std::string& network_id) { const NetworkDevice* cellular = FindCellularDevice(); if (!cellular) { NOTREACHED() << "Calling CellularRegister method w/o cellular device."; return; } chromeos::RequestCellularRegister(cellular->device_path().c_str(), network_id.c_str(), CellularRegisterCallback, this); } static void CellularRegisterCallback(void* object, const char* path, NetworkMethodErrorType error, const char* error_message) { NetworkLibraryImpl* networklib = static_cast<NetworkLibraryImpl*>(object); DCHECK(networklib); // TODO(dpolukhin): Notify observers about network registration status // but not UI doesn't assume such notification so just ignore result. } virtual void SetCellularDataRoamingAllowed(bool new_value) { const NetworkDevice* cellular = FindCellularDevice(); if (!cellular) { NOTREACHED() << "Calling SetCellularDataRoamingAllowed method " "w/o cellular device."; return; } scoped_ptr<Value> value(Value::CreateBooleanValue(new_value)); chromeos::SetNetworkDeviceProperty(cellular->device_path().c_str(), kCellularAllowRoamingProperty, value.get()); } ///////////////////////////////////////////////////////////////////////////// virtual void RequestNetworkScan() { if (EnsureCrosLoaded()) { if (wifi_enabled()) { wifi_scanning_ = true; // Cleared when updates are received. chromeos::RequestNetworkScan(kTypeWifi); RequestRememberedNetworksUpdate(); } if (cellular_network()) cellular_network()->RefreshDataPlansIfNeeded(); } } virtual bool GetWifiAccessPoints(WifiAccessPointVector* result) { if (!EnsureCrosLoaded()) return false; CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DeviceNetworkList* network_list = GetDeviceNetworkList(); if (network_list == NULL) return false; result->clear(); result->reserve(network_list->network_size); const base::Time now = base::Time::Now(); for (size_t i = 0; i < network_list->network_size; ++i) { DCHECK(network_list->networks[i].address); DCHECK(network_list->networks[i].name); WifiAccessPoint ap; ap.mac_address = SafeString(network_list->networks[i].address); ap.name = SafeString(network_list->networks[i].name); ap.timestamp = now - base::TimeDelta::FromSeconds(network_list->networks[i].age_seconds); ap.signal_strength = network_list->networks[i].strength; ap.channel = network_list->networks[i].channel; result->push_back(ap); } FreeDeviceNetworkList(network_list); return true; } static void NetworkConnectCallback(void *object, const char *path, NetworkMethodErrorType error, const char* error_message) { NetworkLibraryImpl* networklib = static_cast<NetworkLibraryImpl*>(object); DCHECK(networklib); Network* network = networklib->FindNetworkByPath(path); if (!network) { LOG(ERROR) << "No network for path: " << path; return; } if (error != NETWORK_METHOD_ERROR_NONE) { LOG(WARNING) << "Error from ServiceConnect callback for: " << network->name() << " Error: " << error << " Message: " << error_message; if (error_message && strcmp(error_message, kErrorPassphraseRequiredMsg) == 0) { // This will trigger the connection failed notification. // TODO(stevenjb): Remove if chromium-os:13203 gets fixed. network->set_state(STATE_FAILURE); network->set_error(ERROR_BAD_PASSPHRASE); networklib->NotifyNetworkManagerChanged(true); // Forced update. } return; } VLOG(1) << "Connected to service: " << network->name(); // Update local cache and notify listeners. if (network->type() == TYPE_WIFI) { WifiNetwork* wifi = static_cast<WifiNetwork *>(network); // If the user asked not to save credentials, flimflam will have // forgotten them. Wipe our cache as well. if (!wifi->save_credentials()) { wifi->EraseCredentials(); } networklib->active_wifi_ = wifi; } else if (network->type() == TYPE_CELLULAR) { networklib->active_cellular_ = static_cast<CellularNetwork *>(network); } else if (network->type() == TYPE_VPN) { networklib->active_virtual_ = static_cast<VirtualNetwork *>(network); } else { LOG(ERROR) << "Network of unexpected type: " << network->type(); } // If we succeed, this network will be remembered; request an update. // TODO(stevenjb): flimflam should do this automatically. networklib->RequestRememberedNetworksUpdate(); // Notify observers. networklib->NotifyNetworkManagerChanged(true); // Forced update. networklib->NotifyUserConnectionInitiated(network); } void CallConnectToNetwork(Network* network) { DCHECK(network); if (!EnsureCrosLoaded() || !network) return; // In order to be certain to trigger any notifications, set the connecting // state locally and notify observers. Otherwise there might be a state // change without a forced notify. network->set_connecting(true); NotifyNetworkManagerChanged(true); // Forced update. RequestNetworkServiceConnect(network->service_path().c_str(), NetworkConnectCallback, this); } virtual void ConnectToWifiNetwork(WifiNetwork* wifi) { // This will happen if a network resets or gets out of range. if (wifi->user_passphrase_ != wifi->passphrase_ || wifi->passphrase_required()) wifi->SetPassphrase(wifi->user_passphrase_); CallConnectToNetwork(wifi); } // Use this to connect to a wifi network by service path. virtual void ConnectToWifiNetwork(const std::string& service_path) { WifiNetwork* wifi = FindWifiNetworkByPath(service_path); if (!wifi) { LOG(WARNING) << "Attempt to connect to non existing network: " << service_path; return; } ConnectToWifiNetwork(wifi); } // Use this to connect to an unlisted wifi network. // This needs to request information about the named service. // The connection attempt will occur in the callback. virtual void ConnectToWifiNetwork(ConnectionSecurity security, const std::string& ssid, const std::string& passphrase, const std::string& identity, const std::string& certpath) { if (!EnsureCrosLoaded()) return; // Store the connection data to be used by the callback. connect_data_.service_name = ssid; connect_data_.passphrase = passphrase; connect_data_.identity = identity; connect_data_.cert_path = certpath; // Asynchronously request service properties and call // WifiServiceUpdateAndConnect. RequestHiddenWifiNetwork(ssid.c_str(), SecurityToString(security), WifiServiceUpdateAndConnect, this); } // Callback static void WifiServiceUpdateAndConnect(void* object, const char* service_path, const Value* info) { NetworkLibraryImpl* networklib = static_cast<NetworkLibraryImpl*>(object); DCHECK(networklib); if (service_path && info) { DCHECK_EQ(info->GetType(), Value::TYPE_DICTIONARY); const DictionaryValue* dict = static_cast<const DictionaryValue*>(info); Network* network = networklib->ParseNetwork(std::string(service_path), dict); DCHECK(network->type() == TYPE_WIFI); networklib->ConnectToWifiNetworkUsingConnectData( static_cast<WifiNetwork*>(network)); } } void ConnectToWifiNetworkUsingConnectData(WifiNetwork* wifi) { ConnectData& data = connect_data_; if (wifi->name() != data.service_name) { LOG(WARNING) << "Wifi network name does not match ConnectData: " << wifi->name() << " != " << data.service_name; return; } wifi->set_added(true); wifi->SetIdentity(data.identity); wifi->SetPassphrase(data.passphrase); if (!data.cert_path.empty()) wifi->SetCertPath(data.cert_path); ConnectToWifiNetwork(wifi); } virtual void ConnectToCellularNetwork(CellularNetwork* cellular) { CallConnectToNetwork(cellular); } // Records information that cellular play payment had happened. virtual void SignalCellularPlanPayment() { DCHECK(!HasRecentCellularPlanPayment()); cellular_plan_payment_time_ = base::Time::Now(); } // Returns true if cellular plan payment had been recorded recently. virtual bool HasRecentCellularPlanPayment() { return (base::Time::Now() - cellular_plan_payment_time_).InHours() < kRecentPlanPaymentHours; } virtual void ConnectToVirtualNetwork(VirtualNetwork* vpn) { CallConnectToNetwork(vpn); } virtual void ConnectToVirtualNetworkPSK( const std::string& service_name, const std::string& server, const std::string& psk, const std::string& username, const std::string& user_passphrase) { if (!EnsureCrosLoaded()) return; // Store the connection data to be used by the callback. connect_data_.service_name = service_name; connect_data_.psk_key = psk; connect_data_.server_hostname = server; connect_data_.identity = username; connect_data_.passphrase = user_passphrase; RequestVirtualNetwork(service_name.c_str(), server.c_str(), kProviderL2tpIpsec, VPNServiceUpdateAndConnect, this); } // Callback static void VPNServiceUpdateAndConnect(void* object, const char* service_path, const Value* info) { NetworkLibraryImpl* networklib = static_cast<NetworkLibraryImpl*>(object); DCHECK(networklib); if (service_path && info) { VLOG(1) << "Connecting to new VPN Service: " << service_path; DCHECK_EQ(info->GetType(), Value::TYPE_DICTIONARY); const DictionaryValue* dict = static_cast<const DictionaryValue*>(info); Network* network = networklib->ParseNetwork(std::string(service_path), dict); DCHECK(network->type() == TYPE_VPN); networklib->ConnectToVirtualNetworkUsingConnectData( static_cast<VirtualNetwork*>(network)); } else { LOG(WARNING) << "Unable to create VPN Service: " << service_path; } } void ConnectToVirtualNetworkUsingConnectData(VirtualNetwork* vpn) { ConnectData& data = connect_data_; if (vpn->name() != data.service_name) { LOG(WARNING) << "Virtual network name does not match ConnectData: " << vpn->name() << " != " << data.service_name; return; } vpn->set_added(true); vpn->set_server_hostname(data.server_hostname); vpn->SetCACert(""); vpn->SetUserCert(""); vpn->SetUserCertKey(""); vpn->SetPSKPassphrase(data.psk_key); vpn->SetUsername(data.identity); vpn->SetUserPassphrase(data.passphrase); CallConnectToNetwork(vpn); } virtual void DisconnectFromNetwork(const Network* network) { DCHECK(network); if (!EnsureCrosLoaded() || !network) return; VLOG(1) << "Disconnect from network: " << network->service_path(); if (chromeos::DisconnectFromNetwork(network->service_path().c_str())) { // Update local cache and notify listeners. Network* found_network = FindNetworkByPath(network->service_path()); if (found_network) { found_network->set_connected(false); if (found_network == active_wifi_) active_wifi_ = NULL; else if (found_network == active_cellular_) active_cellular_ = NULL; else if (found_network == active_virtual_) active_virtual_ = NULL; } NotifyNetworkManagerChanged(true); // Forced update. } } virtual void ForgetWifiNetwork(const std::string& service_path) { if (!EnsureCrosLoaded()) return; DeleteRememberedService(service_path.c_str()); DeleteRememberedWifiNetwork(service_path); NotifyNetworkManagerChanged(true); // Forced update. } virtual std::string GetCellularHomeCarrierId() const { std::string carrier_id; const NetworkDevice* cellular = FindCellularDevice(); if (cellular) { return cellular->home_provider_id(); } return carrier_id; } virtual bool ethernet_available() const { return available_devices_ & (1 << TYPE_ETHERNET); } virtual bool wifi_available() const { return available_devices_ & (1 << TYPE_WIFI); } virtual bool cellular_available() const { return available_devices_ & (1 << TYPE_CELLULAR); } virtual bool ethernet_enabled() const { return enabled_devices_ & (1 << TYPE_ETHERNET); } virtual bool wifi_enabled() const { return enabled_devices_ & (1 << TYPE_WIFI); } virtual bool cellular_enabled() const { return enabled_devices_ & (1 << TYPE_CELLULAR); } virtual bool wifi_scanning() const { return wifi_scanning_; } virtual bool offline_mode() const { return offline_mode_; } // Note: This does not include any virtual networks. virtual const Network* active_network() const { // Use flimflam's ordering of the services to determine what the active // network is (i.e. don't assume priority of network types). Network* result = NULL; if (ethernet_ && ethernet_->is_active()) result = ethernet_; if ((active_wifi_ && active_wifi_->is_active()) && (!result || active_wifi_->priority_order_ < result->priority_order_)) result = active_wifi_; if ((active_cellular_ && active_cellular_->is_active()) && (!result || active_cellular_->priority_order_ < result->priority_order_)) result = active_cellular_; return result; } virtual const Network* connected_network() const { // Use flimflam's ordering of the services to determine what the connected // network is (i.e. don't assume priority of network types). Network* result = NULL; if (ethernet_ && ethernet_->connected()) result = ethernet_; if ((active_wifi_ && active_wifi_->connected()) && (!result || active_wifi_->priority_order_ < result->priority_order_)) result = active_wifi_; if ((active_cellular_ && active_cellular_->connected()) && (!result || active_cellular_->priority_order_ < result->priority_order_)) result = active_cellular_; return result; } virtual void EnableEthernetNetworkDevice(bool enable) { if (is_locked_) return; EnableNetworkDeviceType(TYPE_ETHERNET, enable); } virtual void EnableWifiNetworkDevice(bool enable) { if (is_locked_) return; EnableNetworkDeviceType(TYPE_WIFI, enable); } virtual void EnableCellularNetworkDevice(bool enable) { if (is_locked_) return; EnableNetworkDeviceType(TYPE_CELLULAR, enable); } virtual void EnableOfflineMode(bool enable) { if (!EnsureCrosLoaded()) return; // If network device is already enabled/disabled, then don't do anything. if (enable && offline_mode_) { VLOG(1) << "Trying to enable offline mode when it's already enabled."; return; } if (!enable && !offline_mode_) { VLOG(1) << "Trying to disable offline mode when it's already disabled."; return; } if (SetOfflineMode(enable)) { offline_mode_ = enable; } } virtual NetworkIPConfigVector GetIPConfigs(const std::string& device_path, std::string* hardware_address, HardwareAddressFormat format) { DCHECK(hardware_address); hardware_address->clear(); NetworkIPConfigVector ipconfig_vector; if (EnsureCrosLoaded() && !device_path.empty()) { IPConfigStatus* ipconfig_status = ListIPConfigs(device_path.c_str()); if (ipconfig_status) { for (int i = 0; i < ipconfig_status->size; i++) { IPConfig ipconfig = ipconfig_status->ips[i]; ipconfig_vector.push_back( NetworkIPConfig(device_path, ipconfig.type, ipconfig.address, ipconfig.netmask, ipconfig.gateway, ipconfig.name_servers)); } *hardware_address = ipconfig_status->hardware_address; FreeIPConfigStatus(ipconfig_status); // Sort the list of ip configs by type. std::sort(ipconfig_vector.begin(), ipconfig_vector.end()); } } for (size_t i = 0; i < hardware_address->size(); ++i) (*hardware_address)[i] = toupper((*hardware_address)[i]); if (format == FORMAT_COLON_SEPARATED_HEX) { if (hardware_address->size() % 2 == 0) { std::string output; for (size_t i = 0; i < hardware_address->size(); ++i) { if ((i != 0) && (i % 2 == 0)) output.push_back(':'); output.push_back((*hardware_address)[i]); } *hardware_address = output; } } else { DCHECK(format == FORMAT_RAW_HEX); } return ipconfig_vector; } private: typedef std::map<std::string, Network*> NetworkMap; typedef std::map<std::string, int> PriorityMap; typedef std::map<std::string, NetworkDevice*> NetworkDeviceMap; typedef std::map<std::string, CellularDataPlanVector*> CellularDataPlanMap; class NetworkObserverList : public ObserverList<NetworkObserver> { public: NetworkObserverList(NetworkLibraryImpl* library, const std::string& service_path) { network_monitor_ = MonitorNetworkService(&NetworkStatusChangedHandler, service_path.c_str(), library); } virtual ~NetworkObserverList() { if (network_monitor_) DisconnectPropertyChangeMonitor(network_monitor_); } private: static void NetworkStatusChangedHandler(void* object, const char* path, const char* key, const Value* value) { NetworkLibraryImpl* networklib = static_cast<NetworkLibraryImpl*>(object); DCHECK(networklib); networklib->UpdateNetworkStatus(path, key, value); } PropertyChangeMonitor network_monitor_; DISALLOW_COPY_AND_ASSIGN(NetworkObserverList); }; typedef std::map<std::string, NetworkObserverList*> NetworkObserverMap; class NetworkDeviceObserverList : public ObserverList<NetworkDeviceObserver> { public: NetworkDeviceObserverList(NetworkLibraryImpl* library, const std::string& device_path) { device_monitor_ = MonitorNetworkDevice( &NetworkDevicePropertyChangedHandler, device_path.c_str(), library); } virtual ~NetworkDeviceObserverList() { if (device_monitor_) DisconnectPropertyChangeMonitor(device_monitor_); } private: static void NetworkDevicePropertyChangedHandler(void* object, const char* path, const char* key, const Value* value) { NetworkLibraryImpl* networklib = static_cast<NetworkLibraryImpl*>(object); DCHECK(networklib); networklib->UpdateNetworkDeviceStatus(path, key, value); } PropertyChangeMonitor device_monitor_; DISALLOW_COPY_AND_ASSIGN(NetworkDeviceObserverList); }; typedef std::map<std::string, NetworkDeviceObserverList*> NetworkDeviceObserverMap; //////////////////////////////////////////////////////////////////////////// // Callbacks. static void NetworkManagerStatusChangedHandler(void* object, const char* path, const char* key, const Value* value) { NetworkLibraryImpl* networklib = static_cast<NetworkLibraryImpl*>(object); DCHECK(networklib); networklib->NetworkManagerStatusChanged(key, value); } // This processes all Manager update messages. void NetworkManagerStatusChanged(const char* key, const Value* value) { CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); base::TimeTicks start = base::TimeTicks::Now(); VLOG(1) << "NetworkManagerStatusChanged: KEY=" << key; if (!key) return; int index = property_index_parser().Get(std::string(key)); switch (index) { case PROPERTY_INDEX_STATE: // Currently we ignore the network manager state. break; case PROPERTY_INDEX_AVAILABLE_TECHNOLOGIES: { DCHECK_EQ(value->GetType(), Value::TYPE_LIST); const ListValue* vlist = static_cast<const ListValue*>(value); UpdateAvailableTechnologies(vlist); break; } case PROPERTY_INDEX_ENABLED_TECHNOLOGIES: { DCHECK_EQ(value->GetType(), Value::TYPE_LIST); const ListValue* vlist = static_cast<const ListValue*>(value); UpdateEnabledTechnologies(vlist); break; } case PROPERTY_INDEX_CONNECTED_TECHNOLOGIES: { DCHECK_EQ(value->GetType(), Value::TYPE_LIST); const ListValue* vlist = static_cast<const ListValue*>(value); UpdateConnectedTechnologies(vlist); break; } case PROPERTY_INDEX_DEFAULT_TECHNOLOGY: // Currently we ignore DefaultTechnology. break; case PROPERTY_INDEX_OFFLINE_MODE: { DCHECK_EQ(value->GetType(), Value::TYPE_BOOLEAN); value->GetAsBoolean(&offline_mode_); NotifyNetworkManagerChanged(false); // Not forced. break; } case PROPERTY_INDEX_ACTIVE_PROFILE: { DCHECK_EQ(value->GetType(), Value::TYPE_STRING); value->GetAsString(&active_profile_path_); RequestRememberedNetworksUpdate(); break; } case PROPERTY_INDEX_PROFILES: // Currently we ignore Profiles (list of all profiles). break; case PROPERTY_INDEX_SERVICES: { DCHECK_EQ(value->GetType(), Value::TYPE_LIST); const ListValue* vlist = static_cast<const ListValue*>(value); UpdateNetworkServiceList(vlist); break; } case PROPERTY_INDEX_SERVICE_WATCH_LIST: { DCHECK_EQ(value->GetType(), Value::TYPE_LIST); const ListValue* vlist = static_cast<const ListValue*>(value); UpdateWatchedNetworkServiceList(vlist); break; } case PROPERTY_INDEX_DEVICE: case PROPERTY_INDEX_DEVICES: { DCHECK_EQ(value->GetType(), Value::TYPE_LIST); const ListValue* vlist = static_cast<const ListValue*>(value); UpdateNetworkDeviceList(vlist); break; } default: LOG(WARNING) << "Unhandled key: " << key; break; } base::TimeDelta delta = base::TimeTicks::Now() - start; VLOG(1) << " time: " << delta.InMilliseconds() << " ms."; HISTOGRAM_TIMES("CROS_NETWORK_UPDATE", delta); } static void NetworkManagerUpdate(void* object, const char* manager_path, const Value* info) { NetworkLibraryImpl* networklib = static_cast<NetworkLibraryImpl*>(object); DCHECK(networklib); if (!info) { LOG(ERROR) << "Error retrieving manager properties: " << manager_path; return; } VLOG(1) << "Received NetworkManagerUpdate."; DCHECK_EQ(info->GetType(), Value::TYPE_DICTIONARY); const DictionaryValue* dict = static_cast<const DictionaryValue*>(info); networklib->ParseNetworkManager(dict); } void ParseNetworkManager(const DictionaryValue* dict) { for (DictionaryValue::key_iterator iter = dict->begin_keys(); iter != dict->end_keys(); ++iter) { const std::string& key = *iter; Value* value; bool res = dict->GetWithoutPathExpansion(key, &value); CHECK(res); NetworkManagerStatusChanged(key.c_str(), value); } } static void ProfileUpdate(void* object, const char* profile_path, const Value* info) { NetworkLibraryImpl* networklib = static_cast<NetworkLibraryImpl*>(object); DCHECK(networklib); if (!info) { LOG(ERROR) << "Error retrieving profile: " << profile_path; return; } VLOG(1) << "Received ProfileUpdate for: " << profile_path; DCHECK_EQ(info->GetType(), Value::TYPE_DICTIONARY); const DictionaryValue* dict = static_cast<const DictionaryValue*>(info); ListValue* entries(NULL); dict->GetList(kEntriesProperty, &entries); DCHECK(entries); networklib->UpdateRememberedServiceList(profile_path, entries); } static void NetworkServiceUpdate(void* object, const char* service_path, const Value* info) { NetworkLibraryImpl* networklib = static_cast<NetworkLibraryImpl*>(object); DCHECK(networklib); if (service_path) { if (!info) { // Network no longer exists. networklib->DeleteNetwork(std::string(service_path)); } else { DCHECK_EQ(info->GetType(), Value::TYPE_DICTIONARY); const DictionaryValue* dict = static_cast<const DictionaryValue*>(info); networklib->ParseNetwork(std::string(service_path), dict); } } } static void RememberedNetworkServiceUpdate(void* object, const char* service_path, const Value* info) { NetworkLibraryImpl* networklib = static_cast<NetworkLibraryImpl*>(object); DCHECK(networklib); if (service_path) { if (!info) { // Remembered network no longer exists. networklib->DeleteRememberedWifiNetwork(std::string(service_path)); } else { DCHECK_EQ(info->GetType(), Value::TYPE_DICTIONARY); const DictionaryValue* dict = static_cast<const DictionaryValue*>(info); networklib->ParseRememberedNetwork(std::string(service_path), dict); } } } static void NetworkDeviceUpdate(void* object, const char* device_path, const Value* info) { NetworkLibraryImpl* networklib = static_cast<NetworkLibraryImpl*>(object); DCHECK(networklib); if (device_path) { if (!info) { // device no longer exists. networklib->DeleteDevice(std::string(device_path)); } else { DCHECK_EQ(info->GetType(), Value::TYPE_DICTIONARY); const DictionaryValue* dict = static_cast<const DictionaryValue*>(info); networklib->ParseNetworkDevice(std::string(device_path), dict); } } } static void DataPlanUpdateHandler(void* object, const char* modem_service_path, const CellularDataPlanList* dataplan) { NetworkLibraryImpl* networklib = static_cast<NetworkLibraryImpl*>(object); DCHECK(networklib); if (modem_service_path && dataplan) { networklib->UpdateCellularDataPlan(std::string(modem_service_path), dataplan); } } //////////////////////////////////////////////////////////////////////////// // Network technology functions. void UpdateTechnologies(const ListValue* technologies, int* bitfieldp) { DCHECK(bitfieldp); if (!technologies) return; int bitfield = 0; for (ListValue::const_iterator iter = technologies->begin(); iter != technologies->end(); ++iter) { std::string technology; (*iter)->GetAsString(&technology); if (!technology.empty()) { ConnectionType type = ParseType(technology); bitfield |= 1 << type; } } *bitfieldp = bitfield; NotifyNetworkManagerChanged(false); // Not forced. } void UpdateAvailableTechnologies(const ListValue* technologies) { UpdateTechnologies(technologies, &available_devices_); } void UpdateEnabledTechnologies(const ListValue* technologies) { UpdateTechnologies(technologies, &enabled_devices_); if (!ethernet_enabled()) ethernet_ = NULL; if (!wifi_enabled()) { active_wifi_ = NULL; wifi_networks_.clear(); } if (!cellular_enabled()) { active_cellular_ = NULL; cellular_networks_.clear(); } } void UpdateConnectedTechnologies(const ListValue* technologies) { UpdateTechnologies(technologies, &connected_devices_); } //////////////////////////////////////////////////////////////////////////// // Network list management functions. // Note: sometimes flimflam still returns networks when the device type is // disabled. Always check the appropriate enabled() state before adding // networks to a list or setting an active network so that we do not show them // in the UI. // This relies on services being requested from flimflam in priority order, // and the updates getting processed and received in order. void UpdateActiveNetwork(Network* network) { ConnectionType type(network->type()); if (type == TYPE_ETHERNET) { if (ethernet_enabled()) { // Set ethernet_ to the first connected ethernet service, or the first // disconnected ethernet service if none are connected. if (ethernet_ == NULL || !ethernet_->connected()) ethernet_ = static_cast<EthernetNetwork*>(network); } } else if (type == TYPE_WIFI) { if (wifi_enabled()) { // Set active_wifi_ to the first connected or connecting wifi service. if (active_wifi_ == NULL && network->connecting_or_connected()) active_wifi_ = static_cast<WifiNetwork*>(network); } } else if (type == TYPE_CELLULAR) { if (cellular_enabled()) { // Set active_cellular_ to first connected/connecting celluar service. if (active_cellular_ == NULL && network->connecting_or_connected()) active_cellular_ = static_cast<CellularNetwork*>(network); } } else if (type == TYPE_VPN) { // Set active_virtual_ to the first connected or connecting vpn service. if (active_virtual_ == NULL && network->connecting_or_connected()) active_virtual_ = static_cast<VirtualNetwork*>(network); } } void AddNetwork(Network* network) { std::pair<NetworkMap::iterator,bool> result = network_map_.insert(std::make_pair(network->service_path(), network)); DCHECK(result.second); // Should only get called with new network. VLOG(2) << "Adding Network: " << network->service_path() << " (" << network->name() << ")"; ConnectionType type(network->type()); if (type == TYPE_WIFI) { if (wifi_enabled()) wifi_networks_.push_back(static_cast<WifiNetwork*>(network)); } else if (type == TYPE_CELLULAR) { if (cellular_enabled()) cellular_networks_.push_back(static_cast<CellularNetwork*>(network)); } else if (type == TYPE_VPN) { virtual_networks_.push_back(static_cast<VirtualNetwork*>(network)); } // Do not set the active network here. Wait until we parse the network. } // This only gets called when NetworkServiceUpdate receives a NULL update // for an existing network, e.g. an error occurred while fetching a network. void DeleteNetwork(const std::string& service_path) { NetworkMap::iterator found = network_map_.find(service_path); if (found == network_map_.end()) { // This occurs when we receive an update request followed by a disconnect // which triggers another update. See UpdateNetworkServiceList. return; } Network* network = found->second; network_map_.erase(found); if (!network->unique_id().empty()) network_unique_id_map_.erase(network->unique_id()); ConnectionType type(network->type()); if (type == TYPE_ETHERNET) { if (network == ethernet_) { // This should never happen. LOG(ERROR) << "Deleting active ethernet network: " << service_path; ethernet_ = NULL; } } else if (type == TYPE_WIFI) { WifiNetworkVector::iterator iter = std::find( wifi_networks_.begin(), wifi_networks_.end(), network); if (iter != wifi_networks_.end()) wifi_networks_.erase(iter); if (network == active_wifi_) { // This should never happen. LOG(ERROR) << "Deleting active wifi network: " << service_path; active_wifi_ = NULL; } } else if (type == TYPE_CELLULAR) { CellularNetworkVector::iterator iter = std::find( cellular_networks_.begin(), cellular_networks_.end(), network); if (iter != cellular_networks_.end()) cellular_networks_.erase(iter); if (network == active_cellular_) { // This should never happen. LOG(ERROR) << "Deleting active cellular network: " << service_path; active_cellular_ = NULL; } // Find and delete any existing data plans associated with |service_path|. CellularDataPlanMap::iterator found = data_plan_map_.find(service_path); if (found != data_plan_map_.end()) { CellularDataPlanVector* data_plans = found->second; delete data_plans; data_plan_map_.erase(found); } } else if (type == TYPE_VPN) { VirtualNetworkVector::iterator iter = std::find( virtual_networks_.begin(), virtual_networks_.end(), network); if (iter != virtual_networks_.end()) virtual_networks_.erase(iter); if (network == active_virtual_) { // This should never happen. LOG(ERROR) << "Deleting active virtual network: " << service_path; active_virtual_ = NULL; } } delete network; } void AddRememberedWifiNetwork(WifiNetwork* wifi) { std::pair<NetworkMap::iterator,bool> result = remembered_network_map_.insert( std::make_pair(wifi->service_path(), wifi)); DCHECK(result.second); // Should only get called with new network. remembered_wifi_networks_.push_back(wifi); } void DeleteRememberedWifiNetwork(const std::string& service_path) { NetworkMap::iterator found = remembered_network_map_.find(service_path); if (found == remembered_network_map_.end()) { LOG(WARNING) << "Attempt to delete non-existant remembered network: " << service_path; return; } Network* remembered_network = found->second; remembered_network_map_.erase(found); WifiNetworkVector::iterator iter = std::find( remembered_wifi_networks_.begin(), remembered_wifi_networks_.end(), remembered_network); if (iter != remembered_wifi_networks_.end()) remembered_wifi_networks_.erase(iter); Network* network = FindNetworkFromRemembered(remembered_network); if (network && network->type() == TYPE_WIFI) { // Clear the stored credentials for any visible forgotten networks. WifiNetwork* wifi = static_cast<WifiNetwork*>(network); wifi->EraseCredentials(); } else { // Network is not in visible list. VLOG(2) << "Remembered Network not found: " << remembered_network->unique_id(); } delete remembered_network; } // Update all network lists, and request associated service updates. void UpdateNetworkServiceList(const ListValue* services) { // TODO(stevenjb): Wait for wifi_scanning_ to be false. // Copy the list of existing networks to "old" and clear the map and lists. NetworkMap old_network_map = network_map_; ClearNetworks(false /*don't delete*/); // Clear the list of update requests. int network_priority_order = 0; network_update_requests_.clear(); // wifi_scanning_ will remain false unless we request a network update. wifi_scanning_ = false; // |services| represents a complete list of visible networks. for (ListValue::const_iterator iter = services->begin(); iter != services->end(); ++iter) { std::string service_path; (*iter)->GetAsString(&service_path); if (!service_path.empty()) { // If we find the network in "old", add it immediately to the map // and lists. Otherwise it will get added when NetworkServiceUpdate // calls ParseNetwork. NetworkMap::iterator found = old_network_map.find(service_path); if (found != old_network_map.end()) { AddNetwork(found->second); old_network_map.erase(found); } // Always request network updates. // TODO(stevenjb): Investigate why we are missing updates then // rely on watched network updates and only request updates here for // new networks. // Use update_request map to store network priority. network_update_requests_[service_path] = network_priority_order++; wifi_scanning_ = true; RequestNetworkServiceInfo(service_path.c_str(), &NetworkServiceUpdate, this); } } // Delete any old networks that no longer exist. for (NetworkMap::iterator iter = old_network_map.begin(); iter != old_network_map.end(); ++iter) { delete iter->second; } } // Request updates for watched networks. Does not affect network lists. // Existing networks will be updated. There should not be any new networks // in this list, but if there are they will be added appropriately. void UpdateWatchedNetworkServiceList(const ListValue* services) { for (ListValue::const_iterator iter = services->begin(); iter != services->end(); ++iter) { std::string service_path; (*iter)->GetAsString(&service_path); if (!service_path.empty()) { VLOG(1) << "Watched Service: " << service_path; RequestNetworkServiceInfo( service_path.c_str(), &NetworkServiceUpdate, this); } } } // Request the active profile which lists the remembered networks. void RequestRememberedNetworksUpdate() { if (!active_profile_path_.empty()) { RequestNetworkProfile( active_profile_path_.c_str(), &ProfileUpdate, this); } } // Update the list of remembered (profile) networks, and request associated // service updates. void UpdateRememberedServiceList(const char* profile_path, const ListValue* profile_entries) { // Copy the list of existing networks to "old" and clear the map and list. NetworkMap old_network_map = remembered_network_map_; ClearRememberedNetworks(false /*don't delete*/); // |profile_entries| represents a complete list of remembered networks. for (ListValue::const_iterator iter = profile_entries->begin(); iter != profile_entries->end(); ++iter) { std::string service_path; (*iter)->GetAsString(&service_path); if (!service_path.empty()) { // If we find the network in "old", add it immediately to the map // and list. Otherwise it will get added when // RememberedNetworkServiceUpdate calls ParseRememberedNetwork. NetworkMap::iterator found = old_network_map.find(service_path); if (found != old_network_map.end()) { Network* network = found->second; if (network->type() == TYPE_WIFI) { WifiNetwork* wifi = static_cast<WifiNetwork*>(network); AddRememberedWifiNetwork(wifi); old_network_map.erase(found); } } // Always request updates for remembered networks. RequestNetworkProfileEntry(profile_path, service_path.c_str(), &RememberedNetworkServiceUpdate, this); } } // Delete any old networks that no longer exist. for (NetworkMap::iterator iter = old_network_map.begin(); iter != old_network_map.end(); ++iter) { delete iter->second; } } Network* CreateNewNetwork(ConnectionType type, const std::string& service_path) { switch (type) { case TYPE_ETHERNET: { EthernetNetwork* ethernet = new EthernetNetwork(service_path); return ethernet; } case TYPE_WIFI: { WifiNetwork* wifi = new WifiNetwork(service_path); return wifi; } case TYPE_CELLULAR: { CellularNetwork* cellular = new CellularNetwork(service_path); return cellular; } case TYPE_VPN: { VirtualNetwork* vpn = new VirtualNetwork(service_path); return vpn; } default: { LOG(WARNING) << "Unknown service type: " << type; return new Network(service_path, type); } } } Network* ParseNetwork(const std::string& service_path, const DictionaryValue* info) { Network* network = FindNetworkByPath(service_path); if (!network) { ConnectionType type = ParseTypeFromDictionary(info); network = CreateNewNetwork(type, service_path); AddNetwork(network); } // Erase entry from network_unique_id_map_ in case unique id changes. if (!network->unique_id().empty()) network_unique_id_map_.erase(network->unique_id()); network->ParseInfo(info); // virtual. if (!network->unique_id().empty()) network_unique_id_map_[network->unique_id()] = network; UpdateActiveNetwork(network); // Find and erase entry in update_requests, and set network priority. PriorityMap::iterator found2 = network_update_requests_.find(service_path); if (found2 != network_update_requests_.end()) { network->priority_order_ = found2->second; network_update_requests_.erase(found2); if (network_update_requests_.empty()) { // Clear wifi_scanning_ when we have no pending requests. wifi_scanning_ = false; } } else { // TODO(stevenjb): Enable warning once UpdateNetworkServiceList is fixed. // LOG(WARNING) << "ParseNetwork called with no update request entry: " // << service_path; } VLOG(1) << "ParseNetwork: " << network->name(); NotifyNetworkManagerChanged(false); // Not forced. return network; } // Returns NULL if |service_path| refers to a network that is not a // remembered type. Network* ParseRememberedNetwork(const std::string& service_path, const DictionaryValue* info) { Network* network; NetworkMap::iterator found = remembered_network_map_.find(service_path); if (found != remembered_network_map_.end()) { network = found->second; } else { ConnectionType type = ParseTypeFromDictionary(info); if (type == TYPE_WIFI) { network = CreateNewNetwork(type, service_path); WifiNetwork* wifi = static_cast<WifiNetwork*>(network); AddRememberedWifiNetwork(wifi); } else { VLOG(1) << "Ignoring remembered network: " << service_path << " Type: " << ConnectionTypeToString(type); return NULL; } } network->ParseInfo(info); // virtual. VLOG(1) << "ParseRememberedNetwork: " << network->name(); NotifyNetworkManagerChanged(false); // Not forced. return network; } void ClearNetworks(bool delete_networks) { if (delete_networks) STLDeleteValues(&network_map_); network_map_.clear(); network_unique_id_map_.clear(); ethernet_ = NULL; active_wifi_ = NULL; active_cellular_ = NULL; active_virtual_ = NULL; wifi_networks_.clear(); cellular_networks_.clear(); virtual_networks_.clear(); } void ClearRememberedNetworks(bool delete_networks) { if (delete_networks) STLDeleteValues(&remembered_network_map_); remembered_network_map_.clear(); remembered_wifi_networks_.clear(); } //////////////////////////////////////////////////////////////////////////// // NetworkDevice list management functions. // Returns pointer to device or NULL if device is not found by path. // Use FindNetworkDeviceByPath when you're not intending to change device. NetworkDevice* GetNetworkDeviceByPath(const std::string& path) { NetworkDeviceMap::iterator iter = device_map_.find(path); if (iter != device_map_.end()) return iter->second; LOG(WARNING) << "Device path not found: " << path; return NULL; } // Update device list, and request associated device updates. // |devices| represents a complete list of devices. void UpdateNetworkDeviceList(const ListValue* devices) { NetworkDeviceMap old_device_map = device_map_; device_map_.clear(); VLOG(2) << "Updating Device List."; for (ListValue::const_iterator iter = devices->begin(); iter != devices->end(); ++iter) { std::string device_path; (*iter)->GetAsString(&device_path); if (!device_path.empty()) { NetworkDeviceMap::iterator found = old_device_map.find(device_path); if (found != old_device_map.end()) { VLOG(2) << " Adding existing device: " << device_path; device_map_[device_path] = found->second; old_device_map.erase(found); } RequestNetworkDeviceInfo( device_path.c_str(), &NetworkDeviceUpdate, this); } } // Delete any old devices that no longer exist. for (NetworkDeviceMap::iterator iter = old_device_map.begin(); iter != old_device_map.end(); ++iter) { DeleteDeviceFromDeviceObserversMap(iter->first); // Delete device. delete iter->second; } } void DeleteDeviceFromDeviceObserversMap(const std::string& device_path) { // Delete all device observers associated with this device. NetworkDeviceObserverMap::iterator map_iter = network_device_observers_.find(device_path); if (map_iter != network_device_observers_.end()) { delete map_iter->second; network_device_observers_.erase(map_iter); } } void DeleteDevice(const std::string& device_path) { NetworkDeviceMap::iterator found = device_map_.find(device_path); if (found == device_map_.end()) { LOG(WARNING) << "Attempt to delete non-existant device: " << device_path; return; } VLOG(2) << " Deleting device: " << device_path; NetworkDevice* device = found->second; device_map_.erase(found); DeleteDeviceFromDeviceObserversMap(device_path); delete device; } void ParseNetworkDevice(const std::string& device_path, const DictionaryValue* info) { NetworkDeviceMap::iterator found = device_map_.find(device_path); NetworkDevice* device; if (found != device_map_.end()) { device = found->second; } else { device = new NetworkDevice(device_path); VLOG(2) << " Adding device: " << device_path; device_map_[device_path] = device; if (network_device_observers_.find(device_path) == network_device_observers_.end()) { network_device_observers_[device_path] = new NetworkDeviceObserverList(this, device_path); } } device->ParseInfo(info); VLOG(1) << "ParseNetworkDevice:" << device->name(); NotifyNetworkManagerChanged(false); // Not forced. } //////////////////////////////////////////////////////////////////////////// void EnableNetworkDeviceType(ConnectionType device, bool enable) { if (!EnsureCrosLoaded()) return; // If network device is already enabled/disabled, then don't do anything. if (enable && (enabled_devices_ & (1 << device))) { LOG(WARNING) << "Trying to enable a device that's already enabled: " << device; return; } if (!enable && !(enabled_devices_ & (1 << device))) { LOG(WARNING) << "Trying to disable a device that's already disabled: " << device; return; } RequestNetworkDeviceEnable(ConnectionTypeToString(device), enable); } //////////////////////////////////////////////////////////////////////////// // Notifications. // We call this any time something in NetworkLibrary changes. // TODO(stevenjb): We should consider breaking this into multiple // notifications, e.g. connection state, devices, services, etc. void NotifyNetworkManagerChanged(bool force_update) { CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); // Cancel any pending signals. if (notify_task_) { notify_task_->Cancel(); notify_task_ = NULL; } if (force_update) { // Signal observers now. SignalNetworkManagerObservers(); } else { // Schedule a deleayed signal to limit the frequency of notifications. notify_task_ = NewRunnableMethod( this, &NetworkLibraryImpl::SignalNetworkManagerObservers); BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE, notify_task_, kNetworkNotifyDelayMs); } } void SignalNetworkManagerObservers() { notify_task_ = NULL; FOR_EACH_OBSERVER(NetworkManagerObserver, network_manager_observers_, OnNetworkManagerChanged(this)); } void NotifyNetworkChanged(Network* network) { VLOG(2) << "Network changed: " << network->name(); DCHECK(network); NetworkObserverMap::const_iterator iter = network_observers_.find( network->service_path()); if (iter != network_observers_.end()) { FOR_EACH_OBSERVER(NetworkObserver, *(iter->second), OnNetworkChanged(this, network)); } else { NOTREACHED() << "There weren't supposed to be any property change observers of " << network->service_path(); } } void NotifyNetworkDeviceChanged(NetworkDevice* device) { DCHECK(device); NetworkDeviceObserverMap::const_iterator iter = network_device_observers_.find(device->device_path()); if (iter != network_device_observers_.end()) { NetworkDeviceObserverList* device_observer_list = iter->second; FOR_EACH_OBSERVER(NetworkDeviceObserver, *device_observer_list, OnNetworkDeviceChanged(this, device)); } else { NOTREACHED() << "There weren't supposed to be any property change observers of " << device->device_path(); } } void NotifyCellularDataPlanChanged() { FOR_EACH_OBSERVER(CellularDataPlanObserver, data_plan_observers_, OnCellularDataPlanChanged(this)); } void NotifyPinOperationCompleted(PinOperationError error) { FOR_EACH_OBSERVER(PinOperationObserver, pin_operation_observers_, OnPinOperationCompleted(this, error)); sim_operation_ = SIM_OPERATION_NONE; } void NotifyUserConnectionInitiated(const Network* network) { FOR_EACH_OBSERVER(UserActionObserver, user_action_observers_, OnConnectionInitiated(this, network)); } //////////////////////////////////////////////////////////////////////////// // Device updates. void FlipSimPinRequiredStateIfNeeded() { if (sim_operation_ != SIM_OPERATION_CHANGE_REQUIRE_PIN) return; const NetworkDevice* cellular = FindCellularDevice(); if (cellular) { NetworkDevice* device = GetNetworkDeviceByPath(cellular->device_path()); if (device->sim_pin_required() == SIM_PIN_NOT_REQUIRED) device->sim_pin_required_ = SIM_PIN_REQUIRED; else if (device->sim_pin_required() == SIM_PIN_REQUIRED) device->sim_pin_required_ = SIM_PIN_NOT_REQUIRED; } } void UpdateNetworkDeviceStatus(const char* path, const char* key, const Value* value) { CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); if (key == NULL || value == NULL) return; NetworkDevice* device = GetNetworkDeviceByPath(path); if (device) { VLOG(1) << "UpdateNetworkDeviceStatus: " << device->name() << "." << key; int index = property_index_parser().Get(std::string(key)); if (!device->ParseValue(index, value)) { LOG(WARNING) << "UpdateNetworkDeviceStatus: Error parsing: " << path << "." << key; } else if (strcmp(key, kCellularAllowRoamingProperty) == 0) { bool settings_value = UserCrosSettingsProvider::cached_data_roaming_enabled(); if (device->data_roaming_allowed() != settings_value) { // Switch back to signed settings value. SetCellularDataRoamingAllowed(settings_value); return; } } // Notify only observers on device property change. NotifyNetworkDeviceChanged(device); // If a device's power state changes, new properties may become // defined. if (strcmp(key, kPoweredProperty) == 0) { RequestNetworkDeviceInfo(path, &NetworkDeviceUpdate, this); } } } //////////////////////////////////////////////////////////////////////////// // Service updates. void UpdateNetworkStatus(const char* path, const char* key, const Value* value) { CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); if (key == NULL || value == NULL) return; Network* network = FindNetworkByPath(path); if (network) { VLOG(2) << "UpdateNetworkStatus: " << network->name() << "." << key; // Note: ParseValue is virtual. int index = property_index_parser().Get(std::string(key)); if (!network->ParseValue(index, value)) { LOG(WARNING) << "UpdateNetworkStatus: Error parsing: " << path << "." << key; } NotifyNetworkChanged(network); // Anything observing the manager needs to know about any service change. NotifyNetworkManagerChanged(false); // Not forced. } } //////////////////////////////////////////////////////////////////////////// // Data Plans. const CellularDataPlan* GetSignificantDataPlanFromVector( const CellularDataPlanVector* plans) const { const CellularDataPlan* significant = NULL; for (CellularDataPlanVector::const_iterator iter = plans->begin(); iter != plans->end(); ++iter) { // Set significant to the first plan or to first non metered base plan. if (significant == NULL || significant->plan_type == CELLULAR_DATA_PLAN_METERED_BASE) significant = *iter; } return significant; } CellularNetwork::DataLeft GetDataLeft( CellularDataPlanVector* data_plans) { const CellularDataPlan* plan = GetSignificantDataPlanFromVector(data_plans); if (!plan) return CellularNetwork::DATA_UNKNOWN; if (plan->plan_type == CELLULAR_DATA_PLAN_UNLIMITED) { base::TimeDelta remaining = plan->remaining_time(); if (remaining <= base::TimeDelta::FromSeconds(0)) return CellularNetwork::DATA_NONE; if (remaining <= base::TimeDelta::FromSeconds(kCellularDataVeryLowSecs)) return CellularNetwork::DATA_VERY_LOW; if (remaining <= base::TimeDelta::FromSeconds(kCellularDataLowSecs)) return CellularNetwork::DATA_LOW; return CellularNetwork::DATA_NORMAL; } else if (plan->plan_type == CELLULAR_DATA_PLAN_METERED_PAID || plan->plan_type == CELLULAR_DATA_PLAN_METERED_BASE) { int64 remaining = plan->remaining_data(); if (remaining <= 0) return CellularNetwork::DATA_NONE; if (remaining <= kCellularDataVeryLowBytes) return CellularNetwork::DATA_VERY_LOW; // For base plans, we do not care about low data. if (remaining <= kCellularDataLowBytes && plan->plan_type != CELLULAR_DATA_PLAN_METERED_BASE) return CellularNetwork::DATA_LOW; return CellularNetwork::DATA_NORMAL; } return CellularNetwork::DATA_UNKNOWN; } void UpdateCellularDataPlan(const std::string& service_path, const CellularDataPlanList* data_plan_list) { VLOG(1) << "Updating cellular data plans for: " << service_path; CellularDataPlanVector* data_plans = NULL; // Find and delete any existing data plans associated with |service_path|. CellularDataPlanMap::iterator found = data_plan_map_.find(service_path); if (found != data_plan_map_.end()) { data_plans = found->second; data_plans->reset(); // This will delete existing data plans. } else { data_plans = new CellularDataPlanVector; data_plan_map_[service_path] = data_plans; } for (size_t i = 0; i < data_plan_list->plans_size; i++) { const CellularDataPlanInfo* info(data_plan_list->GetCellularDataPlan(i)); CellularDataPlan* plan = new CellularDataPlan(*info); data_plans->push_back(plan); VLOG(2) << " Plan: " << plan->GetPlanDesciption() << " : " << plan->GetDataRemainingDesciption(); } // Now, update any matching cellular network's cached data CellularNetwork* cellular = FindCellularNetworkByPath(service_path); if (cellular) { CellularNetwork::DataLeft data_left; // If the network needs a new plan, then there's no data. if (cellular->needs_new_plan()) data_left = CellularNetwork::DATA_NONE; else data_left = GetDataLeft(data_plans); VLOG(2) << " Data left: " << data_left << " Need plan: " << cellular->needs_new_plan(); cellular->set_data_left(data_left); } NotifyCellularDataPlanChanged(); } //////////////////////////////////////////////////////////////////////////// void Init() { // First, get the currently available networks. This data is cached // on the connman side, so the call should be quick. if (EnsureCrosLoaded()) { VLOG(1) << "Requesting initial network manager info from libcros."; RequestNetworkManagerInfo(&NetworkManagerUpdate, this); } } void InitTestData() { is_locked_ = false; // Devices int devices = (1 << TYPE_ETHERNET) | (1 << TYPE_WIFI) | (1 << TYPE_CELLULAR); available_devices_ = devices; enabled_devices_ = devices; connected_devices_ = devices; NetworkDevice* cellular = new NetworkDevice("cellular"); scoped_ptr<Value> cellular_type(Value::CreateStringValue(kTypeCellular)); cellular->ParseValue(PROPERTY_INDEX_TYPE, cellular_type.get()); cellular->IMSI_ = "123456789012345"; device_map_["cellular"] = cellular; // Networks ClearNetworks(true /*delete networks*/); ethernet_ = new EthernetNetwork("eth1"); ethernet_->set_connected(true); AddNetwork(ethernet_); WifiNetwork* wifi1 = new WifiNetwork("fw1"); wifi1->set_name("Fake Wifi Connected"); wifi1->set_strength(90); wifi1->set_connected(true); wifi1->set_active(true); wifi1->set_encryption(SECURITY_NONE); AddNetwork(wifi1); WifiNetwork* wifi2 = new WifiNetwork("fw2"); wifi2->set_name("Fake Wifi"); wifi2->set_strength(70); wifi2->set_connected(false); wifi2->set_encryption(SECURITY_NONE); AddNetwork(wifi2); WifiNetwork* wifi3 = new WifiNetwork("fw3"); wifi3->set_name("Fake Wifi Encrypted"); wifi3->set_strength(60); wifi3->set_connected(false); wifi3->set_encryption(SECURITY_WEP); wifi3->set_passphrase_required(true); AddNetwork(wifi3); WifiNetwork* wifi4 = new WifiNetwork("fw4"); wifi4->set_name("Fake Wifi 802.1x"); wifi4->set_strength(50); wifi4->set_connected(false); wifi4->set_connectable(false); wifi4->set_encryption(SECURITY_8021X); wifi4->set_identity("nobody@google.com"); wifi4->set_cert_path("SETTINGS:key_id=3,cert_id=3,pin=111111"); AddNetwork(wifi4); WifiNetwork* wifi5 = new WifiNetwork("fw5"); wifi5->set_name("Fake Wifi UTF-8 SSID "); wifi5->SetSsid("Fake Wifi UTF-8 SSID \u3042\u3044\u3046"); wifi5->set_strength(25); wifi5->set_connected(false); AddNetwork(wifi5); WifiNetwork* wifi6 = new WifiNetwork("fw6"); wifi6->set_name("Fake Wifi latin-1 SSID "); wifi6->SetSsid("Fake Wifi latin-1 SSID \xc0\xcb\xcc\xd6\xfb"); wifi6->set_strength(20); wifi6->set_connected(false); AddNetwork(wifi6); active_wifi_ = wifi1; CellularNetwork* cellular1 = new CellularNetwork("fc1"); cellular1->set_name("Fake Cellular"); cellular1->set_strength(70); cellular1->set_connected(true); cellular1->set_active(true); cellular1->set_activation_state(ACTIVATION_STATE_ACTIVATED); cellular1->set_payment_url(std::string("http://www.google.com")); cellular1->set_usage_url(std::string("http://www.google.com")); cellular1->set_network_technology(NETWORK_TECHNOLOGY_EVDO); cellular1->set_roaming_state(ROAMING_STATE_ROAMING); CellularDataPlan* base_plan = new CellularDataPlan(); base_plan->plan_name = "Base plan"; base_plan->plan_type = CELLULAR_DATA_PLAN_METERED_BASE; base_plan->plan_data_bytes = 100ll * 1024 * 1024; base_plan->data_bytes_used = 75ll * 1024 * 1024; CellularDataPlanVector* data_plans = new CellularDataPlanVector(); data_plan_map_[cellular1->service_path()] = data_plans; data_plans->push_back(base_plan); CellularDataPlan* paid_plan = new CellularDataPlan(); paid_plan->plan_name = "Paid plan"; paid_plan->plan_type = CELLULAR_DATA_PLAN_METERED_PAID; paid_plan->plan_data_bytes = 5ll * 1024 * 1024 * 1024; paid_plan->data_bytes_used = 3ll * 1024 * 1024 * 1024; data_plans->push_back(paid_plan); AddNetwork(cellular1); active_cellular_ = cellular1; CellularNetwork* cellular2 = new CellularNetwork("fc2"); cellular2->set_name("Fake Cellular 2"); cellular2->set_strength(70); cellular2->set_connected(true); cellular2->set_activation_state(ACTIVATION_STATE_ACTIVATED); cellular2->set_network_technology(NETWORK_TECHNOLOGY_UMTS); AddNetwork(cellular2); // Remembered Networks ClearRememberedNetworks(true /*delete networks*/); WifiNetwork* remembered_wifi2 = new WifiNetwork("fw2"); remembered_wifi2->set_name("Fake Wifi 2"); remembered_wifi2->set_strength(70); remembered_wifi2->set_connected(true); remembered_wifi2->set_encryption(SECURITY_WEP); AddRememberedWifiNetwork(remembered_wifi2); // VPNs. VirtualNetwork* vpn1 = new VirtualNetwork("fv1"); vpn1->set_name("Fake VPN Provider 1"); vpn1->set_server_hostname("vpn1server.fake.com"); vpn1->set_provider_type(VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_PSK); vpn1->set_username("VPN User 1"); vpn1->set_connected(false); AddNetwork(vpn1); VirtualNetwork* vpn2 = new VirtualNetwork("fv2"); vpn2->set_name("Fake VPN Provider 2"); vpn2->set_server_hostname("vpn2server.fake.com"); vpn2->set_provider_type(VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_USER_CERT); vpn2->set_username("VPN User 2"); vpn2->set_connected(true); AddNetwork(vpn2); VirtualNetwork* vpn3 = new VirtualNetwork("fv3"); vpn3->set_name("Fake VPN Provider 3"); vpn3->set_server_hostname("vpn3server.fake.com"); vpn3->set_provider_type(VirtualNetwork::PROVIDER_TYPE_OPEN_VPN); vpn3->set_connected(false); AddNetwork(vpn3); active_virtual_ = vpn2; wifi_scanning_ = false; offline_mode_ = false; } // Network manager observer list ObserverList<NetworkManagerObserver> network_manager_observers_; // Cellular data plan observer list ObserverList<CellularDataPlanObserver> data_plan_observers_; // PIN operation observer list. ObserverList<PinOperationObserver> pin_operation_observers_; // User action observer list ObserverList<UserActionObserver> user_action_observers_; // Network observer map NetworkObserverMap network_observers_; // Network device observer map. NetworkDeviceObserverMap network_device_observers_; // For monitoring network manager status changes. PropertyChangeMonitor network_manager_monitor_; // For monitoring data plan changes to the connected cellular network. DataPlanUpdateMonitor data_plan_monitor_; // Network login observer. scoped_ptr<NetworkLoginObserver> network_login_observer_; // A service path based map of all Networks. NetworkMap network_map_; // A unique_id_ based map of Networks. NetworkMap network_unique_id_map_; // A service path based map of all remembered Networks. NetworkMap remembered_network_map_; // A list of services that we are awaiting updates for. PriorityMap network_update_requests_; // A device path based map of all NetworkDevices. NetworkDeviceMap device_map_; // A network service path based map of all CellularDataPlanVectors. CellularDataPlanMap data_plan_map_; // The ethernet network. EthernetNetwork* ethernet_; // The list of available wifi networks. WifiNetworkVector wifi_networks_; // The current connected (or connecting) wifi network. WifiNetwork* active_wifi_; // The remembered wifi networks. WifiNetworkVector remembered_wifi_networks_; // The list of available cellular networks. CellularNetworkVector cellular_networks_; // The current connected (or connecting) cellular network. CellularNetwork* active_cellular_; // The list of available virtual networks. VirtualNetworkVector virtual_networks_; // The current connected (or connecting) virtual network. VirtualNetwork* active_virtual_; // The path of the active profile (for retrieving remembered services). std::string active_profile_path_; // The current available network devices. Bitwise flag of ConnectionTypes. int available_devices_; // The current enabled network devices. Bitwise flag of ConnectionTypes. int enabled_devices_; // The current connected network devices. Bitwise flag of ConnectionTypes. int connected_devices_; // True if we are currently scanning for wifi networks. bool wifi_scanning_; // Currently not implemented. TODO: implement or eliminate. bool offline_mode_; // True if access network library is locked. bool is_locked_; // Type of pending SIM operation, SIM_OPERATION_NONE otherwise. SimOperationType sim_operation_; // Delayed task to notify a network change. CancelableTask* notify_task_; // Cellular plan payment time. base::Time cellular_plan_payment_time_; // Temporary connection data for async connect calls. struct ConnectData { std::string service_name; std::string passphrase; std::string identity; std::string cert_path; std::string psk_key; std::string server_hostname; }; ConnectData connect_data_; DISALLOW_COPY_AND_ASSIGN(NetworkLibraryImpl); }; class NetworkLibraryStubImpl : public NetworkLibrary { public: NetworkLibraryStubImpl() : ip_address_("1.1.1.1"), ethernet_(new EthernetNetwork("eth0")), active_wifi_(NULL), active_cellular_(NULL) { } ~NetworkLibraryStubImpl() { if (ethernet_) delete ethernet_; } virtual void AddNetworkManagerObserver(NetworkManagerObserver* observer) {} virtual void RemoveNetworkManagerObserver(NetworkManagerObserver* observer) {} virtual void AddNetworkObserver(const std::string& service_path, NetworkObserver* observer) {} virtual void RemoveNetworkObserver(const std::string& service_path, NetworkObserver* observer) {} virtual void RemoveObserverForAllNetworks(NetworkObserver* observer) {} virtual void AddNetworkDeviceObserver(const std::string& device_path, NetworkDeviceObserver* observer) {} virtual void RemoveNetworkDeviceObserver(const std::string& device_path, NetworkDeviceObserver* observer) {} virtual void Lock() {} virtual void Unlock() {} virtual bool IsLocked() { return false; } virtual void AddCellularDataPlanObserver( CellularDataPlanObserver* observer) {} virtual void RemoveCellularDataPlanObserver( CellularDataPlanObserver* observer) {} virtual void AddPinOperationObserver(PinOperationObserver* observer) {} virtual void RemovePinOperationObserver(PinOperationObserver* observer) {} virtual void AddUserActionObserver(UserActionObserver* observer) {} virtual void RemoveUserActionObserver(UserActionObserver* observer) {} virtual const EthernetNetwork* ethernet_network() const { return ethernet_; } virtual bool ethernet_connecting() const { return false; } virtual bool ethernet_connected() const { return true; } virtual const WifiNetwork* wifi_network() const { return active_wifi_; } virtual bool wifi_connecting() const { return false; } virtual bool wifi_connected() const { return false; } virtual const CellularNetwork* cellular_network() const { return active_cellular_; } virtual bool cellular_connecting() const { return false; } virtual bool cellular_connected() const { return false; } virtual const VirtualNetwork* virtual_network() const { return active_virtual_; } virtual bool virtual_network_connecting() const { return false; } virtual bool virtual_network_connected() const { return false; } bool Connected() const { return true; } bool Connecting() const { return false; } const std::string& IPAddress() const { return ip_address_; } virtual const WifiNetworkVector& wifi_networks() const { return wifi_networks_; } virtual const WifiNetworkVector& remembered_wifi_networks() const { return wifi_networks_; } virtual const CellularNetworkVector& cellular_networks() const { return cellular_networks_; } virtual const VirtualNetworkVector& virtual_networks() const { return virtual_networks_; } virtual bool has_cellular_networks() const { return cellular_networks_.begin() != cellular_networks_.end(); } ///////////////////////////////////////////////////////////////////////////// virtual const NetworkDevice* FindNetworkDeviceByPath( const std::string& path) const { return NULL; } virtual const NetworkDevice* FindCellularDevice() const { return NULL; } virtual const NetworkDevice* FindEthernetDevice() const { return NULL; } virtual const NetworkDevice* FindWifiDevice() const { return NULL; } virtual Network* FindNetworkByPath( const std::string& path) const { return NULL; } virtual WifiNetwork* FindWifiNetworkByPath( const std::string& path) const { return NULL; } virtual CellularNetwork* FindCellularNetworkByPath( const std::string& path) const { return NULL; } virtual VirtualNetwork* FindVirtualNetworkByPath( const std::string& path) const { return NULL; } virtual Network* FindNetworkFromRemembered( const Network* remembered) const { return NULL; } virtual const CellularDataPlanVector* GetDataPlans( const std::string& path) const { return NULL; } virtual const CellularDataPlan* GetSignificantDataPlan( const std::string& path) const { return NULL; } virtual void ChangePin(const std::string& old_pin, const std::string& new_pin) {} virtual void ChangeRequirePin(bool require_pin, const std::string& pin) {} virtual void EnterPin(const std::string& pin) {} virtual void UnblockPin(const std::string& puk, const std::string& new_pin) {} virtual void RequestCellularScan() {} virtual void RequestCellularRegister(const std::string& network_id) {} virtual void SetCellularDataRoamingAllowed(bool new_value) {} virtual void RequestNetworkScan() {} virtual bool GetWifiAccessPoints(WifiAccessPointVector* result) { return false; } virtual void ConnectToWifiNetwork(WifiNetwork* network) {} virtual void ConnectToWifiNetwork(const std::string& service_path) {} virtual void ConnectToWifiNetwork(ConnectionSecurity security, const std::string& ssid, const std::string& passphrase, const std::string& identity, const std::string& certpath) {} virtual void ConnectToCellularNetwork(CellularNetwork* network) {} virtual void ConnectToVirtualNetwork(VirtualNetwork* network) {} virtual void ConnectToVirtualNetworkPSK( const std::string& service_name, const std::string& server, const std::string& psk, const std::string& username, const std::string& user_passphrase) {} virtual void SignalCellularPlanPayment() {} virtual bool HasRecentCellularPlanPayment() { return false; } virtual void DisconnectFromNetwork(const Network* network) {} virtual void ForgetWifiNetwork(const std::string& service_path) {} virtual std::string GetCellularHomeCarrierId() const { return std::string(); } virtual bool ethernet_available() const { return true; } virtual bool wifi_available() const { return false; } virtual bool cellular_available() const { return false; } virtual bool ethernet_enabled() const { return true; } virtual bool wifi_enabled() const { return false; } virtual bool cellular_enabled() const { return false; } virtual bool wifi_scanning() const { return false; } virtual const Network* active_network() const { return NULL; } virtual const Network* connected_network() const { return NULL; } virtual bool offline_mode() const { return false; } virtual void EnableEthernetNetworkDevice(bool enable) {} virtual void EnableWifiNetworkDevice(bool enable) {} virtual void EnableCellularNetworkDevice(bool enable) {} virtual void EnableOfflineMode(bool enable) {} virtual NetworkIPConfigVector GetIPConfigs(const std::string& device_path, std::string* hardware_address, HardwareAddressFormat) { hardware_address->clear(); return NetworkIPConfigVector(); } private: std::string ip_address_; EthernetNetwork* ethernet_; WifiNetwork* active_wifi_; CellularNetwork* active_cellular_; VirtualNetwork* active_virtual_; WifiNetworkVector wifi_networks_; CellularNetworkVector cellular_networks_; VirtualNetworkVector virtual_networks_; }; // static NetworkLibrary* NetworkLibrary::GetImpl(bool stub) { if (stub) return new NetworkLibraryStubImpl(); else return new NetworkLibraryImpl(); } } // namespace chromeos // Allows InvokeLater without adding refcounting. This class is a Singleton and // won't be deleted until it's last InvokeLater is run. DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::NetworkLibraryImpl);