Thierry Boureille <thierry.boureille@gmail.com>
Paolo Pellegrino <paolo.pellegrino@zirak.it>
Bertrand Aygon <bertrand.aygon@intel.com>
+Jeff Zheng <jeff.zheng@intel.com>
+Philippe Nunes <philippe.nunes@linux.intel.com>
+Danny Jeongseok Seo <s.seo@samsung.com>
+Manfred Kober <manfred.kober@gmx.de>
-ver 0.77.2
- connection: Default gateway is changed when reorganizing services (Fixes BMC#22540)
- network: Read only the ipconfig data if we have no address (Fixes BMC#22767)
- service: Check NULL pointer when setting ipconfig (Fixes BMC#22766)
- wifi: Implement network_changed gsupplicant hook
-
-ver 0.77.1
- ConnMan 0.77 code merge
-
-ver 0.76.2
- ofono: Network name is empty when operator is not available
- network: Set driver pointer to NULL back if not ready (Fixes BMC#21705)
- service : Fix put data on null pointer (Fixes BMC#21709)
-
-ver 0.76.1
- ConnMan 0.76 code merge
-
-ver 0.69.6
- service: Fix Manager.ConnectService D-Bus reply (Fixes BMC#14841)
- tethering: Use tether device IP as DNS server (Fixes BMC#16847)
- ntp: Fix ntpd_running return TRUE most of the time (Fixes BMC#16145)
-
-ver 0.69.5
- core: Clock and timezone implementation
-
-ver 0.69.4
- tethering: Use /proc/sys/net/bridge to detect bridge support.
- tethering: Add wifi interface to bridge after carrier on.
- tethering: Fix tethering scripts.
- main: Initial configuration support.
- dhcp: Reset IP settings upon changes.
-
-ver 0.69.3
- Initial TI shared transport plugin implementation
-
-ver 0.69.2
- Initial scan delays exponential backoff (Fixes BMC#13698)
- Fix infinite recursion in oFono network disconnect
- Do not add NULL domains to the domain list
-
-ver 0.69.1
- ConnMan 0.69 code merge
-
-ver 0.68.2
- dnsproxy: Fallback to resolv.conf if dnsproxy fails
- stats: Fix double free error
-
-ver 0.68.1
- ConnMan 0.68 code merge
-
-ver 0.67.1
- ConnMan 0.67 code merge
-
-ver 0.66.1
- ConnMan 0.66 code merge
-
-ver 0.64.2
- Already powered devices fix (Fixes BMC#10397).
- gdhcp socket initialisation fix.
- gresolv UDP socket error handling.
- oFono signal strength proper reporting.
-
-ver 0.64.1
- ConnMan 0.64 code merge
-
-ver 0.62.5
- DNS proxy fix (Fixes BMC#9960)
- Openconnect plugin security fix
-
-ver 0.62.4
- DNS proxy fix (Fixes BMC#9834)
- Technology disabling fix (Fixes BMC#8074)
- get-proxy-autoconfig fix (Fixes BMC#9178)
- WiFi plugin build fix.
-
-ver 0.62.3
- gsupplicant fixes (Fixes BMC#8750, #8792, #8324, #8363)
- supplicant fix for autoconnecting after a failure.
- Autoconnection of previously failed networks (Partly fixes BMC #8946).
- udev rfkill list traversal fix (Fixes BMC #7915).
- device fix (Fixes BMC #8075).
-
-ver 0.62.2
- Fix a session and counter memory corruption (double free).
- Create less stats file and less often.
- Initialize stats file sze properly.
-
-ver 0.62.1
- ConnMan 0.62 code merge
-
-ver 0.60.5
- Remove EDNS0 option (Fixes BMC #4818)
- Implement DNS over TCP for dnsproxy
-
-ver 0.60.4
- Do not remove wifi network upon disconnection (Fixes BMC #7730, #7734)
- Set WiFi task scanning flag when receiving a Scanning event
- Implement WiFi network driver remove hook
- RemoveProvider argument is an object path
- Remove providers based on their VPN service path
-
-ver 0.60.3
- Fix bug to remove vpn services if offline mode is on (Fixes BMC # 6591)
- Schedule delayed scan if disconnected from an AP (Fixes BMC #6831)
- Use proper definition for finding device structure
- Use __connman_device_get_service_type for getting service type
- Call remove_network() on unsolicited disconnect
- Fix ConnMan crash while disable wifi device (Fixes BMC #6772)
-
-ver 0.60.2
- Ignore Bluetooth adapter if its MAC is zeroed (Fixes BMC #6211, #6906,
- #5796)
- Handle potential NULL pointer with DHCP options
- Fix a crash when doing PEAP/TTLS authentication (Fixes BMC #6970)
-
-ver 0.60.1
- ConnMan 0.60 code merge
-
-ver 0.59.1
- ConnMan 0.59 code merge
-
-ver 0.57.3
- Save profile when enabling device while offline (Fixes BMC #5286)
-
-ver 0.57.2
- Bluetooth network removal when adapter is unplugged (Fixes BMC #5119)
- Disable technology when removing device
-
-ver 0.57.1
- ConnMan 0.57 code merge
-
-ver 0.54.4
- Always create a default profile (Fixes BMC #5024)
- Disable offline devices upon device_set_connected(TRUE) calls
- Set powered_pending from device_set_powered (Fixes BMC #3398)
- Forward device_enable() error from enable_technolgy()
- Do not try to enable a device if it's rfkill blocked (Fixes BMC #3719)
- Toggle the powered_pending device flag if op succeeds (Fixes BMC #2640)
- Use __connman_device_[enable|disable] from set_powered
- Toggle offline mode only if device enablement succeeds
- Disable offline mode when enabling a technology from offline mode
-
-ver 0.54.3
- Return html fetching error when recv returns 0 (Fixes BCM #3697)
- Fix PATH of adapter_watch in bluetooth plugin (Fixes BCM #3897)
-
-ver 0.54.2
- Fix SEGV at first startup
- Fix connman_wifi_load_ssid
- Fix crash in dhclient release
- Create service ipconfig only when it's NULL
-
-ver 0.54.1:
- ConnMan 0.54 code merge
-
-ver 0.52.1:
- Remove supplicant and device scanning state cleaning
- ofono API refactoring: Rename netreg Operator property to Name
- ConnMan 0.52 code merge
-
-ver 0.50.4:
- Remove erroneous DHCP method setting from bluetooth plugin
- Load ipconfig setting from __connman_service_create_ipconfig()
- Reset ipconfig index
- Add __connman_ipconfig_set_index() helper
- Reference PAN network before disconnecting
- Reset connman_network device pointer when it is no longer referenced
- Do not set network index from PAN disconnect reply
- ONLINE and LOGIN are also "connected" states
- Use psk for building hidden WPA SSID group
-
-ver 0.50.3:
- Enable/Disable device when toggling the powered state
- Use udev_device_get_devtype before __connman_inet_get_device_type
- Set network->device as NULL when the device is removed
-
-ver 0.50.2:
- Handle the case that MobileNetworkCodeLength is not provided.
- Correct the modem properties key name.
- Fix convert_wifi_security for psk string.
-
-ver 0.50.1:
- Export MCC and MNC for cellular services.
+ver 0.78.4
+ Apply BMC fix 24943
+
+ver 0.78.3:
+ Update ofono plugin.
+ Apply BMC fixes 24592, 23741, 23740, 24549, 24702, 24651, 24737,
+ 24712, 24942, 24965 and 25026.
+
+ver 0.78.2:
+ Backport ofono with CDMA support
+
+ver 0.78.1:
+ Rebased for connman-stable
+
+ver 0.78:
+ Fix multiple issues with service connection states.
+ Fix multiple issues with technology handling.
+ Fix issue with DHCP file descriptor leakage.
+ Fix issue with open access points and WPS.
+ Fix issue with handling of cellular devices.
+ Fix issue with DNS proxy hostname resolving.
+ Add support for PPTP and L2TP VPN tunneling.
+ Add support for organized settings storage.
+ Add support for WiFi fast connect handling.
+ Add support for better WiFi error handling.
+ Add support for integrated WISPr handling.
+
+ver 0.77:
+ Fix issue with iptables API breakage.
+ Fix issue with agent input handling.
+ Fix issue with empty cellular operator name.
+ Fix issue with reference counting for network objects.
+ Fix issue with missing D-Bus signals for proxy changes.
+ Fix issue with group identifier and hidden WiFi networks.
+ Fix issue with setting wrong gateway for PPP connections.
+ Fix issue with mismatch of stored IP configuration settings.
+ Fix issue with not stopping DHCP for IPv4 configuration.
+ Add support for remembering last IP address from DHCP.
+ Add support for EAP-GTC authentication method.
+
+ver 0.76:
+ Fix issue with loopback interface setup.
+ Fix issue with /etc/localtime being a symlink.
+ Fix issue with not handling dummy network devices.
+ Fix issue with not provisioning existing services.
+ Fix issue with running WPAD on IPv6 connections.
+ Fix issue with client certificate for TTLS/PEAP.
+ Remove internal element infrastructure.
+
+ver 0.75:
+ Fix issue with 3G connect timeout handling.
+ Fix issue with WiFi raw key PSK handling.
+ Fix issue with DHCP renewal timeout handling.
+ Fix issue with DHCP and empty nameserver list.
+ Add support for unit testing.
+
+ver 0.74:
+ Fix issue with race condition in ready/online handling.
+ Fix issue with DHCP release callback handling.
+ Fix multiple issues with session API handling.
+ Add support for using DNS proxy for Tethering.
+ Add support for Private Network API.
+ Add support for Clock API.
+
+ver 0.73:
+ Update support for session API handling.
+ Add support for more advanced roaming policies.
+ Add support for EAP identity and passphrase queries.
+ Add support for IPv6 handling with cellular bearer.
+ Add support for main configuration file.
+ Remove deprecated profile interface.
+
+ver 0.72:
+ Fix issue with overwriting DNS servers from DHCP.
+ Fix issue with DHCP renewal with same configuration.
+ Fix issue with multiple memory leaks.
+ Add support for 6to4 tunneling.
+
+ver 0.71:
+ Fix issue with not storing IPv6 privacy settings.
+ Fix issue with storing fixed and manual IP settings.
+ Fix issue with service state when PAN connection fails.
+ Fix issue with tethering and WiFi bridge handling.
+ Fix issue with autonomously activated contexts.
+ Fix issue with nameserver array for PACrunner.
+ Fix issue with network information memory leak.
+ Fix issue with double-free in statistics handling.
+ Fix issue with handling malformed profiles.
+ Fix issue with pending DHCP client requests.
+ Add initial support for TI shared transport handling.
+
+ver 0.70:
+ Add support for reporting invalid WiFi passphrases.
+ Add support for IPv6 privacy extension.
+ Add support for IPv6 advanced features.
+ Add support for IPv6 nameserver settings.
+ Remove deprecated APN service settings.
+
+ver 0.69:
+ Fix issue with not handling DNS proxy failures gracefully.
+ Fix issue with double free in statistics handling.
+ Fix issue with early tethering bridge creation.
+ Add support for tethering property per technology.
+ Add support for initial WiFi tethering feature.
+ Add support for using PACrunner as proxy driver.
+ Add support for WPS as part of the security property.
+
+ver 0.68:
+ Fix issue with wrong name of PolicyKit configuration file.
+ Fix issue with inconsistency of WiFi scan states.
+ Fix issue with missing auto-reconnect and oFono.
+ Add support for vpnc based private networks.
+ Add support for WiFi Protected Setup handling.
+ Remove legacy WiFi plugin.
+
+ver 0.67:
+ Fix issue with oFono plugin and multiple online calls.
+ Fix issue with checking for AutoConnect service property.
+ Remove deprecated MCC and MNC service properties.
+
+ver 0.66:
+ Fix multiple set of memory leaks.
+ Fix issue with WPA supplicant phase2 values.
+ Fix issue with WiFi access points after kill/restart.
+ Fix issue with correct PACrunner configuration loading.
+ Add support for loading provision files at runtime.
+ Add support for setting proxy auto-configuration.
+ Add support for IPv6 auto-configured addresses.
+
+ver 0.65:
+ Use new WiFi plugin by default.
+ Fix issue with handling already powered devices.
+ Fix issue with handling proxy PAC option from DHCP.
+ Add support for handling regulatory domain settings.
+ Add support for handling IPv6 router advertisements.
+ Add support for handling IPv6 nameservers.
+ Add support for handling multiple search domains.
+ Add support for handling oFono modem lockdown.
+ Add support for handling IPv6 DNS connections.
+ Add support for IPv4 Link-Local negotiation.
+ Add support for USB CDC Tethering functionality.
+
+ver 0.64:
+ Update service name to net.connman domain.
+ Fix issue with disabling a technology twice.
+ Fix issue with using wrong string for Proxy.Method.
+ Fix issue with TCP connection lookup and DNS proxy.
+ Fix issue with TCP receive busy waits and DNS proxy.
+ Fix various issues with WPA Supplicant interaction.
+ Add support for chunk encoding to HTTP client.
+ Add support for internal HTTP client for portal detection.
+ Add support for internal DHCP server setup.
+ Add support for internal NAT and IP forwarding setup.
+ Add support for Bluetooth Tethering functionality.
+ Remove deprecated device and network D-Bus interfaces.
+ Remove support for dhclient plugin.
+
+ver 0.63:
+ Change to use nl80211/cfg80211 WiFi management by default.
+ Fix various issues with new WPA Supplicant interface.
+ Fix issue with not connecting failed networks at boot.
+ Fix issue with properly tracking RFKILL blocked state.
+ Fix issue with missing signals for IPv4/IPv6 gateway details.
+ Add support for using RTNL for setting IPv4/IPv6 details.
+ Add support for using PHONET_PIPE GPRS interfaces.
+ Add support for setting manual proxy configurations.
+ Add support for exporting proxy configurations to PACrunner.
+ Add support for combined home and roaming statistics.
+ Add support for OpenVPN connections.
+ Remove dependency on udev.
+
+ver 0.62:
+ Fix crash with non-existent or extra DHCP result options.
+ Fix crash when doing PEAP/TTLS authentication.
+ Fix issue with handling multiple data counters.
+ Fix issue with Bluetooth adapters without address.
+ Fix issue with multiple scanning attempts after disconnects.
+ Fix issue with VPN services when switching into offline mode.
+ Add support for storing statistics information in separate files.
+ Add support for verification of configuration file parameters.
+ Add support for handling time server values from DHCP.
+ Add support for allowing DNS over TCP within the DNS proxy.
+ Add support for loading proxy configurations into PACrunner.
+ Add support for WiFi plugin using new WPA Supplicant D-Bus API.
+ Add support for requesting passphrases via agents.
+ Remove default support for EDNS0 option.
+
+ver 0.61:
+ Add support for using the internal DHCP client by default.
+ Add support for latest PolicyKit framework.
+ Add support for new oFono D-Bus interfaces.
+
+ver 0.60:
+ Fix issue with missing reset of proxy settings.
+ Fix issue with missing Ethernet property changed signal.
+ Fix issue with offline operation on already blocked devices.
+ Fix issue with offline mode and device powered changes.
+ Fix issue with portal detection and DHCP renewals.
+ Fix issue with connection attempts for removed networks.
+ Fix issue with stale pointers of networks.
+
+ver 0.59:
+ Fix issue with D-Bus object paths of VPN providers.
+
+ver 0.58:
+ Fix various issues around offline mode.
+ Fix various issues with VPN nameserver handling.
+ Add support for home/roaming network statistics.
+ Add support for EAP-TTLS WiFi configuration.
+ Add support for creating backtraces.
+
+ver 0.57:
+ Fix missing default profile creation.
+ Fix missing service integration of VPN providers.
+ Fix missing export of PAC information retrieved from DHCP.
+ Fix issue with detection of new Bluetooth devices.
+ Fix issue with offline mode handling.
+ Fix issue with device power handling.
+
+ver 0.56:
+ Fix issues with offline mode handling.
+ Fix service integration with VPN providers.
+ Add internal asynchronous resolver library.
+ Add internal DHCP client library.
+ Add support for using internal DHCP client.
+ Add support for WPAD proxy auto-configuration.
+ Add support for static IPv6 configuration.
+ Add support for DHCP provided domain names.
+ Add initial support for on-demand connections.
+ Remove uDHCP and resolvconf plugins.
+
+ver 0.55:
+ Fix issue with 3G roaming status indication.
+ Fix issue with using -H option with dhclient.
+ Fix issue with loading WiFi SSID details for scanning.
+ Add support for setting host routes for DNS servers.
+ Add support for more detailed statistics counters.
+ Add support for internal DHCP client library.
+
+ver 0.54:
+ Fix issue with root requests and EDNS0 OPT records.
+ Fix issue with default gateway when route deletion fails.
+ Fix issue with group identifiers for cellular networks.
+ Fix issue with fixed IP settings from cellular networks.
+ Fix issue with nameserver settings and manual configuration.
+ Add support for cellular network name changes.
+ Add support for cellular signal strength changes.
+ Add support for actively scanning for hidden networks.
+ Add support for ASCII based WEP keys.
+ Add support for NTP timeserver updates.
+ Add support for PPP default route settings.
+
+ver 0.53:
+ Fix issue with supplicant and device scanning state cleaning.
+ Fix issue with Bluetooth PAN networks stay in connected state.
+ Fix issue with reference counting and connected state.
+ Fix issue with technology disabling on device removal.
+ Fix issue with two default gateways when using VPN.
+ Fix issue with static IPv4 configuration and signals.
+ Add support for splitting DHCP provided nameserver results.
+ Add support multiple nameservers in /etc/resolv.conf.
+ Add support for setting manual DNS server configuration.
+ Add support for exporting IPv4 gateway information.
+ Add support for newer versions of oFono API.
+
+ver 0.52:
+ Fix issue with new "connected" states.
+ Fix issue with hidden networks and PSK.
+ Fix issue with DHCP and Bluetooth PAN.
+ Fix issue when disconnecting PAN networks.
+ Add support for application sessions.
+ Add plugin for hh2serial GPS support.
+
+ver 0.51:
+ Fix issue with missing device power toggling.
+ Fix issue with D-Bus object path on device removal.
+ Add support for WiFi portal detection.
+ Add support for configuring static gateways.
+ Remove unneeded plugin for Option HSO support.
+ Remove unneeded plugin for Ericsson MBM support.
+
+ver 0.50:
+ Fix configuration loading for unknown services.
+ Fix IP method setting of Ethernet plugin.
+
+ver 0.49:
+ Fix issue with WiFi power changes.
+ Fix issue with Bluetooth device startup.
+ Fix issue with host route settings for VPN.
+ Fix issue with processing of RFKILL events.
+ Fix some WPA Enterprise privacy issues.
+ Add support for basic Ethernet information.
+ Add support for static IP settings.
+
+ver 0.48:
+ Fix signal strength calculation when quality is not provided.
+ Fix issues with wpa_supplicant state tracking.
+ Fix faulty removal of IP address from interface.
+ Fix permissions of newly created /etc/resolv.conf file.
+ Fix DNS proxy handling when in offline mode.
+ Add support for EDNS0 resolver option.
+ Add workaround for large EDNS0 queries.
+ Add workaround for DHCP startup failures with WiFi networks.
+ Add support for handling hostnames and domainnames.
+ Add support for IPv4 configuration via service interface.
+ Add support for fixed and manual IPv4 configuration.
+ Add support for default service changed notifier.
+ Add support for clearing failure state via service removal.
+ Add support for OpenConnect VPN connections.
+ Add support for IEEE 802.1x WiFi networks.
+ Add support for roaming between WPA and WPA2 networks.
+ Add various generic D-Bus helpers and use them.
+ Remove special handling of Ethernet devices.
+
+ver 0.47:
+ Fix segmentation fault on resolver shutdown.
+ Fix issue with adding nameserver that doesn't exist.
+ Fix issue when no broadcast address is given.
+ Fix issue with missing property changed signal.
+ Add checks for invalid supplicant state transitions.
+ Add initial version of oFono GPRS support.
+ Add support for dynamic debug framework.
+
+ver 0.46:
+ Fix reconnect issue when power off or disabling the device.
+ Remove problematic retry on failure code path.
+
+ver 0.45:
+ Fix crash with connect timeout and second connect attempt.
+ Fix reconnect issues after suspend or roaming attempt.
+
+ver 0.44:
+ Fix command line options for device filtering.
+ Fix issue with network reference in MBM support.
+ Fix handling when losing network access in MBM plugin.
+ Fix broken libiWmxSDK callback parameter handling.
+ Add work around Intel WiMAX SDK API breakage.
+
+ver 0.43:
+ Fix issue with missing scanning after power up.
+ Fix issue with udev versus /dev/rfkill event processing.
+ Fix issue with powered down device on connection attempt.
+ Add support for multiple connection attempts.
+ Add support for tracking the operation state.
+ Add full support for Ericsson MBM cellular devices.
+
+ver 0.42:
+ Fix issue with switching between hidden WiFi networks.
+ Fix issue with missing scanning after disconnect.
+ Fix issue with not triggering auto-connect in some cases.
+
+ver 0.41:
+ Fix race condition with WiFi devices and RFKILL.
+ Fix issue with WiFi connect/disconnect and some drivers.
+ Fix issue with WEP encryption and staging drivers.
+ Fix issue with wrong setup of loopback interfaces.
+
+ver 0.40:
+ Fix issue with wrong setting of initial AutoConnect value.
+ Fix issue with IP configuration and loopback devices.
+ Fix issue with build system and include directory.
+ Fix wrong variable for dhclient-script location.
+ Fix disconnect race condition with Bluetooth service.
+ Add support for ignoring bonding Ethernet interfaces.
+
+ver 0.39:
+ Fix file permissions for profile storage.
+ Fix service resorting when they are in different states.
+ Fix support for handling Bluetooth PAN devices.
+ Add support for AutoConnect property of services.
+ Add support for creating, modifying and removing profiles.
+ Add support for fully flexible task handling framework.
+ Add support for more generic RTNL handling and notifications.
+ Add support for full non-recursive build.
+
+ver 0.38:
+ Fix broken check for security modes.
+ Fix requirement of inotify when loopback support is disabled.
+
+ver 0.37:
+ Fix missing update of signal strength from scan results.
+ Fix error handling in case when passphrase is required.
+ Add support for PassphraseRequired property.
+ Add missing check for WiFi security modes.
+
+ver 0.36:
+ Fix missing reset of network reference when disconnecting.
+ Fix wrong variable reference when sending technology replies.
+ Fix wrong identifiers of D-Bus error names.
+
+ver 0.35:
+ Fix missing auto-connect trigger on Ethernet device removal.
+ Fix availability listing for devices without attached drivers.
+ Fix signals for connected and default technologies.
+ Fix notification to use service types instead of device types.
+ Fix potential pending scan result reply messages after removal.
+ Add support for blocking enable and disable technology changes.
+
+ver 0.34:
+ Fix setup of udev context before loading any plugins.
+ Fix rearming the scan trigger if a device got disabled.
+ Fix device power state changes tracking with RFKILL notifications.
+ Fix wrong usage of device types instead of service types.
+ Fix connect method to handle non-WiFi services.
+
+ver 0.33:
+ Add support for RFKILL changes of the WiFi subsystem.
+ Fix state value of Network Manager compatibility support.
+
+ver 0.32:
+ Fix broken device unregistration on removal.
+ Fix WiMAX device detection handling.
+
+ver 0.31:
+ Fix missing enforcement of offline mode for new devices.
+ Add support for persistent storage of offline mode.
+ Add support for persistent storage of device power state.
+ Remove deprecated and unused network storage callbacks.
+
+ver 0.30:
+ Fix issue where hidden network could show up in service list.
+ Fix issue with asynchronous notification of scan requests.
+ Fix message reference leak when adding interface fails.
+ Fix problem when removing network during inactive state.
+ Remove broken and unused callback for joining networks.
+ Remove deprecated device and network interface methods.
+ Remove test scripts for deprecated interface methods.
+
+ver 0.29:
+ Fix missing signal emission for offline mode changes.
+ Fix signal emission for changes in technology properties.
+ Rename Technologies property to AvailableTechnologies.
+
+ver 0.28:
+ Fix another reference counting imbalance when adding networks.
+ Revert supplicant change to always reset scanning after results.
+
+ver 0.27:
+ Fix missing disarming of the connection timeout.
+ Fix handling of multiple supplicant disconnect attempts.
+ Fix simultaneous connects from different technologies limitation.
+
+ver 0.26:
+ Fix broken handling of auto-connect logic.
+ Fix handling of out-of-range access points.
+ Fix support for connecting to hidden networks.
+ Fix reference counting for networks with same SSID.
+ Fix issue with WiFi interfaces not getting switched off.
+ Fix problems with delayed service list updates.
+ Fix disconnect/abort of connection attempts.
+
+ver 0.25:
+ Fix showing of WiFi networks with less than 25% signal strength.
+ Fix potential segmentation fault with network passphrases.
+
+ver 0.24:
+ Fix handling of initial device powered state.
+ Fix missing Powered property changed signals.
+ Fix canceling of a network connection attempt.
+ Fix stalled configuration issue with supplicant.
+ Fix detection of association errors from supplicant.
+ Fix issue with wrong scanning state information.
+ Fix hidden SSID detection routines.
+ Fix visible Ethernet services even without carrier.
+ Add global method call to request scanning.
+ Add support for global technologies list.
+ Add support for delaying service list updates.
+ Update the overall D-Bus API documentation.
+
+ver 0.23:
+ Fix dhclient probe/remove race condition.
+ Fix handling of disconnected services during auto-connect.
+ Add support for proper group name of hidden networks.
+ Add support for storing SSID details of hidden networks.
+
+ver 0.22:
+ Fix wrong auto-connect procedure after user connection.
+ Fix invalid update of already connected network.
+ Fix idle state handling after disconnecting device.
+ Fix disconnect race condition in WiFi supplicant.
+ Fix WiFi signal strength reporting.
+
+ver 0.21:
+ Add udev based network device detection.
+ Add support for global auto-connect feature.
+ Add support for basic service drag and drop.
+ Fix missing passphrase cleanup on service removal.
+ Fix potential duplicate network creation.
+ Fix handling of WEP shared keys.
+
+ver 0.20:
+ Add plugin for Intel WiMAX SDK support.
+ Add special handling for default vendor SSIDs.
+ Add support for default gateway in different network.
+ Add support for automatic switching of default gateway.
+ Add support for asynchronous handling of Powered property.
+ Add support for connecting/disconnecting Ethernet services.
+ Add support for more detailed error states of services.
+ Add support for clearing error state via ClearProperty.
+ Fix error code for invalid or unknown properties.
+ Fix various timeout handling issues.
+ Remove Policy and Priority device and network properties.
+
+ver 0.19:
+ Add hidden networks to the service list.
+ Add support for storing the service name.
+ Fix service list sorting for connected services.
+ Fix missing cancel command when operation times out.
+ Fix various issues with service favorite handling.
+ Remove Available and Remember network properties.
+
+ver 0.18:
+ Add support for asynchronous service connect method.
+ Fix broken storage of service favorite details.
+
+ver 0.17:
+ Add AT chat library implementation.
+ Fix service lookup for WiFi and WiMAX devices.
+ Fix service state signal emission and error handling.
+ Fix storing and loading of configured passphrases for services.
+
+ver 0.16:
+ Update Intel OSPM support to latest specification.
+ Add initial support for new service interface.
+ Add support for builtin plugins.
+ Add extra warning if no nameserver is defined.
+ Add error reporting for state and storage directory creation.
+ Add error message for network and device storing failures
+ Fix stale entry in gateway list after connection changes.
+ Fix handling of DHCP results with no nameserver.
+ Fix infinite loop for service lookup.
+ Fix various format string warnings.
+
+ver 0.15:
+ Detect VMware network interface and ignore them.
+ Fix setting of scan_ssid for hidden networks.
+ Fix empty network name property.
+
+ver 0.14:
+ Add support for detecting DHCP failures.
+ Add support for joining hidden WiFi networks.
+ Add support for device and network address property.
+ Add support for default /etc/resolv.conf generation.
+ Fix issue with wrong address setting for loopback.
+ Fix detection of WiFi access point changes.
+ Fix crash with blob properties.
+
+ver 0.13:
+ Add support for notification infrastructure.
+ Add fully dynamic property storage capabilities.
+ Fix broken loading of last network on bootup.
+ Fix crash when unplugging WiFi devices.
+ Rename OSPM plugin to Intel OSPM plugin.
+ Rename WiMAX plugin to Intel WiMAX SDK plugin.
+
+ver 0.12:
+ Fix connection state change handling.
+ Fix network list enumeration.
+ Fix broken driver matching for devices.
+ Fix issue with network identifier lookup.
+
+ver 0.11:
+ Add plugin priority handling.
+ Add network type for WiMAX.
+ Fix network protocol selection for Bluetooth PAN.
+ Fix parameters for Bluetooth PAN disconnect method.
+
+ver 0.10:
+ Fix races with connection signals.
+ Fix automatic switching of default connection.
+
+ver 0.9:
+ Rename FlightMode to OfflineMode.
+ Add static IPv4 setting support for Ethernet devices.
+ Add extra options to exclude devices and plugins.
+ Add support for toggling debug output.
+ Add support for ScanInterval property.
+ Fix handling of disconnect commands from applications.
+ Fix detection of networks that are out of range.
+ Fix setting network remember status.
+ Fix argument type checking of properties.
+
+ver 0.8:
+ Add Device and Network property to connection interface.
+ Add option to disable installation of data files.
+ Add command line option to show version number.
+ Fix signal emission for network changes.
+
+ver 0.7:
+ Add basic support for flight mode.
+ Add support for multiple storage drivers.
+ Add support for RTNL newlink watch API.
+ Add support for different security privileges.
+ Add support for device and network priorities.
+ Add functions for setting network properties.
+ Fix issue with listing devices without a driver.
+ Fix issue with WiFi scanning indication.
+ Fix detection of WiFi security changes.
+ Update WiFi driver to use new network helpers.
+ Install different D-Bus configuration for PolicyKit.
+
+ver 0.6:
+ Add CONNMAN_API_SUBJECT_TO_CHANGE definition.
+ Add detailed configuration options.
+ Add various D-Bus helper functions.
+ Add generic device driver infrastructure.
+ Add generic network driver infrastructure.
+ Add property for WiFi network mode.
+ Add property for network interface name.
+ Add property for global connection policy.
+ Add support for verbose compiler warnings.
+ Add support for device detection via udev.
+ Add support for systems with udhcpc.
+ Add support for Bluetooth PAN networks.
+ Fix WiFi issue with DHCP restart after handshake.
+ Fix exported symbols list creation.
+ Remove deprecated and unused plugins.
+
+ver 0.5:
+ Add support for handling Bluetooth adapters.
+ Add support for activating wpa_supplicant on demand.
+ Add Device property to network objects.
+ Add Scanning property to device objects.
+ Fix Name property of device objects.
+ Fix WiFi SSID to object path conversion.
+ Fix duplicate wireless scan results.
+ Fix built issue with libudev and uClibc.
+ Fix issues with element registration failures.
+
+ver 0.4:
+ Add DNS proxy resolver plugin.
+ Add support for default connections.
+ Add support for gateway change notifications.
+ Add signal strength property for connections.
+ Add property for connection type.
+ Fix issue with carrier detection.
+ Fix broken resolvconf plugin.
+
+ver 0.3:
+ Add support for automatically connecting known networks.
+ Add improved framework for handling resolver details.
+ Add generic signal strength property.
+ Fix bridge and WiMAX device detection.
+ Fix network listing for Ethernet devices.
+
+ver 0.2:
+ Add support for indicating network changes.
+ Add support for signal strength property.
+ Add support for unique device names.
+ Fix broken device enumeration.
+ Fix issue with device removal callback.
+ Fix issue with wpa_supplicant disconnecting.
+ Fix D-Bus access policy configuration.
+
+ver 0.1:
+ Initial public release.
includedir = @includedir@/connman
include_HEADERS = include/types.h include/log.h include/plugin.h \
- include/notifier.h \
- include/storage.h include/service.h \
+ include/notifier.h include/service.h \
include/resolver.h include/ipconfig.h \
- include/device.h include/network.h include/inet.h
+ include/device.h include/network.h include/inet.h \
+ include/storage.h
nodist_include_HEADERS = include/version.h
noinst_HEADERS = include/rtnl.h include/task.h \
- include/dbus.h include/rfkill.h include/option.h \
- include/profile.h include/provider.h \
+ include/dbus.h include/option.h \
+ include/provider.h \
include/utsname.h include/timeserver.h include/proxy.h \
- include/location.h include/technology.h \
- include/setting.h
+ include/technology.h include/setting.h
local_headers = $(foreach file,$(include_HEADERS) $(nodist_include_HEADERS) \
$(noinst_HEADERS), include/connman/$(notdir $(file)))
src/main.c src/connman.h src/log.c \
src/error.c src/plugin.c src/task.c \
src/device.c src/network.c src/connection.c \
- src/manager.c src/profile.c src/service.c \
+ src/manager.c src/service.c \
src/clock.c src/timezone.c \
src/agent.c src/notifier.c src/provider.c \
src/resolver.c src/ipconfig.c src/detect.c src/inet.c \
src/dhcp.c src/rtnl.c src/proxy.c \
src/utsname.c src/timeserver.c src/rfkill.c \
src/storage.c src/dbus.c src/config.c \
- src/technology.c src/counter.c src/location.c \
+ src/technology.c src/counter.c src/ntp.c \
src/session.c src/tethering.c src/wpad.c src/wispr.c \
src/stats.c src/iptables.c src/dnsproxy.c src/6to4.c
src_connmand_LDFLAGS = -Wl,--export-dynamic \
-Wl,--version-script=$(srcdir)/src/connman.ver
-BUILT_SOURCES = $(local_headers)
+BUILT_SOURCES = $(local_headers) src/builtin.h
-CLEANFILES = src/connman.conf src/builtin.h $(BUILT_SOURCES)
+CLEANFILES = src/connman.conf $(BUILT_SOURCES)
statedir = $(localstatedir)/run/connman
unit_test_session_SOURCES = $(gdbus_sources) src/log.c src/dbus.c \
unit/test-session.c unit/utils.c unit/manager-api.c \
unit/session-api.c unit/test-connman.h
-unit_test_session_LDADD = @GLIB_LIBS@ @DBUS_LIBS@
+unit_test_session_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ -ldl
unit_objects += $(unit_test_session_OBJECTS)
endif
test/set-nameservers test/set-domains test/find-service \
test/get-services test/get-proxy-autoconfig test/set-proxy \
test/enable-tethering test/disable-tethering test/backtrace \
- test/test-session test/provision-service
+ test/test-session test/provision-service test/test-supplicant \
+ test/test-new-supplicant test/service-move-before \
+ test/set-global-timeservers test/get-global-timeservers \
+ test/test-clock
if TEST
testdir = $(pkglibdir)/test
--enable-google \
--enable-meego \
--enable-client \
- --enable-portal \
--enable-hh2serial-gps \
--enable-ntpd \
--enable-openconnect \
ltmain.sh depcomp compile missing install-sh mkinstalldirs
-src/plugin.$(OBJEXT): src/builtin.h
-
src/builtin.h: src/genbuiltin $(builtin_sources)
$(AM_V_GEN)$(srcdir)/src/genbuiltin $(builtin_modules) > $@
$(AM_V_at)$(MKDIR_P) include/connman
$(AM_V_GEN)$(LN_S) $(abs_top_builddir)/$< $@
-include/connman/%.h: include/%.h
+include/connman/%.h: $(abs_top_srcdir)/include/%.h
$(AM_V_at)$(MKDIR_P) include/connman
- $(AM_V_GEN)$(LN_S) $(abs_top_srcdir)/$< $@
+ $(AM_V_GEN)$(LN_S) $< $@
clean-local:
@$(RM) -rf include/connman
@DBUS_CFLAGS@ @GLIB_CFLAGS@
plugin_ldflags = -no-undefined -module -avoid-version
+script_cflags = -fvisibility=hidden -I$(srcdir)/gdbus \
+ @DBUS_CFLAGS@
if LOOPBACK
if LOOPBACK_BUILTIN
endif
endif
-builtin_sources += $(builtin_vpn_sources)
+if L2TP
+if L2TP_BUILTIN
+builtin_modules += l2tp
+builtin_sources += plugins/l2tp.c
+builtin_vpn_sources = plugins/vpn.c plugins/vpn.h
+builtin_cflags += -DL2TP=\"@L2TP@\"
+else
+plugin_LTLIBRARIES += plugins/l2tp.la
+plugin_objects += $(plugins_l2tp_la_OBJECTS)
+plugins_l2tp_la_SOURCES = plugins/vpn.h plugins/vpn.c \
+ plugins/l2tp.c
+plugins_l2tp_la_CFLAGS = $(plugin_cflags) -DL2TP=\"@L2TP@\" \
+ -DSTATEDIR=\""$(statedir)"\" \
+ -DSCRIPTDIR=\""$(build_scriptdir)"\"
+plugins_l2tp_la_LDFLAGS = $(plugin_ldflags)
+endif
+endif
+
+if PPTP
+if PPTP_BUILTIN
+builtin_modules += pptp
+builtin_sources += plugins/pptp.c
+builtin_vpn_sources = plugins/vpn.c plugins/vpn.h
+builtin_cflags += -DPPPD=\"@PPPD@\" -DPPTP=\"@PPTP@\"
+else
+plugin_LTLIBRARIES += plugins/pptp.la
+plugin_objects += $(plugins_pptp_la_OBJECTS)
+plugins_pptp_la_SOURCES = plugins/vpn.h plugins/vpn.c \
+ plugins/pptp.c
+plugins_pptp_la_CFLAGS = $(plugin_cflags) -DPPPD=\"@PPPD@\" \
+ -DPPTP=\"@PPTP@\" \
+ -DSTATEDIR=\""$(statedir)"\" \
+ -DSCRIPTDIR=\""$(build_scriptdir)"\"
+plugins_pptp_la_LDFLAGS = $(plugin_ldflags)
+endif
+endif
-if PORTAL
-if PORTAL_BUILTIN
-builtin_modules += portal
-builtin_sources += plugins/portal.c
+if PPTP
+script_LTLIBRARIES += scripts/libppp-plugin.la
+scripts_libppp_plugin_la_LDFLAGS = $(script_cflags) @DBUS_CFLAGS@
+scripts_libppp_plugin_la_LIBADD = @DBUS_LIBS@
else
-plugin_LTLIBRARIES += plugins/portal.la
-plugin_objects += $(plugins_portal_la_OBJECTS)
-plugins_portal_la_CFLAGS = $(plugin_cflags)
-plugins_portal_la_LDFLAGS = $(plugin_ldflags)
+if L2TP
+script_LTLIBRARIES += scripts/libppp-plugin.la
+scripts_libppp_plugin_la_LDFLAGS = $(script_cflags) @DBUS_CFLAGS@
+scripts_libppp_plugin_la_LIBADD = @DBUS_LIBS@
endif
endif
+builtin_sources += $(builtin_vpn_sources)
+
if PACRUNNER
if PACRUNNER_BUILTIN
builtin_modules += pacrunner
make && make install
+VPN
+===
+
+In order to compile pptp and l2tp VPN plugins, you need ppp development
+package.
+
+To run l2tp you will need
+ - xl2tpd, http://www.xelerance.com/services/software/xl2tpd
+
+To run pptp you will need
+ - pptp client, http://pptpclient.sourceforge.net
+
+Both l2tp and pptp also need pppd.
+
+
Configuration and options
=========================
See http://www.mail-archive.com/connman@connman.net/msg01653.html
-- WiSPR support
-
- Priority: Medium
- Complexity: C4
- Owner: Marcel Holtmann <marcel@holtmann.org>
-
- Based on the portal detection parsing results, and provisioned
- credentials, ConnMan should be able to initiate a WiSPR authentication.
-
-
- DNS caching
Priority: Low
Priority: Low
Complexity: C8
+ Owner: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
- Extend the iptables code and provide a D-Bus API for personal firewalling.
+ Discuss and implement a basic and safe firewalling strategy into
+ Connman. Provide a D-Bus API for personal firewalling.
- PACRunner extensions
VPN
===
-- l2tp support
-
- Priority: Low
- Complexity: C2
- Owner: Mohamed Abbas <mohamed.abbas@intel.com>
-
-
-- pptp support
-
- Priority: Low
- Complexity: C2
- Owner: Mohamed Abbas <mohamed.abbas@intel.com>
-
-
- IPsec
Priority: Low
--enable-pacrunner=builtin \
--enable-google=builtin \
--enable-meego=builtin \
- --enable-portal=builtin \
--enable-nmcompat=builtin \
--enable-polkit=builtin \
--enable-capng \
AC_PREREQ(2.60)
-AC_INIT(connman, 0.77.2)
+AC_INIT(connman, 0.78.4)
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
AM_CONFIG_HEADER(config.h)
if (test "${enable_openconnect}" != "no"); then
if (test -z "${path_openconnect}"); then
AC_PATH_PROG(OPENCONNECT, [openconnect], [], $PATH:/sbin:/usr/sbin)
+ if (test -z "${OPENCONNECT}"); then
+ AC_MSG_ERROR(openconnect binary not found)
+ fi
else
OPENCONNECT="${path_openconnect}"
AC_SUBST(OPENCONNECT)
AM_CONDITIONAL(OPENCONNECT, test "${enable_openconnect}" != "no")
AM_CONDITIONAL(OPENCONNECT_BUILTIN, test "${enable_openconnect}" = "builtin")
-AC_ARG_ENABLE(portal,
- AC_HELP_STRING([--enable-portal], [enable portal detection support]),
- [enable_portal=${enableval}], [enable_portal="no"])
-AM_CONDITIONAL(PORTAL, test "${enable_portal}" != "no")
-AM_CONDITIONAL(PORTAL_BUILTIN, test "${enable_portal}" = "builtin")
-
AC_ARG_WITH(openvpn, AC_HELP_STRING([--with-openvpn=PROGRAM],
[specify location of openvpn binary]), [path_openvpn=${withval}])
if (test "${enable_openvpn}" != "no"); then
if (test -z "${path_openvpn}"); then
AC_PATH_PROG(OPENVPN, [openvpn], [], $PATH:/sbin:/usr/sbin)
+ if (test -z "${OPENVPN}"); then
+ AC_MSG_ERROR(openvpn binary not found)
+ fi
else
OPENVPN="${path_openvpn}"
AC_SUBST(OPENVPN)
if (test "${enable_vpnc}" != "no"); then
if (test -z "${path_vpnc}"); then
AC_PATH_PROG(VPNC, [vpnc], [], $PATH:/sbin:/usr/sbin)
+ if (test -z "${VPNC}"); then
+ AC_MSG_ERROR(vpnc binary not found)
+ fi
else
VPNC="${path_vpnc}"
AC_SUBST(VPNC)
AM_CONDITIONAL(VPNC, test "${enable_vpnc}" != "no")
AM_CONDITIONAL(VPNC_BUILTIN, test "${enable_vpnc}" = "builtin")
+AC_ARG_ENABLE(l2tp,
+ AC_HELP_STRING([--enable-l2tp], [enable l2tp support]),
+ [enable_l2tp=${enableval}], [enable_l2tp="no"])
+if (test "${enable_l2tp}" != "no"); then
+ if (test -z "${path_pppd}"); then
+ AC_PATH_PROG(PPPD, [pppd], [/usr/sbin/pppd], $PATH:/sbin:/usr/sbin)
+ else
+ PPPD="${path_pppd}"
+ AC_SUBST(PPPD)
+ fi
+ AC_CHECK_HEADERS(pppd/pppd.h, dummy=yes,
+ AC_MSG_ERROR(ppp header files are required))
+ if (test -z "${path_l2tp}"); then
+ AC_PATH_PROG(L2TP, [xl2tpd], [/usr/sbin/xl2tpd], $PATH:/sbin:/usr/sbin)
+ else
+ L2TP="${path_l2tp}"
+ AC_SUBST(L2TP)
+ fi
+fi
+AM_CONDITIONAL(L2TP, test "${enable_l2tp}" != "no")
+AM_CONDITIONAL(L2TP_BUILTIN, test "${enable_l2tp}" = "builtin")
+
+AC_ARG_ENABLE(pptp,
+ AC_HELP_STRING([--enable-pptp], [enable pptp support]),
+ [enable_pptp=${enableval}], [enable_pptp="no"])
+if (test "${enable_pptp}" != "no"); then
+ if (test -z "${path_pppd}"); then
+ AC_PATH_PROG(PPPD, [pppd], [/usr/sbin/pppd], $PATH:/sbin:/usr/sbin)
+ else
+ PPPD="${path_pppd}"
+ AC_SUBST(PPPD)
+ fi
+ AC_CHECK_HEADERS(pppd/pppd.h, dummy=yes,
+ AC_MSG_ERROR(ppp header files are required))
+ if (test -z "${path_pptp}"); then
+ AC_PATH_PROG(PPTP, [pptp], [/usr/sbin/pptp], $PATH:/sbin:/usr/sbin)
+ else
+ PPTP="${path_pptp}"
+ AC_SUBST(PPTP)
+ fi
+fi
+AM_CONDITIONAL(PPTP, test "${enable_pptp}" != "no")
+AM_CONDITIONAL(PPTP_BUILTIN, test "${enable_pptp}" = "builtin")
+
AC_ARG_ENABLE(loopback,
AC_HELP_STRING([--enable-loopback], [enable loopback support]),
[enable_loopback=${enableval}], [enable_loopback="yes"])
+connman (0.78.4-0slp2+77) unstable; urgency=low
+
+ * Upgrade ConnMan-stable 0.78.4
+ * Git: slp/pkgs/c/connman
+ * Tag: connman_0.78.4-0slp2+77
+
+ -- Danny Jeongseok Seo <s.seo@samsung.com> Tue, 17 Apr 2012 20:51:49 +0900
+
connman (0.77.2-0slp2+76) unstable; urgency=low
* Update ConnMan init script for Android suplicant
@PREFIX@/share/dbus-1/services/*
@PREFIX@/etc/dbus-1/system.d/*
@PREFIX@/etc/connman/main.conf
-/var/lib/connman/default.profile
+/var/lib/connman/settings
/etc/rc.d/init.d/connman
/etc/rc.d/rc3.d/S61connman
/etc/rc.d/rc5.d/S61connman
#!/bin/sh
-
-chmod 600 /var/lib/connman/default.profile
-
+chmod 600 /var/lib/connman/settings
Section: net
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
-Description: Intel Connection Manager daemon
+Description: Connection Manager
The Linux Connection Manager project provides a daemon for managing
Internet connections within embedded devices running the Linux
operating system. The Connection Manager is designed to be slim and to
Section: net
Architecture: any
Depends: connman (= ${Source-Version}), ${misc:Depends}
-Description: debug symbol for connman
+Description: debug symbols for Connection Manager
$(MAKE) DESTDIR=$(CURDIR)/debian/tmp install
mkdir -p $(CURDIR)/debian/tmp/var/lib/connman
- cp -f $(CURDIR)/resources/var/lib/connman/default.profile \
- $(CURDIR)/debian/tmp/var/lib/connman/default.profile
+ cp -f $(CURDIR)/resources/var/lib/connman/settings \
+ $(CURDIR)/debian/tmp/var/lib/connman/settings
mkdir -p $(CURDIR)/debian/tmp$(PREFIX)/share/dbus-1/services
cp -f $(CURDIR)/resources$(PREFIX)/share/dbus-1/services/net.connman.service \
$(CURDIR)/debian/tmp$(PREFIX)/share/dbus-1/services/net.connman.service
--- /dev/null
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+# These are used for cross-compiling and for saving the configure script
+# from having to guess our platform (since we know it already)
+
+DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
+DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
+
+CFLAGS ?= -Wall -g -O2
+LDFLAGS ?= -Wl,--rpath=$(PREFIX)/lib -Wl,--as-needed
+PREFIX ?= /usr
+DATADIR ?= /opt
+
+CONFIGURE_ARGS = \
+ --localstatedir=/var \
+ --enable-threads \
+ --enable-tizen-ext \
+ --enable-wifi=builtin \
+ $(NULL)
+# --enable-debug \
+# $(NULL)
+
+configure: configure.ac
+ ./autogen.sh
+
+config.status: configure
+ dh_testdir
+ # Add here commands to configure the package.
+ CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" ./configure --prefix=$(PREFIX) $(CONFIGURE_ARGS)
+
+build: build-stamp
+
+build-stamp: config.status
+ dh_testdir
+
+ # Add here commands to compile the package.
+ $(MAKE)
+ #docbook-to-man debian/ncurses.sgml > ncurses.1
+
+ for f in `find $(CURDIR)/debian/ -name "*.in"`; do \
+ cat $$f > $${f%.in}; \
+ sed -i -e "s#@PREFIX@#$(PREFIX)#g" $${f%.in}; \
+ sed -i -e "s#@DATADIR@#$(DATADIR)#g" $${f%.in}; \
+ done
+
+ touch $@
+
+clean:
+ dh_testdir
+ dh_testroot
+ rm -f build-stamp
+
+ # Add here commands to clean up after the build process.
+ -$(MAKE) distclean
+
+ for f in `find $(CURDIR)/debian/ -name "*.in"`; do \
+ rm -f $${f%.in}; \
+ done
+
+ rm -f depcomp
+ rm -f compile
+ rm -f missing
+ rm -f ltmain.sh
+ rm -f install-sh
+ rm -f config.guess
+ rm -f configh.h
+ rm -f config.h.in
+ rm -f config.log
+ rm -f config.sub
+ rm -f config.guess
+ rm -f configure
+ rm -f Makefile.in
+ rm -f aclocal.m4
+ rm -f ../connman_*.deb
+ rm -f ../connman-*.deb
+ rm -f ../connman_*.changes
+ rm -f ../connman_*.dsc
+ rm -f ../connman_*.tar.gz
+
+ dh_clean
+
+install: build
+ dh_testdir
+ dh_testroot
+ dh_clean -k
+ dh_installdirs
+
+ # Add here commands to install the package into debian/connman.
+ $(MAKE) DESTDIR=$(CURDIR)/debian/tmp install
+
+ mkdir -p $(CURDIR)/debian/tmp/var/lib/connman
+ cp -f $(CURDIR)/resources/var/lib/connman/default.profile \
+ $(CURDIR)/debian/tmp/var/lib/connman/default.profile
+ mkdir -p $(CURDIR)/debian/tmp$(PREFIX)/share/dbus-1/services
+ cp -f $(CURDIR)/resources$(PREFIX)/share/dbus-1/services/net.connman.service \
+ $(CURDIR)/debian/tmp$(PREFIX)/share/dbus-1/services/net.connman.service
+ mkdir -p $(CURDIR)/debian/tmp$(PREFIX)/etc/connman
+ cp -f $(CURDIR)/src/main.conf $(CURDIR)/debian/tmp$(PREFIX)/etc/connman/main.conf
+ mkdir -p $(CURDIR)/debian/tmp/etc/rc.d/init.d
+ cp -f $(CURDIR)/resources/etc/rc.d/init.d/connman \
+ $(CURDIR)/debian/tmp/etc/rc.d/init.d/connman
+ mkdir -p $(CURDIR)/debian/tmp/etc/rc.d/rc3.d
+ ln -s ../init.d/connman $(CURDIR)/debian/tmp/etc/rc.d/rc3.d/S61connman
+ mkdir -p $(CURDIR)/debian/tmp/etc/rc.d/rc5.d
+ ln -s ../init.d/connman $(CURDIR)/debian/tmp/etc/rc.d/rc5.d/S61connman
+
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+ dh_testdir
+ dh_testroot
+# dh_installchangelogs
+# dh_installdocs
+# dh_installexamples
+ dh_install --sourcedir=debian/tmp
+# dh_installmenu
+# dh_installdebconf
+# dh_installlogrotate
+# dh_installemacsen
+# dh_installpam
+# dh_installmime
+# dh_python
+# dh_installinit
+# dh_installcron
+# dh_installinfo
+# dh_installman
+ dh_link
+ dh_strip --dbg-package=connman-dbg
+ dh_compress
+ dh_fixperms
+# dh_perl
+ dh_makeshlibs
+ dh_installdeb
+ dh_shlibdeps
+ dh_gencontrol
+ dh_md5sums
+ dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install
--- /dev/null
+--- debian/rules
++++ debian/rules
+@@ -128,7 +128,8 @@
+ dh_install --sourcedir=debian/tmp
+ # dh_installmenu
+ # dh_installdebconf
+-# dh_installlogrotate # dh_installemacsen
++# dh_installlogrotate
++# dh_installemacsen
+ # dh_installpam
+ # dh_installmime
+ # dh_python
void DestroySession(object session)
- Remove the previously created session. The notifier
- will be informed via its release method.
+ Remove the previously created session.
If an application exits unexpectatly the session
will be automatically destroyed.
this value to prevent or permit automatic
connection attempts.
- boolean SetupRequired [readonly]
-
- If the service is Cellular, then this property
- indicates that some extra setup steps are required.
-
- In most cases it is required to fill in the APN
- details.
-
boolean Roaming [readonly]
This property indicates if this service is roaming.
- AllowedBearers (filter and sort)
- RoamingPolicy (filter and sort)
-A stable sorting algorithms maintains the relative order.
+A stable sorting algorithm maintains the relative order.
If a service is removed or added all sessions are updated according
the above rules.
|No |
| |
Service.Disconnect() Do nothing
+
+
+Session States and Transitions
+==============================
+
+There are three main strategies for state changes.
+
+ - Free Ride
+ - Connect
+ - Disconnect
+
+The initial state for all new sessions is Free Ride.
+
+The Free Ride state means that a session will go online if a matching
+service goes online without calling Service.Connect() itself. The idea
+behind this is that a session doesn't request a connection for itself
+instead waits until another session actively requires to go online.
+This is comparable to piggy-backing.
+
+When a session is in the Connect state ConnMan tries to find a
+matching service (see Connect algorithm) and then decides either to
+connect the service or delay the request. ConnMan is allowed to
+connect to the service or to delay it, e.g. group PeriodicConnects
+together. The session will leave the Connect state when the service
+goes offline unless StayConnected is True. It will enter the Free Ride
+mode again.
+
+When the application calls Disconnect() the session enters the
+Disconnect state and stays there until the application calls Connect()
+again.
+
+
+ State Change to offline & StayConnected = True
+ +------+
+ | v
++-----------+ +---------+ -- Disconnect() --> +------------+
+| Free Ride |-- Connect() -->| Connect | | Disconnect |
++-----------+ +---------+ <-- Connect() --- +------------+
+ | ^ | ^
+ | +------------------------ + |
+ | State Change to offline & StayConnected = False |
+ | |
+ | |
+ +----------------------- Disconnect() -----------------------+
+
+Note: this documents the current behavior it is likely to change in near
+future.
+
+
+Additional Information on Settings
+==================================
+
+PeriodicConnect and IdleTimeout
+-------------------------------
+
+If an application wants to go online periodically (e.g. checking for
+new mails) then the application should use PeriodicConnect instead of
+calling Session.Connect() periodically. There is no need for the
+application to maintain timers. ConnMan is also able to try to combine
+several PeriodicConnect calls into one. Applications should not rely on a
+very precise periodic connect. Apart from merging periodic connect
+timeouts there is also the problem that no service might be available
+at that point and ConnMan will defer the connect call.
+
+The IdleTimeout tells ConnMan when a link is idle for given period it
+is okay to disonnect.
+
+PeriodicConnect and IdleTimeout should only consired as hints. ConnMan
+will try to meet them but there is no garantee for doing so. For
+example global settings have precedence over session settings.
The technology state information.
- Valid states are "offline", "available", "enabled"
- and "connected".
+ Valid states are "offline", "enabled" and "connected".
string Name [readonly]
} ClientState;
struct _GDHCPClient {
- gint ref_count;
+ int ref_count;
GDHCPType type;
ClientState state;
int ifindex;
struct ifreq ifr;
int sk, err;
- sk = socket(PF_INET, SOCK_DGRAM, 0);
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0) {
perror("Open socket error");
return;
.filter = (struct sock_filter *) filter_instr,
};
- fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
+ fd = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, htons(ETH_P_IP));
if (fd < 0)
return fd;
if (dhcp_client == NULL)
return NULL;
- g_atomic_int_inc(&dhcp_client->ref_count);
+ __sync_fetch_and_add(&dhcp_client->ref_count, 1);
return dhcp_client;
}
if (dhcp_client == NULL)
return;
- if (g_atomic_int_dec_and_test(&dhcp_client->ref_count) == FALSE)
+ if (__sync_fetch_and_sub(&dhcp_client->ref_count, 1) != 1)
return;
g_dhcp_client_stop(dhcp_client);
offsetof(struct ip_udp_dhcp_packet, udp),
};
- fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
+ fd = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, htons(ETH_P_IP));
if (fd < 0)
return -errno;
*/
n = sendto(fd, &packet, IP_UPD_DHCP_SIZE, 0,
(struct sockaddr *) &dest, sizeof(dest));
+ close(fd);
+
if (n < 0)
return -errno;
- close(fd);
-
return n;
}
EXTEND_FOR_BUGGY_SERVERS,
};
- fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ fd = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
if (fd < 0)
return -errno;
int fd, opt = 1;
struct sockaddr_in addr;
- fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ fd = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if (index < 0)
return NULL;
- sk = socket(PF_INET, SOCK_DGRAM, 0);
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0) {
perror("Open socket error");
return NULL;
struct ifreq ifr;
gboolean ret = FALSE;
- sk = socket(PF_INET, SOCK_DGRAM, 0);
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0) {
perror("Open socket error");
return FALSE;
uint32_t ip_target;
int fd, n;
- fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP));
+ fd = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, htons(ETH_P_ARP));
if (fd < 0)
return -errno;
{
int fd;
struct sockaddr_ll sock;
- fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP));
+ fd = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, htons(ETH_P_ARP));
if (fd < 0)
return fd;
#define OFFER_TIME (5*60)
struct _GDHCPServer {
- gint ref_count;
+ int ref_count;
GDHCPType type;
gboolean started;
int ifindex;
struct sockaddr_in *server_ip;
uint32_t ret = 0;
- sk = socket(PF_INET, SOCK_DGRAM, 0);
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0) {
perror("Open socket error");
return 0;
if (dhcp_server == NULL)
return NULL;
- g_atomic_int_inc(&dhcp_server->ref_count);
+ __sync_fetch_and_add(&dhcp_server->ref_count, 1);
return dhcp_server;
}
if (dhcp_server == NULL)
return;
- if (g_atomic_int_dec_and_test(&dhcp_server->ref_count) == FALSE)
+ if (__sync_fetch_and_sub(&dhcp_server->ref_count, 1) != 1)
return;
g_dhcp_server_stop(dhcp_server);
dbus_message_iter_close_container(iter, &value);
}
+
+void supplicant_dbus_property_append_array(DBusMessageIter *iter,
+ const char *key, int type,
+ supplicant_dbus_array_function function,
+ void *user_data)
+{
+ DBusMessageIter value, array;
+ const char *variant_sig, *array_sig;
+
+ switch (type) {
+ case DBUS_TYPE_STRING:
+ variant_sig = DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_BYTE_AS_STRING;
+ array_sig = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING;
+ break;
+ default:
+ return;
+ }
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &key);
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+ variant_sig, &value);
+
+ dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
+ array_sig, &array);
+ if (function)
+ function(&array, user_data);
+
+ dbus_message_iter_close_container(&value, &array);
+
+ dbus_message_iter_close_container(iter, &value);
+}
typedef void (*supplicant_dbus_result_function) (const char *error,
DBusMessageIter *iter, void *user_data);
+void supplicant_dbus_property_append_array(DBusMessageIter *iter,
+ const char *key, int type,
+ supplicant_dbus_array_function function,
+ void *user_data);
+
void supplicant_dbus_setup(DBusConnection *conn);
void supplicant_dbus_array_foreach(DBusMessageIter *iter,
supplicant_dbus_property_append_fixed_array(&entry, key, type, val, len);
dbus_message_iter_close_container(dict, &entry);
}
+
+static inline void
+supplicant_dbus_dict_append_array(DBusMessageIter *dict,
+ const char *key, int type,
+ supplicant_dbus_array_function function,
+ void *user_data)
+{
+ DBusMessageIter entry;
+
+ dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+ supplicant_dbus_property_append_array(&entry, key, type,
+ function, user_data);
+ dbus_message_iter_close_container(dict, &entry);
+}
#define G_SUPPLICANT_PAIRWISE_TKIP (1 << 1)
#define G_SUPPLICANT_PAIRWISE_CCMP (1 << 2)
+#define G_SUPPLICANT_MAX_FAST_SCAN 4
+
typedef enum {
G_SUPPLICANT_MODE_UNKNOWN,
G_SUPPLICANT_MODE_INFRA,
typedef struct _GSupplicantSSID GSupplicantSSID;
+struct _GSupplicantScanParams {
+ struct scan_ssid {
+ unsigned char ssid[32];
+ uint8_t ssid_len;
+ } ssids[G_SUPPLICANT_MAX_FAST_SCAN];
+
+ uint8_t num_ssids;
+
+ uint16_t freqs[G_SUPPLICANT_MAX_FAST_SCAN];
+};
+
+typedef struct _GSupplicantScanParams GSupplicantScanParams;
+
/* global API */
typedef void (*GSupplicantCountryCallback) (void *user_data);
GSupplicantInterfaceCallback callback,
void *user_data);
int g_supplicant_interface_scan(GSupplicantInterface *interface,
+ GSupplicantScanParams *scan_data,
GSupplicantInterfaceCallback callback,
void *user_data);
unsigned int *ssid_len);
GSupplicantWpsState g_supplicant_interface_get_wps_state(GSupplicantInterface *interface);
unsigned int g_supplicant_interface_get_mode(GSupplicantInterface *interface);
+dbus_bool_t g_supplicant_interface_get_ready(GSupplicantInterface *interface);
+unsigned int g_supplicant_interface_get_max_scan_ssids(
+ GSupplicantInterface *interface);
+
+int g_supplicant_interface_enable_selected_network(GSupplicantInterface *interface,
+ dbus_bool_t enable);
/* Network API */
struct _GSupplicantNetwork;
const char *g_supplicant_network_get_mode(GSupplicantNetwork *network);
const char *g_supplicant_network_get_security(GSupplicantNetwork *network);
dbus_int16_t g_supplicant_network_get_signal(GSupplicantNetwork *network);
+dbus_uint16_t g_supplicant_network_get_frequency(GSupplicantNetwork *network);
dbus_bool_t g_supplicant_network_get_wps(GSupplicantNetwork *network);
#if defined TIZEN_EXT
*/
const unsigned char *g_supplicant_network_get_bssid(GSupplicantNetwork *network);
unsigned int g_supplicant_network_get_maxrate(GSupplicantNetwork *network);
-unsigned short g_supplicant_network_get_frequency(GSupplicantNetwork *network);
const char *g_supplicant_network_get_enc_mode(GSupplicantNetwork *network);
#endif
unsigned int pairwise_capa;
unsigned int scan_capa;
unsigned int mode_capa;
+ unsigned int max_scan_ssids;
dbus_bool_t ready;
GSupplicantState state;
dbus_bool_t scanning;
unsigned char ssid[32];
unsigned int ssid_len;
dbus_int16_t signal;
+ dbus_uint16_t frequency;
struct g_supplicant_bss *best_bss;
GSupplicantMode mode;
GSupplicantSecurity security;
else if (g_strcmp0(key, "Modes") == 0)
supplicant_dbus_array_foreach(iter,
interface_capability_mode, interface);
- else
+ else if (g_strcmp0(key, "MaxScanSSID") == 0) {
+ dbus_int32_t max_scan_ssid;
+
+ dbus_message_iter_get_basic(iter, &max_scan_ssid);
+ interface->max_scan_ssids = max_scan_ssid;
+
+ } else
SUPPLICANT_DBG("key %s type %c",
key, dbus_message_iter_get_arg_type(iter));
}
return interface->mode_capa;
}
+unsigned int g_supplicant_interface_get_max_scan_ssids(
+ GSupplicantInterface *interface)
+{
+ if (interface == NULL)
+ return 0;
+
+ return interface->max_scan_ssids;
+}
+
+static void set_network_enabled(DBusMessageIter *iter, void *user_data)
+{
+ dbus_bool_t enable = *(dbus_bool_t *)user_data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &enable);
+}
+
+int g_supplicant_interface_enable_selected_network(GSupplicantInterface *interface,
+ dbus_bool_t enable)
+{
+ if (interface == NULL)
+ return -1;
+
+ if (interface->network_path == NULL)
+ return -1;
+
+ SUPPLICANT_DBG(" ");
+ return supplicant_dbus_property_set(interface->network_path,
+ SUPPLICANT_INTERFACE ".Network",
+ "Enabled", DBUS_TYPE_BOOLEAN_AS_STRING,
+ set_network_enabled, NULL, &enable);
+}
+
+dbus_bool_t g_supplicant_interface_get_ready(GSupplicantInterface *interface)
+{
+ if (interface == NULL)
+ return FALSE;
+
+ return interface->ready;
+}
+
GSupplicantInterface *g_supplicant_network_get_interface(
GSupplicantNetwork *network)
{
return network->signal;
}
+dbus_uint16_t g_supplicant_network_get_frequency(GSupplicantNetwork *network)
+{
+ if (network == NULL)
+ return 0;
+
+ return network->frequency;
+}
+
dbus_bool_t g_supplicant_network_get_wps(GSupplicantNetwork *network)
{
if (network == NULL)
return network->best_bss->maxrate;
}
-unsigned short g_supplicant_network_get_frequency(GSupplicantNetwork *network)
-{
- if (network == NULL || network->best_bss == NULL)
- return 0;
-
- return network->best_bss->frequency;
-}
-
const char *g_supplicant_network_get_enc_mode(GSupplicantNetwork *network)
{
if (network == NULL || network->best_bss == NULL)
network->ssid_len = bss->ssid_len;
memcpy(network->ssid, bss->ssid, bss->ssid_len);
network->signal = bss->signal;
+ network->frequency = bss->frequency;
network->best_bss = bss;
network->wps = FALSE;
if (ie == NULL || ie_len < 2)
return;
- for (ie_end = ie+ie_len; ie+ie[1]+1 <= ie_end; ie += ie[1]+2) {
+ for (ie_end = ie + ie_len; ie < ie_end && ie + ie[1] + 1 <= ie_end;
+ ie += ie[1] + 2) {
+
if (ie[0] != WMM_WPA1_WPS_INFO || ie[1] < WPS_INFO_MIN_LEN ||
memcmp(ie+2, WPS_OUI, sizeof(WPS_OUI)) != 0)
continue;
}
struct interface_data {
- char *path;
+ GSupplicantInterface *interface;
GSupplicantInterfaceCallback callback;
void *user_data;
};
void *user_data;
};
-static void interface_data_free(struct interface_data *data)
-{
- g_free(data->path);
- dbus_free(data);
-}
+struct interface_scan_data {
+ GSupplicantInterface *interface;
+ GSupplicantInterfaceCallback callback;
+ GSupplicantScanParams *scan_params;
+ void *user_data;
+};
static void interface_create_property(const char *key, DBusMessageIter *iter,
void *user_data)
if (data->callback != NULL)
data->callback(err, NULL, data->user_data);
- interface_data_free(data);
+ dbus_free(data);
}
struct interface_data *data = user_data;
dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
- &data->path);
+ &data->interface->path);
}
if (data == NULL)
return -ENOMEM;
- data->path = g_strdup(interface->path);
+ data->interface = interface;
data->callback = callback;
data->user_data = user_data;
static void interface_scan_result(const char *error,
DBusMessageIter *iter, void *user_data)
{
- struct interface_data *data = user_data;
- GSupplicantInterface *interface;
-
- interface = g_hash_table_lookup(interface_table, data->path);
- if (interface == NULL)
- return;
+ struct interface_scan_data *data = user_data;
if (error != NULL) {
+ SUPPLICANT_DBG("error %s", error);
+
if (data->callback != NULL)
- data->callback(-EIO, interface, data->user_data);
+ data->callback(-EIO, data->interface, data->user_data);
} else {
- interface->scan_callback = data->callback;
- interface->scan_data = data->user_data;
+ data->interface->scan_callback = data->callback;
+ data->interface->scan_data = data->user_data;
}
- interface_data_free(data);
+ if (data != NULL && data->scan_params != NULL)
+ g_free(data->scan_params);
+
+ dbus_free(data);
+}
+
+static void add_scan_frequency(DBusMessageIter *iter, unsigned int freq)
+{
+ DBusMessageIter data;
+ unsigned int width = 0; /* Not used by wpa_supplicant atm */
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &data);
+
+ dbus_message_iter_append_basic(&data, DBUS_TYPE_UINT32, &freq);
+ dbus_message_iter_append_basic(&data, DBUS_TYPE_UINT32, &width);
+
+ dbus_message_iter_close_container(iter, &data);
+}
+
+static void add_scan_frequencies(DBusMessageIter *iter,
+ void *user_data)
+{
+ GSupplicantScanParams *scan_data = user_data;
+ unsigned int freq;
+ int i;
+
+ for (i = 0; i < G_SUPPLICANT_MAX_FAST_SCAN; i++) {
+ freq = scan_data->freqs[i];
+ if (!freq)
+ break;
+
+ add_scan_frequency(iter, freq);
+ }
+}
+
+static void append_ssid(DBusMessageIter *iter,
+ const void *ssid, unsigned int len)
+{
+ DBusMessageIter array;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING, &array);
+
+ dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
+ &ssid, len);
+ dbus_message_iter_close_container(iter, &array);
+}
+
+static void append_ssids(DBusMessageIter *iter, void *user_data)
+{
+ GSupplicantScanParams *scan_data = user_data;
+ int i;
+
+ for (i = 0; i < scan_data->num_ssids; i++)
+ append_ssid(iter, scan_data->ssids[i].ssid,
+ scan_data->ssids[i].ssid_len);
+}
+
+static void supplicant_add_scan_frequency(DBusMessageIter *dict,
+ supplicant_dbus_array_function function,
+ void *user_data)
+{
+ GSupplicantScanParams *scan_params = user_data;
+ DBusMessageIter entry, value, array;
+ const char *key = "Channels";
+
+ if (scan_params->freqs[0] != 0) {
+ dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+ dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_STRUCT_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_UINT32_AS_STRING
+ DBUS_TYPE_UINT32_AS_STRING
+ DBUS_STRUCT_END_CHAR_AS_STRING,
+ &value);
+
+ dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
+ DBUS_STRUCT_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_UINT32_AS_STRING
+ DBUS_TYPE_UINT32_AS_STRING
+ DBUS_STRUCT_END_CHAR_AS_STRING,
+ &array);
+
+ if (function)
+ function(&array, user_data);
+
+ dbus_message_iter_close_container(&value, &array);
+ dbus_message_iter_close_container(&entry, &value);
+ dbus_message_iter_close_container(dict, &entry);
+ }
}
static void interface_scan_params(DBusMessageIter *iter, void *user_data)
{
DBusMessageIter dict;
const char *type = "passive";
+ struct interface_scan_data *data = user_data;
supplicant_dbus_dict_open(iter, &dict);
- supplicant_dbus_dict_append_basic(&dict, "Type",
- DBUS_TYPE_STRING, &type);
+ if (data && data->scan_params) {
+ type = "active";
+
+ supplicant_dbus_dict_append_basic(&dict, "Type",
+ DBUS_TYPE_STRING, &type);
+
+ supplicant_dbus_dict_append_array(&dict, "SSIDs",
+ DBUS_TYPE_STRING,
+ append_ssids,
+ data->scan_params);
+
+ supplicant_add_scan_frequency(&dict, add_scan_frequencies,
+ data->scan_params);
+ } else
+ supplicant_dbus_dict_append_basic(&dict, "Type",
+ DBUS_TYPE_STRING, &type);
supplicant_dbus_dict_close(iter, &dict);
}
int g_supplicant_interface_scan(GSupplicantInterface *interface,
+ GSupplicantScanParams *scan_data,
GSupplicantInterfaceCallback callback,
void *user_data)
{
- struct interface_data *data;
+ struct interface_scan_data *data;
+ int ret;
if (interface == NULL)
return -EINVAL;
if (data == NULL)
return -ENOMEM;
- data->path = g_strdup(interface->path);
+ data->interface = interface;
data->callback = callback;
data->user_data = user_data;
+ data->scan_params = scan_data;
- return supplicant_dbus_method_call(interface->path,
+ ret = supplicant_dbus_method_call(interface->path,
SUPPLICANT_INTERFACE ".Interface", "Scan",
interface_scan_params, interface_scan_result, data);
+
+ if (ret < 0)
+ dbus_free(data);
+
+ return ret;
}
static int parse_supplicant_error(DBusMessageIter *iter)
DBusMessageIter *iter, void *user_data)
{
struct interface_data *data = user_data;
- GSupplicantInterface *interface;
int result = 0;
SUPPLICANT_DBG("");
result = -EIO;
if (data->callback != NULL)
- data->callback(result, interface, data->user_data);
+ data->callback(result, data->interface, data->user_data);
- interface_data_free(data);
+ dbus_free(data);
}
static void network_remove_params(DBusMessageIter *iter, void *user_data)
{
struct interface_data *data = user_data;
- GSupplicantInterface *interface;
- const char *path;
-
- interface = g_hash_table_lookup(interface_table, data->path);
- if (interface == NULL)
- return;
-
- path = interface->network_path;
+ const char *path = data->interface->network_path;
SUPPLICANT_DBG("path %s", path);
static int network_remove(struct interface_data *data)
{
- GSupplicantInterface *interface;
-
- interface = g_hash_table_lookup(interface_table, data->path);
- if (interface == NULL)
- return -ENODEV;
+ GSupplicantInterface *interface = data->interface;
SUPPLICANT_DBG("");
DBusMessageIter *iter, void *user_data)
{
struct interface_data *data = user_data;
- GSupplicantInterface *interface;
SUPPLICANT_DBG("");
- interface = g_hash_table_lookup(interface_table, data->path);
- if (interface == NULL)
- return;
-
#if defined TIZEN_EXT
if (error != NULL && data->callback != NULL) {
- data->callback(-EIO, interface, data->user_data);
+ data->callback(-EIO, data->interface, data->user_data);
data->user_data = NULL;
}
#else
if (error != NULL && data->callback != NULL)
- data->callback(-EIO, interface, data->user_data);
+ data->callback(-EIO, data->interface, data->user_data);
#endif
/* If we are disconnecting from previous WPS successful
* association. i.e.: it did not went through AddNetwork,
* and interface->network_path was never set. */
- if (interface->network_path == NULL)
+ if (data->interface->network_path == NULL)
return;
network_remove(data);
if (data == NULL)
return -ENOMEM;
- data->path = g_strdup(interface->path);
+ data->interface = interface;
data->callback = callback;
data->user_data = user_data;
GIOCondition condition;
};
-static volatile gint global_init_done = 0;
+static volatile int global_init_done = 0;
static inline void g_io_gnutls_global_init(void)
{
- if (g_atomic_int_compare_and_exchange(&global_init_done, 0, 1) == TRUE)
+ if (__sync_bool_compare_and_swap(&global_init_done, 0, 1) == TRUE)
gnutls_global_init();
}
#include <netdb.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
+#include <net/if.h>
#include "gresolv.h"
};
struct _GResolv {
- gint ref_count;
+ int ref_count;
int result_family;
socklen_t sl = sizeof(res->src);
int fd;
- fd = socket(res->dst.sa.sa_family, SOCK_DGRAM, IPPROTO_IP);
+ fd = socket(res->dst.sa.sa_family, SOCK_DGRAM | SOCK_CLOEXEC,
+ IPPROTO_IP);
if (fd < 0)
return;
static void sort_and_return_results(struct resolv_lookup *lookup)
{
- char buf[100];
+ char buf[INET6_ADDRSTRLEN + 1];
GResolvResultStatus status;
char **results = g_try_new0(char *, lookup->nr_results + 1);
int i, n = 0;
if (!results)
return;
+ memset(buf, 0, INET6_ADDRSTRLEN + 1);
+
rfc3484_sort_results(lookup);
for (i = 0; i < lookup->nr_results; i++) {
if (lookup->results[i].dst.sa.sa_family == AF_INET) {
if (inet_ntop(AF_INET,
&lookup->results[i].dst.sin.sin_addr,
- buf, sizeof(buf)) == NULL)
+ buf, sizeof(buf) - 1) == NULL)
continue;
} else if (lookup->results[i].dst.sa.sa_family == AF_INET6) {
if (inet_ntop(AF_INET6,
&lookup->results[i].dst.sin6.sin6_addr,
- buf, sizeof(buf)) == NULL)
+ buf, sizeof(buf) - 1) == NULL)
continue;
} else
continue;
return -EIO;
}
+ /*
+ * If nameserver points to localhost ip, their is no need to
+ * bind the socket on any interface.
+ */
+ if (nameserver->resolv->index > 0 &&
+ strncmp(nameserver->address, "127.0.0.1", 9) != 0) {
+ char interface[IF_NAMESIZE];
+
+ memset(interface, 0, IF_NAMESIZE);
+ if (if_indextoname(nameserver->resolv->index,
+ interface) != NULL) {
+ if (setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
+ interface, IF_NAMESIZE) < 0) {
+ close(sk);
+ freeaddrinfo(rp);
+ return -EIO;
+ }
+ }
+ }
+
if (connect(sk, rp->ai_addr, rp->ai_addrlen) < 0) {
close(sk);
freeaddrinfo(rp);
if (resolv == NULL)
return NULL;
- g_atomic_int_inc(&resolv->ref_count);
+ __sync_fetch_and_add(&resolv->ref_count, 1);
return resolv;
}
if (resolv == NULL)
return;
- if (g_atomic_int_dec_and_test(&resolv->ref_count) == FALSE)
+ if (__sync_fetch_and_sub(&resolv->ref_count, 1) != 1)
return;
while ((query = g_queue_pop_head(resolv->query_queue)))
nameserver->address = g_strdup(address);
nameserver->port = port;
nameserver->flags = flags;
+ nameserver->resolv = resolv;
if (connect_udp_channel(nameserver) < 0) {
free_nameserver(nameserver);
return FALSE;
}
- nameserver->resolv = resolv;
-
resolv->nameserver_list = g_list_append(resolv->nameserver_list,
nameserver);
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
+#include <net/if.h>
#include "giognutls.h"
#include "gresolv.h"
};
struct _GWeb {
- gint ref_count;
+ int ref_count;
guint next_query_id;
if (web == NULL)
return NULL;
- g_atomic_int_inc(&web->ref_count);
+ __sync_fetch_and_add(&web->ref_count, 1);
return web;
}
if (web == NULL)
return;
- if (g_atomic_int_dec_and_test(&web->ref_count) == FALSE)
+ if (__sync_fetch_and_sub(&web->ref_count, 1) != 1)
return;
flush_sessions(web);
GIOFlags flags;
int sk;
- sk = socket(session->addr->ai_family, SOCK_STREAM, IPPROTO_TCP);
+ sk = socket(session->addr->ai_family, SOCK_STREAM | SOCK_CLOEXEC,
+ IPPROTO_TCP);
if (sk < 0)
return -EIO;
+ if (session->web->index > 0) {
+ char interface[IF_NAMESIZE];
+
+ memset(interface, 0, IF_NAMESIZE);
+
+ if (if_indextoname(session->web->index, interface) != NULL) {
+ if (setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
+ interface, IF_NAMESIZE) < 0) {
+ close(sk);
+ return -EIO;
+ }
+
+ debug(session->web, "Use interface %s", interface);
+ }
+ }
+
if (session->flags & SESSION_FLAG_USE_TLS) {
debug(session->web, "using TLS encryption");
session->transport_channel = g_io_channel_gnutls_new(sk);
if (parser == NULL)
return NULL;
- g_atomic_int_inc(&parser->ref_count);
+ __sync_fetch_and_add(&parser->ref_count, 1);
return parser;
}
if (parser == NULL)
return;
- if (g_atomic_int_dec_and_test(&parser->ref_count) == FALSE)
+ if (__sync_fetch_and_sub(&parser->ref_count, 1) != 1)
return;
g_string_free(parser->content, TRUE);
int (*enable) (struct connman_device *device);
int (*disable) (struct connman_device *device);
int (*scan) (struct connman_device *device);
+ int (*scan_fast) (struct connman_device *device);
};
int connman_device_driver_register(struct connman_device_driver *driver);
+++ /dev/null
-/*
- *
- * Connection Manager
- *
- * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifndef __CONNMAN_LOCATION_H
-#define __CONNMAN_LOCATION_H
-
-#include <connman/service.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define CONNMAN_LOCATION_PRIORITY_LOW -100
-#define CONNMAN_LOCATION_PRIORITY_DEFAULT 0
-#define CONNMAN_LOCATION_PRIORITY_HIGH 100
-
-/**
- * SECTION:location
- * @title: Location premitives
- * @short_description: Functions for detecting locations
- */
-
-enum connman_location_result {
- CONNMAN_LOCATION_RESULT_UNKNOWN = 0,
- CONNMAN_LOCATION_RESULT_PORTAL = 1,
- CONNMAN_LOCATION_RESULT_ONLINE = 2,
-};
-
-struct connman_location;
-
-struct connman_location *connman_location_ref(struct connman_location *location);
-void connman_location_unref(struct connman_location *location);
-
-enum connman_service_type connman_location_get_type(struct connman_location *location);
-char *connman_location_get_interface(struct connman_location *location);
-void connman_location_report_result(struct connman_location *location,
- enum connman_location_result result);
-
-void *connman_location_get_data(struct connman_location *location);
-void connman_location_set_data(struct connman_location *location, void *data);
-
-struct connman_service *connman_location_get_service(
- struct connman_location *location);
-
-struct connman_location_driver {
- const char *name;
- enum connman_service_type type;
- int priority;
- int (*detect) (struct connman_location *location);
- int (*finish) (struct connman_location *location);
-};
-
-int connman_location_driver_register(struct connman_location_driver *driver);
-void connman_location_driver_unregister(struct connman_location_driver *driver);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __CONNMAN_LOCATION_H */
+++ /dev/null
-/*
- *
- * Connection Manager
- *
- * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifndef __CONNMAN_PROFILE_H
-#define __CONNMAN_PROFILE_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * SECTION:profile
- * @title: Profile premitives
- * @short_description: Functions for handling profiles
- */
-
-struct connman_profile;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __CONNMAN_PROFILE_H */
#ifndef __CONNMAN_PROVIDER_H
#define __CONNMAN_PROVIDER_H
+#include <glib.h>
#include <connman/types.h>
#ifdef __cplusplus
const char *key, const char *value);
const char *connman_provider_get_driver_name(struct connman_provider *provider);
+const char *connman_provider_get_save_group(struct connman_provider *provider);
struct connman_provider_driver {
const char *name;
int (*remove) (struct connman_provider *provider);
int (*connect) (struct connman_provider *provider);
int (*disconnect) (struct connman_provider *provider);
+ int (*save) (struct connman_provider *provider, GKeyFile *keyfile);
};
int connman_provider_driver_register(struct connman_provider_driver *driver);
+++ /dev/null
-/*
- *
- * Connection Manager
- *
- * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifndef __CONNMAN_RFKILL_H
-#define __CONNMAN_RFKILL_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __CONNMAN_RFKILL_H */
*
* Connection Manager
*
- * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
+ * Copyright (C) 2011 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#ifndef __CONNMAN_STORAGE_H
#define __CONNMAN_STORAGE_H
-#include <connman/profile.h>
-#include <connman/service.h>
-#include <connman/device.h>
+#include <glib.h>
#ifdef __cplusplus
extern "C" {
#endif
-/**
- * SECTION:storage
- * @title: Storage premitives
- * @short_description: Functions for registering storage modules
- */
-
-#define CONNMAN_STORAGE_PRIORITY_LOW -100
-#define CONNMAN_STORAGE_PRIORITY_DEFAULT 0
-#define CONNMAN_STORAGE_PRIORITY_HIGH 100
-
-struct connman_storage {
- const char *name;
- int priority;
- int (*profile_init) (void);
- int (*profile_load) (struct connman_profile *profile);
- int (*profile_save) (struct connman_profile *profile);
- enum connman_service_type service_type;
- int (*service_load) (struct connman_service *service);
- int (*service_save) (struct connman_service *service);
- enum connman_device_type device_type;
- int (*device_load) (struct connman_device *device);
- int (*device_save) (struct connman_device *device);
-};
-
-int connman_storage_register(struct connman_storage *storage);
-void connman_storage_unregister(struct connman_storage *storage);
+gchar **connman_storage_get_services();
+GKeyFile *connman_storage_load_service(const char *service_id);
#ifdef __cplusplus
}
typedef void (* connman_task_exit_t) (struct connman_task *task,
int exit_code, void *user_data);
-typedef void (* connman_task_notify_t) (struct connman_task *task,
+typedef DBusMessage * (* connman_task_notify_t) (struct connman_task *task,
DBusMessage *message, void *user_data);
struct connman_task *connman_task_create(const char *program);
%make_install
mkdir -p %{buildroot}/var/lib/connman
-cp resources/var/lib/connman/default.profile %{buildroot}/var/lib/connman/default.profile
+cp resources/var/lib/connman/settings %{buildroot}/var/lib/connman/settings
mkdir -p %{buildroot}/usr/share/dbus-1/services
cp resources/usr/share/dbus-1/services/net.connman.service %{buildroot}/usr/share/dbus-1/services/net.connman.service
mkdir -p %{buildroot}/usr/etc/connman
%post
#Resource
-chmod 600 /var/lib/connman/default.profile
+chmod 600 /var/lib/connman/settings
%files
%defattr(-,root,root,-)
#%doc AUTHORS COPYING INSTALL ChangeLog NEWS README
%{_sbindir}/*
-%{_var}/lib/connman/default.profile
+%{_var}/lib/connman/settings
%{_libdir}/connman/plugins/*.so
%{_datadir}/dbus-1/services/*
%{_prefix}/etc/dbus-1/system.d/*
--- /dev/null
+#sbs-git:pkgs/c/connman connman 0.77.2
+
+Name: connman
+Summary: Connection Manager
+Version: 0.77.2_75
+Release: 1
+Group: System/Network
+License: GNU General Public License version 2
+URL: http://connman.net
+Source0: %{name}-%{version}.tar.gz
+BuildRequires: pkgconfig(glib-2.0)
+BuildRequires: pkgconfig(dbus-1)
+BuildRequires: pkgconfig(xtables)
+BuildRequires: pkgconfig(libiptc)
+
+%description
+Connection Manager provides a daemon for managing Internet connections
+within embedded devices running the Linux operating system.
+
+%prep
+%setup -q
+
+
+%build
+
+./autogen.sh
+
+./configure --prefix=/usr \
+ --localstatedir=/var \
+ --enable-threads \
+ --enable-tizen-ext \
+ --enable-wifi=builtin
+
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+mkdir -p %{buildroot}/var/lib/connman
+cp resources/var/lib/connman/default.profile %{buildroot}/var/lib/connman/default.profile
+mkdir -p %{buildroot}/usr/share/dbus-1/services
+cp resources/usr/share/dbus-1/services/net.connman.service %{buildroot}/usr/share/dbus-1/services/net.connman.service
+mkdir -p %{buildroot}/usr/etc/connman
+cp src/main.conf %{buildroot}/usr/etc/connman/main.conf
+mkdir -p %{buildroot}/etc/rc.d/init.d
+cp resources/etc/rc.d/init.d/connman %{buildroot}/etc/rc.d/init.d/connman
+mkdir -p %{buildroot}/etc/rc.d/rc3.d
+ln -s ../init.d/connman %{buildroot}/etc/rc.d/rc3.d/S61connman
+mkdir -p %{buildroot}/etc/rc.d/rc5.d
+ln -s ../init.d/connman %{buildroot}/etc/rc.d/rc5.d/S61connman
+
+rm -rf %{buildroot}/usr/include/
+rm -rf %{buildroot}/usr/lib/pkgconfig/
+rm %{buildroot}/etc/dbus-1/system.d/*.conf
+
+mkdir -p %{buildroot}/usr/etc/dbus-1/system.d/
+cp src/connman.conf %{buildroot}/usr/etc/dbus-1/system.d/
+
+
+%post
+#Resource
+chmod 600 /var/lib/connman/default.profile
+
+
+%files
+%defattr(-,root,root,-)
+#%doc AUTHORS COPYING INSTALL ChangeLog NEWS README
+%{_sbindir}/*
+%{_var}/lib/connman/default.profile
+%{_libdir}/connman/plugins/*.so
+%{_datadir}/dbus-1/services/*
+%{_prefix}/etc/dbus-1/system.d/*
+%{_prefix}/etc/connman/main.conf
+%{_prefix}/etc/dbus-1/system.d/*.conf
+%{_sysconfdir}/rc.d/init.d/connman
+%{_sysconfdir}/rc.d/rc3.d/S61connman
+%{_sysconfdir}/rc.d/rc5.d/S61connman
--- /dev/null
+--- packaging/connman.spec
++++ packaging/connman.spec
+@@ -1,8 +1,8 @@
+-#sbs-git:pkgs/c/connman connman 0.77.2
++#sbs-git:pkgs/c/connman connman 0.78.4
+
+ Name: connman
+ Summary: Connection Manager
+-Version: 0.77.2_76
++Version: 0.78.4_77
+ Release: 1
+ Group: System/Network
+ License: GNU General Public License version 2
if (err < 0) {
connman_device_driver_unregister(&bluetooth_driver);
connman_network_driver_unregister(&pan_driver);
- return err;
+ goto remove;
}
return 0;
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2010 BMW Car IT GmbH. All rights reserved.
+ * Copyright (C) 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <stdio.h>
+#include <net/if.h>
+
+#include <glib.h>
+
+#define CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/plugin.h>
+#include <connman/provider.h>
+#include <connman/log.h>
+#include <connman/task.h>
+#include <connman/dbus.h>
+#include <connman/inet.h>
+
+#include "vpn.h"
+
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+enum {
+ OPT_STRING = 1,
+ OPT_BOOL = 2,
+};
+
+enum {
+ OPT_ALL = 1,
+ OPT_L2G = 2,
+ OPT_L2 = 3,
+ OPT_PPPD = 4,
+};
+
+struct {
+ const char *cm_opt;
+ const char *pppd_opt;
+ int sub;
+ const char *vpn_default;
+ int type;
+} pppd_options[] = {
+ { "L2TP.User", "name", OPT_ALL, NULL, OPT_STRING },
+ { "L2TP.BPS", "bps", OPT_L2, NULL, OPT_STRING },
+ { "L2TP.LengthBit", "length bit", OPT_L2, NULL, OPT_STRING },
+ { "L2TP.Challenge", "challenge", OPT_L2, NULL, OPT_STRING },
+ { "L2TP.DefaultRoute", "defaultroute", OPT_L2, NULL, OPT_STRING },
+ { "L2TP.FlowBit", "flow bit", OPT_L2, NULL, OPT_STRING },
+ { "L2TP.TunnelRWS", "tunnel rws", OPT_L2, NULL, OPT_STRING },
+ { "L2TP.Exclusive", "exclusive", OPT_L2, NULL, OPT_STRING },
+ { "L2TP.Autodial", "autodial", OPT_L2, "yes", OPT_STRING },
+ { "L2TP.Redial", "redial", OPT_L2, "yes", OPT_STRING },
+ { "L2TP.RedialTimeout", "redial timeout", OPT_L2, "10", OPT_STRING },
+ { "L2TP.MaxRedials", "max redials", OPT_L2, NULL, OPT_STRING },
+ { "L2TP.RequirePAP", "require pap", OPT_L2, "no", OPT_STRING },
+ { "L2TP.RequireCHAP", "require chap", OPT_L2, "yes", OPT_STRING },
+ { "L2TP.ReqAuth", "require authentication", OPT_L2, "no", OPT_STRING },
+ { "L2TP.AccessControl", "access control", OPT_L2G, "yes", OPT_STRING },
+ { "L2TP.AuthFile", "auth file", OPT_L2G, NULL, OPT_STRING },
+ { "L2TP.ForceUserSpace", "force userspace", OPT_L2G, NULL, OPT_STRING },
+ { "L2TP.ListenAddr", "listen-addr", OPT_L2G, NULL, OPT_STRING },
+ { "L2TP.Rand Source", "rand source", OPT_L2G, NULL, OPT_STRING },
+ { "L2TP.IPsecSaref", "ipsec saref", OPT_L2G, NULL, OPT_STRING },
+ { "L2TP.Port", "port", OPT_L2G, NULL, OPT_STRING },
+ { "L2TP.EchoFailure", "lcp-echo-failure", OPT_PPPD, "0", OPT_STRING },
+ { "L2TP.EchoInterval", "lcp-echo-interval", OPT_PPPD, "0", OPT_STRING },
+ { "L2TP.Debug", "debug", OPT_PPPD, NULL, OPT_STRING },
+ { "L2TP.RefuseEAP", "refuse-eap", OPT_PPPD, NULL, OPT_BOOL },
+ { "L2TP.RefusePAP", "refuse-pap", OPT_PPPD, NULL, OPT_BOOL },
+ { "L2TP.RefuseCHAP", "refuse-chap", OPT_PPPD, NULL, OPT_BOOL },
+ { "L2TP.RefuseMSCHAP", "refuse-mschap", OPT_PPPD, NULL, OPT_BOOL },
+ { "L2TP.RefuseMSCHAP2", "refuse-mschapv2", OPT_PPPD, NULL, OPT_BOOL },
+ { "L2TP.NoBSDComp", "nobsdcomp", OPT_PPPD, NULL, OPT_BOOL },
+ { "L2TP.NoPcomp", "nopcomp", OPT_PPPD, NULL, OPT_BOOL },
+ { "L2TP.UseAccomp", "accomp", OPT_PPPD, NULL, OPT_BOOL },
+ { "L2TP.NoDeflate", "nodeflatey", OPT_PPPD, NULL, OPT_BOOL },
+ { "L2TP.ReqMPPE", "require-mppe", OPT_PPPD, NULL, OPT_BOOL },
+ { "L2TP.ReqMPPE40", "require-mppe-40", OPT_PPPD, NULL, OPT_BOOL },
+ { "L2TP.ReqMPPE128", "require-mppe-128", OPT_PPPD, NULL, OPT_BOOL },
+ { "L2TP.ReqMPPEStateful", "mppe-stateful", OPT_PPPD, NULL, OPT_BOOL },
+ { "L2TP.NoVJ", "no-vj-comp", OPT_PPPD, NULL, OPT_BOOL },
+};
+
+static DBusConnection *connection;
+
+static DBusMessage *l2tp_get_sec(struct connman_task *task,
+ DBusMessage *msg, void *user_data)
+{
+ const char *user, *passwd;
+ struct connman_provider *provider = user_data;
+
+ if (dbus_message_get_no_reply(msg) == FALSE) {
+ DBusMessage *reply;
+
+ user = connman_provider_get_string(provider, "L2TP.User");
+ passwd = connman_provider_get_string(provider, "L2TP.Password");
+
+ if (user == NULL || strlen(user) == 0 ||
+ passwd == NULL || strlen(passwd) == 0)
+ return NULL;
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &user,
+ DBUS_TYPE_STRING, &passwd,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+ }
+
+ return NULL;
+}
+
+static int l2tp_notify(DBusMessage *msg, struct connman_provider *provider)
+{
+ DBusMessageIter iter, dict;
+ const char *reason, *key, *value;
+ char *addressv4 = NULL, *netmask = NULL, *gateway = NULL;
+ char *ifname = NULL, *nameservers = NULL;
+ struct connman_ipaddress *ipaddress = NULL;
+
+ dbus_message_iter_init(msg, &iter);
+
+ dbus_message_iter_get_basic(&iter, &reason);
+ dbus_message_iter_next(&iter);
+
+ if (!provider) {
+ connman_error("No provider found");
+ return VPN_STATE_FAILURE;
+ }
+
+ if (strcmp(reason, "auth failed") == 0)
+ return VPN_STATE_AUTH_FAILURE;
+
+ if (strcmp(reason, "connect"))
+ return VPN_STATE_DISCONNECT;
+
+ dbus_message_iter_recurse(&iter, &dict);
+
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry;
+
+ dbus_message_iter_recurse(&dict, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_get_basic(&entry, &value);
+
+ DBG("%s = %s", key, value);
+
+ if (!strcmp(key, "INTERNAL_IP4_ADDRESS")) {
+ connman_provider_set_string(provider, "Address", value);
+ addressv4 = g_strdup(value);
+ }
+
+ if (!strcmp(key, "INTERNAL_IP4_NETMASK")) {
+ connman_provider_set_string(provider, "Netmask", value);
+ netmask = g_strdup(value);
+ }
+
+ if (!strcmp(key, "INTERNAL_IP4_DNS")) {
+ connman_provider_set_string(provider, "DNS", value);
+ nameservers = g_strdup(value);
+ }
+
+ if (!strcmp(key, "INTERNAL_IFNAME"))
+ ifname = g_strdup(value);
+
+ dbus_message_iter_next(&dict);
+ }
+
+ if (vpn_set_ifname(provider, ifname) < 0) {
+ g_free(ifname);
+ g_free(addressv4);
+ g_free(netmask);
+ g_free(nameservers);
+ return VPN_STATE_FAILURE;
+ }
+
+ if (addressv4 != NULL)
+ ipaddress = connman_ipaddress_alloc(AF_INET);
+
+ g_free(ifname);
+
+ if (ipaddress == NULL) {
+ connman_error("No IP address for provider");
+ g_free(addressv4);
+ g_free(netmask);
+ g_free(nameservers);
+ return VPN_STATE_FAILURE;
+ }
+
+ value = connman_provider_get_string(provider, "Host");
+ if (value != NULL) {
+ connman_provider_set_string(provider, "Gateway", value);
+ gateway = g_strdup(value);
+ }
+
+ if (addressv4 != NULL)
+ connman_ipaddress_set_ipv4(ipaddress, addressv4, netmask,
+ gateway);
+
+ connman_provider_set_ipaddress(provider, ipaddress);
+ connman_provider_set_nameservers(provider, nameservers);
+
+ g_free(addressv4);
+ g_free(netmask);
+ g_free(gateway);
+ g_free(nameservers);
+ connman_ipaddress_free(ipaddress);
+
+ return VPN_STATE_CONNECT;
+}
+
+static int l2tp_save(struct connman_provider *provider, GKeyFile *keyfile)
+{
+ const char *option;
+ int i;
+
+ for (i = 0; i < (int)ARRAY_SIZE(pppd_options); i++) {
+ if (strncmp(pppd_options[i].cm_opt, "L2TP.", 5) == 0) {
+ option = connman_provider_get_string(provider,
+ pppd_options[i].cm_opt);
+ if (option == NULL)
+ continue;
+
+ g_key_file_set_string(keyfile,
+ connman_provider_get_save_group(provider),
+ pppd_options[i].cm_opt, option);
+ }
+ }
+ return 0;
+}
+
+static ssize_t full_write(int fd, const void *buf, size_t len)
+{
+ ssize_t byte_write;
+
+ while (len) {
+ byte_write = write(fd, buf, len);
+ if (byte_write < 0) {
+ connman_error("failed to write config to l2tp: %s\n",
+ strerror(errno));
+ return byte_write;
+ }
+ len -= byte_write;
+ buf += byte_write;
+ }
+
+ return 0;
+}
+
+static ssize_t l2tp_write_bool_option(int fd,
+ const char *key, const char *value)
+{
+ gchar *buf;
+ ssize_t ret = 0;
+
+ if (key != NULL && value != NULL) {
+ if (strcmp(value, "yes") == 0) {
+ buf = g_strdup_printf("%s\n", key);
+ ret = full_write(fd, buf, strlen(buf));
+
+ g_free(buf);
+ }
+ }
+
+ return ret;
+}
+
+static int l2tp_write_option(int fd, const char *key, const char *value)
+{
+ gchar *buf;
+ ssize_t ret = 0;
+
+ if (key != NULL) {
+ if (value != NULL)
+ buf = g_strdup_printf("%s %s\n", key, value);
+ else
+ buf = g_strdup_printf("%s\n", key);
+
+ ret = full_write(fd, buf, strlen(buf));
+
+ g_free(buf);
+ }
+
+ return ret;
+}
+
+static int l2tp_write_section(int fd, const char *key, const char *value)
+{
+ gchar *buf;
+ ssize_t ret = 0;
+
+ if (key != NULL && value != NULL) {
+ buf = g_strdup_printf("%s = %s\n", key, value);
+ ret = full_write(fd, buf, strlen(buf));
+
+ g_free(buf);
+ }
+
+ return ret;
+}
+
+static int write_pppd_option(struct connman_provider *provider, int fd)
+{
+ int i;
+ const char *opt_s;
+
+ l2tp_write_option(fd, "nodetach", NULL);
+ l2tp_write_option(fd, "lock", NULL);
+ l2tp_write_option(fd, "usepeerdns", NULL);
+ l2tp_write_option(fd, "noipdefault", NULL);
+ l2tp_write_option(fd, "noauth", NULL);
+ l2tp_write_option(fd, "nodefaultroute", NULL);
+ l2tp_write_option(fd, "ipparam", "l2tp_plugin");
+
+ for (i = 0; i < (int)ARRAY_SIZE(pppd_options); i++) {
+ if (pppd_options[i].sub != OPT_ALL &&
+ pppd_options[i].sub != OPT_PPPD)
+ continue;
+
+ opt_s = connman_provider_get_string(provider,
+ pppd_options[i].cm_opt);
+ if (!opt_s)
+ opt_s = pppd_options[i].vpn_default;
+
+ if (!opt_s)
+ continue;
+
+ if (pppd_options[i].type == OPT_STRING)
+ l2tp_write_option(fd,
+ pppd_options[i].pppd_opt, opt_s);
+ else if (pppd_options[i].type == OPT_BOOL)
+ l2tp_write_bool_option(fd,
+ pppd_options[i].pppd_opt, opt_s);
+ }
+
+ l2tp_write_option(fd, "plugin",
+ SCRIPTDIR "/libppp-plugin.so");
+
+ return 0;
+}
+
+
+static int l2tp_write_fields(struct connman_provider *provider,
+ int fd, int sub)
+{
+ int i;
+ const char *opt_s;
+
+ for (i = 0; i < (int)ARRAY_SIZE(pppd_options); i++) {
+ if (pppd_options[i].sub != sub)
+ continue;
+
+ opt_s = connman_provider_get_string(provider,
+ pppd_options[i].cm_opt);
+ if (!opt_s)
+ opt_s = pppd_options[i].vpn_default;
+
+ if (!opt_s)
+ continue;
+
+ if (pppd_options[i].type == OPT_STRING)
+ l2tp_write_section(fd,
+ pppd_options[i].pppd_opt, opt_s);
+ else if (pppd_options[i].type == OPT_BOOL)
+ l2tp_write_bool_option(fd,
+ pppd_options[i].pppd_opt, opt_s);
+ }
+
+ return 0;
+}
+
+static int l2tp_write_config(struct connman_provider *provider,
+ const char *pppd_name, int fd)
+{
+ const char *option;
+
+ l2tp_write_option(fd, "[global]", NULL);
+ l2tp_write_fields(provider, fd, OPT_L2G);
+
+ l2tp_write_option(fd, "[lac l2tp]", NULL);
+
+ option = connman_provider_get_string(provider, "Host");
+ l2tp_write_option(fd, "lns =", option);
+
+ l2tp_write_fields(provider, fd, OPT_ALL);
+ l2tp_write_fields(provider, fd, OPT_L2);
+
+ l2tp_write_option(fd, "pppoptfile =", pppd_name);
+
+ return 0;
+}
+
+static void l2tp_died(struct connman_task *task, int exit_code, void *user_data)
+{
+ char *conf_file;
+
+ vpn_died(task, exit_code, user_data);
+
+ conf_file = g_strdup_printf("/var/run/connman/connman-xl2tpd.conf");
+ unlink(conf_file);
+ g_free(conf_file);
+
+ conf_file = g_strdup_printf("/var/run/connman/connman-ppp-option.conf");
+ unlink(conf_file);
+ g_free(conf_file);
+}
+
+static int l2tp_connect(struct connman_provider *provider,
+ struct connman_task *task, const char *if_name)
+{
+ const char *host;
+ char *l2tp_name, *pppd_name;
+ int l2tp_fd, pppd_fd;
+ int err;
+
+ if (connman_task_set_notify(task, "getsec",
+ l2tp_get_sec, provider))
+ return -ENOMEM;
+
+ host = connman_provider_get_string(provider, "Host");
+ if (host == NULL) {
+ connman_error("Host not set; cannot enable VPN");
+ return -EINVAL;
+ }
+
+ l2tp_name = g_strdup_printf("/var/run/connman/connman-xl2tpd.conf");
+
+ l2tp_fd = open(l2tp_name, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
+ if (l2tp_fd < 0) {
+ g_free(l2tp_name);
+ connman_error("Error writing l2tp config");
+ return -EIO;
+ }
+
+ pppd_name = g_strdup_printf("/var/run/connman/connman-ppp-option.conf");
+
+ pppd_fd = open(pppd_name, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
+ if (pppd_fd < 0) {
+ connman_error("Error writing pppd config");
+ g_free(l2tp_name);
+ g_free(pppd_name);
+ close(l2tp_fd);
+ return -EIO;
+ }
+
+ l2tp_write_config(provider, pppd_name, l2tp_fd);
+
+ write_pppd_option(provider, pppd_fd);
+
+ connman_task_add_argument(task, "-D", NULL);
+ connman_task_add_argument(task, "-c", l2tp_name);
+
+ g_free(l2tp_name);
+ g_free(pppd_name);
+
+ err = connman_task_run(task, l2tp_died, provider,
+ NULL, NULL, NULL);
+ if (err < 0) {
+ connman_error("l2tp failed to start");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int l2tp_error_code(int exit_code)
+{
+ switch (exit_code) {
+ case 1:
+ return CONNMAN_PROVIDER_ERROR_CONNECT_FAILED;
+ default:
+ return CONNMAN_PROVIDER_ERROR_UNKNOWN;
+ }
+}
+
+static struct vpn_driver vpn_driver = {
+ .flags = VPN_FLAG_NO_TUN,
+ .notify = l2tp_notify,
+ .connect = l2tp_connect,
+ .error_code = l2tp_error_code,
+ .save = l2tp_save,
+};
+
+static int l2tp_init(void)
+{
+ connection = connman_dbus_get_connection();
+
+ return vpn_register("l2tp", &vpn_driver, L2TP);
+}
+
+static void l2tp_exit(void)
+{
+ vpn_unregister("l2tp");
+
+ dbus_connection_unref(connection);
+}
+
+CONNMAN_PLUGIN_DEFINE(l2tp, "l2tp plugin", VERSION,
+ CONNMAN_PLUGIN_PRIORITY_DEFAULT, l2tp_init, l2tp_exit)
struct sockaddr_in addr;
int sk, err;
- sk = socket(PF_INET, SOCK_DGRAM, 0);
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return -errno;
#include <connman/dbus.h>
enum {
- NM_STATE_UNKNOWN = 0,
- NM_STATE_ASLEEP,
- NM_STATE_CONNECTING,
- NM_STATE_CONNECTED,
- NM_STATE_DISCONNECTED
+ NM_STATE_UNKNOWN = 0,
+ NM_STATE_ASLEEP = 10,
+ NM_STATE_DISCONNECTED = 20,
+ NM_STATE_DISCONNECTING = 30,
+ NM_STATE_CONNECTING = 40,
+ NM_STATE_CONNECTED_LOCAL = 50,
+ NM_STATE_CONNECTED_SITE = 60,
+ NM_STATE_CONNECTED_GLOBAL = 70
};
+#define NM_STATE_CONNECTED NM_STATE_CONNECTED_GLOBAL
+
#define NM_SERVICE "org.freedesktop.NetworkManager"
#define NM_PATH "/org/freedesktop/NetworkManager"
#define NM_INTERFACE NM_SERVICE
static DBusConnection *connection = NULL;
static dbus_uint32_t state = NM_STATE_UNKNOWN;
-
-static void nm_send_signal(const char *name, dbus_uint32_t state)
+static void state_changed(dbus_uint32_t state)
{
DBusMessage *signal;
- signal = dbus_message_new_signal(NM_PATH, NM_INTERFACE, name);
+ signal = dbus_message_new_signal(NM_PATH, NM_INTERFACE,
+ "StateChanged");
if (signal == NULL)
return;
g_dbus_send_message(connection, signal);
}
-static void nm_send_prop_signal(dbus_uint32_t state)
+static void properties_changed(dbus_uint32_t state)
{
const char *key = "State";
DBusMessageIter iter, dict, dict_entry, dict_val;
&dict);
dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
- NULL, &dict_entry);
+ NULL, &dict_entry);
- dbus_message_iter_append_basic(&dict_entry, DBUS_TYPE_STRING,
- &key);
+ dbus_message_iter_append_basic(&dict_entry, DBUS_TYPE_STRING, &key);
- dbus_message_iter_open_container(&dict_entry,
- DBUS_TYPE_VARIANT,
+ dbus_message_iter_open_container(&dict_entry, DBUS_TYPE_VARIANT,
DBUS_TYPE_UINT32_AS_STRING, &dict_val);
dbus_message_iter_append_basic(&dict_val, DBUS_TYPE_UINT32, &state);
DBG("%p %d", service, state);
- /* older deprecated signal, in case applications still use this */
- nm_send_signal("StateChange", state);
+ state_changed(state);
- /* the preferred current signal */
- nm_send_signal("StateChanged", state);
-
- nm_send_prop_signal(state);
+ properties_changed(state);
}
static struct connman_notifier notifier = {
.default_changed= default_changed,
};
-static DBusMessage *nm_sleep(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- DBusMessage *reply;
-
- DBG("conn %p", conn);
-
- reply = dbus_message_new_method_return(msg);
- if (reply == NULL)
- return NULL;
-
- dbus_message_append_args(reply, DBUS_TYPE_INVALID);
-
- return reply;
-}
-
-static DBusMessage *nm_wake(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- DBusMessage *reply;
-
- DBG("conn %p", conn);
-
- reply = dbus_message_new_method_return(msg);
- if (reply == NULL)
- return NULL;
-
- dbus_message_append_args(reply, DBUS_TYPE_INVALID);
-
- return reply;
-}
-
-static DBusMessage *nm_state(DBusConnection *conn,
+static DBusMessage *property_get(DBusConnection *conn,
DBusMessage *msg, void *data)
{
- DBusMessage *reply;
-
- DBG("conn %p", conn);
-
- reply = dbus_message_new_method_return(msg);
- if (reply == NULL)
- return NULL;
-
- dbus_message_append_args(reply, DBUS_TYPE_UINT32, &state,
- DBUS_TYPE_INVALID);
-
- return reply;
-}
-
-static GDBusMethodTable nm_methods[] = {
- { "sleep", "", "", nm_sleep },
- { "wake", "", "", nm_wake },
- { "state", "", "u", nm_state },
- { },
-};
-
-static DBusMessage *nm_prop_get(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- DBusMessageIter iter, value;
const char *interface, *key;
- DBusMessage *reply;
DBG("conn %p", conn);
- reply = dbus_message_new_method_return(msg);
- if (reply == NULL)
- return NULL;
-
dbus_message_get_args(msg, NULL,
DBUS_TYPE_STRING, &interface,
DBUS_TYPE_STRING, &key,
DBUS_TYPE_INVALID);
+ DBG("interface %s property %s", interface, key);
+
if (g_strcmp0(key, "State") == 0) {
+ DBusMessage *reply;
+ DBusMessageIter iter, value;
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
dbus_message_iter_append_basic(&value, DBUS_TYPE_UINT32,
&state);
dbus_message_iter_close_container(&iter, &value);
- } else {
- dbus_message_unref(reply);
- return dbus_message_new_error(msg, DBUS_ERROR_FAILED,
- "Unsupported property");
+
+ return reply;
}
- return reply;
+ return dbus_message_new_error(msg, DBUS_ERROR_FAILED,
+ "Unsupported property");
}
-static GDBusMethodTable nm_prop_methods[] = {
- { "Get", "ss", "v", nm_prop_get },
+static GDBusMethodTable methods[] = {
+ { "Get", "ss", "v", property_get },
+ { },
+};
+
+static GDBusSignalTable signals[] = {
+ { "PropertiesChanged", "a{sv}" },
+ { "StateChanged", "u" },
{ },
};
static int nmcompat_init(void)
{
- gboolean ret;
-
DBG("");
connection = connman_dbus_get_connection();
return -1;
if (g_dbus_request_name(connection, NM_SERVICE, NULL) == FALSE) {
- connman_error("nmcompat: can't register nm service\n");
+ connman_error("nmcompat: failed register service\n");
return -1;
}
return -1;
}
- ret = g_dbus_register_interface(connection, NM_PATH, NM_INTERFACE,
- nm_methods, NULL, NULL, NULL, NULL);
- if (ret == FALSE) {
- connman_error("nmcompat: can't register " NM_INTERFACE);
- return -1;
- }
-
- ret = g_dbus_register_interface(connection, NM_PATH,
- DBUS_PROPERTIES_INTERFACE,
- nm_prop_methods, NULL, NULL,
- NULL, NULL);
- if (ret == FALSE) {
- connman_error("nmcompat: can't register "
- DBUS_PROPERTIES_INTERFACE);
+ if (g_dbus_register_interface(connection, NM_PATH,
+ DBUS_PROPERTIES_INTERFACE,
+ methods, signals, NULL, NULL, NULL) == FALSE) {
+ connman_error("nmcompat: failed to register "
+ DBUS_PROPERTIES_INTERFACE);
return -1;
}
if (connection == NULL)
return;
- g_dbus_unregister_interface(connection, NM_PATH, NM_INTERFACE);
+ g_dbus_unregister_interface(connection, NM_PATH,
+ DBUS_PROPERTIES_INTERFACE);
dbus_connection_unref(connection);
}
struct ntpd_peer {
char *server;
- gint refcount;
+ int refcount;
};
struct ntpdate_task {
static void remove_peer(GList *peer_list, struct ntpd_peer *peer)
{
- if (!g_atomic_int_dec_and_test(&peer->refcount))
+ if (__sync_fetch_and_sub(&peer->refcount, 1) != 1)
return;
g_free(peer->server);
connman_bool_t ret;
struct sockaddr_in server_addr;
- if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+ if ((sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0)) == -1)
return FALSE;
server_addr.sin_family = AF_INET;
if ((peer = find_peer(pending_peers, server)) ||
(peer = find_peer(peers, server))) {
- g_atomic_int_inc(&peer->refcount);
+ __sync_fetch_and_add(&peer->refcount, 1);
return 0;
}
*
* Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2011 BWM Car IT GmbH. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include <gdbus.h>
#include <string.h>
+#include <stdint.h>
#define CONNMAN_API_SUBJECT_TO_CHANGE
#include <connman/plugin.h>
#include <connman/device.h>
#include <connman/network.h>
-#include <connman/ipconfig.h>
-#include <connman/dbus.h>
#include <connman/inet.h>
-#include <connman/technology.h>
+#include <connman/dbus.h>
#include <connman/log.h>
+#include <connman/technology.h>
#include "mcc.h"
+#define uninitialized_var(x) x = x
+
#define OFONO_SERVICE "org.ofono"
#define OFONO_MANAGER_INTERFACE OFONO_SERVICE ".Manager"
#define OFONO_MODEM_INTERFACE OFONO_SERVICE ".Modem"
-#define OFONO_GPRS_INTERFACE OFONO_SERVICE ".ConnectionManager"
-#define OFONO_CONTEXT_INTERFACE OFONO_SERVICE ".ConnectionContext"
#define OFONO_SIM_INTERFACE OFONO_SERVICE ".SimManager"
-#define OFONO_REGISTRATION_INTERFACE OFONO_SERVICE ".NetworkRegistration"
+#define OFONO_NETREG_INTERFACE OFONO_SERVICE ".NetworkRegistration"
+#define OFONO_CM_INTERFACE OFONO_SERVICE ".ConnectionManager"
+#define OFONO_CONTEXT_INTERFACE OFONO_SERVICE ".ConnectionContext"
+#define OFONO_CDMA_CM_INTERFACE OFONO_SERVICE ".cdma.ConnectionManager"
+#define OFONO_CDMA_NETREG_INTERFACE OFONO_SERVICE ".cdma.NetworkRegistration"
+#define MODEM_ADDED "ModemAdded"
+#define MODEM_REMOVED "ModemRemoved"
#define PROPERTY_CHANGED "PropertyChanged"
-#define GET_PROPERTIES "GetProperties"
-#define SET_PROPERTY "SetProperty"
#define CONTEXT_ADDED "ContextAdded"
#define CONTEXT_REMOVED "ContextRemoved"
-#define ADD_CONTEXT "AddContext"
-#define GET_MODEMS "GetModems"
-#define MODEM_ADDED "ModemAdded"
-#define MODEM_REMOVED "ModemRemoved"
+#define GET_PROPERTIES "GetProperties"
+#define SET_PROPERTY "SetProperty"
+#define GET_MODEMS "GetModems"
+#define GET_CONTEXTS "GetContexts"
#define TIMEOUT 40000
+enum ofono_api {
+ OFONO_API_SIM = 0x1,
+ OFONO_API_NETREG = 0x2,
+ OFONO_API_CM = 0x4,
+ OFONO_API_CDMA_NETREG = 0x8,
+ OFONO_API_CDMA_CM = 0x10,
+};
+
+/*
+ * The way this plugin works is following:
+ *
+ * powered -> SubscriberIdentity or Online = True -> gprs, context ->
+ * attached -> netreg -> ready
+ *
+ * Enabling and disabling modems are steered through the rfkill
+ * interface. That means when ConnMan toggles the rfkill bit oFono
+ * will add or remove the modems.
+ *
+ * ConnMan will always power up (set Powered and Online) the
+ * modems. No need to power them down because this will be done
+ * through the rfkill inteface.
+ */
+
static DBusConnection *connection;
-static GHashTable *modem_hash = NULL;
+static GHashTable *modem_hash;
+static GHashTable *context_hash;
+
+struct network_context {
+ char *path;
+ int index;
+
+ enum connman_ipconfig_method ipv4_method;
+ struct connman_ipaddress *ipv4_address;
+ char *ipv4_nameservers;
-static GHashTable *network_hash;
+ enum connman_ipconfig_method ipv6_method;
+ struct connman_ipaddress *ipv6_address;
+ char *ipv6_nameservers;
+};
struct modem_data {
char *path;
- struct connman_device *device;
- gboolean has_sim;
- gboolean has_reg;
- gboolean has_gprs;
- gboolean available;
- gboolean pending_online;
- dbus_bool_t requested_online;
- dbus_bool_t online;
-
- /* org.ofono.ConnectionManager properties */
- dbus_bool_t powered;
- dbus_bool_t attached;
- dbus_bool_t roaming_allowed;
-
- connman_bool_t registered;
- connman_bool_t roaming;
- uint8_t strength, has_strength;
- char *operator;
-};
-struct network_info {
+ struct connman_device *device;
struct connman_network *network;
- enum connman_ipconfig_method ipv4_method;
- struct connman_ipaddress ipv4_address;
+ struct network_context *context;
- enum connman_ipconfig_method ipv6_method;
- struct connman_ipaddress ipv6_address;
+ /* Modem Interface */
+ char *serial;
+ connman_bool_t powered;
+ connman_bool_t online;
+ uint8_t interfaces;
+ connman_bool_t ignore;
+
+ connman_bool_t set_powered;
+
+ /* CDMA ConnectionManager Interface */
+ connman_bool_t cdma_cm_powered;
+
+ /* ConnectionManager Interface */
+ connman_bool_t attached;
+ connman_bool_t cm_powered;
+
+ /* ConnectionContext Interface */
+ connman_bool_t active;
+ connman_bool_t set_active;
+
+ /* SimManager Interface */
+ char *imsi;
+
+ /* Netreg Interface */
+ char *name;
+ uint8_t strength;
+ uint8_t data_strength; /* 1xEVDO signal strength */
+ connman_bool_t roaming;
+
+ /* pending calls */
+ DBusPendingCall *call_set_property;
+ DBusPendingCall *call_get_properties;
+ DBusPendingCall *call_get_contexts;
};
-static int modem_probe(struct connman_device *device)
+static const char *api2string(enum ofono_api api)
+{
+ switch (api) {
+ case OFONO_API_SIM:
+ return "sim";
+ case OFONO_API_NETREG:
+ return "netreg";
+ case OFONO_API_CM:
+ return "cm";
+ case OFONO_API_CDMA_NETREG:
+ return "cdma-netreg";
+ case OFONO_API_CDMA_CM:
+ return "cmda-cm";
+ }
+
+ return "unknown";
+}
+
+static char *get_ident(const char *path)
{
- DBG("device %p", device);
+ char *pos;
- return 0;
+ if (*path != '/')
+ return NULL;
+
+ pos = strrchr(path, '/');
+ if (pos == NULL)
+ return NULL;
+
+ return pos + 1;
}
-static void modem_remove(struct connman_device *device)
+static struct network_context *network_context_alloc(const char *path)
{
- DBG("device %p", device);
+ struct network_context *context;
+
+ context = g_try_new0(struct network_context, 1);
+ if (context == NULL)
+ return NULL;
+
+ context->path = g_strdup(path);
+ context->index = -1;
+
+ context->ipv4_method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
+ context->ipv4_address = NULL;
+ context->ipv4_nameservers = NULL;
+
+ context->ipv6_method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
+ context->ipv6_address = NULL;
+ context->ipv6_nameservers = NULL;
+
+ return context;
}
-static int call_ofono(const char *path,
- const char *interface, const char *method,
- DBusPendingCallNotifyFunction notify, void *user_data,
- DBusFreeFunction free_function,
- int type, ...)
+static void network_context_free(struct network_context *context)
{
- DBusMessage *message;
- DBusPendingCall *call;
- dbus_bool_t ok;
- va_list va;
+ g_free(context->path);
- DBG("path %s %s.%s", path, interface, method);
+ connman_ipaddress_free(context->ipv4_address);
+ g_free(context->ipv4_nameservers);
- if (path == NULL)
- return -EINVAL;
+ connman_ipaddress_free(context->ipv6_address);
+ g_free(context->ipv6_nameservers);
- message = dbus_message_new_method_call(OFONO_SERVICE, path,
- interface, method);
- if (message == NULL)
- return -ENOMEM;
+ free(context);
+}
- dbus_message_set_auto_start(message, FALSE);
+static void set_connected(struct modem_data *modem)
+{
+ connman_bool_t setip = FALSE;
- va_start(va, type);
- ok = dbus_message_append_args_valist(message, type, va);
- va_end(va);
+ DBG("%s", modem->path);
- if (!ok)
- return -ENOMEM;
+ connman_network_set_index(modem->network, modem->context->index);
- if (dbus_connection_send_with_reply(connection, message,
- &call, TIMEOUT) == FALSE) {
- connman_error("Failed to call %s.%s", interface, method);
- dbus_message_unref(message);
- return -EINVAL;
+ switch (modem->context->ipv4_method) {
+ case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
+ case CONNMAN_IPCONFIG_METHOD_OFF:
+ case CONNMAN_IPCONFIG_METHOD_MANUAL:
+ case CONNMAN_IPCONFIG_METHOD_AUTO:
+ break;
+
+ case CONNMAN_IPCONFIG_METHOD_FIXED:
+ connman_network_set_ipv4_method(modem->network,
+ modem->context->ipv4_method);
+ connman_network_set_ipaddress(modem->network,
+ modem->context->ipv4_address);
+ connman_network_set_nameservers(modem->network,
+ modem->context->ipv4_nameservers);
+ setip = TRUE;
+ break;
+
+ case CONNMAN_IPCONFIG_METHOD_DHCP:
+ connman_network_set_ipv4_method(modem->network,
+ modem->context->ipv4_method);
+ setip = TRUE;
+ break;
}
- if (call == NULL) {
- connman_error("D-Bus connection not available");
- dbus_message_unref(message);
- return -EINVAL;
+ switch (modem->context->ipv6_method) {
+ case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
+ case CONNMAN_IPCONFIG_METHOD_OFF:
+ case CONNMAN_IPCONFIG_METHOD_MANUAL:
+ case CONNMAN_IPCONFIG_METHOD_DHCP:
+ case CONNMAN_IPCONFIG_METHOD_AUTO:
+ break;
+
+ case CONNMAN_IPCONFIG_METHOD_FIXED:
+ connman_network_set_ipv6_method(modem->network,
+ modem->context->ipv6_method);
+ connman_network_set_ipaddress(modem->network,
+ modem->context->ipv6_address);
+ setip = TRUE;
+ break;
}
- dbus_pending_call_set_notify(call, notify, user_data, free_function);
+ if (setip == TRUE)
+ connman_network_set_connected(modem->network, TRUE);
+}
- dbus_message_unref(message);
+static void set_disconnected(struct modem_data *modem)
+{
+ DBG("%s", modem->path);
- return -EINPROGRESS;
+ if (modem->network == NULL)
+ return;
+
+ connman_network_set_connected(modem->network, FALSE);
}
+typedef void (*set_property_cb)(struct modem_data *data,
+ connman_bool_t success);
+typedef void (*get_properties_cb)(struct modem_data *data,
+ DBusMessageIter *dict);
+
+struct property_info {
+ struct modem_data *modem;
+ const char *path;
+ const char *interface;
+ const char *property;
+ set_property_cb set_property_cb;
+ get_properties_cb get_properties_cb;
+};
+
static void set_property_reply(DBusPendingCall *call, void *user_data)
{
+ struct property_info *info = user_data;
DBusMessage *reply;
DBusError error;
- char const *name = user_data;
+ connman_bool_t success = TRUE;
- DBG("");
+ DBG("%s path %s %s.%s", info->modem->path,
+ info->path, info->interface, info->property);
+
+ info->modem->call_set_property = NULL;
dbus_error_init(&error);
reply = dbus_pending_call_steal_reply(call);
if (dbus_set_error_from_message(&error, reply)) {
- connman_error("SetProperty(%s) %s %s", name,
+ connman_error("Failed to change property: %s %s.%s: %s %s",
+ info->path, info->interface, info->property,
error.name, error.message);
dbus_error_free(&error);
+ success = FALSE;
}
+ if (info->set_property_cb != NULL)
+ (*info->set_property_cb)(info->modem, success);
+
dbus_message_unref(reply);
dbus_pending_call_unref(call);
}
-static int set_property(const char *path, const char *interface,
+static int set_property(struct modem_data *modem,
+ const char *path, const char *interface,
const char *property, int type, void *value,
- DBusPendingCallNotifyFunction notify, void *user_data,
- DBusFreeFunction free_function)
+ set_property_cb notify)
{
DBusMessage *message;
DBusMessageIter iter;
- DBusPendingCall *call;
+ struct property_info *info;
- DBG("path %s %s.%s", path, interface, property);
+ DBG("%s path %s %s.%s", modem->path, path, interface, property);
- g_assert(notify == NULL ? free_function == NULL : 1);
+ if (modem->call_set_property != NULL) {
+ DBG("Cancel pending SetProperty");
- if (path == NULL)
- return -EINVAL;
+ dbus_pending_call_cancel(modem->call_set_property);
+ modem->call_set_property = NULL;
+ }
message = dbus_message_new_method_call(OFONO_SERVICE, path,
interface, SET_PROPERTY);
if (message == NULL)
return -ENOMEM;
- dbus_message_set_auto_start(message, FALSE);
-
dbus_message_iter_init_append(message, &iter);
connman_dbus_property_append_basic(&iter, property, type, value);
if (dbus_connection_send_with_reply(connection, message,
- &call, TIMEOUT) == FALSE) {
- connman_error("Failed to change \"%s\" property on %s",
- property, interface);
+ &modem->call_set_property, TIMEOUT) == FALSE) {
+ connman_error("Failed to change property: %s %s.%s",
+ path, interface, property);
dbus_message_unref(message);
return -EINVAL;
}
- if (call == NULL) {
+ if (modem->call_set_property == NULL) {
connman_error("D-Bus connection not available");
dbus_message_unref(message);
return -EINVAL;
}
- if (notify == NULL) {
- notify = set_property_reply;
- user_data = (void *)property;
- free_function = NULL;
+ info = g_try_new0(struct property_info, 1);
+ if (info == NULL) {
+ dbus_message_unref(message);
+ return -ENOMEM;
}
- dbus_pending_call_set_notify(call, notify, user_data, free_function);
+ info->modem = modem;
+ info->path = path;
+ info->interface = interface;
+ info->property = property;
+ info->set_property_cb = notify;
+
+ dbus_pending_call_set_notify(modem->call_set_property,
+ set_property_reply, info, g_free);
dbus_message_unref(message);
return -EINPROGRESS;
}
-static void update_modem_online(struct modem_data *modem,
- connman_bool_t online)
-{
- DBG("modem %p path %s online %d", modem, modem->path, online);
-
- modem->online = online;
- modem->requested_online = online;
- modem->pending_online = FALSE;
-
- if (modem->device)
- connman_device_set_powered(modem->device, online);
-}
-
-static void set_online_reply(DBusPendingCall *call, void *user_data)
+static void get_properties_reply(DBusPendingCall *call, void *user_data)
{
- struct modem_data *modem;
+ struct property_info *info = user_data;
+ DBusMessageIter array, dict;
DBusMessage *reply;
DBusError error;
- gboolean result;
- DBG("path %s", (char *)user_data);
+ DBG("%s path %s %s", info->modem->path, info->path, info->interface);
- if (modem_hash == NULL)
- return;
+ info->modem->call_get_properties = NULL;
- modem = g_hash_table_lookup(modem_hash, user_data);
- if (modem == NULL)
- return;
+ dbus_error_init(&error);
reply = dbus_pending_call_steal_reply(call);
- dbus_error_init(&error);
-
if (dbus_set_error_from_message(&error, reply)) {
- connman_error("SetProperty(Online) %s %s",
+ connman_error("Failed to get properties: %s %s: %s %s",
+ info->path, info->interface,
error.name, error.message);
dbus_error_free(&error);
- result = modem->online;
- } else
- result = modem->requested_online;
+ goto done;
+ }
+
+ if (dbus_message_iter_init(reply, &array) == FALSE)
+ goto done;
+
+ if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
+ goto done;
+
+ dbus_message_iter_recurse(&array, &dict);
+
+ if (info->get_properties_cb != NULL)
+ (*info->get_properties_cb)(info->modem, &dict);
- if (modem->pending_online)
- update_modem_online(modem, result);
+done:
dbus_message_unref(reply);
dbus_pending_call_unref(call);
}
-static int modem_change_online(char const *path, dbus_bool_t online)
+static int get_properties(const char *path, const char *interface,
+ get_properties_cb notify,
+ struct modem_data *modem)
{
- struct modem_data *modem = g_hash_table_lookup(modem_hash, path);
+ DBusMessage *message;
+ struct property_info *info;
- if (modem == NULL)
- return -ENODEV;
+ DBG("%s path %s %s", modem->path, path, interface);
- if (modem->online == online)
- return -EALREADY;
+ if (modem->call_get_properties != NULL) {
+ connman_error("Pending GetProperties");
+ return -EBUSY;
+ }
- modem->requested_online = online;
+ message = dbus_message_new_method_call(OFONO_SERVICE, path,
+ interface, GET_PROPERTIES);
+ if (message == NULL)
+ return -ENOMEM;
- return set_property(path, OFONO_MODEM_INTERFACE, "Online",
- DBUS_TYPE_BOOLEAN, &online,
- set_online_reply,
- (void *)g_strdup(path), g_free);
-}
+ if (dbus_connection_send_with_reply(connection, message,
+ &modem->call_get_properties, TIMEOUT) == FALSE) {
+ connman_error("Failed to call %s.GetProperties()", interface);
+ dbus_message_unref(message);
+ return -EINVAL;
+ }
-static int modem_enable(struct connman_device *device)
-{
- const char *path = connman_device_get_string(device, "Path");
+ if (modem->call_get_properties == NULL) {
+ connman_error("D-Bus connection not available");
+ dbus_message_unref(message);
+ return -EINVAL;
+ }
- DBG("device %p, path, %s", device, path);
+ info = g_try_new0(struct property_info, 1);
+ if (info == NULL) {
+ dbus_message_unref(message);
+ return -ENOMEM;
+ }
- return modem_change_online(path, TRUE);
-}
+ info->modem = modem;
+ info->path = path;
+ info->interface = interface;
+ info->get_properties_cb = notify;
-static int modem_disable(struct connman_device *device)
-{
- const char *path = connman_device_get_string(device, "Path");
+ dbus_pending_call_set_notify(modem->call_get_properties,
+ get_properties_reply, info, g_free);
- DBG("device %p path %s", device, path);
+ dbus_message_unref(message);
- return modem_change_online(path, FALSE);
+ return -EINPROGRESS;
}
-static struct connman_device_driver modem_driver = {
- .name = "modem",
- .type = CONNMAN_DEVICE_TYPE_CELLULAR,
- .probe = modem_probe,
- .remove = modem_remove,
- .enable = modem_enable,
- .disable = modem_disable,
-};
-
-static void remove_device_networks(struct connman_device *device)
+static void context_set_active_reply(struct modem_data *modem,
+ connman_bool_t success)
{
- GHashTableIter iter;
- gpointer key, value;
- GSList *info_list = NULL;
- GSList *list;
+ DBG("%s", modem->path);
- if (network_hash == NULL)
+ if (success == TRUE) {
+ /*
+ * Don't handle do anything on success here. oFono will send
+ * the change via PropertyChanged singal.
+ */
return;
+ }
- g_hash_table_iter_init(&iter, network_hash);
+ /*
+ * Active = True might fail due a timeout. That means oFono
+ * still tries to go online. If we retry to set Active = True,
+ * we just get a InProgress error message. Should we power
+ * cycle the modem in such cases?
+ */
+
+ if (modem->network == NULL) {
+ /*
+ * In the case where we power down the device
+ * we don't wait for the reply, therefore the network
+ * might already be gone.
+ */
+ return;
+ }
- while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
- struct network_info *info = value;
+ connman_network_set_error(modem->network,
+ CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
+}
- if (connman_network_get_device(info->network) != device)
- continue;
+static int context_set_active(struct modem_data *modem,
+ connman_bool_t active)
+{
+ int err;
- info_list = g_slist_append(info_list, info);
- }
+ DBG("%s active %d", modem->path, active);
- for (list = info_list; list != NULL; list = list->next) {
- struct network_info *info = list->data;
+ err = set_property(modem, modem->context->path,
+ OFONO_CONTEXT_INTERFACE,
+ "Active", DBUS_TYPE_BOOLEAN,
+ &active,
+ context_set_active_reply);
- connman_device_remove_network(device, info->network);
- }
+ if (active == FALSE && err == -EINPROGRESS)
+ return 0;
- g_slist_free(info_list);
+ return err;
}
-static void modem_remove_device(struct modem_data *modem)
+static void cdma_cm_set_powered_reply(struct modem_data *modem,
+ connman_bool_t success)
{
- DBG("modem %p path %s device %p", modem, modem->path, modem->device);
+ DBG("%s", modem->path);
- if (modem->device == NULL)
+ if (success == TRUE) {
+ /*
+ * Don't handle do anything on success here. oFono will send
+ * the change via PropertyChanged singal.
+ */
return;
+ }
- remove_device_networks(modem->device);
-
- connman_device_unregister(modem->device);
- connman_device_unref(modem->device);
+ /*
+ * Powered = True might fail due a timeout. That means oFono
+ * still tries to go online. If we retry to set Powered = True,
+ * we just get a InProgress error message. Should we power
+ * cycle the modem in such cases?
+ */
+
+ if (modem->network == NULL) {
+ /*
+ * In the case where we power down the device
+ * we don't wait for the reply, therefore the network
+ * might already be gone.
+ */
+ return;
+ }
- modem->device = NULL;
+ connman_network_set_error(modem->network,
+ CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
}
-static void remove_modem(gpointer data)
+static int cdma_cm_set_powered(struct modem_data *modem, connman_bool_t powered)
{
- struct modem_data *modem = data;
+ int err;
- modem_remove_device(modem);
+ DBG("%s powered %d", modem->path, powered);
- g_free(modem->path);
- g_free(modem->operator);
+ err = set_property(modem, modem->path, OFONO_CDMA_CM_INTERFACE,
+ "Powered", DBUS_TYPE_BOOLEAN,
+ &powered,
+ cdma_cm_set_powered_reply);
- g_free(modem);
+ if (powered == FALSE && err == -EINPROGRESS)
+ return 0;
+
+ return err;
}
-static void remove_network(gpointer data)
+static int modem_set_online(struct modem_data *modem, connman_bool_t online)
{
- struct network_info *info = data;
- struct connman_device *device;
-
- device = connman_network_get_device(info->network);
- if (device != NULL)
- connman_device_remove_network(device, info->network);
-
- connman_network_unref(info->network);
+ DBG("%s online %d", modem->path, online);
- g_free(info);
+ return set_property(modem, modem->path,
+ OFONO_MODEM_INTERFACE,
+ "Online", DBUS_TYPE_BOOLEAN,
+ &online,
+ NULL);
}
-static char *get_ident(const char *path)
+static int cm_set_powered(struct modem_data *modem, connman_bool_t powered)
{
- char *pos;
+ int err;
- if (*path != '/')
- return NULL;
+ DBG("%s powered %d", modem->path, powered);
- pos = strrchr(path, '/');
- if (pos == NULL)
- return NULL;
+ err = set_property(modem, modem->path,
+ OFONO_CM_INTERFACE,
+ "Powered", DBUS_TYPE_BOOLEAN,
+ &powered,
+ NULL);
- return pos + 1;
+ if (powered == FALSE && err == -EINPROGRESS)
+ return 0;
+
+ return err;
}
-static void create_service(struct connman_network *network)
+static int modem_set_powered(struct modem_data *modem, connman_bool_t powered)
{
- const char *path;
- char *group;
+ int err;
- DBG("");
+ DBG("%s powered %d", modem->path, powered);
- path = connman_network_get_string(network, "Path");
+ modem->set_powered = powered;
- group = get_ident(path);
+ err = set_property(modem, modem->path,
+ OFONO_MODEM_INTERFACE,
+ "Powered", DBUS_TYPE_BOOLEAN,
+ &powered,
+ NULL);
- connman_network_set_group(network, group);
-}
+ if (powered == FALSE && err == -EINPROGRESS)
+ return 0;
-static int network_probe(struct connman_network *network)
-{
- return 0;
+ return err;
}
-static gboolean pending_network_is_available(struct connman_network *network)
+static connman_bool_t has_interface(uint8_t interfaces,
+ enum ofono_api api)
{
- /* Modem or network may be removed */
- if (network == NULL || connman_network_get_device(network) == NULL) {
- DBG("Modem or network was removed");
- return FALSE;
- }
+ if ((interfaces & api) == api)
+ return TRUE;
- return TRUE;
+ return FALSE;
}
-static void set_connected(struct network_info *info,
- connman_bool_t connected)
+static uint8_t extract_interfaces(DBusMessageIter *array)
{
- gboolean setip = FALSE;
+ DBusMessageIter entry;
+ uint8_t interfaces = 0;
- DBG("network %p connected %d", info->network, connected);
+ dbus_message_iter_recurse(array, &entry);
- switch (info->ipv4_method) {
- case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
- case CONNMAN_IPCONFIG_METHOD_OFF:
- case CONNMAN_IPCONFIG_METHOD_MANUAL:
- case CONNMAN_IPCONFIG_METHOD_AUTO:
- break;
+ while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
+ const char *name;
- case CONNMAN_IPCONFIG_METHOD_FIXED:
- connman_network_set_ipv4_method(info->network,
- info->ipv4_method);
- connman_network_set_ipaddress(info->network,
- &info->ipv4_address);
- setip = TRUE;
- break;
-
- case CONNMAN_IPCONFIG_METHOD_DHCP:
- connman_network_set_ipv4_method(info->network,
- info->ipv4_method);
- setip = TRUE;
- break;
- }
+ dbus_message_iter_get_basic(&entry, &name);
- switch (info->ipv6_method) {
- case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
- case CONNMAN_IPCONFIG_METHOD_OFF:
- case CONNMAN_IPCONFIG_METHOD_MANUAL:
- case CONNMAN_IPCONFIG_METHOD_DHCP:
- case CONNMAN_IPCONFIG_METHOD_AUTO:
- break;
+ if (g_str_equal(name, OFONO_SIM_INTERFACE) == TRUE)
+ interfaces |= OFONO_API_SIM;
+ else if (g_str_equal(name, OFONO_NETREG_INTERFACE) == TRUE)
+ interfaces |= OFONO_API_NETREG;
+ else if (g_str_equal(name, OFONO_CM_INTERFACE) == TRUE)
+ interfaces |= OFONO_API_CM;
+ else if (g_str_equal(name, OFONO_CDMA_CM_INTERFACE) == TRUE)
+ interfaces |= OFONO_API_CDMA_CM;
+ else if (g_str_equal(name, OFONO_CDMA_NETREG_INTERFACE) == TRUE)
+ interfaces |= OFONO_API_CDMA_NETREG;
- case CONNMAN_IPCONFIG_METHOD_FIXED:
- connman_network_set_ipv6_method(info->network,
- info->ipv6_method);
- connman_network_set_ipaddress(info->network,
- &info->ipv6_address);
- setip = TRUE;
- break;
+ dbus_message_iter_next(&entry);
}
- if (setip == TRUE)
- connman_network_set_connected(info->network, connected);
-}
-
-static void set_active_reply(DBusPendingCall *call, void *user_data)
-{
- char const *path = user_data;
- DBusMessage *reply;
- DBusError error;
- struct network_info *info;
-
- info = g_hash_table_lookup(network_hash, path);
-
- reply = dbus_pending_call_steal_reply(call);
-
- if (info == NULL)
- goto done;
-
- DBG("path %s network %p", path, info->network);
-
- if (!pending_network_is_available(info->network))
- goto done;
-
- dbus_error_init(&error);
-
- if (dbus_set_error_from_message(&error, reply)) {
- connman_error("SetProperty(Active) %s %s",
- error.name, error.message);
-
- if (connman_network_get_index(info->network) < 0)
- connman_network_set_error(info->network,
- CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
-
- dbus_error_free(&error);
- } else if (connman_network_get_index(info->network) >= 0)
- set_connected(info, TRUE);
-
-done:
- dbus_message_unref(reply);
-
- dbus_pending_call_unref(call);
-}
-
-static int set_network_active(struct connman_network *network)
-{
- dbus_bool_t value = TRUE;
- const char *path = connman_network_get_string(network, "Path");
-
- DBG("network %p, path %s", network, path);
-
- return set_property(path, OFONO_CONTEXT_INTERFACE,
- "Active", DBUS_TYPE_BOOLEAN, &value,
- set_active_reply, g_strdup(path), g_free);
-}
-
-static int set_network_inactive(struct connman_network *network)
-{
- int err;
- dbus_bool_t value = FALSE;
- const char *path = connman_network_get_string(network, "Path");
-
- DBG("network %p, path %s", network, path);
-
- err = set_property(path, OFONO_CONTEXT_INTERFACE,
- "Active", DBUS_TYPE_BOOLEAN, &value,
- NULL, NULL, NULL);
-
- if (err == -EINPROGRESS)
- err = 0;
-
- return err;
-}
-
-static int network_connect(struct connman_network *network)
-{
- struct connman_device *device;
- struct modem_data *modem;
-
- DBG("network %p", network);
-
- device = connman_network_get_device(network);
- if (device == NULL)
- return -ENODEV;
-
- modem = connman_device_get_data(device);
- if (modem == NULL)
- return -ENODEV;
-
- if (modem->registered == FALSE)
- return -ENOLINK;
-
- if (modem->powered == FALSE)
- return -ENOLINK;
-
- if (modem->roaming_allowed == FALSE && modem->roaming == TRUE)
- return -ENOLINK;
-
- return set_network_active(network);
-}
-
-static int network_disconnect(struct connman_network *network)
-{
- DBG("network %p", network);
-
- if (connman_network_get_index(network) < 0)
- return -ENOTCONN;
-
- connman_network_set_associating(network, FALSE);
-
- return set_network_inactive(network);
-}
-
-static void network_remove(struct connman_network *network)
-{
- char const *path = connman_network_get_string(network, "Path");
-
- DBG("network %p path %s", network, path);
-
- g_hash_table_remove(network_hash, path);
+ return interfaces;
}
-static struct connman_network_driver network_driver = {
- .name = "network",
- .type = CONNMAN_NETWORK_TYPE_CELLULAR,
- .probe = network_probe,
- .remove = network_remove,
- .connect = network_connect,
- .disconnect = network_disconnect,
-};
-
-static void get_dns(DBusMessageIter *array, struct network_info *info)
+static char *extract_nameservers(DBusMessageIter *array)
{
DBusMessageIter entry;
- gchar *nameservers = NULL, *nameservers_old = NULL;
-
- DBG("");
-
+ char *nameservers = NULL;
+ char *tmp;
dbus_message_iter_recurse(array, &entry);
while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
- const char *dns;
+ const char *nameserver;
- dbus_message_iter_get_basic(&entry, &dns);
-
- DBG("dns %s", dns);
+ dbus_message_iter_get_basic(&entry, &nameserver);
if (nameservers == NULL) {
-
- nameservers = g_strdup(dns);
+ nameservers = g_strdup(nameserver);
} else {
-
- nameservers_old = nameservers;
- nameservers = g_strdup_printf("%s %s",
- nameservers_old, dns);
- g_free(nameservers_old);
+ tmp = nameservers;
+ nameservers = g_strdup_printf("%s %s", tmp, nameserver);
+ g_free(tmp);
}
dbus_message_iter_next(&entry);
}
- connman_network_set_nameservers(info->network, nameservers);
-
- g_free(nameservers);
+ return nameservers;
}
-static void update_ipv4_settings(DBusMessageIter *array,
- struct network_info *info)
+static void extract_ipv4_settings(DBusMessageIter *array,
+ struct network_context *context)
{
DBusMessageIter dict;
char *address = NULL, *netmask = NULL, *gateway = NULL;
+ char *nameservers = NULL;
const char *interface = NULL;
-
- DBG("network %p", info->network);
+ int index = -1;
if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
return;
dbus_message_iter_recurse(&dict, &entry);
dbus_message_iter_get_basic(&entry, &key);
- DBG("key %s", key);
-
dbus_message_iter_next(&entry);
dbus_message_iter_recurse(&entry, &value);
if (g_str_equal(key, "Interface") == TRUE) {
- int index;
-
dbus_message_iter_get_basic(&value, &interface);
- DBG("interface %s", interface);
+ DBG("Interface %s", interface);
index = connman_inet_ifindex(interface);
- if (index >= 0) {
- connman_network_set_index(info->network, index);
- } else {
- connman_error("Can not find interface %s",
- interface);
- break;
- }
- } else if (g_str_equal(key, "Method") == TRUE) {
- const char *method;
- dbus_message_iter_get_basic(&value, &method);
-
- if (g_strcmp0(method, "static") == 0) {
+ DBG("index %d", index);
+ } else if (g_str_equal(key, "Method") == TRUE) {
+ dbus_message_iter_get_basic(&value, &val);
- info->ipv4_method =
- CONNMAN_IPCONFIG_METHOD_FIXED;
- } else if (g_strcmp0(method, "dhcp") == 0) {
+ DBG("Method %s", val);
- info->ipv4_method =
- CONNMAN_IPCONFIG_METHOD_DHCP;
+ if (g_strcmp0(val, "static") == 0) {
+ context->ipv4_method = CONNMAN_IPCONFIG_METHOD_FIXED;
+ } else if (g_strcmp0(val, "dhcp") == 0) {
+ context->ipv4_method = CONNMAN_IPCONFIG_METHOD_DHCP;
break;
}
} else if (g_str_equal(key, "Address") == TRUE) {
address = g_strdup(val);
- DBG("address %s", address);
+ DBG("Address %s", address);
} else if (g_str_equal(key, "Netmask") == TRUE) {
dbus_message_iter_get_basic(&value, &val);
netmask = g_strdup(val);
- DBG("netmask %s", netmask);
+ DBG("Netmask %s", netmask);
} else if (g_str_equal(key, "DomainNameServers") == TRUE) {
+ nameservers = extract_nameservers(&value);
- get_dns(&value, info);
+ DBG("Nameservers %s", nameservers);
} else if (g_str_equal(key, "Gateway") == TRUE) {
dbus_message_iter_get_basic(&value, &val);
gateway = g_strdup(val);
- DBG("gateway %s", gateway);
+ DBG("Gateway %s", gateway);
}
dbus_message_iter_next(&dict);
}
+ if (index < 0)
+ goto out;
- if (info->ipv4_method == CONNMAN_IPCONFIG_METHOD_FIXED) {
- connman_ipaddress_set_ipv4(&info->ipv4_address, address,
- netmask, gateway);
- }
+ if (context->ipv4_method != CONNMAN_IPCONFIG_METHOD_FIXED)
+ goto out;
+
+ context->ipv4_address = connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV4);
+ if (context->ipv4_address == NULL)
+ goto out;
+
+ context->index = index;
+ connman_ipaddress_set_ipv4(context->ipv4_address, address,
+ netmask, gateway);
- /* deactive, oFono send NULL inteface before deactive signal */
- if (interface == NULL)
- connman_network_set_index(info->network, -1);
+ context->ipv4_nameservers = nameservers;
+
+out:
+ if (context->ipv4_nameservers != nameservers)
+ g_free(nameservers);
g_free(address);
g_free(netmask);
g_free(gateway);
}
-static void update_ipv6_settings(DBusMessageIter *array,
- struct network_info *info)
+static void extract_ipv6_settings(DBusMessageIter *array,
+ struct network_context *context)
{
DBusMessageIter dict;
char *address = NULL, *gateway = NULL;
unsigned char prefix_length;
+ char *nameservers = NULL;
const char *interface = NULL;
-
- DBG("network %p", info->network);
+ int index = -1;
if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
return;
dbus_message_iter_recurse(array, &dict);
- info->ipv6_method = CONNMAN_IPCONFIG_METHOD_FIXED;
-
while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
DBusMessageIter entry, value;
const char *key, *val;
dbus_message_iter_recurse(&dict, &entry);
dbus_message_iter_get_basic(&entry, &key);
- DBG("key %s", key);
-
dbus_message_iter_next(&entry);
dbus_message_iter_recurse(&entry, &value);
if (g_str_equal(key, "Interface") == TRUE) {
- int index;
-
dbus_message_iter_get_basic(&value, &interface);
- DBG("interface %s", interface);
+ DBG("Interface %s", interface);
index = connman_inet_ifindex(interface);
- if (index >= 0) {
- connman_network_set_index(info->network, index);
- } else {
- connman_error("Can not find interface %s",
- interface);
- break;
- }
+
+ DBG("index %d", index);
} else if (g_str_equal(key, "Address") == TRUE) {
dbus_message_iter_get_basic(&value, &val);
address = g_strdup(val);
- DBG("address %s", address);
+ DBG("Address %s", address);
} else if (g_str_equal(key, "PrefixLength") == TRUE) {
dbus_message_iter_get_basic(&value, &prefix_length);
DBG("prefix length %d", prefix_length);
} else if (g_str_equal(key, "DomainNameServers") == TRUE) {
+ nameservers = extract_nameservers(&value);
- get_dns(&value, info);
+ DBG("Nameservers %s", nameservers);
} else if (g_str_equal(key, "Gateway") == TRUE) {
dbus_message_iter_get_basic(&value, &val);
gateway = g_strdup(val);
- DBG("gateway %s", gateway);
+ DBG("Gateway %s", gateway);
}
dbus_message_iter_next(&dict);
}
- connman_ipaddress_set_ipv6(&info->ipv6_address, address,
- prefix_length, gateway);
+ if (index < 0)
+ goto out;
+
+ context->ipv6_method = CONNMAN_IPCONFIG_METHOD_FIXED;
+
+ context->ipv6_address =
+ connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV6);
+ if (context->ipv6_address == NULL)
+ goto out;
+
+ context->index = index;
+ connman_ipaddress_set_ipv6(context->ipv6_address, address,
+ prefix_length, gateway);
+
+ context->ipv6_nameservers = nameservers;
- /* deactive, oFono send NULL inteface before deactive signal */
- if (interface == NULL)
- connman_network_set_index(info->network, -1);
+out:
+ if (context->ipv6_nameservers != nameservers)
+ g_free(nameservers);
g_free(address);
g_free(gateway);
}
-static int add_network(struct connman_device *device,
- const char *path, DBusMessageIter *dict)
+static connman_bool_t ready_to_create_device(struct modem_data *modem)
{
- struct modem_data *modem = connman_device_get_data(device);
- struct connman_network *network;
- struct network_info *info;
- char *ident;
- dbus_bool_t active = FALSE;
-
- DBG("modem %p device %p path %s", modem, device, path);
-
- ident = get_ident(path);
+ /*
+ * There are three different modem types which behave slightly
+ * different:
+ * - GSM modems will expose the SIM interface then the
+ * CM interface.
+ * - CDMA modems will expose CM first and sometime later
+ * a unique serial number.
+ *
+ * This functions tests if we have the necessary information gathered
+ * before we are able to create a device.
+ */
- network = connman_device_get_network(device, ident);
- if (network != NULL)
- return -EALREADY;
-
- info = g_hash_table_lookup(network_hash, path);
- if (info != NULL) {
- DBG("path %p already exists with device %p", path,
- connman_network_get_device(info->network));
- if (connman_network_get_device(info->network))
- return -EALREADY;
- g_hash_table_remove(network_hash, path);
- }
+ if (modem->device != NULL)
+ return FALSE;
- network = connman_network_create(ident, CONNMAN_NETWORK_TYPE_CELLULAR);
- if (network == NULL)
- return -ENOMEM;
+ if (modem->imsi != NULL || modem->serial != NULL)
+ return TRUE;
- info = g_try_new0(struct network_info, 1);
- if (info == NULL) {
- connman_network_unref(network);
- return -ENOMEM;
- }
+ return FALSE;
+}
- connman_ipaddress_clear(&info->ipv4_address);
- connman_ipaddress_clear(&info->ipv6_address);
- info->network = network;
+static void create_device(struct modem_data *modem)
+{
+ struct connman_device *device;
+ char *uninitialized_var(ident);
- connman_network_set_string(network, "Path", path);
+ DBG("%s", modem->path);
- create_service(network);
+ if (modem->imsi != NULL)
+ ident = modem->imsi;
+ else if (modem->serial != NULL)
+ ident = modem->serial;
- g_hash_table_insert(network_hash, g_strdup(path), info);
+ if (connman_dbus_validate_ident(ident) == FALSE)
+ ident = connman_dbus_encode_string(ident);
+ else
+ ident = g_strdup(ident);
- connman_network_set_available(network, TRUE);
- connman_network_set_index(network, -1);
+ device = connman_device_create(ident, CONNMAN_DEVICE_TYPE_CELLULAR);
+ if (device == NULL)
+ goto out;
- if (modem->operator)
- connman_network_set_name(network, modem->operator);
- else
- connman_network_set_name(network, "");
+ DBG("device %p", device);
- if (modem->has_strength)
- connman_network_set_strength(network, modem->strength);
+ connman_device_set_ident(device, ident);
- connman_network_set_roaming(network, modem->roaming);
+ connman_device_set_string(device, "Path", modem->path);
- while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
- DBusMessageIter entry, value;
- const char *key;
+ connman_device_set_data(device, modem);
- dbus_message_iter_recurse(dict, &entry);
- dbus_message_iter_get_basic(&entry, &key);
+ if (connman_device_register(device) < 0) {
+ connman_error("Failed to register cellular device");
+ connman_device_unref(device);
+ goto out;
+ }
- dbus_message_iter_next(&entry);
- dbus_message_iter_recurse(&entry, &value);
+ modem->device = device;
- if (g_str_equal(key, "Type")) {
- const char *type;
+ connman_device_set_powered(modem->device, modem->online);
+out:
+ g_free(ident);
+}
- dbus_message_iter_get_basic(&value, &type);
- if (g_strcmp0(type, "internet") != 0) {
- DBG("path %p type %s", path, type);
- g_hash_table_remove(network_hash, path);
- return -EIO;
- }
- } else if (g_str_equal(key, "Settings"))
- update_ipv4_settings(&value, info);
- else if (g_str_equal(key, "IPv6.Settings"))
- update_ipv6_settings(&value, info);
- else if (g_str_equal(key, "Active") == TRUE)
- dbus_message_iter_get_basic(&value, &active);
+static void destroy_device(struct modem_data *modem)
+{
+ DBG("%s", modem->path);
- dbus_message_iter_next(dict);
- }
+ connman_device_set_powered(modem->device, FALSE);
- if (connman_device_add_network(device, network) != 0) {
- g_hash_table_remove(network_hash, path);
- return -EIO;
+ if (modem->network != NULL) {
+ connman_device_remove_network(modem->device, modem->network);
+ connman_network_unref(modem->network);
+ modem->network = NULL;
}
- /* Connect only if requested to do so */
- if (active && connman_network_get_connecting(network) == TRUE)
- set_connected(info, active);
+ connman_device_unregister(modem->device);
+ connman_device_unref(modem->device);
- return 0;
+ modem->device = NULL;
}
-static void check_networks_reply(DBusPendingCall *call, void *user_data)
+static void add_network(struct modem_data *modem)
{
- char *path = user_data;
- struct modem_data *modem;
- DBusMessage *reply;
- DBusMessageIter array, entry, value, properties;
+ const char *group;
- DBG("path %s", path);
+ DBG("%s", modem->path);
- modem = g_hash_table_lookup(modem_hash, path);
- if (modem == NULL)
+ if (modem->network != NULL)
return;
- if (modem->device == NULL)
+
+ modem->network = connman_network_create(modem->context->path,
+ CONNMAN_NETWORK_TYPE_CELLULAR);
+ if (modem->network == NULL)
return;
- reply = dbus_pending_call_steal_reply(call);
+ DBG("network %p", modem->network);
- if (dbus_message_has_signature(reply, "a(oa{sv})") == FALSE)
- goto done;
+ connman_network_set_data(modem->network, modem);
- dbus_message_iter_init(reply, &array);
+ connman_network_set_string(modem->network, "Path",
+ modem->context->path);
- dbus_message_iter_recurse(&array, &entry);
+ connman_network_set_index(modem->network, modem->context->index);
- while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRUCT) {
- char const *network_path;
+ if (modem->name != NULL)
+ connman_network_set_name(modem->network, modem->name);
+ else
+ connman_network_set_name(modem->network, "");
- dbus_message_iter_recurse(&entry, &value);
- dbus_message_iter_get_basic(&value, &network_path);
+ connman_network_set_strength(modem->network, modem->strength);
- dbus_message_iter_next(&value);
- dbus_message_iter_recurse(&value, &properties);
+ group = get_ident(modem->context->path);
+ connman_network_set_group(modem->network, group);
- add_network(modem->device, network_path, &properties);
+ connman_network_set_available(modem->network, TRUE);
- dbus_message_iter_next(&entry);
- }
+ connman_network_set_bool(modem->network, "Roaming",
+ modem->roaming);
-done:
- dbus_message_unref(reply);
+ if (connman_device_add_network(modem->device, modem->network) < 0) {
+ connman_network_unref(modem->network);
+ modem->network = NULL;
+ return;
+ }
- dbus_pending_call_unref(call);
+ /*
+ * Create the ipconfig layer before trying to connect. Withouth
+ * the ipconfig layer the core is not ready to process errors.
+ */
+ connman_network_set_index(modem->network, -1);
}
-static void check_networks(struct modem_data *modem)
+static void remove_network(struct modem_data *modem)
{
- char const *path = modem->path;
+ DBG("%s", modem->path);
- DBG("modem %p path %s", modem, path);
+ if (modem->network == NULL)
+ return;
+
+ DBG("network %p", modem->network);
- call_ofono(path, OFONO_GPRS_INTERFACE, "GetContexts",
- check_networks_reply, g_strdup(path), g_free,
- DBUS_TYPE_INVALID);
+ connman_device_remove_network(modem->device, modem->network);
+ connman_network_unref(modem->network);
+ modem->network = NULL;
}
-static void modem_clear_network_errors(struct modem_data *modem)
+static int add_cm_context(struct modem_data *modem, const char *context_path,
+ DBusMessageIter *dict)
{
- struct connman_device *device = modem->device;
- GHashTableIter i;
- gpointer value;
+ const char *context_type;
+ struct network_context *context = NULL;
+ connman_bool_t active = FALSE;
- if (device == NULL)
- return;
+ DBG("%s context path %s", modem->path, context_path);
- g_hash_table_iter_init(&i, network_hash);
+ if (modem->context != NULL) {
+ /*
+ * We have already assigned a context to this modem
+ * and we do only support one Internet context.
+ */
+ return -EALREADY;
+ }
- while (g_hash_table_iter_next(&i, NULL, &value)) {
- struct network_info *info = value;
+ context = network_context_alloc(context_path);
+ if (context == NULL)
+ return -ENOMEM;
- if (connman_network_get_device(info->network) == device)
- connman_network_clear_error(info->network);
- }
-}
+ while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value;
+ const char *key;
-static void modem_operator_name_changed(struct modem_data *modem,
- char const *name)
-{
- struct connman_device *device = modem->device;
- GHashTableIter i;
- gpointer value;
+ dbus_message_iter_recurse(dict, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
- if (device == NULL)
- return;
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &value);
+
+ if (g_str_equal(key, "Type") == TRUE) {
+ dbus_message_iter_get_basic(&value, &context_type);
- if (modem->operator != NULL)
- g_free(modem->operator);
- modem->operator = g_strdup(name);
+ DBG("%s context %s type %s", modem->path,
+ context_path, context_type);
+ } else if (g_str_equal(key, "Settings") == TRUE) {
+ DBG("%s Settings", modem->path);
- for (g_hash_table_iter_init(&i, network_hash);
- g_hash_table_iter_next(&i, NULL, &value);) {
- struct network_info *info = value;
+ extract_ipv4_settings(&value, context);
+ } else if (g_str_equal(key, "IPv6.Settings") == TRUE) {
+ DBG("%s IPv6.Settings", modem->path);
- if (connman_network_get_device(info->network) == device) {
- connman_network_set_name(info->network, name);
- connman_network_update(info->network);
+ extract_ipv6_settings(&value, context);
+ } else if (g_str_equal(key, "Active") == TRUE) {
+ dbus_message_iter_get_basic(&value, &active);
+
+ DBG("%s Active %d", modem->path, active);
}
+
+ dbus_message_iter_next(dict);
}
-}
-static void modem_strength_changed(struct modem_data *modem, uint8_t strength)
-{
- struct connman_device *device = modem->device;
- GHashTableIter i;
- gpointer value;
+ if (g_strcmp0(context_type, "internet") != 0) {
+ network_context_free(context);
+ return -EINVAL;
+ }
- modem->strength = strength;
- modem->has_strength = TRUE;
+ modem->context = context;
+ modem->active = active;
- if (device == NULL)
+ g_hash_table_replace(context_hash, g_strdup(context_path), modem);
+
+ return 0;
+}
+
+static void remove_cm_context(struct modem_data *modem,
+ const char *context_path)
+{
+ if (modem->context == NULL)
return;
- for (g_hash_table_iter_init(&i, network_hash);
- g_hash_table_iter_next(&i, NULL, &value);) {
- struct network_info *info = value;
+ if (modem->network != NULL)
+ remove_network(modem);
- if (connman_network_get_device(info->network) == device) {
- connman_network_set_strength(info->network, strength);
- connman_network_update(info->network);
- }
- }
+ g_hash_table_remove(context_hash, context_path);
+
+ network_context_free(modem->context);
+ modem->context = NULL;
}
-static void modem_roaming_changed(struct modem_data *modem,
- char const *status)
+static gboolean context_changed(DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
{
- struct connman_device *device = modem->device;
- connman_bool_t roaming = FALSE;
- connman_bool_t registered = FALSE;
- connman_bool_t was_roaming = modem->roaming;
- GHashTableIter i;
- gpointer value;
+ const char *context_path = dbus_message_get_path(message);
+ struct modem_data *modem = NULL;
+ DBusMessageIter iter, value;
+ const char *key;
- if (g_str_equal(status, "roaming"))
- roaming = TRUE;
- else if (g_str_equal(status, "registered"))
- registered = TRUE;
+ DBG("context_path %s", context_path);
- registered = registered || roaming;
+ modem = g_hash_table_lookup(context_hash, context_path);
+ if (modem == NULL)
+ return TRUE;
- if (modem->roaming == roaming && modem->registered == registered)
- return;
+ if (dbus_message_iter_init(message, &iter) == FALSE)
+ return TRUE;
- modem->registered = registered;
- modem->roaming = roaming;
+ dbus_message_iter_get_basic(&iter, &key);
- if (roaming == was_roaming)
- return;
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &value);
- if (device == NULL)
- return;
+ /*
+ * oFono guarantees the ordering of Settings and
+ * Active. Settings will always be send before Active = True.
+ * That means we don't have to order here.
+ */
+ if (g_str_equal(key, "Settings") == TRUE) {
+ DBG("%s Settings", modem->path);
- g_hash_table_iter_init(&i, network_hash);
+ extract_ipv4_settings(&value, modem->context);
+ } else if (g_str_equal(key, "IPv6.Settings") == TRUE) {
+ DBG("%s IPv6.Settings", modem->path);
- while (g_hash_table_iter_next(&i, NULL, &value)) {
- struct network_info *info = value;
+ extract_ipv6_settings(&value, modem->context);
+ } else if (g_str_equal(key, "Active") == TRUE) {
+ dbus_message_iter_get_basic(&value, &modem->active);
- if (connman_network_get_device(info->network) == device) {
- connman_network_set_roaming(info->network, roaming);
- connman_network_update(info->network);
- }
+ DBG("%s Active %d", modem->path, modem->active);
+
+ if (modem->active == TRUE)
+ set_connected(modem);
+ else
+ set_disconnected(modem);
}
-}
-static void modem_registration_removed(struct modem_data *modem)
-{
- modem->registered = FALSE;
- modem->roaming = FALSE;
+ return TRUE;
}
-static void modem_registration_changed(struct modem_data *modem,
- DBusMessageIter *entry)
+static void cm_get_contexts_reply(DBusPendingCall *call, void *user_data)
{
- DBusMessageIter iter;
- const char *key;
- int type;
- connman_uint8_t strength;
- char const *name, *status, *mcc_s;
+ struct modem_data *modem = user_data;
+ DBusMessageIter array, dict, entry, value;
+ DBusMessage *reply;
+ DBusError error;
- dbus_message_iter_get_basic(entry, &key);
+ DBG("%s", modem->path);
- DBG("key %s", key);
+ modem->call_get_contexts = NULL;
- dbus_message_iter_next(entry);
+ reply = dbus_pending_call_steal_reply(call);
- dbus_message_iter_recurse(entry, &iter);
-
- type = dbus_message_iter_get_arg_type(&iter);
- if (type != DBUS_TYPE_BYTE && type != DBUS_TYPE_STRING)
- return;
-
- if (g_str_equal(key, "Name") && type == DBUS_TYPE_STRING) {
- dbus_message_iter_get_basic(&iter, &name);
- modem_operator_name_changed(modem, name);
- } else if (g_str_equal(key, "Strength") && type == DBUS_TYPE_BYTE) {
- dbus_message_iter_get_basic(&iter, &strength);
- modem_strength_changed(modem, strength);
- } else if (g_str_equal(key, "Status") && type == DBUS_TYPE_STRING) {
- dbus_message_iter_get_basic(&iter, &status);
- modem_roaming_changed(modem, status);
- } else if (g_str_equal(key, "MobileCountryCode") &&
- type == DBUS_TYPE_STRING) {
- int mcc;
- char *alpha2;
-
- dbus_message_iter_get_basic(&iter, &mcc_s);
-
- mcc = atoi(mcc_s);
- if (mcc > 799)
- return;
+ dbus_error_init(&error);
- alpha2 = mcc_country_codes[mcc - 200];
- connman_technology_set_regdom(alpha2);
+ if (dbus_set_error_from_message(&error, reply) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ goto done;
}
-}
-
-static gboolean reg_changed(DBusConnection *connection,
- DBusMessage *message, void *user_data)
-{
- const char *path = dbus_message_get_path(message);
- struct modem_data *modem;
- DBusMessageIter iter;
-
- DBG("path %s", path);
-
- modem = g_hash_table_lookup(modem_hash, path);
- if (modem == NULL)
- return TRUE;
-
- if (dbus_message_iter_init(message, &iter))
- modem_registration_changed(modem, &iter);
-
- return TRUE;
-}
-
-static void check_registration_reply(DBusPendingCall *call, void *user_data)
-{
- char const *path = user_data;
- struct modem_data *modem;
- DBusMessage *reply;
- DBusMessageIter array, dict, entry;
-
- DBG("path %s", path);
-
- modem = g_hash_table_lookup(modem_hash, path);
- if (modem == NULL)
- return;
-
- reply = dbus_pending_call_steal_reply(call);
-
if (dbus_message_iter_init(reply, &array) == FALSE)
goto done;
goto done;
dbus_message_iter_recurse(&array, &dict);
- while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
+ const char *context_path;
+
dbus_message_iter_recurse(&dict, &entry);
- modem_registration_changed(modem, &entry);
+ dbus_message_iter_get_basic(&entry, &context_path);
+
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &value);
+
+ if (add_cm_context(modem, context_path, &value) == 0)
+ break;
+
dbus_message_iter_next(&dict);
}
dbus_pending_call_unref(call);
}
-static void check_registration(struct modem_data *modem)
+static int cm_get_contexts(struct modem_data *modem)
{
- char const *path = modem->path;
+ DBusMessage *message;
- DBG("modem %p path %s", modem, path);
+ DBG("%s", modem->path);
- call_ofono(path, OFONO_REGISTRATION_INTERFACE, GET_PROPERTIES,
- check_registration_reply, g_strdup(path), g_free,
- DBUS_TYPE_INVALID);
-}
+ if (modem->call_get_contexts != NULL)
+ return -EBUSY;
-static void modem_gprs_changed(struct modem_data *modem,
- DBusMessageIter *entry)
-{
- DBusMessageIter iter;
- const char *key;
- int type;
- dbus_bool_t value;
+ message = dbus_message_new_method_call(OFONO_SERVICE, modem->path,
+ OFONO_CM_INTERFACE, GET_CONTEXTS);
+ if (message == NULL)
+ return -ENOMEM;
- dbus_message_iter_get_basic(entry, &key);
+ if (dbus_connection_send_with_reply(connection, message,
+ &modem->call_get_contexts, TIMEOUT) == FALSE) {
+ connman_error("Failed to call GetContexts()");
+ dbus_message_unref(message);
+ return -EINVAL;
+ }
- DBG("key %s", key);
+ if (modem->call_get_contexts == NULL) {
+ connman_error("D-Bus connection not available");
+ dbus_message_unref(message);
+ return -EINVAL;
+ }
- dbus_message_iter_next(entry);
+ dbus_pending_call_set_notify(modem->call_get_contexts,
+ cm_get_contexts_reply,
+ modem, NULL);
- dbus_message_iter_recurse(entry, &iter);
+ dbus_message_unref(message);
- type = dbus_message_iter_get_arg_type(&iter);
+ return -EINPROGRESS;
+}
- if (type != DBUS_TYPE_BOOLEAN)
- return;
+static gboolean cm_context_added(DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ const char *path = dbus_message_get_path(message);
+ char *context_path;
+ struct modem_data *modem;
+ DBusMessageIter iter, properties;
- dbus_message_iter_get_basic(&iter, &value);
+ DBG("%s", path);
+
+ modem = g_hash_table_lookup(modem_hash, path);
+ if (modem == NULL)
+ return TRUE;
- if (g_str_equal(key, "Attached") == TRUE) {
- DBG("Attached %d", value);
+ if (dbus_message_iter_init(message, &iter) == FALSE)
+ return TRUE;
- modem->attached = value;
+ dbus_message_iter_get_basic(&iter, &context_path);
- if (value)
- modem_clear_network_errors(modem);
- } else if (g_str_equal(key, "Powered") == TRUE) {
- DBG("Powered %d", value);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &properties);
- modem->powered = value;
- } else if (g_str_equal(key, "RoamingAllowed") == TRUE) {
- DBG("RoamingAllowed %d", value);
+ if (add_cm_context(modem, context_path, &properties) != 0)
+ return TRUE;
- modem->roaming_allowed = value;
- }
+ return TRUE;
}
-static void check_gprs_reply(DBusPendingCall *call, void *user_data)
+static gboolean cm_context_removed(DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
{
- char const *path = user_data;
+ const char *path = dbus_message_get_path(message);
+ const char *context_path;
struct modem_data *modem;
- DBusMessage *reply;
- DBusMessageIter array, dict, entry;
+ DBusMessageIter iter;
- DBG("path %s", path);
+ DBG("context path %s", path);
- modem = g_hash_table_lookup(modem_hash, path);
+ if (dbus_message_iter_init(message, &iter) == FALSE)
+ return TRUE;
+
+ dbus_message_iter_get_basic(&iter, &context_path);
+
+ modem = g_hash_table_lookup(context_hash, context_path);
if (modem == NULL)
- return;
+ return TRUE;
- reply = dbus_pending_call_steal_reply(call);
+ remove_cm_context(modem, context_path);
- if (dbus_message_iter_init(reply, &array) == FALSE)
- goto done;
+ return TRUE;
+}
- if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
- goto done;
+static void netreg_update_name(struct modem_data *modem,
+ DBusMessageIter* value)
+{
+ char *name;
- dbus_message_iter_recurse(&array, &dict);
- while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
- dbus_message_iter_recurse(&dict, &entry);
- modem_gprs_changed(modem, &entry);
- dbus_message_iter_next(&dict);
- }
+ dbus_message_iter_get_basic(value, &name);
-done:
- dbus_message_unref(reply);
+ DBG("%s Name %s", modem->path, name);
- dbus_pending_call_unref(call);
+ g_free(modem->name);
+ modem->name = g_strdup(name);
+
+ if (modem->network == NULL)
+ return;
- check_networks(modem);
+ connman_network_set_name(modem->network, modem->name);
+ connman_network_update(modem->network);
}
-static void check_gprs(struct modem_data *modem)
+static void netreg_update_strength(struct modem_data *modem,
+ DBusMessageIter *value)
{
- char const *path = modem->path;
+ dbus_message_iter_get_basic(value, &modem->strength);
+
+ DBG("%s Strength %d", modem->path, modem->strength);
- DBG("modem %p path %s", modem, path);
+ if (modem->network == NULL)
+ return;
+
+ /*
+ * GSM:
+ * We don't have 2 signal notifications we always report the strength
+ * signal. data_strength is always equal to 0.
+ *
+ * CDMA:
+ * In the case we have a data_strength signal (from 1xEVDO network)
+ * we don't need to update the value with strength signal (from 1xCDMA)
+ * because the modem is registered to 1xEVDO network for data call.
+ * In case we have no data_strength signal (not registered to 1xEVDO
+ * network), we must report the strength signal (registered to 1xCDMA
+ * network e.g slow mode).
+ */
+ if (modem->data_strength != 0)
+ return;
- call_ofono(path, OFONO_GPRS_INTERFACE, GET_PROPERTIES,
- check_gprs_reply, g_strdup(path), g_free,
- DBUS_TYPE_INVALID);
+ connman_network_set_strength(modem->network, modem->strength);
+ connman_network_update(modem->network);
}
-static void add_device(const char *path, const char *imsi)
+/* Retrieve 1xEVDO Data Strength signal */
+static void netreg_update_datastrength(struct modem_data *modem,
+ DBusMessageIter *value)
{
- struct modem_data *modem;
- struct connman_device *device;
+ dbus_message_iter_get_basic(value, &modem->data_strength);
- DBG("path %s imsi %s", path, imsi);
+ DBG("%s Data Strength %d", modem->path, modem->data_strength);
- if (path == NULL)
+ if (modem->network == NULL)
return;
- if (imsi == NULL)
+ /*
+ * CDMA modem is not registered to 1xEVDO network, let
+ * update_signal_strength() reporting the value on the Strength signal
+ * notification.
+ */
+ if (modem->data_strength == 0)
return;
- modem = g_hash_table_lookup(modem_hash, path);
- if (modem == NULL)
- return;
+ connman_network_set_strength(modem->network, modem->data_strength);
+ connman_network_update(modem->network);
+}
- if (modem->device) {
- if (!g_strcmp0(imsi, connman_device_get_ident(modem->device)))
- return;
+static void netreg_update_roaming(struct modem_data *modem,
+ DBusMessageIter *value)
+{
+ char *status;
+ connman_bool_t roaming;
- modem_remove_device(modem);
- }
+ dbus_message_iter_get_basic(value, &status);
+
+ if (g_str_equal(status, "roaming") == TRUE)
+ roaming = TRUE;
+ else
+ roaming = FALSE;
- if (strlen(imsi) == 0)
+ if (roaming == modem->roaming)
return;
- device = connman_device_create(imsi, CONNMAN_DEVICE_TYPE_CELLULAR);
- if (device == NULL)
+ modem->roaming = roaming;
+
+ if (modem->network == NULL)
return;
- connman_device_set_ident(device, imsi);
+ connman_network_set_bool(modem->network,
+ "Roaming", modem->roaming);
+ connman_network_update(modem->network);
+}
- connman_device_set_string(device, "Path", path);
+static void netreg_update_regdom(struct modem_data *modem,
+ DBusMessageIter *value)
+{
+ char *mobile_country_code;
+ char *alpha2;
+ int mcc;
- connman_device_set_data(device, modem);
+ dbus_message_iter_get_basic(value, &mobile_country_code);
- if (connman_device_register(device) < 0) {
- connman_device_unref(device);
- return;
- }
+ DBG("%s MobileContryCode %s", modem->path, mobile_country_code);
- modem->device = device;
- if (modem->has_reg)
- check_registration(modem);
+ mcc = atoi(mobile_country_code);
+ if (mcc > 799 || mcc < 200)
+ return;
- if (modem->has_gprs)
- check_gprs(modem);
+ alpha2 = mcc_country_codes[mcc - 200];
+ if (alpha2 != NULL)
+ connman_technology_set_regdom(alpha2);
}
-static void sim_properties_reply(DBusPendingCall *call, void *user_data)
+static gboolean netreg_changed(DBusConnection *connection, DBusMessage *message,
+ void *user_data)
{
- const char *path = user_data;
- const char *imsi = NULL;
- DBusMessage *reply;
- DBusMessageIter array, dict;
+ const char *path = dbus_message_get_path(message);
+ struct modem_data *modem;
+ DBusMessageIter iter, value;
+ const char *key;
- DBG("path %s", path);
+ modem = g_hash_table_lookup(modem_hash, path);
+ if (modem == NULL)
+ return TRUE;
- reply = dbus_pending_call_steal_reply(call);
+ if (modem->ignore == TRUE)
+ return TRUE;
- if (dbus_message_iter_init(reply, &array) == FALSE)
- goto done;
+ if (dbus_message_iter_init(message, &iter) == FALSE)
+ return TRUE;
- if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
- goto done;
+ dbus_message_iter_get_basic(&iter, &key);
- dbus_message_iter_recurse(&array, &dict);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &value);
- while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ if (g_str_equal(key, "Name") == TRUE)
+ netreg_update_name(modem, &value);
+ else if (g_str_equal(key, "Strength") == TRUE)
+ netreg_update_strength(modem, &value);
+ else if (g_str_equal(key, "Status") == TRUE)
+ netreg_update_roaming(modem, &value);
+ else if (g_str_equal(key, "MobileCountryCode") == TRUE)
+ netreg_update_regdom(modem, &value);
+
+ return TRUE;
+}
+
+static void netreg_properties_reply(struct modem_data *modem,
+ DBusMessageIter *dict)
+{
+ DBG("%s", modem->path);
+
+ while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
DBusMessageIter entry, value;
const char *key;
- dbus_message_iter_recurse(&dict, &entry);
+ dbus_message_iter_recurse(dict, &entry);
dbus_message_iter_get_basic(&entry, &key);
dbus_message_iter_next(&entry);
dbus_message_iter_recurse(&entry, &value);
- if (g_str_equal(key, "SubscriberIdentity")) {
- dbus_message_iter_get_basic(&value, &imsi);
- add_device(path, imsi);
- }
+ if (g_str_equal(key, "Name") == TRUE)
+ netreg_update_name(modem, &value);
+ else if (g_str_equal(key, "Strength") == TRUE)
+ netreg_update_strength(modem, &value);
+ else if (g_str_equal(key, "Status") == TRUE)
+ netreg_update_roaming(modem, &value);
+ else if (g_str_equal(key, "MobileCountryCode") == TRUE)
+ netreg_update_regdom(modem, &value);
- dbus_message_iter_next(&dict);
+ dbus_message_iter_next(dict);
}
-done:
- dbus_message_unref(reply);
+ if (modem->context == NULL) {
+ /*
+ * netgreg_get_properties() was issued after we got
+ * cm_get_contexts_reply() where we create the
+ * context. Though before we got the
+ * netreg_properties_reply the context was removed
+ * again. Therefore we have to skip the network
+ * creation.
+ */
+ return;
+ }
- dbus_pending_call_unref(call);
+ add_network(modem);
+
+ if (modem->active == TRUE)
+ set_connected(modem);
}
-static void get_imsi(const char *path)
+static int netreg_get_properties(struct modem_data *modem)
{
- DBG("path %s", path);
-
- call_ofono(path, OFONO_SIM_INTERFACE, GET_PROPERTIES,
- sim_properties_reply, g_strdup(path), g_free,
- DBUS_TYPE_INVALID);
+ return get_properties(modem->path, OFONO_NETREG_INTERFACE,
+ netreg_properties_reply, modem);
}
-static int gprs_change_powered(const char *path, dbus_bool_t powered)
+static void add_cdma_network(struct modem_data *modem)
{
- DBG("path %s powered %d", path, powered);
+ /* Be sure that device is created before adding CDMA network */
+ if (modem->device == NULL)
+ return;
- return set_property(path, OFONO_GPRS_INTERFACE, "Powered",
- DBUS_TYPE_BOOLEAN, &powered,
- NULL, NULL, NULL);
-}
+ /*
+ * CDMA modems don't need contexts for data call, however the current
+ * add_network() logic needs one, so we create one to proceed.
+ */
+ if (modem->context == NULL)
+ modem->context = network_context_alloc(modem->path);
-static int modem_change_powered(const char *path, dbus_bool_t powered)
-{
- DBG("path %s powered %d", path, powered);
+ if (modem->name == NULL)
+ modem->name = g_strdup("CDMA Network");
- return set_property(path, OFONO_MODEM_INTERFACE, "Powered",
- DBUS_TYPE_BOOLEAN, &powered,
- NULL, NULL, NULL);
-}
+ add_network(modem);
+ if (modem->cdma_cm_powered == TRUE)
+ set_connected(modem);
+}
-static gboolean modem_has_interface(DBusMessageIter *array,
- char const *interface)
+static gboolean cdma_netreg_changed(DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
{
- DBusMessageIter entry;
+ const char *path = dbus_message_get_path(message);
+ struct modem_data *modem;
+ DBusMessageIter iter, value;
+ const char *key;
- dbus_message_iter_recurse(array, &entry);
+ DBG("");
- while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
- const char *element;
+ modem = g_hash_table_lookup(modem_hash, path);
+ if (modem == NULL)
+ return TRUE;
- dbus_message_iter_get_basic(&entry, &element);
+ if (modem->ignore == TRUE)
+ return TRUE;
- if (g_strcmp0(interface, element) == 0)
- return TRUE;
+ if (dbus_message_iter_init(message, &iter) == FALSE)
+ return TRUE;
- dbus_message_iter_next(&entry);
- }
+ dbus_message_iter_get_basic(&iter, &key);
- return FALSE;
-}
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &value);
-static gboolean modem_has_sim(DBusMessageIter *array)
-{
- return modem_has_interface(array, OFONO_SIM_INTERFACE);
-}
+ if (g_str_equal(key, "Name") == TRUE)
+ netreg_update_name(modem, &value);
+ else if (g_str_equal(key, "Strength") == TRUE)
+ netreg_update_strength(modem, &value);
+ else if (g_str_equal(key, "DataStrength") == TRUE)
+ netreg_update_datastrength(modem, &value);
+ else if (g_str_equal(key, "Status") == TRUE)
+ netreg_update_roaming(modem, &value);
-static gboolean modem_has_reg(DBusMessageIter *array)
-{
- return modem_has_interface(array, OFONO_REGISTRATION_INTERFACE);
-}
+ add_cdma_network(modem);
-static gboolean modem_has_gprs(DBusMessageIter *array)
-{
- return modem_has_interface(array, OFONO_GPRS_INTERFACE);
+ return TRUE;
}
-static void add_modem(const char *path, DBusMessageIter *prop)
+static void cdma_netreg_properties_reply(struct modem_data *modem,
+ DBusMessageIter *dict)
{
- struct modem_data *modem;
- dbus_bool_t powered = FALSE;
- dbus_bool_t online = FALSE;
- dbus_bool_t locked = FALSE;
- gboolean has_sim = FALSE;
- gboolean has_reg = FALSE;
- gboolean has_gprs = FALSE;
-
- modem = g_hash_table_lookup(modem_hash, path);
-
- if (modem != NULL)
- return;
-
- modem = g_try_new0(struct modem_data, 1);
- if (modem == NULL)
- return;
-
- modem->path = g_strdup(path);
- modem->device = NULL;
- modem->available = TRUE;
-
- g_hash_table_insert(modem_hash, g_strdup(path), modem);
+ DBG("%s", modem->path);
- while (dbus_message_iter_get_arg_type(prop) == DBUS_TYPE_DICT_ENTRY) {
+ while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
DBusMessageIter entry, value;
const char *key;
- dbus_message_iter_recurse(prop, &entry);
+ dbus_message_iter_recurse(dict, &entry);
dbus_message_iter_get_basic(&entry, &key);
dbus_message_iter_next(&entry);
dbus_message_iter_recurse(&entry, &value);
- if (g_str_equal(key, "Powered") == TRUE)
- dbus_message_iter_get_basic(&value, &powered);
- else if (g_str_equal(key, "Lockdown") == TRUE)
- dbus_message_iter_get_basic(&value, &locked);
- else if (g_str_equal(key, "Interfaces") == TRUE) {
- has_sim = modem_has_sim(&value);
- has_reg = modem_has_reg(&value);
- has_gprs = modem_has_gprs(&value);
- }
+ if (g_str_equal(key, "Name") == TRUE)
+ netreg_update_name(modem, &value);
+ else if (g_str_equal(key, "Strength") == TRUE)
+ netreg_update_strength(modem, &value);
+ else if (g_str_equal(key, "DataStrength") == TRUE)
+ netreg_update_datastrength(modem, &value);
+ else if (g_str_equal(key, "Status") == TRUE)
+ netreg_update_roaming(modem, &value);
- dbus_message_iter_next(prop);
+ dbus_message_iter_next(dict);
}
- if (locked)
- return;
+ add_cdma_network(modem);
+}
+
+static int cdma_netreg_get_properties(struct modem_data *modem)
+{
+ return get_properties(modem->path, OFONO_CDMA_NETREG_INTERFACE,
+ cdma_netreg_properties_reply, modem);
+}
+
+static void cm_update_attached(struct modem_data *modem,
+ DBusMessageIter *value)
+{
+ dbus_message_iter_get_basic(value, &modem->attached);
- if (!powered)
- modem_change_powered(path, TRUE);
+ DBG("%s Attached %d", modem->path, modem->attached);
- modem->has_sim = has_sim;
- modem->has_reg = has_reg;
- modem->has_gprs = has_gprs;
+ if (modem->attached == FALSE)
+ return;
- update_modem_online(modem, online);
+ if (has_interface(modem->interfaces,
+ OFONO_API_NETREG) == FALSE) {
+ return;
+ }
- if (has_sim)
- get_imsi(path);
+ netreg_get_properties(modem);
}
-static void manager_modems_reply(DBusPendingCall *call, void *user_data)
+static void cm_update_powered(struct modem_data *modem,
+ DBusMessageIter *value)
{
- DBusMessage *reply;
- DBusError error;
- DBusMessageIter array, dict;
-
- DBG("");
+ dbus_message_iter_get_basic(value, &modem->cm_powered);
- reply = dbus_pending_call_steal_reply(call);
+ DBG("%s ConnnectionManager Powered %d", modem->path,
+ modem->cm_powered);
- if (dbus_message_has_signature(reply, "a(oa{sv})") == FALSE)
- goto done;
+ if (modem->cm_powered == TRUE)
+ return;
- dbus_error_init(&error);
+ cm_set_powered(modem, TRUE);
+}
- if (dbus_set_error_from_message(&error, reply)) {
- connman_error("ModemManager.GetModems() %s %s",
- error.name, error.message);
- dbus_error_free(&error);
- goto done;
- }
-
- if (dbus_message_iter_init(reply, &array) == FALSE)
- goto done;
-
- dbus_message_iter_recurse(&array, &dict);
+static gboolean cm_changed(DBusConnection *connection, DBusMessage *message,
+ void *user_data)
+{
+ const char *path = dbus_message_get_path(message);
+ struct modem_data *modem;
+ DBusMessageIter iter, value;
+ const char *key;
- while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
- DBusMessageIter value, properties;
- const char *modem_path;
+ modem = g_hash_table_lookup(modem_hash, path);
+ if (modem == NULL)
+ return TRUE;
- dbus_message_iter_recurse(&dict, &value);
- dbus_message_iter_get_basic(&value, &modem_path);
+ if (modem->ignore == TRUE)
+ return TRUE;
- dbus_message_iter_next(&value);
- dbus_message_iter_recurse(&value, &properties);
+ if (dbus_message_iter_init(message, &iter) == FALSE)
+ return TRUE;
- /* Add modem */
- add_modem(modem_path, &properties);
+ dbus_message_iter_get_basic(&iter, &key);
- dbus_message_iter_next(&dict);
- }
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &value);
-done:
- dbus_message_unref(reply);
+ if (g_str_equal(key, "Attached") == TRUE)
+ cm_update_attached(modem, &value);
+ else if (g_str_equal(key, "Powered") == TRUE)
+ cm_update_powered(modem, &value);
- dbus_pending_call_unref(call);
+ return TRUE;
}
-static void ofono_connect(DBusConnection *connection, void *user_data)
+static void cdma_cm_update_powered(struct modem_data *modem,
+ DBusMessageIter *value)
{
- DBG("connection %p", connection);
+ dbus_message_iter_get_basic(value, &modem->cdma_cm_powered);
- modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
- g_free, remove_modem);
+ DBG("%s CDMA cm Powered %d", modem->path, modem->cdma_cm_powered);
- network_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
- g_free, remove_network);
+ if (modem->network == NULL)
+ return;
- call_ofono("/", OFONO_MANAGER_INTERFACE, GET_MODEMS,
- manager_modems_reply, NULL, NULL,
- DBUS_TYPE_INVALID);
+ if (modem->cdma_cm_powered == TRUE)
+ set_connected(modem);
+ else
+ set_disconnected(modem);
}
-static void ofono_disconnect(DBusConnection *connection, void *user_data)
+static void cdma_cm_update_settings(struct modem_data *modem,
+ DBusMessageIter *value)
{
- DBG("connection %p", connection);
+ DBG("%s Settings", modem->path);
- if (modem_hash != NULL) {
- g_hash_table_destroy(modem_hash);
- modem_hash = NULL;
- }
-
- if (network_hash != NULL) {
- g_hash_table_destroy(network_hash);
- network_hash = NULL;
- }
+ extract_ipv4_settings(value, modem->context);
}
-static gboolean modem_changed(DBusConnection *connection, DBusMessage *message,
- void *user_data)
+static gboolean cdma_cm_changed(DBusConnection *connection,
+ DBusMessage *message, void *user_data)
{
const char *path = dbus_message_get_path(message);
struct modem_data *modem;
DBusMessageIter iter, value;
const char *key;
- DBG("path %s", path);
-
modem = g_hash_table_lookup(modem_hash, path);
if (modem == NULL)
return TRUE;
+ if (modem->online == TRUE && modem->network == NULL)
+ cdma_netreg_get_properties(modem);
+
if (dbus_message_iter_init(message, &iter) == FALSE)
return TRUE;
dbus_message_iter_next(&iter);
dbus_message_iter_recurse(&iter, &value);
- if (g_str_equal(key, "Powered") == TRUE) {
- dbus_bool_t powered;
+ if (g_str_equal(key, "Powered") == TRUE)
+ cdma_cm_update_powered(modem, &value);
+ if (g_str_equal(key, "Settings") == TRUE)
+ cdma_cm_update_settings(modem, &value);
- dbus_message_iter_get_basic(&value, &powered);
- if (powered == TRUE)
- return TRUE;
+ return TRUE;
+}
- modem->has_sim = FALSE;
- modem->has_reg = FALSE;
- modem->has_gprs = FALSE;
+static void cm_properties_reply(struct modem_data *modem, DBusMessageIter *dict)
+{
+ DBG("%s", modem->path);
- modem_remove_device(modem);
- } else if (g_str_equal(key, "Online") == TRUE) {
- dbus_bool_t online;
+ while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value;
+ const char *key;
+
+ dbus_message_iter_recurse(dict, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
- dbus_message_iter_get_basic(&value, &online);
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &value);
- update_modem_online(modem, online);
- } else if (g_str_equal(key, "Lockdown") == TRUE) {
- dbus_bool_t locked;
+ if (g_str_equal(key, "Attached") == TRUE)
+ cm_update_attached(modem, &value);
+ else if (g_str_equal(key, "Powered") == TRUE)
+ cm_update_powered(modem, &value);
- dbus_message_iter_get_basic(&value, &locked);
+ dbus_message_iter_next(dict);
+ }
+}
- if (!locked)
- modem_change_powered(path, TRUE);
+static int cm_get_properties(struct modem_data *modem)
+{
+ return get_properties(modem->path, OFONO_CM_INTERFACE,
+ cm_properties_reply, modem);
+}
- } else if (g_str_equal(key, "Interfaces") == TRUE) {
- gboolean has_sim = modem_has_sim(&value);
- gboolean has_reg = modem_has_reg(&value);
- gboolean had_reg = modem->has_reg;
- gboolean has_gprs = modem_has_gprs(&value);
- gboolean had_gprs = modem->has_gprs;
-
- modem->has_sim = has_sim;
- modem->has_reg = has_reg;
- modem->has_gprs = has_gprs;
-
- if (modem->device == NULL) {
- if (has_sim)
- get_imsi(modem->path);
- } else if (!has_sim) {
- modem_remove_device(modem);
- } else {
- if (has_reg && !had_reg)
- check_registration(modem);
- else if (had_reg && !has_reg)
- modem_registration_removed(modem);
-
- if (has_gprs && !had_gprs) {
- gprs_change_powered(modem->path, TRUE);
- check_gprs(modem);
- }
- }
+static void cdma_cm_properties_reply(struct modem_data *modem,
+ DBusMessageIter *dict)
+{
+ DBG("%s", modem->path);
+
+ if (modem->online == TRUE)
+ cdma_netreg_get_properties(modem);
+
+ while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value;
+ const char *key;
+
+ dbus_message_iter_recurse(dict, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &value);
+
+ if (g_str_equal(key, "Powered") == TRUE)
+ cdma_cm_update_powered(modem, &value);
+ if (g_str_equal(key, "Settings") == TRUE)
+ cdma_cm_update_settings(modem, &value);
+
+ dbus_message_iter_next(dict);
}
+}
- return TRUE;
+static int cdma_cm_get_properties(struct modem_data *modem)
+{
+ return get_properties(modem->path, OFONO_CDMA_CM_INTERFACE,
+ cdma_cm_properties_reply, modem);
+}
+
+static void sim_update_imsi(struct modem_data *modem,
+ DBusMessageIter* value)
+{
+ char *imsi;
+
+ dbus_message_iter_get_basic(value, &imsi);
+
+ DBG("%s imsi %s", modem->path, imsi);
+
+ g_free(modem->imsi);
+ modem->imsi = g_strdup(imsi);
}
static gboolean sim_changed(DBusConnection *connection, DBusMessage *message,
DBusMessageIter iter, value;
const char *key;
- DBG("path %s", path);
-
modem = g_hash_table_lookup(modem_hash, path);
if (modem == NULL)
return TRUE;
+ if (modem->ignore == TRUE)
+ return TRUE;
+
if (dbus_message_iter_init(message, &iter) == FALSE)
return TRUE;
dbus_message_iter_recurse(&iter, &value);
if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
- char *imsi;
-
- dbus_message_iter_get_basic(&value, &imsi);
+ sim_update_imsi(modem, &value);
- add_device(path, imsi);
- } else if (g_str_equal(key, "Present") == TRUE) {
- dbus_bool_t present;
-
- dbus_message_iter_get_basic(&value, &present);
-
- if (present)
+ if (ready_to_create_device(modem) == FALSE)
return TRUE;
- if (modem->device != NULL)
- modem_remove_device(modem);
-
- modem->has_gprs = FALSE;
- modem->has_reg = FALSE;
+ /*
+ * This is a GSM modem. Create the device and
+ * register it at the core. Enabling (setting
+ * it online is done through the
+ * modem_enable() callback.
+ */
+ create_device(modem);
}
return TRUE;
}
-static gboolean gprs_changed(DBusConnection *connection, DBusMessage *message,
- void *user_data)
+static void sim_properties_reply(struct modem_data *modem,
+ DBusMessageIter *dict)
{
- const char *path = dbus_message_get_path(message);
- struct modem_data *modem;
- DBusMessageIter iter;
+ DBG("%s", modem->path);
- DBG("path %s", path);
+ while (dbus_message_iter_get_arg_type(dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value;
+ const char *key;
- modem = g_hash_table_lookup(modem_hash, path);
- if (modem == NULL)
- return TRUE;
+ dbus_message_iter_recurse(dict, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
- if (dbus_message_iter_init(message, &iter))
- modem_gprs_changed(modem, &iter);
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &value);
- return TRUE;
+ if (g_str_equal(key, "SubscriberIdentity") == TRUE) {
+ sim_update_imsi(modem, &value);
+
+ if (ready_to_create_device(modem) == FALSE)
+ return;
+
+ /*
+ * This is a GSM modem. Create the device and
+ * register it at the core. Enabling (setting
+ * it online is done through the
+ * modem_enable() callback.
+ */
+ create_device(modem);
+
+ if (modem->online == FALSE)
+ return;
+
+ /*
+ * The modem is already online and we have the CM interface.
+ * There will be no interface update and therefore our
+ * state machine will not go to next step. We have to
+ * trigger it from here.
+ */
+ if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE) {
+ cm_get_properties(modem);
+ cm_get_contexts(modem);
+ }
+ return;
+ }
+
+ dbus_message_iter_next(dict);
+ }
}
-static gboolean context_added(DBusConnection *connection,
- DBusMessage *message, void *user_data)
+static int sim_get_properties(struct modem_data *modem)
{
- const char *path = dbus_message_get_path(message);
- const char *network_path;
- struct modem_data *modem;
- DBusMessageIter iter, properties;
-
- DBG("path %s", path);
-
- modem = g_hash_table_lookup(modem_hash, path);
- if (modem == NULL || modem->device == NULL)
- return TRUE;
+ return get_properties(modem->path, OFONO_SIM_INTERFACE,
+ sim_properties_reply, modem);
+}
- if (dbus_message_iter_init(message, &iter) == FALSE)
+static connman_bool_t api_added(uint8_t old_iface, uint8_t new_iface,
+ enum ofono_api api)
+{
+ if (has_interface(old_iface, api) == FALSE &&
+ has_interface(new_iface, api) == TRUE) {
+ DBG("%s added", api2string(api));
return TRUE;
+ }
- dbus_message_iter_get_basic(&iter, &network_path);
-
- dbus_message_iter_next(&iter);
- dbus_message_iter_recurse(&iter, &properties);
-
- add_network(modem->device, network_path, &properties);
-
- return TRUE;
+ return FALSE;
}
-static gboolean context_removed(DBusConnection *connection,
- DBusMessage *message, void *user_data)
+static connman_bool_t api_removed(uint8_t old_iface, uint8_t new_iface,
+ enum ofono_api api)
{
- const char *path = dbus_message_get_path(message);
- const char *network_path;
- struct modem_data *modem;
- DBusMessageIter iter;
-
- DBG("path %s", path);
-
- modem = g_hash_table_lookup(modem_hash, path);
- if (modem == NULL || modem->device == NULL)
- return TRUE;
-
- if (dbus_message_iter_init(message, &iter) == FALSE)
+ if (has_interface(old_iface, api) == TRUE &&
+ has_interface(new_iface, api) == FALSE) {
+ DBG("%s removed", api2string(api));
return TRUE;
+ }
- dbus_message_iter_get_basic(&iter, &network_path);
-
- g_hash_table_remove(network_hash, network_path);
- return TRUE;
+ return FALSE;
}
-static gboolean modem_added(DBusConnection *connection,
- DBusMessage *message, void *user_data)
+static void modem_update_interfaces(struct modem_data *modem,
+ uint8_t old_ifaces,
+ uint8_t new_ifaces)
{
- DBusMessageIter iter, properties;
- const char *modem_path;
-
- DBG("");
-
- if (dbus_message_iter_init(message, &iter) == FALSE)
- return TRUE;
+ DBG("%s", modem->path);
- dbus_message_iter_get_basic(&iter, &modem_path);
+ if (api_added(old_ifaces, new_ifaces, OFONO_API_SIM) == TRUE) {
+ if (modem->imsi == NULL &&
+ modem->set_powered == FALSE) {
+ /*
+ * Only use do GetProperties() when
+ * device has not been powered up.
+ */
+ sim_get_properties(modem);
+ }
+ }
- dbus_message_iter_next(&iter);
- dbus_message_iter_recurse(&iter, &properties);
+ if (api_added(old_ifaces, new_ifaces, OFONO_API_CM) == TRUE) {
+ if (modem->device != NULL) {
+ cm_get_properties(modem);
+ cm_get_contexts(modem);
+ }
+ }
- add_modem(modem_path, &properties);
+ if (api_added(old_ifaces, new_ifaces, OFONO_API_CDMA_CM) == TRUE) {
+ if (ready_to_create_device(modem) == TRUE)
+ create_device(modem);
- return TRUE;
-}
+ if (modem->device != NULL)
+ cdma_cm_get_properties(modem);
+ }
-static gboolean modem_removed(DBusConnection *connection,
- DBusMessage *message, void *user_data)
-{
- DBusMessageIter iter;
- const char *modem_path;
+ if (api_added(old_ifaces, new_ifaces, OFONO_API_NETREG) == TRUE) {
+ if (modem->attached == TRUE)
+ netreg_get_properties(modem);
+ }
- DBG("");
+ if (api_added(old_ifaces, new_ifaces, OFONO_API_CDMA_NETREG) == TRUE) {
+ cdma_netreg_get_properties(modem);
+ }
- if (dbus_message_iter_init(message, &iter) == FALSE)
- return TRUE;
+ if (api_removed(old_ifaces, new_ifaces, OFONO_API_CM) == TRUE) {
+ remove_cm_context(modem, modem->context->path);
+ }
- dbus_message_iter_get_basic(&iter, &modem_path);
+ if (api_removed(old_ifaces, new_ifaces, OFONO_API_CDMA_CM) == TRUE) {
+ remove_cm_context(modem, modem->context->path);
+ }
- g_hash_table_remove(modem_hash, modem_path);
+ if (api_removed(old_ifaces, new_ifaces, OFONO_API_NETREG) == TRUE) {
+ remove_network(modem);
+ }
- return TRUE;
+ if (api_removed(old_ifaces, new_ifaces, OFONO_API_CDMA_NETREG == TRUE)) {
+ remove_network(modem);
+ }
}
-static gboolean context_changed(DBusConnection *connection,
- DBusMessage *message, void *user_data)
+static gboolean modem_changed(DBusConnection *connection, DBusMessage *message,
+ void *user_data)
{
const char *path = dbus_message_get_path(message);
- struct network_info *info;
+ struct modem_data *modem;
DBusMessageIter iter, value;
const char *key;
- DBG("path %s", path);
-
- info = g_hash_table_lookup(network_hash, path);
- if (info == NULL)
+ modem = g_hash_table_lookup(modem_hash, path);
+ if (modem == NULL)
return TRUE;
- if (!pending_network_is_available(info->network)) {
- g_hash_table_remove(network_hash, path);
+ if (modem->ignore == TRUE)
return TRUE;
- }
if (dbus_message_iter_init(message, &iter) == FALSE)
return TRUE;
dbus_message_iter_next(&iter);
dbus_message_iter_recurse(&iter, &value);
- DBG("key %s", key);
+ if (g_str_equal(key, "Powered") == TRUE) {
+ dbus_message_iter_get_basic(&value, &modem->powered);
- if (g_str_equal(key, "Settings") == TRUE)
- update_ipv4_settings(&value, info);
- else if (g_str_equal(key, "IPv6.Settings"))
- update_ipv6_settings(&value, info);
- else if (g_str_equal(key, "Active") == TRUE) {
- dbus_bool_t active;
+ DBG("%s Powered %d", modem->path, modem->powered);
- dbus_message_iter_get_basic(&value, &active);
+ if (modem->powered == FALSE)
+ modem_set_powered(modem, TRUE);
+ } else if (g_str_equal(key, "Online") == TRUE) {
+ dbus_message_iter_get_basic(&value, &modem->online);
- if (active == FALSE)
- set_connected(info, active);
- else if (connman_network_get_connecting(info->network) == TRUE)
- /* Connect only if requested to do so */
- set_connected(info, active);
- }
+ DBG("%s Online %d", modem->path, modem->online);
- return TRUE;
-}
+ if (modem->device == NULL)
+ return TRUE;
-static guint watch;
-static guint reg_watch;
-static guint sim_watch;
-static guint gprs_watch;
-static guint context_added_watch;
-static guint context_removed_watch;
-static guint modem_watch;
-static guint modem_added_watch;
-static guint modem_removed_watch;
-static guint context_watch;
+ connman_device_set_powered(modem->device, modem->online);
+ } else if (g_str_equal(key, "Interfaces") == TRUE) {
+ uint8_t interfaces;
-static int ofono_init(void)
-{
- int err;
+ interfaces = extract_interfaces(&value);
- connection = connman_dbus_get_connection();
- if (connection == NULL)
- return -EIO;
+ if (interfaces == modem->interfaces)
+ return TRUE;
- watch = g_dbus_add_service_watch(connection, OFONO_SERVICE,
- ofono_connect, ofono_disconnect, NULL, NULL);
+ DBG("%s Interfaces 0x%02x", modem->path, interfaces);
- reg_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
- OFONO_REGISTRATION_INTERFACE,
- PROPERTY_CHANGED,
- reg_changed,
- NULL, NULL);
+ modem_update_interfaces(modem, modem->interfaces, interfaces);
- gprs_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
- OFONO_GPRS_INTERFACE,
- PROPERTY_CHANGED,
- gprs_changed,
- NULL, NULL);
+ modem->interfaces = interfaces;
+ } else if (g_str_equal(key, "Serial") == TRUE) {
+ char *serial;
- context_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
- OFONO_GPRS_INTERFACE,
- CONTEXT_ADDED,
- context_added,
- NULL, NULL);
+ dbus_message_iter_get_basic(&value, &serial);
- context_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
- OFONO_GPRS_INTERFACE,
- CONTEXT_REMOVED,
- context_removed,
- NULL, NULL);
+ g_free(modem->serial);
+ modem->serial = g_strdup(serial);
- modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
- OFONO_MODEM_INTERFACE,
- PROPERTY_CHANGED,
- modem_changed,
- NULL, NULL);
+ DBG("%s Serial %s", modem->path, modem->serial);
- sim_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
- OFONO_SIM_INTERFACE,
- PROPERTY_CHANGED,
- sim_changed,
- NULL, NULL);
+ if (has_interface(modem->interfaces,
+ OFONO_API_CDMA_CM) == TRUE) {
+ if (ready_to_create_device(modem) == TRUE)
+ create_device(modem);
+ }
+ }
- modem_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
- OFONO_MANAGER_INTERFACE,
- MODEM_ADDED,
- modem_added,
- NULL, NULL);
+ return TRUE;
+}
- modem_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
- OFONO_MANAGER_INTERFACE,
+static void add_modem(const char *path, DBusMessageIter *prop)
+{
+ struct modem_data *modem;
+
+ DBG("%s", path);
+
+ modem = g_hash_table_lookup(modem_hash, path);
+ if (modem != NULL) {
+ /*
+ * When oFono powers up we ask for the modems and oFono is
+ * reporting with modem_added signal the modems. Only
+ * handle them once.
+ */
+ return;
+ }
+
+ modem = g_try_new0(struct modem_data, 1);
+ if (modem == NULL)
+ return;
+
+ modem->path = g_strdup(path);
+
+ g_hash_table_insert(modem_hash, g_strdup(path), modem);
+
+ while (dbus_message_iter_get_arg_type(prop) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value;
+ const char *key;
+
+ dbus_message_iter_recurse(prop, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &value);
+
+ if (g_str_equal(key, "Powered") == TRUE) {
+ dbus_message_iter_get_basic(&value, &modem->powered);
+
+ DBG("%s Powered %d", modem->path, modem->powered);
+ } else if (g_str_equal(key, "Online") == TRUE) {
+ dbus_message_iter_get_basic(&value, &modem->online);
+
+ DBG("%s Online %d", modem->path, modem->online);
+ } else if (g_str_equal(key, "Interfaces") == TRUE) {
+ modem->interfaces = extract_interfaces(&value);
+
+ DBG("%s Interfaces 0x%02x", modem->path,
+ modem->interfaces);
+ } else if (g_str_equal(key, "Serial") == TRUE) {
+ char *serial;
+
+ dbus_message_iter_get_basic(&value, &serial);
+ modem->serial = g_strdup(serial);
+
+ DBG("%s Serial %s", modem->path, modem->serial);
+ } else if (g_str_equal(key, "Type") == TRUE) {
+ char *type;
+
+ dbus_message_iter_get_basic(&value, &type);
+
+ DBG("%s Type %s", modem->path, type);
+ if (g_strcmp0(type, "hardware") != 0) {
+ DBG("%s Ignore this modem", modem->path);
+ modem->ignore = TRUE;
+ }
+ }
+
+ dbus_message_iter_next(prop);
+ }
+
+ if (modem->ignore == TRUE)
+ return;
+
+ if (modem->powered == FALSE) {
+ modem_set_powered(modem, TRUE);
+ return;
+ }
+
+ modem_update_interfaces(modem, 0, modem->interfaces);
+}
+
+static void modem_power_down(gpointer key, gpointer value, gpointer user_data)
+{
+ struct modem_data *modem = value;
+
+ DBG("%s", modem->path);
+
+ if (modem->ignore == TRUE)
+ return;
+
+ modem_set_powered(modem, FALSE);
+}
+
+static void remove_modem(gpointer data)
+{
+ struct modem_data *modem = data;
+
+ DBG("%s", modem->path);
+
+ if (modem->call_set_property != NULL)
+ dbus_pending_call_cancel(modem->call_set_property);
+
+ if (modem->call_get_properties != NULL)
+ dbus_pending_call_cancel(modem->call_get_properties);
+
+ if (modem->call_get_contexts != NULL)
+ dbus_pending_call_cancel(modem->call_get_contexts);
+
+ if (modem->device != NULL)
+ destroy_device(modem);
+
+ if (modem->context != NULL)
+ remove_cm_context(modem, modem->context->path);
+
+ g_free(modem->serial);
+ g_free(modem->name);
+ g_free(modem->imsi);
+ g_free(modem->path);
+
+ g_free(modem);
+}
+
+static gboolean modem_added(DBusConnection *connection,
+ DBusMessage *message, void *user_data)
+{
+ DBusMessageIter iter, properties;
+ const char *path;
+
+ DBG("");
+
+ if (dbus_message_iter_init(message, &iter) == FALSE)
+ return TRUE;
+
+ dbus_message_iter_get_basic(&iter, &path);
+
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &properties);
+
+ add_modem(path, &properties);
+
+ return TRUE;
+}
+
+static gboolean modem_removed(DBusConnection *connection,
+ DBusMessage *message, void *user_data)
+{
+ DBusMessageIter iter;
+ const char *path;
+
+ DBG("");
+
+ if (dbus_message_iter_init(message, &iter) == FALSE)
+ return TRUE;
+
+ dbus_message_iter_get_basic(&iter, &path);
+
+ g_hash_table_remove(modem_hash, path);
+
+ return TRUE;
+}
+
+static void manager_get_modems_reply(DBusPendingCall *call, void *user_data)
+{
+ DBusMessage *reply;
+ DBusError error;
+ DBusMessageIter array, dict;
+
+ DBG("");
+
+ reply = dbus_pending_call_steal_reply(call);
+
+ dbus_error_init(&error);
+
+ if (dbus_set_error_from_message(&error, reply) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ goto done;
+ }
+
+ if (dbus_message_iter_init(reply, &array) == FALSE)
+ goto done;
+
+ dbus_message_iter_recurse(&array, &dict);
+
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
+ DBusMessageIter value, properties;
+ const char *path;
+
+ dbus_message_iter_recurse(&dict, &value);
+ dbus_message_iter_get_basic(&value, &path);
+
+ dbus_message_iter_next(&value);
+ dbus_message_iter_recurse(&value, &properties);
+
+ add_modem(path, &properties);
+
+ dbus_message_iter_next(&dict);
+ }
+
+done:
+ dbus_message_unref(reply);
+
+ dbus_pending_call_unref(call);
+}
+
+static int manager_get_modems(void)
+{
+ DBusMessage *message;
+ DBusPendingCall *call;
+
+ DBG("");
+
+ message = dbus_message_new_method_call(OFONO_SERVICE, "/",
+ OFONO_MANAGER_INTERFACE, GET_MODEMS);
+ if (message == NULL)
+ return -ENOMEM;
+
+ if (dbus_connection_send_with_reply(connection, message,
+ &call, TIMEOUT) == FALSE) {
+ connman_error("Failed to call GetModems()");
+ dbus_message_unref(message);
+ return -EINVAL;
+ }
+
+ if (call == NULL) {
+ connman_error("D-Bus connection not available");
+ dbus_message_unref(message);
+ return -EINVAL;
+ }
+
+ dbus_pending_call_set_notify(call, manager_get_modems_reply,
+ NULL, NULL);
+
+ dbus_message_unref(message);
+
+ return -EINPROGRESS;
+}
+
+static void ofono_connect(DBusConnection *conn, void *user_data)
+{
+ DBG("");
+
+ modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, remove_modem);
+ if (modem_hash == NULL)
+ return;
+
+ context_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, NULL);
+ if (context_hash == NULL) {
+ g_hash_table_destroy(modem_hash);
+ return;
+ }
+
+ manager_get_modems();
+}
+
+static void ofono_disconnect(DBusConnection *conn, void *user_data)
+{
+ DBG("");
+
+ if (modem_hash == NULL || context_hash == NULL)
+ return;
+
+ g_hash_table_destroy(modem_hash);
+ modem_hash = NULL;
+
+ g_hash_table_destroy(context_hash);
+ context_hash = NULL;
+}
+
+static int network_probe(struct connman_network *network)
+{
+ struct modem_data *modem = connman_network_get_data(network);
+
+ DBG("%s network %p", modem->path, network);
+
+ return 0;
+}
+
+static void network_remove(struct connman_network *network)
+{
+ struct modem_data *modem = connman_network_get_data(network);
+
+ DBG("%s network %p", modem->path, network);
+}
+
+static int network_connect(struct connman_network *network)
+{
+ struct modem_data *modem = connman_network_get_data(network);
+
+ DBG("%s network %p", modem->path, network);
+
+ if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE)
+ return context_set_active(modem, TRUE);
+ else if (has_interface(modem->interfaces, OFONO_API_CDMA_CM) == TRUE)
+ return cdma_cm_set_powered(modem, TRUE);
+
+ connman_error("Connection manager interface not available");
+
+ return -ENOSYS;
+}
+
+static int network_disconnect(struct connman_network *network)
+{
+ struct modem_data *modem = connman_network_get_data(network);
+
+ DBG("%s network %p", modem->path, network);
+
+ if (has_interface(modem->interfaces, OFONO_API_CM) == TRUE)
+ return context_set_active(modem, FALSE);
+ else if (has_interface(modem->interfaces, OFONO_API_CDMA_CM) == TRUE)
+ return cdma_cm_set_powered(modem, FALSE);
+
+ connman_error("Connection manager interface not available");
+
+ return -ENOSYS;
+}
+
+static struct connman_network_driver network_driver = {
+ .name = "network",
+ .type = CONNMAN_NETWORK_TYPE_CELLULAR,
+ .probe = network_probe,
+ .remove = network_remove,
+ .connect = network_connect,
+ .disconnect = network_disconnect,
+};
+
+static int modem_probe(struct connman_device *device)
+{
+ struct modem_data *modem = connman_device_get_data(device);
+
+ DBG("%s device %p", modem->path, device);
+
+ return 0;
+}
+
+static void modem_remove(struct connman_device *device)
+{
+ struct modem_data *modem = connman_device_get_data(device);
+
+ DBG("%s device %p", modem->path, device);
+}
+
+static int modem_enable(struct connman_device *device)
+{
+ struct modem_data *modem = connman_device_get_data(device);
+
+ DBG("%s device %p", modem->path, device);
+
+ if (modem->online == TRUE)
+ return 0;
+
+ return modem_set_online(modem, TRUE);
+}
+
+static int modem_disable(struct connman_device *device)
+{
+ struct modem_data *modem = connman_device_get_data(device);
+
+ DBG("%s device %p", modem->path, device);
+
+ if (modem->online == FALSE)
+ return 0;
+
+ return modem_set_online(modem, FALSE);
+}
+
+static struct connman_device_driver modem_driver = {
+ .name = "modem",
+ .type = CONNMAN_DEVICE_TYPE_CELLULAR,
+ .probe = modem_probe,
+ .remove = modem_remove,
+ .enable = modem_enable,
+ .disable = modem_disable,
+};
+
+static int tech_probe(struct connman_technology *technology)
+{
+ return 0;
+}
+
+static void tech_remove(struct connman_technology *technology)
+{
+}
+
+static struct connman_technology_driver tech_driver = {
+ .name = "cellular",
+ .type = CONNMAN_SERVICE_TYPE_CELLULAR,
+ .probe = tech_probe,
+ .remove = tech_remove,
+};
+
+static guint watch;
+static guint modem_added_watch;
+static guint modem_removed_watch;
+static guint modem_watch;
+static guint cm_watch;
+static guint sim_watch;
+static guint context_added_watch;
+static guint context_removed_watch;
+static guint netreg_watch;
+static guint context_watch;
+static guint cdma_cm_watch;
+static guint cdma_netreg_watch;
+
+static int ofono_init(void)
+{
+ int err;
+
+ DBG("");
+
+ connection = connman_dbus_get_connection();
+ if (connection == NULL)
+ return -EIO;
+
+ watch = g_dbus_add_service_watch(connection,
+ OFONO_SERVICE, ofono_connect,
+ ofono_disconnect, NULL, NULL);
+
+ modem_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ OFONO_MANAGER_INTERFACE,
+ MODEM_ADDED,
+ modem_added,
+ NULL, NULL);
+
+ modem_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ OFONO_MANAGER_INTERFACE,
MODEM_REMOVED,
modem_removed,
NULL, NULL);
+ modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ OFONO_MODEM_INTERFACE,
+ PROPERTY_CHANGED,
+ modem_changed,
+ NULL, NULL);
+
+ cm_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ OFONO_CM_INTERFACE,
+ PROPERTY_CHANGED,
+ cm_changed,
+ NULL, NULL);
+
+ sim_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ OFONO_SIM_INTERFACE,
+ PROPERTY_CHANGED,
+ sim_changed,
+ NULL, NULL);
+
+ context_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ OFONO_CM_INTERFACE,
+ CONTEXT_ADDED,
+ cm_context_added,
+ NULL, NULL);
+
+ context_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ OFONO_CM_INTERFACE,
+ CONTEXT_REMOVED,
+ cm_context_removed,
+ NULL, NULL);
+
context_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
OFONO_CONTEXT_INTERFACE,
PROPERTY_CHANGED,
context_changed,
NULL, NULL);
- if (watch == 0 || gprs_watch == 0 || context_added_watch == 0 ||
- context_removed_watch == 0 || modem_watch == 0 ||
- reg_watch == 0 || sim_watch == 0 ||
- modem_added_watch == 0 || modem_removed_watch == 0 ||
- context_watch == 0) {
+ netreg_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ OFONO_NETREG_INTERFACE,
+ PROPERTY_CHANGED,
+ netreg_changed,
+ NULL, NULL);
+
+ cdma_cm_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ OFONO_CDMA_CM_INTERFACE,
+ PROPERTY_CHANGED,
+ cdma_cm_changed,
+ NULL, NULL);
+
+ cdma_netreg_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ OFONO_CDMA_NETREG_INTERFACE,
+ PROPERTY_CHANGED,
+ cdma_netreg_changed,
+ NULL, NULL);
+
+
+ if (watch == 0 || modem_added_watch == 0 || modem_removed_watch == 0 ||
+ modem_watch == 0 || cm_watch == 0 || sim_watch == 0 ||
+ context_added_watch == 0 ||
+ context_removed_watch == 0 ||
+ context_watch == 0 || netreg_watch == 0 ||
+ cdma_cm_watch == 0 || cdma_netreg_watch == 0) {
err = -EIO;
goto remove;
}
goto remove;
}
+ err = connman_technology_driver_register(&tech_driver);
+ if (err < 0) {
+ connman_device_driver_unregister(&modem_driver);
+ connman_network_driver_unregister(&network_driver);
+ goto remove;
+ }
+
return 0;
remove:
- g_dbus_remove_watch(connection, watch);
- g_dbus_remove_watch(connection, sim_watch);
- g_dbus_remove_watch(connection, reg_watch);
- g_dbus_remove_watch(connection, gprs_watch);
- g_dbus_remove_watch(connection, context_added_watch);
+ g_dbus_remove_watch(connection, cdma_netreg_watch);
+ g_dbus_remove_watch(connection, cdma_cm_watch);
+ g_dbus_remove_watch(connection, netreg_watch);
+ g_dbus_remove_watch(connection, context_watch);
g_dbus_remove_watch(connection, context_removed_watch);
+ g_dbus_remove_watch(connection, context_added_watch);
+ g_dbus_remove_watch(connection, sim_watch);
+ g_dbus_remove_watch(connection, cm_watch);
g_dbus_remove_watch(connection, modem_watch);
- g_dbus_remove_watch(connection, modem_added_watch);
g_dbus_remove_watch(connection, modem_removed_watch);
- g_dbus_remove_watch(connection, context_watch);
-
+ g_dbus_remove_watch(connection, modem_added_watch);
+ g_dbus_remove_watch(connection, watch);
dbus_connection_unref(connection);
return err;
static void ofono_exit(void)
{
- g_dbus_remove_watch(connection, watch);
- g_dbus_remove_watch(connection, sim_watch);
- g_dbus_remove_watch(connection, reg_watch);
- g_dbus_remove_watch(connection, gprs_watch);
- g_dbus_remove_watch(connection, context_added_watch);
- g_dbus_remove_watch(connection, context_removed_watch);
- g_dbus_remove_watch(connection, modem_watch);
- g_dbus_remove_watch(connection, modem_added_watch);
- g_dbus_remove_watch(connection, modem_removed_watch);
- g_dbus_remove_watch(connection, context_watch);
+ DBG("");
- ofono_disconnect(connection, NULL);
+ if (modem_hash != NULL) {
+ /*
+ * We should propably wait for the SetProperty() reply
+ * message, because ...
+ */
+ g_hash_table_foreach(modem_hash, modem_power_down, NULL);
+
+ /*
+ * ... here we will cancel the call.
+ */
+ g_hash_table_destroy(modem_hash);
+ modem_hash = NULL;
+ }
+ if (context_hash != NULL) {
+ g_hash_table_destroy(context_hash);
+ context_hash = NULL;
+ }
+
+ connman_technology_driver_unregister(&tech_driver);
connman_device_driver_unregister(&modem_driver);
connman_network_driver_unregister(&network_driver);
+ g_dbus_remove_watch(connection, cdma_netreg_watch);
+ g_dbus_remove_watch(connection, cdma_cm_watch);
+ g_dbus_remove_watch(connection, netreg_watch);
+ g_dbus_remove_watch(connection, context_watch);
+ g_dbus_remove_watch(connection, context_removed_watch);
+ g_dbus_remove_watch(connection, context_added_watch);
+ g_dbus_remove_watch(connection, sim_watch);
+ g_dbus_remove_watch(connection, cm_watch);
+ g_dbus_remove_watch(connection, modem_watch);
+ g_dbus_remove_watch(connection, modem_added_watch);
+ g_dbus_remove_watch(connection, modem_removed_watch);
+ g_dbus_remove_watch(connection, watch);
+
dbus_connection_unref(connection);
}
return 0;
}
+static int oc_save (struct connman_provider *provider, GKeyFile *keyfile)
+{
+ const char *setting;
+
+ setting = connman_provider_get_string(provider,
+ "OpenConnect.ServerCert");
+ if (setting != NULL)
+ g_key_file_set_string(keyfile,
+ connman_provider_get_save_group(provider),
+ "OpenConnect.ServerCert", setting);
+
+ setting = connman_provider_get_string(provider,
+ "OpenConnect.CACert");
+ if (setting != NULL)
+ g_key_file_set_string(keyfile,
+ connman_provider_get_save_group(provider),
+ "OpenConnect.CACert", setting);
+
+ setting = connman_provider_get_string(provider,
+ "VPN.MTU");
+ if (setting != NULL)
+ g_key_file_set_string(keyfile,
+ connman_provider_get_save_group(provider),
+ "VPN.MTU", setting);
+
+ return 0;
+}
+
static int oc_error_code(int exit_code)
{
.notify = oc_notify,
.connect = oc_connect,
.error_code = oc_error_code,
+ .save = oc_save,
};
static int openconnect_init(void)
return VPN_STATE_CONNECT;
}
+static int ov_save(struct connman_provider *provider, GKeyFile *keyfile)
+{
+ const char *option;
+ int i;
+
+ for (i = 0; i < (int)ARRAY_SIZE(ov_options); i++) {
+ if (strncmp(ov_options[i].cm_opt, "OpenVPN.", 8) == 0) {
+ option = connman_provider_get_string(provider,
+ ov_options[i].cm_opt);
+ if (option == NULL)
+ continue;
+
+ g_key_file_set_string(keyfile,
+ connman_provider_get_save_group(provider),
+ ov_options[i].cm_opt, option);
+ }
+ }
+ return 0;
+}
+
static int task_append_config_data(struct connman_provider *provider,
struct connman_task *task)
{
static struct vpn_driver vpn_driver = {
.notify = ov_notify,
.connect = ov_connect,
+ .save = ov_save,
};
static int openvpn_init(void)
+++ /dev/null
-/*
- *
- * Connection Manager
- *
- * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <errno.h>
-#include <stdlib.h>
-
-#include <glib.h>
-
-#define CONNMAN_API_SUBJECT_TO_CHANGE
-#include <connman/plugin.h>
-#include <connman/location.h>
-#include <connman/proxy.h>
-#include <connman/log.h>
-
-#include "gweb/gweb.h"
-
-#define STATUS_URL "http://www.connman.net/online/status.html"
-
-struct server_data {
- unsigned int token;
- GWeb *web;
- guint request_id;
-};
-
-static void web_debug(const char *str, void *data)
-{
- connman_info("%s: %s\n", (const char *) data, str);
-}
-
-static gboolean web_result(GWebResult *result, gpointer user_data)
-{
- struct connman_location *location = user_data;
- struct server_data *data = connman_location_get_data(location);
- const char *str;
- guint16 status;
-
- if (data->request_id == 0)
- return FALSE;
-
- status = g_web_result_get_status(result);
-
- /* If status header is not available, it is a portal */
- if (g_web_result_get_header(result, "X-ConnMan-Status", &str) == FALSE)
- status = 302;
-
- DBG("status %u", status);
-
- switch (status) {
- case 200:
- if (g_web_result_get_header(result, "X-ConnMan-Client-IP",
- &str) == TRUE)
- connman_info("Client-IP: %s", str);
-
- if (g_web_result_get_header(result, "X-ConnMan-Client-Country",
- &str) == TRUE)
- connman_info("Client-Country: %s", str);
-
- if (g_web_result_get_header(result, "X-ConnMan-Client-Region",
- &str) == TRUE)
- connman_info("Client-Region: %s", str);
-
- connman_location_report_result(location,
- CONNMAN_LOCATION_RESULT_ONLINE);
- break;
- case 302:
- connman_location_report_result(location,
- CONNMAN_LOCATION_RESULT_PORTAL);
- break;
- default:
- connman_location_report_result(location,
- CONNMAN_LOCATION_RESULT_UNKNOWN);
- break;
- }
-
- data->request_id = 0;
-
- return FALSE;
-}
-
-static void proxy_callback(const char *proxy, void *user_data)
-{
- struct connman_location *location = user_data;
- struct server_data *data = connman_location_get_data(location);
-
- DBG("proxy %s", proxy);
-
- if (proxy == NULL)
- proxy = getenv("http_proxy");
-
- if (data != NULL) {
- if (proxy != NULL && g_strcmp0(proxy, "DIRECT") != 0)
- g_web_set_proxy(data->web, proxy);
-
- data->request_id = g_web_request_get(data->web, STATUS_URL,
- web_result, location);
-
- data->token = 0;
- }
-
- connman_location_unref(location);
-}
-
-static int location_detect(struct connman_location *location)
-{
- struct server_data *data;
- struct connman_service *service;
- enum connman_service_type service_type;
- char *interface;
- int err;
-
- DBG("location %p", location);
-
- service_type = connman_location_get_type(location);
-
- switch (service_type) {
- case CONNMAN_SERVICE_TYPE_ETHERNET:
- case CONNMAN_SERVICE_TYPE_WIFI:
- case CONNMAN_SERVICE_TYPE_WIMAX:
- case CONNMAN_SERVICE_TYPE_BLUETOOTH:
- case CONNMAN_SERVICE_TYPE_CELLULAR:
- break;
- case CONNMAN_SERVICE_TYPE_UNKNOWN:
- case CONNMAN_SERVICE_TYPE_SYSTEM:
- case CONNMAN_SERVICE_TYPE_GPS:
- case CONNMAN_SERVICE_TYPE_VPN:
- case CONNMAN_SERVICE_TYPE_GADGET:
- return -EOPNOTSUPP;
- }
-
- interface = connman_location_get_interface(location);
- if (interface == NULL)
- return -EINVAL;
-
- DBG("interface %s", interface);
-
- data = g_try_new0(struct server_data, 1);
- if (data == NULL) {
- err = -ENOMEM;
- goto done;
- }
-
- connman_location_set_data(location, data);
-
- data->web = g_web_new(0);
- if (data->web == NULL) {
- g_free(data);
- err = -ENOMEM;
- goto done;
- }
-
- if (getenv("CONNMAN_WEB_DEBUG"))
- g_web_set_debug(data->web, web_debug, "WEB");
-
- g_web_set_accept(data->web, NULL);
- g_web_set_user_agent(data->web, "ConnMan/%s", VERSION);
- g_web_set_close_connection(data->web, TRUE);
-
- connman_location_ref(location);
-
- service = connman_location_get_service(location);
- data->token = connman_proxy_lookup(interface, STATUS_URL,
- service, proxy_callback, location);
-
- if (data->token == 0) {
- connman_location_unref(location);
- err = -EINVAL;
- } else
- err = 0;
-
-done:
- g_free(interface);
- return err;
-}
-
-static int location_finish(struct connman_location *location)
-{
- struct server_data *data = connman_location_get_data(location);
-
- DBG("location %p", location);
-
- connman_location_set_data(location, NULL);
-
- if (data->request_id > 0)
- g_web_cancel_request(data->web, data->request_id);
-
- if (data->token > 0) {
- connman_proxy_lookup_cancel(data->token);
- connman_location_unref(location);
- }
-
- g_web_unref(data->web);
-
- g_free(data);
-
- return 0;
-}
-
-static struct connman_location_driver location = {
- .name = "portal",
- .type = CONNMAN_SERVICE_TYPE_WIFI,
- .priority = CONNMAN_LOCATION_PRIORITY_HIGH,
- .detect = location_detect,
- .finish = location_finish,
-};
-
-static int portal_init(void)
-{
- return connman_location_driver_register(&location);
-}
-
-static void portal_exit(void)
-{
- connman_location_driver_unregister(&location);
-}
-
-CONNMAN_PLUGIN_DEFINE(portal, "Portal detection plugin", VERSION,
- CONNMAN_PLUGIN_PRIORITY_DEFAULT, portal_init, portal_exit)
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2010 BMW Car IT GmbH. All rights reserved.
+ * Copyright (C) 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <net/if.h>
+
+#include <glib.h>
+
+#define CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/plugin.h>
+#include <connman/provider.h>
+#include <connman/log.h>
+#include <connman/task.h>
+#include <connman/dbus.h>
+#include <connman/inet.h>
+
+#include "vpn.h"
+
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+enum {
+ OPT_STRING = 1,
+ OPT_BOOL = 2,
+};
+
+struct {
+ const char *cm_opt;
+ const char *pptp_opt;
+ const char *vpnc_default;
+ int type;
+} pptp_options[] = {
+ { "PPTP.User", "user", NULL, OPT_STRING },
+ { "PPTP.EchoFailure", "lcp-echo-failure", "0", OPT_STRING },
+ { "PPTP.EchoInterval", "lcp-echo-interval", "0", OPT_STRING },
+ { "PPTP.Debug", "debug", NULL, OPT_STRING },
+ { "PPTP.RefuseEAP", "refuse-eap", NULL, OPT_BOOL },
+ { "PPTP.RefusePAP", "refuse-pap", NULL, OPT_BOOL },
+ { "PPTP.RefuseCHAP", "refuse-chap", NULL, OPT_BOOL },
+ { "PPTP.RefuseMSCHAP", "refuse-mschap", NULL, OPT_BOOL },
+ { "PPTP.RefuseMSCHAP2", "refuse-mschapv2", NULL, OPT_BOOL },
+ { "PPTP.NoBSDComp", "nobsdcomp", NULL, OPT_BOOL },
+ { "PPTP.NoDeflate", "nodeflatey", NULL, OPT_BOOL },
+ { "PPTP.RequirMPPE", "require-mppe", NULL, OPT_BOOL },
+ { "PPTP.RequirMPPE40", "require-mppe-40", NULL, OPT_BOOL },
+ { "PPTP.RequirMPPE128", "require-mppe-128", NULL, OPT_BOOL },
+ { "PPTP.RequirMPPEStateful", "mppe-stateful", NULL, OPT_BOOL },
+ { "PPTP.NoVJ", "no-vj-comp", NULL, OPT_BOOL },
+};
+
+static DBusConnection *connection;
+
+static DBusMessage *pptp_get_sec(struct connman_task *task,
+ DBusMessage *msg, void *user_data)
+{
+ const char *user, *passwd;
+ struct connman_provider *provider = user_data;
+ DBusMessage *reply;
+
+ if (dbus_message_get_no_reply(msg) == TRUE)
+ return NULL;
+
+ user = connman_provider_get_string(provider, "PPTP.User");
+ passwd = connman_provider_get_string(provider, "PPTP.Password");
+ if (user == NULL || strlen(user) == 0 ||
+ passwd == NULL || strlen(passwd) == 0)
+ return NULL;
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &user,
+ DBUS_TYPE_STRING, &passwd,
+ DBUS_TYPE_INVALID);
+ return reply;
+}
+
+static int pptp_notify(DBusMessage *msg, struct connman_provider *provider)
+{
+ DBusMessageIter iter, dict;
+ const char *reason, *key, *value;
+ char *addressv4 = NULL, *netmask = NULL, *gateway = NULL;
+ char *ifname = NULL, *nameservers = NULL;
+ struct connman_ipaddress *ipaddress = NULL;
+
+ dbus_message_iter_init(msg, &iter);
+
+ dbus_message_iter_get_basic(&iter, &reason);
+ dbus_message_iter_next(&iter);
+
+ if (provider == NULL) {
+ connman_error("No provider found");
+ return VPN_STATE_FAILURE;
+ }
+
+ if (strcmp(reason, "auth failed") == 0)
+ return VPN_STATE_AUTH_FAILURE;
+
+ if (strcmp(reason, "connect"))
+ return VPN_STATE_DISCONNECT;
+
+ dbus_message_iter_recurse(&iter, &dict);
+
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry;
+
+ dbus_message_iter_recurse(&dict, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_get_basic(&entry, &value);
+
+ DBG("%s = %s", key, value);
+
+ if (!strcmp(key, "INTERNAL_IP4_ADDRESS")) {
+ connman_provider_set_string(provider, "Address", value);
+ addressv4 = g_strdup(value);
+ }
+
+ if (!strcmp(key, "INTERNAL_IP4_NETMASK")) {
+ connman_provider_set_string(provider, "Netmask", value);
+ netmask = g_strdup(value);
+ }
+
+ if (!strcmp(key, "INTERNAL_IP4_DNS")) {
+ connman_provider_set_string(provider, "DNS", value);
+ nameservers = g_strdup(value);
+ }
+
+ if (!strcmp(key, "INTERNAL_IFNAME"))
+ ifname = g_strdup(value);
+
+ dbus_message_iter_next(&dict);
+ }
+
+ if (vpn_set_ifname(provider, ifname) < 0) {
+ g_free(ifname);
+ g_free(addressv4);
+ g_free(netmask);
+ g_free(nameservers);
+ return VPN_STATE_FAILURE;
+ }
+
+ if (addressv4 != NULL)
+ ipaddress = connman_ipaddress_alloc(AF_INET);
+
+ g_free(ifname);
+
+ if (ipaddress == NULL) {
+ connman_error("No IP address for provider");
+ g_free(addressv4);
+ g_free(netmask);
+ g_free(nameservers);
+ return VPN_STATE_FAILURE;
+ }
+
+ value = connman_provider_get_string(provider, "Host");
+ if (value != NULL) {
+ connman_provider_set_string(provider, "Gateway", value);
+ gateway = g_strdup(value);
+ }
+
+ if (addressv4 != NULL)
+ connman_ipaddress_set_ipv4(ipaddress, addressv4, netmask,
+ gateway);
+
+ connman_provider_set_ipaddress(provider, ipaddress);
+ connman_provider_set_nameservers(provider, nameservers);
+
+ g_free(addressv4);
+ g_free(netmask);
+ g_free(gateway);
+ g_free(nameservers);
+ connman_ipaddress_free(ipaddress);
+
+ return VPN_STATE_CONNECT;
+}
+
+static int pptp_save(struct connman_provider *provider, GKeyFile *keyfile)
+{
+ const char *option;
+ int i;
+
+ for (i = 0; i < (int)ARRAY_SIZE(pptp_options); i++) {
+ if (strncmp(pptp_options[i].cm_opt, "PPTP.", 5) == 0) {
+ option = connman_provider_get_string(provider,
+ pptp_options[i].cm_opt);
+ if (option == NULL)
+ continue;
+
+ g_key_file_set_string(keyfile,
+ connman_provider_get_save_group(provider),
+ pptp_options[i].cm_opt, option);
+ }
+ }
+ return 0;
+}
+
+static void pptp_write_bool_option(struct connman_task *task,
+ const char *key, const char *value)
+{
+ if (key != NULL && value != NULL) {
+ if (strcmp(value, "yes") == 0)
+ connman_task_add_argument(task, key, NULL);
+ }
+}
+
+static int pptp_connect(struct connman_provider *provider,
+ struct connman_task *task, const char *if_name)
+{
+ const char *opt_s, *host;
+ char *str;
+ int err, i;
+
+ if (connman_task_set_notify(task, "getsec",
+ pptp_get_sec, provider))
+ return -ENOMEM;
+
+ host = connman_provider_get_string(provider, "Host");
+ if (host == NULL) {
+ connman_error("Host not set; cannot enable VPN");
+ return -EINVAL;
+ }
+
+ str = g_strdup_printf("%s %s --nolaunchpppd --loglevel 2",
+ PPTP, host);
+ if (str == NULL) {
+ connman_error("can not allocate memory");
+ return -ENOMEM;
+ }
+
+ connman_task_add_argument(task, "pty", str);
+ g_free(str);
+
+ connman_task_add_argument(task, "nodetach", NULL);
+ connman_task_add_argument(task, "lock", NULL);
+ connman_task_add_argument(task, "usepeerdns", NULL);
+ connman_task_add_argument(task, "noipdefault", NULL);
+ connman_task_add_argument(task, "noauth", NULL);
+ connman_task_add_argument(task, "nodefaultroute", NULL);
+ connman_task_add_argument(task, "ipparam", "pptp_plugin");
+
+ for (i = 0; i < (int)ARRAY_SIZE(pptp_options); i++) {
+ opt_s = connman_provider_get_string(provider,
+ pptp_options[i].cm_opt);
+ if (opt_s == NULL)
+ opt_s = pptp_options[i].vpnc_default;
+
+ if (opt_s == NULL)
+ continue;
+
+ if (pptp_options[i].type == OPT_STRING)
+ connman_task_add_argument(task,
+ pptp_options[i].pptp_opt, opt_s);
+ else if (pptp_options[i].type == OPT_BOOL)
+ pptp_write_bool_option(task,
+ pptp_options[i].pptp_opt, opt_s);
+ }
+
+ connman_task_add_argument(task, "plugin",
+ SCRIPTDIR "/libppp-plugin.so");
+
+ err = connman_task_run(task, vpn_died, provider,
+ NULL, NULL, NULL);
+ if (err < 0) {
+ connman_error("pptp failed to start");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int pptp_error_code(int exit_code)
+{
+
+ switch (exit_code) {
+ case 1:
+ return CONNMAN_PROVIDER_ERROR_CONNECT_FAILED;
+ case 2:
+ return CONNMAN_PROVIDER_ERROR_LOGIN_FAILED;
+ case 16:
+ return CONNMAN_PROVIDER_ERROR_AUTH_FAILED;
+ default:
+ return CONNMAN_PROVIDER_ERROR_UNKNOWN;
+ }
+}
+
+static struct vpn_driver vpn_driver = {
+ .flags = VPN_FLAG_NO_TUN,
+ .notify = pptp_notify,
+ .connect = pptp_connect,
+ .error_code = pptp_error_code,
+ .save = pptp_save,
+};
+
+static int pptp_init(void)
+{
+ connection = connman_dbus_get_connection();
+
+ return vpn_register("pptp", &vpn_driver, PPPD);
+}
+
+static void pptp_exit(void)
+{
+ vpn_unregister("pptp");
+
+ dbus_connection_unref(connection);
+}
+
+CONNMAN_PLUGIN_DEFINE(pptp, "pptp plugin", VERSION,
+ CONNMAN_PLUGIN_PRIORITY_DEFAULT, pptp_init, pptp_exit)
#include <config.h>
#endif
+#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
static guint install_watch = 0;
static guint uart_watch = 0;
-static gint install_count = 0;
+static int install_count = 0;
#define NCCS2 19
struct termios2 {
if (ioctl(uart_fd, TIOCSETD, &ldisc) < 0)
goto err;
- g_atomic_int_set(&install_count, 0);
+ install_count = 1;
+ __sync_synchronize();
return FALSE;
err:
- g_atomic_int_set(&install_count, 0);
+ install_count = 0;
+ __sync_synchronize();
+
g_io_channel_shutdown(channel, TRUE, NULL);
g_io_channel_unref(channel);
DBG("%d %p", install, uart_channel);
if (install == FALSE) {
- g_atomic_int_set(&install_count, 0);
+ install_count = 0;
+ __sync_synchronize();
if (uart_channel == NULL) {
DBG("UART channel is NULL");
DBG("opening %s custom baud %lu", uart_dev_name, baud_rate);
- uart_fd = open(uart_dev_name, O_RDWR);
+ uart_fd = open(uart_dev_name, O_RDWR | O_CLOEXEC);
if (uart_fd < 0)
return -EIO;
uart_channel = NULL;
}
- g_atomic_int_set(&install_count, 0);
+ install_count = 0;
+ __sync_synchronize();
return 0;
}
return FALSE;
}
- if (g_atomic_int_get(&install_count) != 0) {
+ __sync_synchronize();
+ if (install_count != 0) {
status = g_io_channel_seek_position(channel, 0, G_SEEK_SET, NULL);
if (status != G_IO_STATUS_NORMAL) {
g_io_channel_shutdown(channel, TRUE, NULL);
return TRUE;
} else {
- g_atomic_int_set(&install_count, 1);
+ install_count = 1;
+ __sync_synchronize();
}
status = g_io_channel_seek_position(channel, 0, G_SEEK_SET, NULL);
if (install_ldisc(channel, install) < 0) {
connman_error("ldisc installation failed");
- g_atomic_int_set(&install_count, 0);
+ install_count = 0;
+ __sync_synchronize();
return TRUE;
}
return err;
}
- fd = open(TIST_SYSFS_INSTALL, O_RDONLY);
+ fd = open(TIST_SYSFS_INSTALL, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
connman_error("Failed to open TI ST sysfs install file");
return -EIO;
install_event, NULL, NULL);
if (install_state) {
- g_atomic_int_set(&install_count, 1);
+ install_count = 1;
+ __sync_synchronize();
+
err = install_ldisc(install_channel, TRUE);
if (err < 0) {
connman_error("ldisc installtion failed");
#include <config.h>
#endif
+#define _GNU_SOURCE
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
GHashTable *driver_hash = NULL;
-static int kill_tun(char *tun_name)
+static int stop_vpn(struct connman_provider *provider)
{
+ struct vpn_data *data = connman_provider_get_data(provider);
+ struct vpn_driver_data *vpn_driver_data;
+ const char *name;
struct ifreq ifr;
int fd, err;
+ if (data == NULL)
+ return -EINVAL;
+
+ name = connman_provider_get_driver_name(provider);
+ if (name == NULL)
+ return -EINVAL;
+
+ vpn_driver_data = g_hash_table_lookup(driver_hash, name);
+
+ if (vpn_driver_data != NULL && vpn_driver_data->vpn_driver != NULL &&
+ vpn_driver_data->vpn_driver->flags == VPN_FLAG_NO_TUN)
+ return 0;
+
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
- sprintf(ifr.ifr_name, "%s", tun_name);
+ sprintf(ifr.ifr_name, "%s", data->if_name);
- fd = open("/dev/net/tun", O_RDWR);
+ fd = open("/dev/net/tun", O_RDWR | O_CLOEXEC);
if (fd < 0) {
err = -errno;
connman_error("Failed to open /dev/net/tun to device %s: %s",
- tun_name, strerror(errno));
+ data->if_name, strerror(errno));
return err;
}
if (ioctl(fd, TUNSETIFF, (void *)&ifr)) {
err = -errno;
connman_error("Failed to TUNSETIFF for device %s to it: %s",
- tun_name, strerror(errno));
+ data->if_name, strerror(errno));
close(fd);
return err;
}
if (ioctl(fd, TUNSETPERSIST, 0)) {
err = -errno;
connman_error("Failed to set tun device %s nonpersistent: %s",
- tun_name, strerror(errno));
+ data->if_name, strerror(errno));
close(fd);
return err;
}
close(fd);
- DBG("Killed tun device %s", tun_name);
+ DBG("Killed tun device %s", data->if_name);
return 0;
}
state = data->state;
- kill_tun(data->if_name);
+ stop_vpn(provider);
connman_provider_set_data(provider, NULL);
connman_rtnl_remove_watch(data->watch);
vpn_exit:
if (state != VPN_STATE_READY && state != VPN_STATE_DISCONNECT) {
const char *name;
- struct vpn_driver_data *vpn_data;
+ struct vpn_driver_data *vpn_data = NULL;
name = connman_provider_get_driver_name(provider);
- vpn_data = g_hash_table_lookup(driver_hash, name);
+ if (name != NULL)
+ vpn_data = g_hash_table_lookup(driver_hash, name);
+
if (vpn_data != NULL &&
vpn_data->vpn_driver->error_code != NULL)
ret = vpn_data->vpn_driver->error_code(exit_code);
connman_provider_set_index(provider, -1);
connman_provider_unref(data->provider);
+
+ g_free(data->if_name);
g_free(data);
connman_task_destroy(task);
}
+int vpn_set_ifname(struct connman_provider *provider, const char *ifname)
+{
+ struct vpn_data *data = connman_provider_get_data(provider);
+ int index;
+
+ if (ifname == NULL || data == NULL)
+ return -EIO;
+
+ index = connman_inet_ifindex(ifname);
+ if (index < 0)
+ return -EIO;
+
+ if (data->if_name != NULL)
+ g_free(data->if_name);
+
+ data->if_name = (char *)g_strdup(ifname);
+ connman_provider_set_index(provider, index);
+
+ return 0;
+}
+
static void vpn_newlink(unsigned flags, unsigned change, void *user_data)
{
struct connman_provider *provider = user_data;
data->flags = flags;
}
-static void vpn_notify(struct connman_task *task,
+static DBusMessage *vpn_notify(struct connman_task *task,
DBusMessage *msg, void *user_data)
{
struct connman_provider *provider = user_data;
data = connman_provider_get_data(provider);
name = connman_provider_get_driver_name(provider);
+ if (name == NULL)
+ return NULL;
+
vpn_driver_data = g_hash_table_lookup(driver_hash, name);
if (vpn_driver_data == NULL)
- return;
+ return NULL;
state = vpn_driver_data->vpn_driver->notify(msg, provider);
switch (state) {
connman_provider_set_state(provider,
CONNMAN_PROVIDER_STATE_DISCONNECT);
break;
+
+ case VPN_STATE_AUTH_FAILURE:
+ connman_provider_indicate_error(provider,
+ CONNMAN_PROVIDER_ERROR_AUTH_FAILED);
+ break;
}
+
+ return NULL;
}
-static int vpn_connect(struct connman_provider *provider)
+static int vpn_create_tun(struct connman_provider *provider)
{
struct vpn_data *data = connman_provider_get_data(provider);
- struct vpn_driver_data *vpn_driver_data;
struct ifreq ifr;
- const char *name;
int i, fd, index;
int ret = 0;
- if (data != NULL)
- return -EISCONN;
-
- data = g_try_new0(struct vpn_data, 1);
if (data == NULL)
- return -ENOMEM;
-
- data->provider = connman_provider_ref(provider);
- data->watch = 0;
- data->flags = 0;
- data->task = NULL;
- data->state = VPN_STATE_IDLE;
-
- connman_provider_set_data(provider, data);
-
- name = connman_provider_get_driver_name(provider);
- vpn_driver_data = g_hash_table_lookup(driver_hash, name);
+ return -EISCONN;
- fd = open("/dev/net/tun", O_RDWR);
+ fd = open("/dev/net/tun", O_RDWR | O_CLOEXEC);
if (fd < 0) {
i = -errno;
connman_error("Failed to open /dev/net/tun: %s",
index = connman_inet_ifindex(data->if_name);
if (index < 0) {
connman_error("Failed to get tun ifindex");
- kill_tun(data->if_name);
+ stop_vpn(provider);
ret = -EIO;
goto exist_err;
}
connman_provider_set_index(provider, index);
+ return 0;
+
+exist_err:
+ return ret;
+}
+
+static int vpn_connect(struct connman_provider *provider)
+{
+ struct vpn_data *data = connman_provider_get_data(provider);
+ struct vpn_driver_data *vpn_driver_data;
+ const char *name;
+ int ret = 0;
+
+ if (data != NULL)
+ return -EISCONN;
+
+ data = g_try_new0(struct vpn_data, 1);
+ if (data == NULL)
+ return -ENOMEM;
+
+ data->provider = connman_provider_ref(provider);
+ data->watch = 0;
+ data->flags = 0;
+ data->task = NULL;
+ data->state = VPN_STATE_IDLE;
+
+ connman_provider_set_data(provider, data);
+
+ name = connman_provider_get_driver_name(provider);
+ if (name == NULL)
+ return -EINVAL;
+
+ vpn_driver_data = g_hash_table_lookup(driver_hash, name);
+
+ if (vpn_driver_data != NULL && vpn_driver_data->vpn_driver != NULL &&
+ vpn_driver_data->vpn_driver->flags != VPN_FLAG_NO_TUN) {
+
+ ret = vpn_create_tun(provider);
+ if (ret < 0)
+ goto exist_err;
+ }
+
data->task = connman_task_create(vpn_driver_data->program);
if (data->task == NULL) {
ret = -ENOMEM;
- kill_tun(data->if_name);
+ stop_vpn(provider);
goto exist_err;
}
if (connman_task_set_notify(data->task, "notify",
vpn_notify, provider)) {
ret = -ENOMEM;
- kill_tun(data->if_name);
+ stop_vpn(provider);
connman_task_destroy(data->task);
data->task = NULL;
goto exist_err;
ret = vpn_driver_data->vpn_driver->connect(provider, data->task,
data->if_name);
if (ret < 0) {
- kill_tun(data->if_name);
+ stop_vpn(provider);
connman_task_destroy(data->task);
data->task = NULL;
goto exist_err;
connman_provider_set_index(provider, -1);
connman_provider_set_data(provider, NULL);
connman_provider_unref(data->provider);
+ g_free(data->if_name);
g_free(data);
return ret;
return 0;
name = connman_provider_get_driver_name(provider);
+ if (name == NULL)
+ return 0;
+
vpn_driver_data = g_hash_table_lookup(driver_hash, name);
if (vpn_driver_data->vpn_driver->disconnect)
vpn_driver_data->vpn_driver->disconnect();
struct vpn_data *data;
data = connman_provider_get_data(provider);
- connman_provider_set_data(provider, NULL);
if (data == NULL)
return 0;
connman_task_stop(data->task);
g_usleep(G_USEC_PER_SEC);
- kill_tun(data->if_name);
+ stop_vpn(provider);
+ return 0;
+}
+
+static int vpn_save (struct connman_provider *provider, GKeyFile *keyfile)
+{
+ struct vpn_driver_data *vpn_driver_data;
+ const char *name;
+
+ name = connman_provider_get_driver_name(provider);
+ vpn_driver_data = g_hash_table_lookup(driver_hash, name);
+ if (vpn_driver_data != NULL &&
+ vpn_driver_data->vpn_driver->save != NULL)
+ return vpn_driver_data->vpn_driver->save(provider, keyfile);
+
return 0;
}
data->provider_driver.connect = vpn_connect;
data->provider_driver.probe = vpn_probe;
data->provider_driver.remove = vpn_remove;
+ data->provider_driver.save = vpn_save;
if (driver_hash == NULL) {
driver_hash = g_hash_table_new_full(g_str_hash,
*
*/
+#define VPN_FLAG_NO_TUN 1
+
enum vpn_state {
VPN_STATE_UNKNOWN = 0,
VPN_STATE_IDLE = 1,
VPN_STATE_READY = 3,
VPN_STATE_DISCONNECT = 4,
VPN_STATE_FAILURE = 5,
+ VPN_STATE_AUTH_FAILURE = 6,
};
struct vpn_driver {
+ int flags;
int (*notify) (DBusMessage *msg, struct connman_provider *provider);
int (*connect) (struct connman_provider *provider,
struct connman_task *task, const char *if_name);
void (*disconnect) (void);
int (*error_code) (int exit_code);
+ int (*save) (struct connman_provider *provider, GKeyFile *keyfile);
};
int vpn_register(const char *name, struct vpn_driver *driver,
const char *program);
void vpn_unregister(const char *provider_name);
void vpn_died(struct connman_task *task, int exit_code, void *user_data);
+int vpn_set_ifname(struct connman_provider *provider, const char *ifname);
return 0;
}
+static int vc_save(struct connman_provider *provider, GKeyFile *keyfile)
+{
+ char *option;
+ int i;
+
+ for (i = 0; i < (int)ARRAY_SIZE(vpnc_options); i++) {
+ if (strncmp(vpnc_options[i].cm_opt, "VPNC.", 5) == 0) {
+ option = connman_provider_get_string(provider,
+ vpnc_options[i].cm_opt);
+ if (option == NULL)
+ continue;
+
+ g_key_file_set_string(keyfile,
+ connman_provider_get_save_group(provider),
+ vpnc_options[i].cm_opt, option);
+ }
+ }
+ return 0;
+}
+
static int vc_connect(struct connman_provider *provider,
struct connman_task *task, const char *if_name)
{
.notify = vc_notify,
.connect = vc_connect,
.error_code = vc_error_code,
+ .save = vc_save,
};
static int vpnc_init(void)
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
+#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <connman/technology.h>
#include <connman/log.h>
#include <connman/option.h>
+#include <connman/storage.h>
#include <gsupplicant/gsupplicant.h>
#define CLEANUP_TIMEOUT 8 /* in seconds */
#define INACTIVE_TIMEOUT 12 /* in seconds */
+#define MAXIMUM_RETRIES 4
struct connman_technology *wifi_technology = NULL;
int index;
unsigned flags;
unsigned int watch;
+ int retries;
};
#if defined TIZEN_EXT
{
struct wifi_data *wifi = connman_device_get_data(device);
- DBG("device %p", device);
+ DBG("device %p wifi %p", device, wifi);
if (wifi == NULL)
return;
remove_networks(device, wifi);
- if (wifi->network != NULL) {
- connman_network_set_connected(wifi->network, FALSE);
- wifi->network = NULL;
- }
-
connman_device_set_data(device, NULL);
connman_device_unref(wifi->device);
connman_rtnl_remove_watch(wifi->watch);
{
struct wifi_data *wifi = user_data;
- DBG("result %d ifname %s", result,
- g_supplicant_interface_get_ifname(interface));
+ DBG("result %d ifname %s, wifi %p", result,
+ g_supplicant_interface_get_ifname(interface),
+ wifi);
- if (result < 0)
+ if (result < 0 || wifi == NULL)
return;
+
#if defined TIZEN_EXT
if (g_list_find(iface_list, wifi) == NULL) {
return;
#endif
wifi->interface = interface;
g_supplicant_interface_set_data(interface, wifi);
+
+ if (g_supplicant_interface_get_ready(interface) == FALSE)
+ return;
+
+ DBG("interface is ready wifi %p tethering %d", wifi, wifi->tethering);
+
+ if (wifi->device == NULL) {
+ connman_error("WiFi device not set");
+ return;
+ }
+
+ connman_device_set_powered(wifi->device, TRUE);
}
static void interface_remove_callback(int result,
GSupplicantInterface *interface,
void *user_data)
{
- struct wifi_data *wifi = user_data;
+ struct wifi_data *wifi;
- DBG("result %d", result);
+ wifi = g_supplicant_interface_get_data(interface);
- if (result < 0)
+ DBG("result %d wifi %p", result, wifi);
+
+ if (result < 0 || wifi == NULL)
return;
wifi->interface = NULL;
}
+
static int wifi_enable(struct connman_device *device)
{
struct wifi_data *wifi = connman_device_get_data(device);
const char *interface = connman_device_get_string(device, "Interface");
const char *driver = connman_option_get_string("wifi");
-#if !defined TIZEN_EXT
int ret;
-#endif
DBG("device %p %p", device, wifi);
-#if defined TIZEN_EXT
- /*
- * Description: Fix interface_create temporarily
- * It's because our driver responds to ifocnfig eth0 up with insmod
- * It will be in ConnMan 0.77.3 Release
- */
- return g_supplicant_interface_create(interface, driver, NULL,
- interface_create_callback,
- wifi);
-#else
ret = g_supplicant_interface_create(interface, driver, NULL,
interface_create_callback,
wifi);
return ret;
return -EINPROGRESS;
-#endif
}
static int wifi_disable(struct connman_device *device)
ret = g_supplicant_interface_remove(wifi->interface,
interface_remove_callback,
- wifi);
+ NULL);
if (ret < 0)
return ret;
static void scan_callback(int result, GSupplicantInterface *interface,
void *user_data)
{
-#if defined TIZEN_EXT
- struct callback_data *cb_data = user_data;
- struct wifi_data *wifi;
- struct connman_device *device;
-#else
struct connman_device *device = user_data;
-#endif
+
DBG("result %d", result);
-#if defined TIZEN_EXT
- if (cb_data == NULL)
- return;
- wifi = cb_data->wifi_inf_data;
+ if (result < 0)
+ connman_device_reset_scanning(device);
+ else
+ connman_device_set_scanning(device, FALSE);
+ connman_device_unref(device);
+}
- if (wifi == NULL) {
- g_free(cb_data);
- return;
+static int add_scan_param(gchar *hex_ssid, int freq,
+ GSupplicantScanParams *scan_data,
+ int driver_max_scan_ssids)
+{
+ unsigned int i;
+
+ if (driver_max_scan_ssids > scan_data->num_ssids && hex_ssid != NULL) {
+ gchar *ssid;
+ unsigned int j = 0, hex;
+ size_t hex_ssid_len = strlen(hex_ssid);
+
+ ssid = g_try_malloc0(hex_ssid_len / 2);
+ if (ssid == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < hex_ssid_len; i += 2) {
+ sscanf(hex_ssid + i, "%02x", &hex);
+ ssid[j++] = hex;
+ }
+
+ memcpy(scan_data->ssids[scan_data->num_ssids].ssid, ssid, j);
+ scan_data->ssids[scan_data->num_ssids].ssid_len = j;
+ scan_data->num_ssids++;
+
+ g_free(ssid);
}
- if (g_list_find(iface_list, wifi) == NULL) {
- g_free(cb_data);
- return;
+ /* Don't add duplicate entries */
+ for (i = 0; i < G_SUPPLICANT_MAX_FAST_SCAN; i++) {
+ if (scan_data->freqs[i] == 0) {
+ scan_data->freqs[i] = freq;
+ break;
+ } else if (scan_data->freqs[i] == freq)
+ break;
}
- device = cb_data->data;
-#endif
- if (result < 0)
- connman_device_reset_scanning(device);
- else
- connman_device_set_scanning(device, FALSE);
-#if defined TIZEN_EXT
- g_free(cb_data);
-#endif
+ return 0;
+}
+
+struct last_connected {
+ GTimeVal modified;
+ gchar *ssid;
+ int freq;
+};
+
+static gint sort_entry(gconstpointer a, gconstpointer b, gpointer user_data)
+{
+ GTimeVal *aval = (GTimeVal *)a;
+ GTimeVal *bval = (GTimeVal *)b;
+
+ /* Note that the sort order is descending */
+ if (aval->tv_sec < bval->tv_sec)
+ return 1;
+
+ if (aval->tv_sec > bval->tv_sec)
+ return -1;
+
+ return 0;
+}
+
+static void free_entry(gpointer data)
+{
+ struct last_connected *entry = data;
+
+ g_free(entry->ssid);
+ g_free(entry);
+}
+
+static int get_latest_connections(int max_ssids,
+ GSupplicantScanParams *scan_data)
+{
+ GSequenceIter *iter;
+ GSequence *latest_list;
+ struct last_connected *entry;
+ GKeyFile *keyfile;
+ GTimeVal modified;
+ gchar **services;
+ gchar *str;
+ char *ssid;
+ int i, freq;
+ int num_ssids = 0;
+
+ latest_list = g_sequence_new(free_entry);
+ if (latest_list == NULL)
+ return -ENOMEM;
+
+ services = connman_storage_get_services();
+ for (i = 0; services && services[i]; i++) {
+ if (strncmp(services[i], "wifi_", 5) != 0)
+ continue;
+
+ keyfile = connman_storage_load_service(services[i]);
+
+ str = g_key_file_get_string(keyfile,
+ services[i], "Favorite", NULL);
+ if (str == NULL || g_strcmp0(str, "true")) {
+ if (str)
+ g_free(str);
+ g_key_file_free(keyfile);
+ continue;
+ }
+ g_free(str);
+
+ str = g_key_file_get_string(keyfile,
+ services[i], "AutoConnect", NULL);
+ if (str == NULL || g_strcmp0(str, "true")) {
+ if (str)
+ g_free(str);
+ g_key_file_free(keyfile);
+ continue;
+ }
+ g_free(str);
+
+ str = g_key_file_get_string(keyfile,
+ services[i], "Modified", NULL);
+ if (str != NULL) {
+ g_time_val_from_iso8601(str, &modified);
+ g_free(str);
+ }
+
+ ssid = g_key_file_get_string(keyfile,
+ services[i], "SSID", NULL);
+
+ freq = g_key_file_get_integer(keyfile, services[i],
+ "Frequency", NULL);
+ if (freq) {
+ entry = g_try_new(struct last_connected, 1);
+ if (entry == NULL) {
+ g_sequence_free(latest_list);
+ g_key_file_free(keyfile);
+ g_free(ssid);
+ return -ENOMEM;
+ }
+
+ entry->ssid = ssid;
+ entry->modified = modified;
+ entry->freq = freq;
+
+ g_sequence_insert_sorted(latest_list, entry,
+ sort_entry, NULL);
+ num_ssids++;
+ } else
+ g_free(ssid);
+
+ g_key_file_free(keyfile);
+ }
+
+ g_strfreev(services);
+
+ num_ssids = num_ssids > G_SUPPLICANT_MAX_FAST_SCAN ?
+ G_SUPPLICANT_MAX_FAST_SCAN : num_ssids;
+
+ iter = g_sequence_get_begin_iter(latest_list);
+
+ for (i = 0; i < num_ssids; i++) {
+ entry = g_sequence_get(iter);
+
+ DBG("ssid %s freq %d modified %lu", entry->ssid, entry->freq,
+ entry->modified.tv_sec);
+
+ add_scan_param(entry->ssid, entry->freq, scan_data, max_ssids);
+
+ iter = g_sequence_iter_next(iter);
+ }
+
+ g_sequence_free(latest_list);
+ return num_ssids;
}
static int wifi_scan(struct connman_device *device)
{
struct wifi_data *wifi = connman_device_get_data(device);
-#if defined TIZEN_EXT
- struct callback_data *cb_data;
-#endif
int ret;
DBG("device %p %p", device, wifi->interface);
if (wifi->tethering == TRUE)
return 0;
-#if defined TIZEN_EXT
- cb_data = g_try_malloc0(sizeof(struct callback_data));
- if (cb_data == NULL) {
+ connman_device_ref(device);
+ ret = g_supplicant_interface_scan(wifi->interface, NULL,
+ scan_callback, device);
+ if (ret == 0)
+ connman_device_set_scanning(device, TRUE);
+ else
+ connman_device_unref(device);
+
+ return ret;
+}
+
+static int wifi_scan_fast(struct connman_device *device)
+{
+ struct wifi_data *wifi = connman_device_get_data(device);
+ GSupplicantScanParams *scan_params = NULL;
+ int ret;
+ int driver_max_ssids = 0;
+
+ DBG("device %p %p", device, wifi->interface);
+
+ if (wifi->tethering == TRUE)
+ return 0;
+
+ driver_max_ssids = g_supplicant_interface_get_max_scan_ssids(
+ wifi->interface);
+ DBG("max ssids %d", driver_max_ssids);
+ if (driver_max_ssids == 0)
+ return wifi_scan(device);
+
+ scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
+ if (scan_params == NULL)
return -ENOMEM;
- }
- cb_data->wifi_inf_data = wifi;
- cb_data->data = device;
+ ret = get_latest_connections(driver_max_ssids, scan_params);
+ if (ret <= 0) {
+ g_free(scan_params);
+ return wifi_scan(device);
+ }
- ret = g_supplicant_interface_scan(wifi->interface, scan_callback,
- cb_data);
-#else
- ret = g_supplicant_interface_scan(wifi->interface, scan_callback,
- device);
-#endif
+ connman_device_ref(device);
+ ret = g_supplicant_interface_scan(wifi->interface, scan_params,
+ scan_callback, device);
if (ret == 0)
connman_device_set_scanning(device, TRUE);
+ else {
+ g_free(scan_params);
+ connman_device_unref(device);
+ }
return ret;
}
.enable = wifi_enable,
.disable = wifi_disable,
.scan = wifi_scan,
+ .scan_fast = wifi_scan_fast,
};
static void system_ready(void)
#endif
DBG("network %p result %d", network, result);
+
#if defined TIZEN_EXT
if (wifi->networks == NULL) {
g_free(cb_data);
ssid = g_try_malloc0(sizeof(GSupplicantSSID));
if (ssid == NULL)
return -ENOMEM;
+
#if defined TIZEN_EXT
cb_data = g_try_malloc0(sizeof(struct callback_data));
if (cb_data == NULL) {
wifi->pending_network = network;
else {
wifi->network = network;
+ wifi->retries = 0;
+
#if defined TIZEN_EXT
cb_data->wifi_inf_data = wifi;
cb_data->data = network;
-
return g_supplicant_interface_connect(interface, ssid,
connect_callback, cb_data);
#else
{
#if defined TIZEN_EXT
struct callback_data *cb_data = user_data;
-#endif
struct wifi_data *wifi;
DBG("");
-#if defined TIZEN_EXT
+
if (cb_data == NULL)
return;
return;
}
#else
- if (wifi == NULL)
- return;
+ struct wifi_data *wifi = user_data;
#endif
if (wifi->network != NULL) {
disconnect_callback, cb_data);
#else
err = g_supplicant_interface_disconnect(wifi->interface,
- disconnect_callback, NULL);
+ disconnect_callback, wifi);
#endif
if (err < 0)
wifi->disconnecting = FALSE;
if (wifi->tethering == TRUE)
return;
-
- wifi_scan(wifi->device);
}
static connman_bool_t is_idle(struct wifi_data *wifi)
return TRUE;
}
+static connman_bool_t handle_4way_handshake_failure(GSupplicantInterface *interface,
+ struct connman_network *network,
+ struct wifi_data *wifi)
+{
+ if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
+ return FALSE;
+
+ wifi->retries++;
+
+ if (wifi->retries < MAXIMUM_RETRIES)
+ return TRUE;
+
+ /* We disable the selected network, if not then
+ * wpa_supplicant will loop retrying */
+ if (g_supplicant_interface_enable_selected_network(interface,
+ FALSE) != 0)
+ DBG("Could not disables selected network");
+
+ connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY);
+
+ return FALSE;
+}
+
static void interface_state(GSupplicantInterface *interface)
{
struct connman_network *network;
if (is_idle(wifi))
break;
+
+ /* If previous state was 4way-handshake, then
+ * it's either: psk was incorrect and thus we retry
+ * or if we reach the maximum retries we declare the
+ * psk as wrong */
+ if (handle_4way_handshake_failure(interface,
+ network, wifi) == TRUE)
+ break;
+
#if !defined TIZEN_EXT
/*
* Dec. 2nd, 2011. TIZEN
static void scan_started(GSupplicantInterface *interface)
{
- struct wifi_data *wifi;
-
DBG("");
-
- wifi = g_supplicant_interface_get_data(interface);
-
- if (wifi == NULL)
- return;
}
static void scan_finished(GSupplicantInterface *interface)
{
- struct wifi_data *wifi;
-
DBG("");
-
- wifi = g_supplicant_interface_get_data(interface);
-
- if (wifi == NULL)
- return;
}
static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network)
struct connman_network *network;
GSupplicantInterface *interface;
struct wifi_data *wifi;
- const char *name, *identifier, *security, *group;
+ const char *name, *identifier, *security, *group, *mode;
const unsigned char *ssid;
unsigned int ssid_len;
connman_bool_t wps;
security = g_supplicant_network_get_security(supplicant_network);
group = g_supplicant_network_get_identifier(supplicant_network);
wps = g_supplicant_network_get_wps(supplicant_network);
+ mode = g_supplicant_network_get_mode(supplicant_network);
if (wifi == NULL)
return;
wifi->networks = g_slist_append(wifi->networks, network);
}
+#if defined TIZEN_EXT
connman_debug("--------------------------------------------");
connman_debug("name : %s", name);
connman_debug("ssid : %s", ssid);
connman_debug("security : %s", security);
connman_debug("strength : %d", calculate_strength(supplicant_network));
connman_debug("wps & WiFi.WPS : %d", wps);
+#endif
if (name != NULL && name[0] != '\0')
connman_network_set_name(network, name);
calculate_strength(supplicant_network));
connman_network_set_bool(network, "WiFi.WPS", wps);
- connman_network_set_available(network, TRUE);
+ connman_network_set_frequency(network,
+ g_supplicant_network_get_frequency(supplicant_network));
#if defined TIZEN_EXT
connman_network_set_bssid(network,
g_supplicant_network_get_bssid(supplicant_network));
connman_network_set_maxrate(network,
g_supplicant_network_get_maxrate(supplicant_network));
- connman_network_set_frequency(network,
- g_supplicant_network_get_frequency(supplicant_network));
connman_network_set_enc_mode(network,
g_supplicant_network_get_enc_mode(supplicant_network));
#endif
+ connman_network_set_available(network, TRUE);
+ connman_network_set_string(network, "WiFi.Mode", mode);
+
if (ssid != NULL)
connman_network_set_group(network, group);
}
+++ /dev/null
-
-[device_Wireless]
-Powered=false
--- /dev/null
+
+[global]
+OfflineMode=false
+
+[WiFi]
+Enable=false
+
+[Bluetooth]
+Enable=false
+
+[Wired]
+Enable=false
+
+[3G]
+Enable=false
+
+[WiMAX]
+Enable=false
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <pppd/pppd.h>
+#include <pppd/fsm.h>
+#include <pppd/ipcp.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <dbus/dbus.h>
+
+#define INET_ADDRES_LEN (INET_ADDRSTRLEN + 5)
+#define INET_DNS_LEN (2*INET_ADDRSTRLEN + 9)
+
+static char *busname;
+static char *interface;
+static char *path;
+
+static DBusConnection *connection;
+static int prev_phase;
+
+char pppd_version[] = VERSION;
+
+int plugin_init(void);
+
+static void append(DBusMessageIter *dict, const char *key, const char *value)
+{
+ DBusMessageIter entry;
+
+ /* We clean the environment before invoking pppd, but
+ * might as well still filter out the few things that get
+ * added that we're not interested in
+ */
+ if (!strcmp(key, "PWD") || !strcmp(key, "_") ||
+ !strcmp(key, "SHLVL") ||
+ !strcmp(key, "connman_busname") ||
+ !strcmp(key, "connman_network"))
+ return;
+
+ dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &value);
+
+ dbus_message_iter_close_container(dict, &entry);
+}
+
+
+static int ppp_have_secret()
+{
+ return 1;
+}
+
+static int ppp_get_secret(char *username, char *password)
+{
+ DBusMessage *msg, *reply;
+ const char *user, *pass;
+ DBusError err;
+
+ if (username == NULL && password == NULL)
+ return -1;
+
+ if (password == NULL)
+ return 1;
+
+ if (connection == NULL)
+ return -1;
+
+ dbus_error_init(&err);
+
+ msg = dbus_message_new_method_call(busname, path, interface, "getsec");
+ if (msg == NULL)
+ return -1;
+
+ dbus_message_append_args(msg, DBUS_TYPE_INVALID, DBUS_TYPE_INVALID);
+
+ reply = dbus_connection_send_with_reply_and_block(connection,
+ msg, -1, &err);
+ if (reply == NULL) {
+ if (dbus_error_is_set(&err) == TRUE)
+ dbus_error_free(&err);
+
+ dbus_message_unref(msg);
+ return -1;
+ }
+
+ dbus_message_unref(msg);
+
+ dbus_error_init(&err);
+
+ if (dbus_message_get_args(reply, &err, DBUS_TYPE_STRING, &user,
+ DBUS_TYPE_STRING, &pass,
+ DBUS_TYPE_INVALID) == FALSE) {
+ if (dbus_error_is_set(&err) == TRUE)
+ dbus_error_free(&err);
+
+ dbus_message_unref(reply);
+ return -1;
+ }
+
+ if (username != NULL)
+ strcpy(username, user);
+
+ strcpy(password, pass);
+
+ dbus_message_unref(reply);
+
+ return 1;
+}
+
+static void ppp_up(void *data, int arg)
+{
+ char buf[INET_ADDRES_LEN];
+ char dns[INET_DNS_LEN];
+ const char *reason = "connect";
+ bool add_blank = FALSE;
+ DBusMessageIter iter, dict;
+ DBusMessage *msg;
+
+ if (connection == NULL)
+ return;
+
+ if (ipcp_gotoptions[0].ouraddr == 0)
+ return;
+
+ msg = dbus_message_new_method_call(busname, path,
+ interface, "notify");
+ if (msg == NULL)
+ return;
+
+ dbus_message_set_no_reply(msg, TRUE);
+
+ dbus_message_append_args(msg,
+ DBUS_TYPE_STRING, &reason, DBUS_TYPE_INVALID);
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ append(&dict, "INTERNAL_IFNAME", ifname);
+
+ inet_ntop(AF_INET, &ipcp_gotoptions[0].ouraddr, buf, INET_ADDRSTRLEN);
+ append(&dict, "INTERNAL_IP4_ADDRESS", buf);
+
+ strcpy(buf, "255.255.255.255");
+ append(&dict, "INTERNAL_IP4_NETMASK", buf);
+
+ if (ipcp_gotoptions[0].dnsaddr[0] || ipcp_gotoptions[0].dnsaddr[1]) {
+ memset(dns, 0, sizeof(dns));
+ dns[0] = '\0';
+
+ if (ipcp_gotoptions[0].dnsaddr[0]) {
+ inet_ntop(AF_INET, &ipcp_gotoptions[0].dnsaddr[0],
+ buf, INET_ADDRSTRLEN);
+ strcat(dns, buf);
+
+ add_blank = TRUE;
+ }
+
+ if (ipcp_gotoptions[0].dnsaddr[1]) {
+ inet_ntop(AF_INET, &ipcp_gotoptions[0].dnsaddr[1],
+ buf, INET_ADDRSTRLEN);
+ if (add_blank == TRUE)
+ strcat(dns, " ");
+
+ strcat(dns, buf);
+ }
+ append(&dict, "INTERNAL_IP4_DNS", dns);
+ }
+
+ append(&dict, "MTU", "1400");
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ dbus_connection_send(connection, msg, NULL);
+
+ dbus_connection_flush(connection);
+
+ dbus_message_unref(msg);
+}
+
+static void ppp_exit(void *data, int arg)
+{
+ if (connection != NULL) {
+ dbus_connection_unref(connection);
+ connection = NULL;
+ }
+
+ if (busname != NULL) {
+ free(busname);
+ busname = NULL;
+ }
+
+ if (interface != NULL) {
+ free(interface);
+ interface = NULL;
+ }
+
+ if (path != NULL) {
+ free(path);
+ path = NULL;
+ }
+}
+
+static void ppp_phase_change(void *data, int arg)
+{
+ const char *reason = "disconnect";
+ DBusMessage *msg;
+ int send_msg = 0;
+
+ if (connection == NULL)
+ return;
+
+ if (prev_phase == PHASE_AUTHENTICATE &&
+ arg == PHASE_TERMINATE) {
+ reason = "auth failed";
+ send_msg = 1;
+ }
+
+ if (send_msg > 0 || arg == PHASE_DEAD || arg == PHASE_DISCONNECT) {
+ msg = dbus_message_new_method_call(busname, path,
+ interface, "notify");
+ if (msg == NULL)
+ return;
+
+ dbus_message_set_no_reply(msg, TRUE);
+
+ dbus_message_append_args(msg,
+ DBUS_TYPE_STRING, &reason, DBUS_TYPE_INVALID);
+
+ dbus_connection_send(connection, msg, NULL);
+
+ dbus_connection_flush(connection);
+
+ dbus_message_unref(msg);
+ }
+
+ prev_phase = arg;
+}
+
+int plugin_init(void)
+{
+ DBusError error;
+ static const char *bus, *inter, *p;
+
+ dbus_error_init(&error);
+
+ bus = getenv("CONNMAN_BUSNAME");
+ inter = getenv("CONNMAN_INTERFACE");
+ p = getenv("CONNMAN_PATH");
+
+ if (bus == NULL || inter == NULL || p == NULL)
+ return -1;
+
+ busname = strdup(bus);
+ interface = strdup(inter);
+ path = strdup(p);
+
+ if (busname == NULL || interface == NULL || path == NULL) {
+ ppp_exit(NULL, 0);
+ return -1;
+ }
+
+ connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
+ if (connection == NULL) {
+ if (dbus_error_is_set(&error) == TRUE)
+ dbus_error_free(&error);
+
+ ppp_exit(NULL, 0);
+ return -1;
+ }
+
+ pap_passwd_hook = ppp_get_secret;
+ chap_passwd_hook = ppp_get_secret;
+
+ chap_check_hook = ppp_have_secret;
+ pap_check_hook = ppp_have_secret;
+
+ add_notifier(&ip_up_notifier, ppp_up, NULL);
+ add_notifier(&phasechange, ppp_phase_change, NULL);
+ add_notifier(&exitnotify, ppp_exit, connection);
+
+ return 0;
+}
static GWeb *web;
static guint web_request_id;
-#define STATUS_URL "http://ipv6.google.com/"
+#define STATUS_URL "http://ipv6.connman.net/online/status.html"
#define NLMSG_TAIL(nmsg) \
((struct rtattr *) (((void *)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
memset(rth, 0, sizeof(*rth));
- rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ rth->fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
if (rth->fd < 0) {
connman_error("Can not open netlink socket: %s",
strerror(errno));
strncpy(ifr.ifr_name, "sit0", IFNAMSIZ);
ifr.ifr_ifru.ifru_data = (void *)&p;
- fd = socket(AF_INET, SOCK_DGRAM, 0);
+ fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
ret = ioctl(fd, SIOCADDTUNNEL, &ifr);
if (ret)
connman_error("add tunnel %s failed: %s", ifr.ifr_name,
strncpy(ifr.ifr_name, "tun6to4", IFNAMSIZ);
ifr.ifr_ifru.ifru_data = (void *)&p;
- fd = socket(AF_INET, SOCK_DGRAM, 0);
+ fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (fd < 0) {
connman_error("socket failed: %s", strerror(errno));
return;
static int init_6to4(struct in_addr *ip4addr)
{
unsigned int a, b, c, d;
+ int ret, if_index;
in_addr_t addr;
- int ret;
DBG("");
if (ret)
goto error;
+ if_index = connman_inet_ifindex("tun6to4");
+ if (if_index < 0)
+ goto error;
+
/* We try to verify that connectivity through tunnel works ok.
*/
- web = g_web_new(0);
+ web = g_web_new(if_index);
if (web == NULL)
goto error;
DBUS_TYPE_STRING, &str);
}
-int __connman_agent_request_input(struct connman_service *service,
+static void request_input_append_password(DBusMessageIter *iter,
+ void *user_data)
+{
+ char *str = "passphrase";
+
+ connman_dbus_dict_append_basic(iter, "Type",
+ DBUS_TYPE_STRING, &str);
+ str = "Mandatory";
+ connman_dbus_dict_append_basic(iter, "Requirement",
+ DBUS_TYPE_STRING, &str);
+}
+
+static void request_input_login_reply(DBusPendingCall *call, void *user_data)
+{
+ struct request_input_reply *username_password_reply = user_data;
+ char *username = NULL;
+ char *password = NULL;
+ char *key;
+ DBusMessageIter iter, dict;
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+
+ if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
+ goto done;
+
+ dbus_message_iter_init(reply, &iter);
+ dbus_message_iter_recurse(&iter, &dict);
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value;
+
+ dbus_message_iter_recurse(&dict, &entry);
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+ break;
+
+ dbus_message_iter_get_basic(&entry, &key);
+
+ if (g_str_equal(key, "Username")) {
+ dbus_message_iter_next(&entry);
+ if (dbus_message_iter_get_arg_type(&entry)
+ != DBUS_TYPE_VARIANT)
+ break;
+ dbus_message_iter_recurse(&entry, &value);
+ dbus_message_iter_get_basic(&value, &username);
+
+ } else if (g_str_equal(key, "Password")) {
+ dbus_message_iter_next(&entry);
+ if (dbus_message_iter_get_arg_type(&entry) !=
+ DBUS_TYPE_VARIANT)
+ break;
+ dbus_message_iter_recurse(&entry, &value);
+ dbus_message_iter_get_basic(&value, &password);
+ }
+
+ dbus_message_iter_next(&dict);
+ }
+
+done:
+ username_password_reply->callback(username_password_reply->service,
+ username, password,
+ username_password_reply->user_data);
+ connman_service_unref(username_password_reply->service);
+ dbus_message_unref(reply);
+ g_free(username_password_reply);
+}
+
+int __connman_agent_request_passphrase_input(struct connman_service *service,
authentication_cb_t callback, void *user_data)
{
DBusMessage *message;
return -EIO;
}
+int __connman_agent_request_login_input(struct connman_service *service,
+ authentication_cb_t callback, void *user_data)
+{
+ DBusMessage *message;
+ const char *path;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ DBusPendingCall *call;
+ struct request_input_reply *username_password_reply;
+
+ if (service == NULL || agent_path == NULL || callback == NULL)
+ return -ESRCH;
+
+ message = dbus_message_new_method_call(agent_sender, agent_path,
+ CONNMAN_AGENT_INTERFACE,
+ "RequestInput");
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_message_iter_init_append(message, &iter);
+
+ path = __connman_service_get_path(service);
+ dbus_message_iter_append_basic(&iter,
+ DBUS_TYPE_OBJECT_PATH, &path);
+
+ connman_dbus_dict_open(&iter, &dict);
+
+ connman_dbus_dict_append_dict(&dict, "Username",
+ request_input_append_identity, service);
+
+ connman_dbus_dict_append_dict(&dict, "Password",
+ request_input_append_password, service);
+
+ connman_dbus_dict_close(&iter, &dict);
+
+ username_password_reply = g_try_new0(struct request_input_reply, 1);
+ if (username_password_reply == NULL) {
+ dbus_message_unref(message);
+ return -ENOMEM;
+ }
+
+ if (dbus_connection_send_with_reply(connection, message,
+ &call, -1) == FALSE) {
+ dbus_message_unref(message);
+ g_free(username_password_reply);
+ return -ESRCH;
+ }
+
+ if (call == NULL) {
+ dbus_message_unref(message);
+ g_free(username_password_reply);
+ return -ESRCH;
+ }
+
+ username_password_reply->service = connman_service_ref(service);
+ username_password_reply->callback = callback;
+ username_password_reply->user_data = user_data;
+
+ dbus_pending_call_set_notify(call, request_input_login_reply,
+ username_password_reply, NULL);
+
+ dbus_message_unref(message);
+
+ return -EIO;
+}
+
struct report_error_data {
struct connman_service *service;
report_error_cb_t callback;
if (settimeofday(&tv, NULL) < 0)
return __connman_error_invalid_arguments(msg);
+
+ connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
+ CONNMAN_CLOCK_INTERFACE, "Time",
+ DBUS_TYPE_UINT64, &newval);
} else if (g_str_equal(name, "TimeUpdates") == TRUE) {
const char *strval;
enum time_updates newval;
DBG("config %p", config);
- keyfile = __connman_storage_open_config(config->ident);
+ keyfile = __connman_storage_load_config(config->ident);
if (keyfile == NULL)
return -EIO;
g_strfreev(groups);
- __connman_storage_close_config(config->ident, keyfile, FALSE);
+ g_key_file_free(keyfile);
return 0;
}
{
struct connman_config *config;
const char *service_name;
- char *ident, *filename = NULL, *content = NULL;
+ char *ident, *content = NULL;
gsize content_length;
int err;
goto out;
}
- filename = g_strdup_printf("%s/%s.config", STORAGEDIR, ident);
- if (filename == NULL) {
- err = -ENOMEM;
- goto out;
- }
-
DBG("Saving %zu bytes to %s", content_length, service_name);
- if (g_file_set_contents(filename, content,
- content_length, NULL) == FALSE) {
- err = -EIO;
- goto out;
- }
+ __connman_storage_save_config(keyfile, ident);
return 0;
out:
g_free(ident);
g_free(content);
- g_free(filename);
return err;
}
}
}
+ connman_service_ref(service);
g_hash_table_replace(gateway_hash, service, data);
return data;
&& do_ipv4 == TRUE) ||
(data->ipv6_gateway != NULL && data->ipv4_gateway == NULL
&& do_ipv6 == TRUE)
- )
+ ) {
+ connman_service_unref(service);
g_hash_table_remove(gateway_hash, service);
- else
+ } else
DBG("Not yet removing gw ipv4 %p/%d ipv6 %p/%d",
data->ipv4_gateway, do_ipv4,
data->ipv6_gateway, do_ipv6);
unset_default_gateway(active_gateway,
CONNMAN_IPCONFIG_TYPE_IPV6);
- __connman_service_downgrade_state(active_gateway->service);
-
if (default_gateway) {
if (default_gateway->ipv4_gateway)
set_default_gateway(default_gateway,
void *user_data);
typedef void (* report_error_cb_t) (struct connman_service *service,
gboolean retry, void *user_data);
-int __connman_agent_request_input(struct connman_service *service,
+int __connman_agent_request_passphrase_input(struct connman_service *service,
+ authentication_cb_t callback, void *user_data);
+int __connman_agent_request_login_input(struct connman_service *service,
authentication_cb_t callback, void *user_data);
int __connman_agent_report_error(struct connman_service *service,
const char *error,
#include <connman/log.h>
-int __connman_log_init(const char *debug, connman_bool_t detach);
+int __connman_log_init(const char *program, const char *debug,
+ connman_bool_t detach);
void __connman_log_cleanup(void);
void __connman_log_enable(struct connman_debug_desc *start,
struct connman_debug_desc *stop);
int __connman_inet_ipv6_send_rs(int index, int timeout,
__connman_inet_rs_cb_t callback, void *user_data);
-#include <connman/rfkill.h>
-
-int __connman_rfkill_init(void);
-void __connman_rfkill_cleanup(void);
-
#include <connman/resolver.h>
int __connman_resolver_init(connman_bool_t dnsproxy);
int __connman_resolvfile_append(const char *interface, const char *domain, const char *server);
int __connman_resolvfile_remove(const char *interface, const char *domain, const char *server);
-#include <connman/storage.h>
-
-int __connman_storage_init(void);
-void __connman_storage_cleanup(void);
-
-GKeyFile *__connman_storage_open(const char *ident, const char *suffix);
-void __connman_storage_close(const char *ident, const char *suffix,
- GKeyFile *keyfile, gboolean save);
-void __connman_storage_delete(const char *ident, const char *suffix);
+void __connman_storage_migrate(void);
+GKeyFile *__connman_storage_open_global();
+GKeyFile *__connman_storage_load_global();
+void __connman_storage_save_global(GKeyFile *keyfile);
+void __connman_storage_delete_global();
-GKeyFile *__connman_storage_open_profile(const char *ident);
-void __connman_storage_close_profile(const char *ident,
- GKeyFile *keyfile, gboolean save);
-void __connman_storage_delete_profile(const char *ident);
-
-GKeyFile *__connman_storage_open_config(const char *ident);
-void __connman_storage_close_config(const char *ident,
- GKeyFile *keyfile, gboolean save);
+GKeyFile *__connman_storage_load_config(const char *ident);
+void __connman_storage_save_config(GKeyFile *keyfile, const char *ident);
void __connman_storage_delete_config(const char *ident);
-int __connman_storage_init_profile(void);
-int __connman_storage_load_profile(struct connman_profile *profile);
-int __connman_storage_save_profile(struct connman_profile *profile);
-int __connman_storage_load_service(struct connman_service *service);
-int __connman_storage_save_service(struct connman_service *service);
-int __connman_storage_load_device(struct connman_device *device);
-int __connman_storage_save_device(struct connman_device *device);
+GKeyFile *__connman_storage_open_service(const char *ident);
+void __connman_storage_save_service(GKeyFile *keyfile, const char *ident);
+GKeyFile *__connman_storage_load_provider(const char *identifier);
+void __connman_storage_save_provider(GKeyFile *keyfile, const char *identifier);
int __connman_detect_init(void);
void __connman_detect_cleanup(void);
int __connman_ipconfig_save(struct connman_ipconfig *ipconfig,
GKeyFile *keyfile, const char *identifier, const char *prefix);
+int __connman_ipconfig_set_rp_filter();
+void __connman_ipconfig_unset_rp_filter(int old_value);
+
#include <connman/utsname.h>
int __connman_utsname_set_hostname(const char *hostname);
void __connman_connection_gateway_activate(struct connman_service *service,
enum connman_ipconfig_type type);
+int __connman_ntp_start(const char *interface, const char *resolver,
+ const char *server);
+void __connman_ntp_stop(const char *interface);
+
int __connman_wpad_init(void);
void __connman_wpad_cleanup(void);
int __connman_wpad_start(struct connman_service *service);
int __connman_wispr_init(void);
void __connman_wispr_cleanup(void);
+int __connman_wispr_start(struct connman_service *service,
+ enum connman_ipconfig_type type);
+void __connman_wispr_stop(struct connman_service *service);
#include <connman/technology.h>
int __connman_technology_add_device(struct connman_device *device);
int __connman_technology_remove_device(struct connman_device *device);
-int __connman_technology_enable(enum connman_service_type type);
-int __connman_technology_disable(enum connman_service_type type);
+int __connman_technology_enabled(enum connman_service_type type);
+int __connman_technology_enable(enum connman_service_type type, DBusMessage *msg);
+int __connman_technology_disabled(enum connman_service_type type);
+int __connman_technology_disable(enum connman_service_type type, DBusMessage *msg);
+int __connman_technology_set_offlinemode(connman_bool_t offlinemode);
+connman_bool_t __connman_technology_get_offlinemode(void);
+
int __connman_technology_add_rfkill(unsigned int index,
enum connman_service_type type,
connman_bool_t softblock,
connman_bool_t hardblock);
int __connman_technology_update_rfkill(unsigned int index,
+ enum connman_service_type type,
connman_bool_t softblock,
connman_bool_t hardblock);
-int __connman_technology_remove_rfkill(unsigned int index);
+int __connman_technology_remove_rfkill(unsigned int index,
+ enum connman_service_type type);
void __connman_technology_add_interface(enum connman_service_type type,
int index, const char *name, const char *ident);
void __connman_technology_remove_interface(enum connman_service_type type,
int index, const char *name, const char *ident);
-connman_bool_t __connman_technology_get_blocked(enum connman_service_type type);
-
#include <connman/device.h>
int __connman_device_init(const char *device, const char *nodevice);
enum connman_service_type __connman_device_get_service_type(struct connman_device *device);
struct connman_device *__connman_device_find_device(enum connman_service_type type);
int __connman_device_request_scan(enum connman_service_type type);
-int __connman_device_enable_technology(enum connman_service_type type);
-int __connman_device_disable_technology(enum connman_service_type type);
connman_bool_t __connman_device_isfiltered(const char *devname);
int __connman_device_get_phyindex(struct connman_device *device);
void __connman_device_set_phyindex(struct connman_device *device,
int phyindex);
-int __connman_device_set_blocked(struct connman_device *device,
- connman_bool_t blocked);
-connman_bool_t __connman_device_get_blocked(struct connman_device *device);
void __connman_device_set_network(struct connman_device *device,
struct connman_network *network);
void __connman_device_cleanup_networks(struct connman_device *device);
-int __connman_device_scan(struct connman_device *device);
int __connman_device_enable(struct connman_device *device);
-int __connman_device_enable_persistent(struct connman_device *device);
int __connman_device_disable(struct connman_device *device);
-int __connman_device_disable_persistent(struct connman_device *device);
int __connman_device_disconnect(struct connman_device *device);
connman_bool_t __connman_device_scanning(struct connman_device *device);
const char *__connman_device_get_type(struct connman_device *device);
-int __connman_device_set_offlinemode(connman_bool_t offlinemode);
+int __connman_rfkill_init(void);
+void __connman_rfkill_cleanup(void);
+int __connman_rfkill_block(enum connman_service_type type, connman_bool_t block);
#include <connman/network.h>
int __connman_config_provision_service_ident(struct connman_service *service,
const char *ident);
-#include <connman/profile.h>
-
-int __connman_profile_init();
-void __connman_profile_cleanup(void);
-
-connman_bool_t __connman_profile_get_offlinemode(void);
-int __connman_profile_set_offlinemode(connman_bool_t offlinemode, connman_bool_t all_devices);
-int __connman_profile_save_default(void);
-
-void __connman_profile_list(DBusMessageIter *iter, void *user_data);
-const char *__connman_profile_active_ident(void);
-const char *__connman_profile_active_path(void);
-
-int __connman_profile_create(const char *name, const char **path);
-int __connman_profile_remove(const char *path);
-
-void __connman_profile_changed(gboolean delayed);
-
int __connman_tethering_init(void);
void __connman_tethering_cleanup(void);
int __connman_service_ipconfig_indicate_state(struct connman_service *service,
enum connman_service_state new_state,
enum connman_ipconfig_type type);
+enum connman_service_state __connman_service_ipconfig_get_state(
+ struct connman_service *service,
+ enum connman_ipconfig_type type);
int __connman_service_indicate_error(struct connman_service *service,
enum connman_service_error error);
const char *__connman_service_type2string(enum connman_service_type type);
int __connman_service_nameserver_append(struct connman_service *service,
- const char *nameserver);
+ const char *nameserver, gboolean is_auto);
int __connman_service_nameserver_remove(struct connman_service *service,
- const char *nameserver);
+ const char *nameserver, gboolean is_auto);
void __connman_service_nameserver_clear(struct connman_service *service);
void __connman_service_nameserver_add_routes(struct connman_service *service,
const char *gw);
int __connman_service_counter_register(const char *counter);
void __connman_service_counter_unregister(const char *counter);
-void __connman_service_downgrade_state(struct connman_service *service);
struct connman_session;
struct service_entry;
void __connman_service_session_inc(struct connman_service *service);
connman_bool_t __connman_service_session_dec(struct connman_service *service);
-#include <connman/location.h>
-
-int __connman_location_init(void);
-void __connman_location_cleanup(void);
-
-struct connman_location *__connman_location_create(struct connman_service *service);
-struct connman_location *__connman_service_get_location(struct connman_service *service);
-
-int __connman_location_detect(struct connman_service *service);
-int __connman_location_finish(struct connman_service *service);
-
#include <connman/notifier.h>
int __connman_technology_init(void);
connman_device_unregister(device);
connman_device_unref(device);
+#if defined TIZEN_EXT
+ if (__connman_device_scanning(device) == TRUE) {
+ connman_device_reset_scanning(device);
+ connman_device_unref(device);
+ }
+#endif
}
static struct connman_rtnl detect_rtnl = {
static gchar **device_filter = NULL;
static gchar **nodevice_filter = NULL;
+enum connman_pending_type {
+ PENDING_NONE = 0,
+ PENDING_ENABLE = 1,
+ PENDING_DISABLE = 2,
+};
+
struct connman_device {
- gint refcount;
+ int refcount;
enum connman_device_type type;
- connman_bool_t offlinemode;
- connman_bool_t blocked;
+ enum connman_pending_type powered_pending; /* Indicates a pending
+ enable/disable request */
connman_bool_t powered;
- connman_bool_t powered_pending;
- connman_bool_t powered_persistent;
connman_bool_t scanning;
connman_bool_t disconnected;
connman_bool_t reconnect;
int phyindex;
int index;
guint scan_timeout;
+ guint pending_timeout;
struct connman_device_driver *driver;
void *driver_data;
connman_bool_t connman_device_significant_wifi_profile_unref_and_test(struct connman_device *device)
{
- g_assert(device->significant_wifi_profile_refcount > 0);
- return (connman_bool_t)g_atomic_int_dec_and_test(&device->significant_wifi_profile_refcount);
+ if (device->significant_wifi_profile_refcount > 0)
+ return (connman_bool_t)g_atomic_int_dec_and_test(&device->significant_wifi_profile_refcount);
+
+ return FALSE;
}
static connman_bool_t __connman_device_is_no_ref_significant_wifi_profile(struct connman_device *device)
}
}
+static void clear_pending_trigger(struct connman_device *device)
+{
+ if (device->pending_timeout > 0) {
+ g_source_remove(device->pending_timeout);
+ device->pending_timeout = 0;
+ }
+}
+
static void reset_scan_trigger(struct connman_device *device)
{
clear_scan_trigger(device);
return CONNMAN_SERVICE_TYPE_UNKNOWN;
}
+static gboolean device_pending_reset(gpointer user_data)
+{
+ struct connman_device *device = user_data;
+
+ DBG("device %p", device);
+
+ /* Power request timedout, reset power pending state. */
+ device->pending_timeout = 0;
+ device->powered_pending = PENDING_NONE;
+
+ return FALSE;
+}
+
int __connman_device_enable(struct connman_device *device)
{
int err;
- enum connman_service_type type;
- DBG("device %p %d", device, device->blocked);
+ DBG("device %p", device);
if (!device->driver || !device->driver->enable)
return -EOPNOTSUPP;
- if (device->powered_pending == TRUE)
+ /* There is an ongoing power disable request. */
+ if (device->powered_pending == PENDING_DISABLE)
+ return -EBUSY;
+
+ if (device->powered_pending == PENDING_ENABLE)
return -EALREADY;
- if (device->blocked == TRUE)
- return -ENOLINK;
+ if (device->powered_pending == PENDING_NONE && device->powered == TRUE)
+ return -EALREADY;
- connman_device_set_disconnected(device, FALSE);
- device->scanning = FALSE;
+ device->powered_pending = PENDING_ENABLE;
err = device->driver->enable(device);
- if (err < 0 && err != -EALREADY) {
- if (err == -EINPROGRESS) {
- device->powered_pending = TRUE;
- device->offlinemode = FALSE;
- if (__connman_profile_get_offlinemode() == TRUE)
- __connman_profile_set_offlinemode(FALSE, FALSE);
- }
- return err;
+ /*
+ * device gets enabled right away.
+ * Invoke the callback
+ */
+ if (err == 0) {
+ connman_device_set_powered(device, TRUE);
+ goto done;
}
- device->powered_pending = TRUE;
- device->powered = TRUE;
- device->offlinemode = FALSE;
- if (__connman_profile_get_offlinemode() == TRUE)
- __connman_profile_set_offlinemode(FALSE, FALSE);
-
- type = __connman_device_get_service_type(device);
- __connman_technology_enable(type);
-
- return 0;
+ if (err == -EALREADY) {
+ /* If device is already powered, but connman is not updated */
+ connman_device_set_powered(device, TRUE);
+ goto done;
+ }
+ /*
+ * if err == -EINPROGRESS, then the DBus call to the respective daemon
+ * was successful. We set a 4 sec timeout so if the daemon never
+ * returns a reply, we would reset the pending request.
+ */
+ if (err == -EINPROGRESS)
+ device->pending_timeout = g_timeout_add_seconds(4,
+ device_pending_reset, device);
+done:
+ return err;
}
int __connman_device_disable(struct connman_device *device)
{
int err;
- enum connman_service_type type;
DBG("device %p", device);
if (!device->driver || !device->driver->disable)
return -EOPNOTSUPP;
- if (device->powered == FALSE)
- return -ENOLINK;
+ /* Ongoing power enable request */
+ if (device->powered_pending == PENDING_ENABLE)
+ return -EBUSY;
+
+ if (device->powered_pending == PENDING_DISABLE)
+ return -EALREADY;
- if (device->powered_pending == FALSE)
+ if (device->powered_pending == PENDING_NONE && device->powered == FALSE)
return -EALREADY;
+ device->powered_pending = PENDING_DISABLE;
device->reconnect = FALSE;
clear_scan_trigger(device);
- err = device->driver->disable(device);
- if (err < 0 && err != -EALREADY) {
- if (err == -EINPROGRESS)
- device->powered_pending = FALSE;
- return err;
- }
-
- g_hash_table_remove_all(device->networks);
+ if (device->network) {
+ struct connman_service *service =
+ __connman_service_lookup_from_network(device->network);
- device->powered_pending = FALSE;
- device->powered = FALSE;
-
- type = __connman_device_get_service_type(device);
- __connman_technology_disable(type);
-
- return 0;
-}
-
-static int set_powered(struct connman_device *device, connman_bool_t powered)
-{
- DBG("device %p powered %d", device, powered);
-
- if (powered == TRUE)
- return __connman_device_enable(device);
- else
- return __connman_device_disable(device);
-}
-
-static int setup_device(struct connman_device *device)
-{
- DBG("device %p", device);
+ if (service != NULL)
+ __connman_service_disconnect(service);
+ else
+ connman_network_set_connected(device->network, FALSE);
+ }
- __connman_technology_add_device(device);
+ err = device->driver->disable(device);
+ if (err == 0) {
+ connman_device_set_powered(device, FALSE);
+ goto done;
+ }
- if (device->offlinemode == FALSE &&
- device->powered_persistent == TRUE)
- __connman_device_enable(device);
+ if (err == -EALREADY) {
+ connman_device_set_powered(device, FALSE);
+ goto done;
+ }
- return 0;
+ if (err == -EINPROGRESS)
+ device->pending_timeout = g_timeout_add_seconds(4,
+ device_pending_reset, device);
+done:
+ return err;
}
static void probe_driver(struct connman_device_driver *driver)
device->driver = driver;
- setup_device(device);
+ __connman_technology_add_device(device);
}
}
{
DBG("device %p name %s", device, device->name);
+ clear_pending_trigger(device);
clear_scan_trigger(device);
g_free(device->ident);
connman_bool_t connman_device_load_significant_wifi_profile_refcount_from_storage(struct connman_device *device)
{
GKeyFile *keyfile = NULL;
- gchar *pathname = NULL;
- gchar *data = NULL;
- gsize length = 0;
- gint refcount = 0;
-
- pathname = g_strdup_printf("%s/%s.profile", STORAGEDIR, __connman_profile_active_ident());
- if (pathname == NULL)
- return FALSE;
-
- if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
- g_free(pathname);
- return FALSE;
- }
-
- g_free(pathname);
-
- keyfile = g_key_file_new();
- if (g_key_file_load_from_data(keyfile, data, length, 0, NULL) == FALSE) {
- g_key_file_free(keyfile);
- g_free(data);
- return FALSE;
- }
- g_free(data);
+ keyfile = __connman_storage_load_global();
if (g_key_file_has_group(keyfile, CONNMAN_SIG_WIFI_REFCOUNT_GROUP_NAME) == FALSE) {
g_key_file_free(keyfile);
return FALSE;
}
- refcount = g_key_file_get_integer(keyfile, CONNMAN_SIG_WIFI_REFCOUNT_GROUP_NAME, "ReferenceCount", NULL);
- __connman_device_set_significant_wifi_profile_refcount(device, refcount);
+ __connman_device_set_significant_wifi_profile_refcount(device,
+ g_key_file_get_integer(keyfile, CONNMAN_SIG_WIFI_REFCOUNT_GROUP_NAME, "ReferenceCount", NULL));
g_key_file_free(keyfile);
-
return TRUE;
}
connman_bool_t connman_device_save_significant_wifi_profile_refcount_to_storage(struct connman_device *device)
{
GKeyFile *keyfile = NULL;
- gchar *pathname = NULL;
- gchar *data = NULL;
- gchar *value = NULL;
- gsize length = 0;
- connman_bool_t ret = FALSE;
-
- pathname = g_strdup_printf("%s/%s.profile", STORAGEDIR, __connman_profile_active_ident());
- if (pathname == NULL)
- return FALSE;
- keyfile = g_key_file_new();
+ keyfile = __connman_storage_load_global();
- if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
- goto new_file;
-
- if (length > 0) {
- if (g_key_file_load_from_data(keyfile, data, length, 0, NULL) == FALSE)
- goto done;
- }
+ g_key_file_set_integer(keyfile, CONNMAN_SIG_WIFI_REFCOUNT_GROUP_NAME, "ReferenceCount",
+ device->significant_wifi_profile_refcount);
- g_free(data);
-
-new_file:
- value = g_strdup_printf("%d", device->significant_wifi_profile_refcount);
-
- g_key_file_set_string(keyfile, CONNMAN_SIG_WIFI_REFCOUNT_GROUP_NAME, "ReferenceCount", value);
-
- data = g_key_file_to_data(keyfile, &length, NULL);
-
- ret = (connman_bool_t)g_file_set_contents(pathname, data, length, NULL);
- if (ret == FALSE)
- connman_error("Failed to store service information");
-
- g_free(value);
-
-done:
- g_free(data);
+ __connman_storage_save_global(keyfile);
g_key_file_free(keyfile);
-
- g_free(pathname);
-
- return ret;
+ return TRUE;
}
#endif
enum connman_device_type type)
{
struct connman_device *device;
- enum connman_service_type service_type;
connman_bool_t bg_scan;
DBG("node %s type %d", node, type);
device->refcount = 1;
bg_scan = connman_setting_get_bool("BackgroundScanning");
+
#if defined TIZEN_EXT
if (type == CONNMAN_DEVICE_TYPE_WIFI) {
/* Load significant_wifi_profile_refcount */
device->type = type;
device->name = g_strdup(type2description(device->type));
- device->powered_persistent = TRUE;
-
device->phyindex = -1;
- service_type = __connman_device_get_service_type(device);
- device->blocked = __connman_technology_get_blocked(service_type);
device->backoff_interval = SCAN_INITIAL_DELAY;
switch (type) {
{
DBG("%p", device);
- g_atomic_int_inc(&device->refcount);
+ __sync_fetch_and_add(&device->refcount, 1);
return device;
}
*/
void connman_device_unref(struct connman_device *device)
{
- if (g_atomic_int_dec_and_test(&device->refcount) == FALSE)
+ if (__sync_fetch_and_sub(&device->refcount, 1) != 1)
return;
if (device->driver) {
int connman_device_set_powered(struct connman_device *device,
connman_bool_t powered)
{
- int err;
enum connman_service_type type;
DBG("driver %p powered %d", device, powered);
- if (device->powered == powered) {
- device->powered_pending = powered;
+ if (device->powered == powered)
return -EALREADY;
- }
- if (powered == TRUE)
- err = __connman_device_enable(device);
- else
- err = __connman_device_disable(device);
+ clear_pending_trigger(device);
- if (err < 0 && err != -EINPROGRESS && err != -EALREADY)
- return err;
+ device->powered_pending = PENDING_NONE;
device->powered = powered;
- device->powered_pending = powered;
type = __connman_device_get_service_type(device);
if (device->powered == TRUE)
- __connman_technology_enable(type);
+ __connman_technology_enabled(type);
else
- __connman_technology_disable(type);
-
- if (device->offlinemode == TRUE && powered == TRUE)
- return connman_device_set_powered(device, FALSE);
+ __connman_technology_disabled(type);
if (powered == FALSE)
return 0;
+ connman_device_set_disconnected(device, FALSE);
+ device->scanning = FALSE;
+
reset_scan_trigger(device);
- if (device->driver && device->driver->scan)
+ if (device->driver && device->driver->scan_fast)
+ device->driver->scan_fast(device);
+ else if (device->driver && device->driver->scan)
device->driver->scan(device);
return 0;
}
-int __connman_device_set_blocked(struct connman_device *device,
- connman_bool_t blocked)
-{
- connman_bool_t powered;
-
- DBG("device %p blocked %d", device, blocked);
-
- device->blocked = blocked;
-
- if (device->offlinemode == TRUE)
- return 0;
-
- connman_info("%s {rfkill} blocked %d", device->interface, blocked);
-
- if (blocked == FALSE)
- powered = device->powered_persistent;
- else
- powered = FALSE;
-
- return set_powered(device, powered);
-}
-
-connman_bool_t __connman_device_get_blocked(struct connman_device *device)
-{
- return device->blocked;
-}
-
-int __connman_device_scan(struct connman_device *device)
+static int device_scan(struct connman_device *device)
{
if (!device->driver || !device->driver->scan)
return -EOPNOTSUPP;
if (connman_network_get_type(network) != CONNMAN_NETWORK_TYPE_WIFI)
continue;
- /* If there is a connected or connecting network, don't try to scan. */
+ /* If there is connecting network, don't try to scan. */
if (connman_network_get_connecting(network) == TRUE ||
connman_network_get_associating(network) == TRUE) {
DBG("network(%s) is connecting", connman_network_get_string(network, "Name"));
return device->driver->scan(device);
}
-int __connman_device_enable_persistent(struct connman_device *device)
-{
- int err;
-
- DBG("device %p", device);
-
- device->powered_persistent = TRUE;
-
- __connman_storage_save_device(device);
-
- err = __connman_device_enable(device);
- if (err == 0 || err == -EINPROGRESS) {
- device->offlinemode = FALSE;
- if (__connman_profile_get_offlinemode() == TRUE) {
- __connman_profile_set_offlinemode(FALSE, FALSE);
-
- __connman_profile_save_default();
- }
- }
-
- return err;
-}
-
-int __connman_device_disable_persistent(struct connman_device *device)
-{
- DBG("device %p", device);
-
- device->powered_persistent = FALSE;
-
- __connman_storage_save_device(device);
-
- return __connman_device_disable(device);
-}
-
int __connman_device_disconnect(struct connman_device *device)
{
GHashTableIter iter;
void connman_device_reset_scanning(struct connman_device *device)
{
- if (device == NULL)
- return;
-
device->scanning = FALSE;
- if (device->networks == NULL)
- return;
-
g_hash_table_foreach(device->networks,
mark_network_available, NULL);
* because scan UX of a Wi-Fi setting application has an active scan procedure
* and it needs scan complete signal whether success or not
*/
-
__connman_notifier_scan_completed(TRUE);
#endif
#if defined TIZEN_EXT
if (device->type == CONNMAN_DEVICE_TYPE_CELLULAR)
{
- DBG("do not need the scan");
+ DBG("Cellular device does not need to scan.");
return 0;
}
#endif
return NULL;
}
-static void set_offlinemode(struct connman_device *device,
- connman_bool_t offlinemode)
-{
- connman_bool_t powered;
-
- DBG("device %p name %s", device, device->name);
-
- if (device == NULL)
- return;
-
- device->offlinemode = offlinemode;
-
- if (device->blocked == TRUE)
- return;
-
- powered = (offlinemode == TRUE) ? FALSE : TRUE;
-
- if (device->powered == powered)
- return;
-
- if (device->powered_persistent == FALSE)
- powered = FALSE;
-
- set_powered(device, powered);
-}
-
-int __connman_device_set_offlinemode(connman_bool_t offlinemode)
-{
- GSList *list;
-
- DBG("offlinmode %d", offlinemode);
-
- for (list = device_list; list != NULL; list = list->next) {
- struct connman_device *device = list->data;
-
- set_offlinemode(device, offlinemode);
- }
-
- __connman_notifier_offlinemode(offlinemode);
-
- return 0;
-}
-
/**
* connman_device_add_network:
* @device: device structure
return FALSE;
}
-static int device_probe(struct connman_device *device)
+/**
+ * connman_device_register:
+ * @device: device structure
+ *
+ * Register device with the system
+ */
+int connman_device_register(struct connman_device *device)
{
GSList *list;
if (device->driver == NULL)
return 0;
- return setup_device(device);
-}
-
-static void device_remove(struct connman_device *device)
-{
- DBG("device %p name %s", device, device->name);
-
- if (device->driver == NULL)
- return;
-
- remove_device(device);
-}
-
-/**
- * connman_device_register:
- * @device: device structure
- *
- * Register device with the system
- */
-int connman_device_register(struct connman_device *device)
-{
- __connman_storage_load_device(device);
-
- device->offlinemode = __connman_profile_get_offlinemode();
-
- return device_probe(device);
+ return __connman_technology_add_device(device);
}
/**
*/
void connman_device_unregister(struct connman_device *device)
{
- __connman_storage_save_device(device);
+ DBG("device %p name %s", device, device->name);
+
+ if (device->driver == NULL)
+ return;
- device_remove(device);
+ remove_device(device);
}
/**
*/
void *connman_device_get_data(struct connman_device *device)
{
- DBG("device %p", device);
return device->driver_data;
}
continue;
}
- err = __connman_device_scan(device);
- if (err < 0 && err != -EINPROGRESS) {
- DBG("err %d", err);
- /* XXX maybe only a continue? */
- return err;
- }
- }
-
- return 0;
-}
-
-static int set_technology(enum connman_service_type type, connman_bool_t enable)
-{
- GSList *list;
- int err;
-
- DBG("type %d enable %d", type, enable);
-
- switch (type) {
- case CONNMAN_SERVICE_TYPE_UNKNOWN:
- case CONNMAN_SERVICE_TYPE_SYSTEM:
- case CONNMAN_SERVICE_TYPE_GPS:
- case CONNMAN_SERVICE_TYPE_VPN:
- case CONNMAN_SERVICE_TYPE_GADGET:
- return 0;
- case CONNMAN_SERVICE_TYPE_ETHERNET:
- case CONNMAN_SERVICE_TYPE_WIFI:
- case CONNMAN_SERVICE_TYPE_WIMAX:
- case CONNMAN_SERVICE_TYPE_BLUETOOTH:
- case CONNMAN_SERVICE_TYPE_CELLULAR:
- break;
- }
-
- for (list = device_list; list != NULL; list = list->next) {
- struct connman_device *device = list->data;
- enum connman_service_type service_type =
- __connman_device_get_service_type(device);
-
- if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN &&
- service_type != type) {
- continue;
- }
-
- if (enable == TRUE)
- err = __connman_device_enable_persistent(device);
- else
- err = __connman_device_disable_persistent(device);
-
+ err = device_scan(device);
if (err < 0 && err != -EINPROGRESS) {
DBG("err %d", err);
/* XXX maybe only a continue? */
return 0;
}
-int __connman_device_enable_technology(enum connman_service_type type)
-{
- return set_technology(type, TRUE);
-}
-
-int __connman_device_disable_technology(enum connman_service_type type)
-{
- return set_technology(type, FALSE);
-}
-
connman_bool_t __connman_device_isfiltered(const char *devname)
{
char **pattern;
return FALSE;
}
-static int device_load(struct connman_device *device)
-{
- const char *ident = __connman_profile_active_ident();
- GKeyFile *keyfile;
- GError *error = NULL;
- gchar *identifier;
- connman_bool_t powered;
-
- DBG("device %p", device);
-
- keyfile = __connman_storage_open_profile(ident);
- if (keyfile == NULL)
- return 0;
-
- identifier = g_strdup_printf("device_%s", device->name);
- if (identifier == NULL)
- goto done;
-
- powered = g_key_file_get_boolean(keyfile, identifier,
- "Powered", &error);
- if (error == NULL)
- device->powered_persistent = powered;
- g_clear_error(&error);
-
-done:
- g_free(identifier);
-
- __connman_storage_close_profile(ident, keyfile, FALSE);
-
- return 0;
-}
-
-static int device_save(struct connman_device *device)
-{
- const char *ident = __connman_profile_active_ident();
- GKeyFile *keyfile;
- gchar *identifier;
-
- DBG("device %p", device);
-
- keyfile = __connman_storage_open_profile(ident);
- if (keyfile == NULL)
- return 0;
-
- identifier = g_strdup_printf("device_%s", device->name);
- if (identifier == NULL)
- goto done;
-
- g_key_file_set_boolean(keyfile, identifier,
- "Powered", device->powered_persistent);
-
-done:
- g_free(identifier);
-
- __connman_storage_close_profile(ident, keyfile, TRUE);
-
- return 0;
-}
-
-static struct connman_storage device_storage = {
- .name = "device",
- .priority = CONNMAN_STORAGE_PRIORITY_LOW,
- .device_load = device_load,
- .device_save = device_save,
-};
-
int __connman_device_init(const char *device, const char *nodevice)
{
DBG("");
if (nodevice != NULL)
nodevice_filter = g_strsplit(nodevice, ",", -1);
- return connman_storage_register(&device_storage);
+ return 0;
}
void __connman_device_cleanup(void)
g_strfreev(nodevice_filter);
g_strfreev(device_filter);
-
- connman_storage_unregister(&device_storage);
}
if (dhcp->nameservers != NULL) {
for (i = 0; dhcp->nameservers[i] != NULL; i++) {
__connman_service_nameserver_remove(service,
- dhcp->nameservers[i]);
+ dhcp->nameservers[i], FALSE);
}
}
if (dhcp->nameservers != NULL) {
for (i = 0; dhcp->nameservers[i] != NULL; i++) {
__connman_service_nameserver_remove(service,
- dhcp->nameservers[i]);
+ dhcp->nameservers[i], FALSE);
}
g_strfreev(dhcp->nameservers);
}
for (i = 0; dhcp->nameservers[i] != NULL; i++) {
__connman_service_nameserver_append(service,
- dhcp->nameservers[i]);
+ dhcp->nameservers[i], FALSE);
}
} else {
g_strfreev(nameservers);
DBG("IPV4LL available");
#if defined TIZEN_EXT
+ /*
+ * Description: When DHCP is failed,
+ * most of naive users cannot understand auto-generated IP
+ * (IPV4 link local) and serious troubles to make Internet connection.
+ */
dhcp_invalidate(dhcp, TRUE);
+
+ service = __connman_service_lookup_from_network(dhcp->network);
+ if (service == NULL)
+ return;
+
+ __connman_service_ipconfig_indicate_state(service,
+ CONNMAN_SERVICE_STATE_IDLE,
+ CONNMAN_IPCONFIG_TYPE_IPV4);
+ __connman_service_ipconfig_indicate_state(service,
+ CONNMAN_SERVICE_STATE_IDLE,
+ CONNMAN_IPCONFIG_TYPE_IPV6);
#else
service = __connman_service_lookup_from_network(dhcp->network);
if (service == NULL)
dhcp->network = network;
dhcp->callback = callback;
+ connman_network_ref(network);
+
g_hash_table_replace(network_table, network, dhcp);
return dhcp_request(dhcp);
if (network_table == NULL)
return;
- g_hash_table_remove(network_table, network);
+ if (g_hash_table_remove(network_table, network) == TRUE)
+ connman_network_unref(network);
}
int __connman_dhcp_init(void)
gpointer resp;
gsize resplen;
struct listener_data *ifdata;
+ gboolean append_domain;
};
struct listener_data {
{
unsigned char *ptr = buf;
char *offset;
+ int len;
DBG("query %s domain %s", query, domain);
tmp = strchr(offset, '.');
if (tmp == NULL) {
- if (strlen(offset) == 0)
+ len = strlen(offset);
+ if (len == 0)
break;
- *ptr = strlen(offset);
- memcpy(ptr + 1, offset, strlen(offset));
- ptr += strlen(offset) + 1;
+ *ptr = len;
+ memcpy(ptr + 1, offset, len);
+ ptr += len + 1;
break;
}
tmp = strchr(offset, '.');
if (tmp == NULL) {
- if (strlen(offset) == 0)
+ len = strlen(offset);
+ if (len == 0)
break;
- *ptr = strlen(offset);
- memcpy(ptr + 1, offset, strlen(offset));
- ptr += strlen(offset) + 1;
+ *ptr = len;
+ memcpy(ptr + 1, offset, len);
+ ptr += len + 1;
break;
}
if (dot != NULL && dot != lookup + strlen(lookup) - 1)
return 0;
+ if (server->domains != NULL && server->domains->data != NULL)
+ req->append_domain = TRUE;
+
for (list = server->domains; list; list = list->next) {
char *domain;
unsigned char alt[1024];
memcpy(alt + offset + altlen,
request + offset + altlen - domlen,
- req->request_len - altlen + domlen);
+ req->request_len - altlen - offset + domlen);
if (server->protocol == IPPROTO_TCP) {
- int req_len = req->request_len + domlen - 1;
+ int req_len = req->request_len + domlen - 2;
alt[0] = (req_len >> 8) & 0xff;
alt[1] = req_len & 0xff;
}
- err = send(sk, alt, req->request_len + domlen + 1, 0);
+ err = send(sk, alt, req->request_len + domlen, 0);
if (err < 0)
return -EIO;
req->numresp++;
if (hdr->rcode == 0 || req->resp == NULL) {
+
+ /*
+ * If the domain name was append
+ * remove it before forwarding the reply.
+ */
+ if (req->append_domain == TRUE) {
+ unsigned char *ptr;
+ uint8_t host_len;
+ unsigned int domain_len;
+
+ /*
+ * ptr points to the first char of the hostname.
+ * ->hostname.domain.net
+ */
+ ptr = reply + offset + sizeof(struct domain_hdr);
+ host_len = *ptr;
+ domain_len = strlen((const char *)ptr) - host_len - 1;
+
+ /*
+ * remove the domain name and replaced it by the end
+ * of reply.
+ */
+ memmove(ptr + host_len + 1,
+ ptr + host_len + domain_len + 1,
+ reply_len - (ptr - reply + domain_len));
+
+ reply_len = reply_len - domain_len;
+ }
+
g_free(req->resp);
req->resplen = 0;
req->numserv = 0;
req->ifdata = (struct listener_data *) ifdata;
+ req->append_domain = FALSE;
request_list = g_slist_append(request_list, req);
for (list = server_list; list; list = list->next) {
req->numserv = 0;
req->ifdata = (struct listener_data *) ifdata;
req->timeout = g_timeout_add_seconds(5, request_timeout, req);
+ req->append_domain = FALSE;
request_list = g_slist_append(request_list, req);
return resolv(req, buf, query);
}
-static int create_dns_listener(int protocol, const char *ifname)
+static int create_dns_listener(int protocol, struct listener_data *ifdata)
{
GIOChannel *channel;
const char *proto;
socklen_t slen;
int sk, type, v6only = 0;
int family = AF_INET6;
- struct listener_data *ifdata;
- DBG("interface %s", ifname);
- ifdata = g_hash_table_lookup(listener_table, ifname);
- if (ifdata == NULL)
- return -ENODEV;
+ DBG("interface %s", ifdata->ifname);
switch (protocol) {
case IPPROTO_UDP:
proto = "UDP";
- type = SOCK_DGRAM;
+ type = SOCK_DGRAM | SOCK_CLOEXEC;
break;
case IPPROTO_TCP:
proto = "TCP";
- type = SOCK_STREAM;
+ type = SOCK_STREAM | SOCK_CLOEXEC;
break;
default:
}
if (setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
- ifname, strlen(ifname) + 1) < 0) {
+ ifdata->ifname,
+ strlen(ifdata->ifname) + 1) < 0) {
connman_error("Failed to bind %s listener interface", proto);
close(sk);
return -EIO;
return 0;
}
-static void destroy_udp_listener(const char *interface)
+static void destroy_udp_listener(struct listener_data *ifdata)
{
- struct listener_data *ifdata;
-
- DBG("interface %s", interface);
-
- ifdata = g_hash_table_lookup(listener_table, interface);
- if (ifdata == NULL)
- return;
+ DBG("interface %s", ifdata->ifname);
if (ifdata->udp_listener_watch > 0)
g_source_remove(ifdata->udp_listener_watch);
g_io_channel_unref(ifdata->udp_listener_channel);
}
-static void destroy_tcp_listener(const char *interface)
+static void destroy_tcp_listener(struct listener_data *ifdata)
{
- struct listener_data *ifdata;
-
- DBG("interface %s", interface);
-
- ifdata = g_hash_table_lookup(listener_table, interface);
- if (ifdata == NULL)
- return;
+ DBG("interface %s", ifdata->ifname);
if (ifdata->tcp_listener_watch > 0)
g_source_remove(ifdata->tcp_listener_watch);
g_io_channel_unref(ifdata->tcp_listener_channel);
}
-static int create_listener(const char *interface)
+static int create_listener(struct listener_data *ifdata)
{
int err;
- err = create_dns_listener(IPPROTO_UDP, interface);
+ err = create_dns_listener(IPPROTO_UDP, ifdata);
if (err < 0)
return err;
- err = create_dns_listener(IPPROTO_TCP, interface);
+ err = create_dns_listener(IPPROTO_TCP, ifdata);
if (err < 0) {
- destroy_udp_listener(interface);
+ destroy_udp_listener(ifdata);
return err;
}
- if (g_strcmp0(interface, "lo") == 0)
+ if (g_strcmp0(ifdata->ifname, "lo") == 0)
__connman_resolvfile_append("lo", NULL, "127.0.0.1");
return 0;
}
-static void destroy_listener(const char *interface)
+static void destroy_listener(struct listener_data *ifdata)
{
GSList *list;
- if (interface == NULL)
- return;
-
- if (g_strcmp0(interface, "lo") == 0)
+ if (g_strcmp0(ifdata->ifname, "lo") == 0)
__connman_resolvfile_remove("lo", NULL, "127.0.0.1");
for (list = request_pending_list; list; list = list->next) {
g_slist_free(request_list);
request_list = NULL;
- destroy_tcp_listener(interface);
- destroy_udp_listener(interface);
+ destroy_tcp_listener(ifdata);
+ destroy_udp_listener(ifdata);
}
int __connman_dnsproxy_add_listener(const char *interface)
ifdata->udp_listener_watch = 0;
ifdata->tcp_listener_channel = NULL;
ifdata->tcp_listener_watch = 0;
- g_hash_table_insert(listener_table, ifdata->ifname, ifdata);
- err = create_listener(interface);
- if (err < 0)
+ err = create_listener(ifdata);
+ if (err < 0) {
+ connman_error("Couldn't create listener for %s err %d",
+ interface, err);
+ g_free(ifdata->ifname);
+ g_free(ifdata);
return err;
+ }
+ g_hash_table_insert(listener_table, ifdata->ifname, ifdata);
return 0;
}
void __connman_dnsproxy_remove_listener(const char *interface)
{
+ struct listener_data *ifdata;
+
DBG("interface %s", interface);
- destroy_listener(interface);
+ ifdata = g_hash_table_lookup(listener_table, interface);
+ if (ifdata == NULL)
+ return;
+
+ destroy_listener(ifdata);
g_hash_table_remove(listener_table, interface);
}
#include <config.h>
#endif
+#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
return err;
}
- sk = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ sk = socket(AF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_ROUTE);
if (sk < 0)
return -errno;
if (name == NULL)
return -1;
- sk = socket(PF_INET, SOCK_DGRAM, 0);
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return -1;
if (index < 0)
return NULL;
- sk = socket(PF_INET, SOCK_DGRAM, 0);
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return NULL;
struct ifreq ifr;
int sk, err;
- sk = socket(PF_INET, SOCK_DGRAM, 0);
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return -errno;
struct ifreq ifr;
int sk, err;
- sk = socket(PF_INET, SOCK_DGRAM, 0);
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return -errno;
struct ifreq ifr;
int sk, err;
- sk = socket(PF_INET, SOCK_DGRAM, 0);
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return -errno;
if (index < 0)
return NULL;
- sk = socket(PF_INET, SOCK_DGRAM, 0);
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return NULL;
if (index < 0)
return NULL;
- sk = socket(PF_INET, SOCK_DGRAM, 0);
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return NULL;
struct ifreq ifr;
int sk;
- sk = socket(PF_INET, SOCK_DGRAM, 0);
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return FALSE;
struct sockaddr_in addr;
int sk, err;
- sk = socket(PF_INET, SOCK_DGRAM, 0);
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return -1;
struct sockaddr_in addr;
int sk, err;
- sk = socket(PF_INET, SOCK_DGRAM, 0);
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return -1;
rt.rtmsg_metric = 1;
rt.rtmsg_ifindex = index;
- sk = socket(AF_INET6, SOCK_DGRAM, 0);
+ sk = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0) {
err = -1;
goto out;
rt.rtmsg_metric = 1;
rt.rtmsg_ifindex = index;
- sk = socket(AF_INET6, SOCK_DGRAM, 0);
+ sk = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0) {
err = -1;
goto out;
rt.rtmsg_dst_len = 0;
rt.rtmsg_ifindex = index;
- sk = socket(AF_INET6, SOCK_DGRAM, 0);
+ sk = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0) {
err = -1;
goto out;
rt.rtmsg_dst_len = 0;
rt.rtmsg_ifindex = index;
- sk = socket(AF_INET6, SOCK_DGRAM, 0);
+ sk = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0) {
err = -1;
goto out;
struct sockaddr_in addr;
int sk, err;
- sk = socket(PF_INET, SOCK_DGRAM, 0);
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return -1;
DBG("");
- sk = socket(PF_INET, SOCK_DGRAM, 0);
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return -1;
DBG("");
- sk = socket(PF_INET6, SOCK_DGRAM, 0);
+ sk = socket(PF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return -1;
DBG("");
- sk = socket(PF_INET, SOCK_DGRAM, 0);
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return -1;
DBG("");
- sk = socket(PF_INET, SOCK_DGRAM, 0);
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return -1;
DBG("");
- sk = socket(PF_INET6, SOCK_DGRAM, 0);
+ sk = socket(PF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return -1;
return -1;
host_addr = _host_addr.s_addr;
- sk = socket(PF_INET, SOCK_DGRAM, 0);
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return FALSE;
close(sk);
return FALSE;
}
+
+ close(sk);
+
addr = (struct sockaddr_in *)&ifr.ifr_addr;
if_addr = addr->sin_addr.s_addr;
if (bridge == NULL)
return -EINVAL;
- sk = socket(AF_INET, SOCK_STREAM, 0);
+ sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return sk;
if (bridge == NULL)
return -EINVAL;
- sk = socket(AF_INET, SOCK_STREAM, 0);
+ sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return sk;
struct ifreq ifr;
int sk, err;
- sk = socket(AF_INET, SOCK_DGRAM, 0);
+ sk = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return sk;
if (tunnel == NULL)
return -EINVAL;
- sk = socket(AF_INET, SOCK_DGRAM, 0);
+ sk = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return sk;
struct ifreq ifr;
int i, fd;
- fd = open("/dev/net/tun", O_RDWR);
+ fd = open("/dev/net/tun", O_RDWR | O_CLOEXEC);
if (fd < 0) {
i = -errno;
connman_error("Failed to open /dev/net/tun: %s",
__connman_inet_rs_cb_t callback;
struct sockaddr_in6 addr;
guint rs_timeout;
+ guint watch_id;
void *user_data;
};
static const struct in6_addr in6addr_all_routers_mc =
IN6ADDR_ALL_ROUTERS_MC_INIT;
-/* from netinet/in.h */
-struct in6_pktinfo {
- struct in6_addr ipi6_addr; /* src/dst IPv6 address */
- unsigned int ipi6_ifindex; /* send/recv interface index */
-};
-
static void rs_cleanup(struct rs_cb_data *data)
{
g_io_channel_shutdown(data->channel, TRUE, NULL);
if (data->rs_timeout > 0)
g_source_remove(data->rs_timeout);
+ if (data->watch_id > 0)
+ g_source_remove(data->watch_id);
+
g_free(data);
}
len = recvmsg(fd, &mhdr, 0);
if (len < 0) {
data->callback(NULL, data->user_data);
+ rs_cleanup(data);
return -errno;
}
DBG("");
- fd = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
+ fd = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_RAW);
if (fd < 0)
return -errno;
data->user_data = user_data;
data->rs_timeout = g_timeout_add_seconds(timeout, rs_timeout_cb, data);
- sk = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+ sk = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_ICMPV6);
if (sk < 0)
return -errno;
g_io_channel_set_encoding(data->channel, NULL, NULL);
g_io_channel_set_buffered(data->channel, FALSE);
- g_io_add_watch(data->channel,
+ data->watch_id = g_io_add_watch(data->channel,
G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
icmpv6_event, data);
#include "connman.h"
struct connman_ipconfig {
- gint refcount;
+ int refcount;
int index;
enum connman_ipconfig_type type;
fclose(f);
}
+static int get_rp_filter()
+{
+ FILE *f;
+ int value = -EINVAL, tmp;
+
+ f = fopen("/proc/sys/net/ipv4/conf/all/rp_filter", "r");
+
+ if (f != NULL) {
+ if (fscanf(f, "%d", &tmp) == 1)
+ value = tmp;
+ fclose(f);
+ }
+
+ return value;
+}
+
+static void set_rp_filter(int value)
+{
+ FILE *f;
+
+ f = fopen("/proc/sys/net/ipv4/conf/all/rp_filter", "r+");
+
+ if (f == NULL)
+ return;
+
+ fprintf(f, "%d", value);
+
+ fclose(f);
+}
+
+int __connman_ipconfig_set_rp_filter()
+{
+ int value;
+
+ value = get_rp_filter();
+
+ if (value < 0)
+ return value;
+
+ set_rp_filter(2);
+
+ connman_info("rp_filter set to 2 (loose mode routing), "
+ "old value was %d", value);
+
+ return value;
+}
+
+void __connman_ipconfig_unset_rp_filter(int old_value)
+{
+ set_rp_filter(old_value);
+
+ connman_info("rp_filter restored to %d", old_value);
+}
+
static void free_ipdevice(gpointer data)
{
struct connman_ipdevice *ipdevice = data;
ipdevice->index = index;
ipdevice->ifname = connman_inet_ifname(index);
- if (ipdevice->ifname == NULL) {
- g_free(ipdevice);
- return;
- }
ipdevice->type = type;
ipdevice->ipv6_enabled = get_ipv6_state(ipdevice->ifname);
*/
struct connman_ipconfig *connman_ipconfig_ref(struct connman_ipconfig *ipconfig)
{
- DBG("ipconfig %p refcount %d", ipconfig,
- g_atomic_int_get(&ipconfig->refcount) + 1);
+ DBG("ipconfig %p refcount %d", ipconfig, ipconfig->refcount + 1);
- g_atomic_int_inc(&ipconfig->refcount);
+ __sync_fetch_and_add(&ipconfig->refcount, 1);
return ipconfig;
}
if (ipconfig == NULL)
return;
- DBG("ipconfig %p refcount %d", ipconfig,
- g_atomic_int_get(&ipconfig->refcount) - 1);
+ DBG("ipconfig %p refcount %d", ipconfig, ipconfig->refcount - 1);
- if (g_atomic_int_dec_and_test(&ipconfig->refcount) == TRUE) {
- __connman_ipconfig_disable(ipconfig);
+ if (__sync_fetch_and_sub(&ipconfig->refcount, 1) != 1)
+ return;
- connman_ipconfig_set_ops(ipconfig, NULL);
+ if (__connman_ipconfig_disable(ipconfig) < 0)
+ ipconfig_list = g_list_remove(ipconfig_list, ipconfig);
- if (ipconfig->origin != NULL) {
- connman_ipconfig_unref(ipconfig->origin);
- ipconfig->origin = NULL;
- }
+ connman_ipconfig_set_ops(ipconfig, NULL);
- connman_ipaddress_free(ipconfig->system);
- connman_ipaddress_free(ipconfig->address);
- g_free(ipconfig->last_dhcp_address);
- g_free(ipconfig);
+ if (ipconfig->origin != NULL) {
+ connman_ipconfig_unref(ipconfig->origin);
+ ipconfig->origin = NULL;
}
+
+ connman_ipaddress_free(ipconfig->system);
+ connman_ipaddress_free(ipconfig->address);
+ g_free(ipconfig->last_dhcp_address);
+ g_free(ipconfig);
}
/**
switch (ipconfig->method) {
case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
case CONNMAN_IPCONFIG_METHOD_OFF:
- case CONNMAN_IPCONFIG_METHOD_FIXED:
case CONNMAN_IPCONFIG_METHOD_DHCP:
case CONNMAN_IPCONFIG_METHOD_AUTO:
return;
+ case CONNMAN_IPCONFIG_METHOD_FIXED:
case CONNMAN_IPCONFIG_METHOD_MANUAL:
break;
}
*
* Connection Manager
*
- * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
+ * Copyright (C) 2007-2011 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#define LABEL_QUEUE "QUEUE"
#define LABEL_RETURN "RETURN"
+#define XT_OPTION_OFFSET_SCALE 256
+
/* fn returns 0 to continue iteration */
#define _XT_ENTRY_ITERATE_CONTINUE(type, entries, size, n, fn, args...) \
({ \
type *__entry; \
\
for (__i = 0, __n = 0; __i < (size); \
- __i += __entry->next_offset, __n++) { \
+ __i += __entry->next_offset, __n++) { \
__entry = (void *)(entries) + __i; \
if (__n < n) \
continue; \
static GList *find_chain_tail(struct connman_iptables *table,
char *chain_name)
{
+ struct connman_iptables_entry *tail;
GList *chain_head, *list;
- struct connman_iptables_entry *head, *tail;
- struct ipt_entry *entry;
- struct xt_entry_target *target;
- int builtin;
-
- /* First we look for the head */
- for (list = table->entries; list; list = list->next) {
- head = list->data;
- entry = head->entry;
-
- /* Buit-in chain */
- builtin = head->builtin;
- if (builtin >= 0 && !strcmp(hooknames[builtin], chain_name))
- break;
- /* User defined chain */
- target = ipt_get_target(entry);
- if (!strcmp(target->u.user.name, IPT_ERROR_TARGET) &&
- !strcmp((char *)target->data, chain_name))
- break;
- }
-
- if (list == NULL)
+ chain_head = find_chain_head(table, chain_name);
+ if (chain_head == NULL)
return NULL;
- chain_head = list;
-
/* Then we look for the next chain */
for (list = chain_head->next; list; list = list->next) {
tail = list->data;
- entry = tail->entry;
if (is_chain(table, tail))
return list;
}
}
+static void update_targets_reference(struct connman_iptables *table,
+ struct connman_iptables_entry *entry_before,
+ struct connman_iptables_entry *modified_entry,
+ gboolean is_removing)
+{
+ struct connman_iptables_entry *tmp;
+ struct xt_standard_target *t;
+ GList *list;
+ int offset;
+
+ offset = modified_entry->entry->next_offset;
+
+ for (list = table->entries; list; list = list->next) {
+ tmp = list->data;
+
+ if (!is_jump(tmp))
+ continue;
+
+ t = (struct xt_standard_target *)ipt_get_target(tmp->entry);
+
+ if (is_removing == TRUE) {
+ if (t->verdict >= entry_before->offset)
+ t->verdict -= offset;
+ } else {
+ if (t->verdict > entry_before->offset)
+ t->verdict += offset;
+ }
+ }
+}
+
static int iptables_add_entry(struct connman_iptables *table,
struct ipt_entry *entry, GList *before,
int builtin)
{
- GList *list;
- struct connman_iptables_entry *e, *tmp, *entry_before;
- struct xt_standard_target *t;
+ struct connman_iptables_entry *e, *entry_before;
if (table == NULL)
return -1;
entry_before = before->data;
/*
- * We've just insterted a new entry. All references before it
+ * We've just appended/insterted a new entry. All references
* should be bumped accordingly.
*/
- for (list = table->entries; list != before; list = list->next) {
- tmp = list->data;
+ update_targets_reference(table, entry_before, e, FALSE);
- if (!is_jump(tmp))
- continue;
+ update_offsets(table);
- t = (struct xt_standard_target *)ipt_get_target(tmp->entry);
+ return 0;
+}
- if (t->verdict >= entry_before->offset)
- t->verdict += entry->next_offset;
- }
+static int remove_table_entry(struct connman_iptables *table,
+ struct connman_iptables_entry *entry)
+{
+ int removed = 0;
- update_offsets(table);
+ table->num_entries--;
+ table->size -= entry->entry->next_offset;
+ removed = entry->entry->next_offset;
- return 0;
+ g_free(entry->entry);
+
+ table->entries = g_list_remove(table->entries, entry);
+
+ return removed;
}
static int iptables_flush_chain(struct connman_iptables *table,
entry = list->data;
next = g_list_next(list);
- table->num_entries--;
- table->size -= entry->entry->next_offset;
- removed += entry->entry->next_offset;
-
- g_free(entry->entry);
-
- table->entries = g_list_remove(table->entries, list->data);
+ removed += remove_table_entry(table, entry);
list = next;
}
return -ENOMEM;
}
-static struct ipt_entry *
-new_rule(struct connman_iptables *table, struct ipt_ip *ip,
+static int iptables_delete_chain(struct connman_iptables *table, char *name)
+{
+ struct connman_iptables_entry *entry;
+ GList *chain_head, *chain_tail;
+
+ chain_head = find_chain_head(table, name);
+ if (chain_head == NULL)
+ return -EINVAL;
+
+ entry = chain_head->data;
+
+ /* We cannot remove builtin chain */
+ if (entry->builtin >= 0)
+ return -EINVAL;
+
+ chain_tail = find_chain_tail(table, name);
+ if (chain_tail == NULL)
+ return -EINVAL;
+
+ /* Chain must be flushed */
+ if (chain_head->next != chain_tail->prev)
+ return -EINVAL;
+
+ remove_table_entry(table, entry);
+
+ entry = chain_tail->prev->data;
+ remove_table_entry(table, entry);
+
+ update_offsets(table);
+
+ return 0;
+}
+
+static struct ipt_entry *new_rule(struct ipt_ip *ip,
char *target_name, struct xtables_target *xt_t,
- char *match_name, struct xtables_match *xt_m)
+ struct xtables_rule_match *xt_rm)
{
+ struct xtables_rule_match *tmp_xt_rm;
struct ipt_entry *new_entry;
size_t match_size, target_size;
- int is_builtin = is_builtin_target(target_name);
- if (xt_m)
- match_size = xt_m->m->u.match_size;
- else
- match_size = 0;
+ match_size = 0;
+ for (tmp_xt_rm = xt_rm; tmp_xt_rm != NULL; tmp_xt_rm = tmp_xt_rm->next)
+ match_size += tmp_xt_rm->match->m->u.match_size;
if (xt_t)
target_size = ALIGN(xt_t->t->u.target_size);
new_entry->target_offset = sizeof(struct ipt_entry) + match_size;
new_entry->next_offset = sizeof(struct ipt_entry) + target_size +
match_size;
- if (xt_m) {
- struct xt_entry_match *entry_match;
- entry_match = (struct xt_entry_match *)new_entry->elems;
- memcpy(entry_match, xt_m->m, match_size);
+ match_size = 0;
+ for (tmp_xt_rm = xt_rm; tmp_xt_rm != NULL;
+ tmp_xt_rm = tmp_xt_rm->next) {
+ memcpy(new_entry->elems + match_size, tmp_xt_rm->match->m,
+ tmp_xt_rm->match->m->u.match_size);
+ match_size += tmp_xt_rm->match->m->u.match_size;
}
if (xt_t) {
struct xt_entry_target *entry_target;
- if (is_builtin) {
- struct xt_standard_target *target;
-
- target = (struct xt_standard_target *)(xt_t->t);
- strcpy(target->target.u.user.name, IPT_STANDARD_TARGET);
- target->verdict = target_to_verdict(target_name);
- }
-
entry_target = ipt_get_target(new_entry);
memcpy(entry_target, xt_t->t, target_size);
- } else {
- struct connman_iptables_entry *target_rule;
- struct xt_standard_target *target;
- GList *chain_head;
-
- /*
- * This is a user defined target, i.e. a chain jump.
- * We search for the chain head, and the target verdict
- * is the first rule's offset on this chain.
- * The offset is from the beginning of the table.
- */
-
- chain_head = find_chain_head(table, target_name);
- if (chain_head == NULL || chain_head->next == NULL) {
- g_free(new_entry);
- return NULL;
- }
-
- target_rule = chain_head->next->data;
-
- target = (struct xt_standard_target *)ipt_get_target(new_entry);
- strcpy(target->target.u.user.name, IPT_STANDARD_TARGET);
- target->target.u.user.target_size = target_size;
- target->verdict = target_rule->offset;
}
return new_entry;
}
}
-static int
-iptables_add_rule(struct connman_iptables *table,
+static struct ipt_entry *prepare_rule_inclusion(struct connman_iptables *table,
struct ipt_ip *ip, char *chain_name,
char *target_name, struct xtables_target *xt_t,
- char *match_name, struct xtables_match *xt_m)
+ int *builtin, struct xtables_rule_match *xt_rm)
{
GList *chain_tail, *chain_head;
struct ipt_entry *new_entry;
struct connman_iptables_entry *head;
- int builtin = -1;
-
- DBG("");
chain_head = find_chain_head(table, chain_name);
if (chain_head == NULL)
- return -EINVAL;
+ return NULL;
chain_tail = find_chain_tail(table, chain_name);
if (chain_tail == NULL)
- return -EINVAL;
+ return NULL;
- new_entry = new_rule(table, ip,
- target_name, xt_t,
- match_name, xt_m);
+ new_entry = new_rule(ip, target_name, xt_t, xt_rm);
if (new_entry == NULL)
- return -EINVAL;
+ return NULL;
update_hooks(table, chain_head, new_entry);
*/
head = chain_head->data;
if (head->builtin < 0)
- builtin = -1;
+ *builtin = -1;
else if (chain_head == chain_tail->prev) {
- builtin = head->builtin;
+ *builtin = head->builtin;
head->builtin = -1;
}
- return iptables_add_entry(table, new_entry, chain_tail->prev, builtin);
+ return new_entry;
+}
+
+static int iptables_append_rule(struct connman_iptables *table,
+ struct ipt_ip *ip, char *chain_name,
+ char *target_name, struct xtables_target *xt_t,
+ struct xtables_rule_match *xt_rm)
+{
+ GList *chain_tail;
+ struct ipt_entry *new_entry;
+ int builtin = -1, ret;
+
+ DBG("");
+
+ chain_tail = find_chain_tail(table, chain_name);
+ if (chain_tail == NULL)
+ return -EINVAL;
+
+ new_entry = prepare_rule_inclusion(table, ip, chain_name,
+ target_name, xt_t, &builtin, xt_rm);
+ if (new_entry == NULL)
+ return -EINVAL;
+
+ ret = iptables_add_entry(table, new_entry, chain_tail->prev, builtin);
+ if (ret < 0)
+ g_free(new_entry);
+
+ return ret;
+}
+
+static int iptables_insert_rule(struct connman_iptables *table,
+ struct ipt_ip *ip, char *chain_name,
+ char *target_name, struct xtables_target *xt_t,
+ struct xtables_rule_match *xt_rm)
+{
+ struct ipt_entry *new_entry;
+ int builtin = -1, ret;
+ GList *chain_head;
+
+ chain_head = find_chain_head(table, chain_name);
+ if (chain_head == NULL)
+ return -EINVAL;
+
+ new_entry = prepare_rule_inclusion(table, ip, chain_name,
+ target_name, xt_t, &builtin, xt_rm);
+ if (new_entry == NULL)
+ return -EINVAL;
+
+ ret = iptables_add_entry(table, new_entry, chain_head->next, builtin);
+ if (ret < 0)
+ g_free(new_entry);
+
+ return ret;
+}
+
+static gboolean is_same_ipt_entry(struct ipt_entry *i_e1,
+ struct ipt_entry *i_e2)
+{
+ if (memcmp(&i_e1->ip, &i_e2->ip, sizeof(struct ipt_ip)) != 0)
+ return FALSE;
+
+ if (i_e1->target_offset != i_e2->target_offset)
+ return FALSE;
+
+ if (i_e1->next_offset != i_e2->next_offset)
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean is_same_target(struct xt_entry_target *xt_e_t1,
+ struct xt_entry_target *xt_e_t2)
+{
+ if (xt_e_t1 == NULL || xt_e_t2 == NULL)
+ return FALSE;
+
+ if (strcmp(xt_e_t1->u.user.name, IPT_STANDARD_TARGET) == 0) {
+ struct xt_standard_target *xt_s_t1;
+ struct xt_standard_target *xt_s_t2;
+
+ xt_s_t1 = (struct xt_standard_target *) xt_e_t1;
+ xt_s_t2 = (struct xt_standard_target *) xt_e_t2;
+
+ if (xt_s_t1->verdict != xt_s_t2->verdict)
+ return FALSE;
+ } else {
+ if (xt_e_t1->u.target_size != xt_e_t2->u.target_size)
+ return FALSE;
+
+ if (strcmp(xt_e_t1->u.user.name, xt_e_t2->u.user.name) != 0)
+ return FALSE;
+ }
+
+ return TRUE;
}
-static struct ipt_replace *
-iptables_blob(struct connman_iptables *table)
+static gboolean is_same_match(struct xt_entry_match *xt_e_m1,
+ struct xt_entry_match *xt_e_m2)
+{
+ if (xt_e_m1 == NULL || xt_e_m2 == NULL)
+ return FALSE;
+
+ if (xt_e_m1->u.match_size != xt_e_m2->u.match_size)
+ return FALSE;
+
+ if (xt_e_m1->u.user.revision != xt_e_m2->u.user.revision)
+ return FALSE;
+
+ if (strcmp(xt_e_m1->u.user.name, xt_e_m2->u.user.name) != 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static int iptables_delete_rule(struct connman_iptables *table,
+ struct ipt_ip *ip, char *chain_name,
+ char *target_name, struct xtables_target *xt_t,
+ struct xtables_match *xt_m,
+ struct xtables_rule_match *xt_rm)
+{
+ GList *chain_tail, *chain_head, *list;
+ struct xt_entry_target *xt_e_t = NULL;
+ struct xt_entry_match *xt_e_m = NULL;
+ struct connman_iptables_entry *entry;
+ struct ipt_entry *entry_test;
+ int builtin, removed;
+
+ removed = 0;
+
+ chain_head = find_chain_head(table, chain_name);
+ if (chain_head == NULL)
+ return -EINVAL;
+
+ chain_tail = find_chain_tail(table, chain_name);
+ if (chain_tail == NULL)
+ return -EINVAL;
+
+ if (!xt_t && !xt_m)
+ return -EINVAL;
+
+ entry_test = new_rule(ip, target_name, xt_t, xt_rm);
+ if (entry_test == NULL)
+ return -EINVAL;
+
+ if (xt_t != NULL)
+ xt_e_t = ipt_get_target(entry_test);
+ if (xt_m != NULL)
+ xt_e_m = (struct xt_entry_match *)entry_test->elems;
+
+ entry = chain_head->data;
+ builtin = entry->builtin;
+
+ if (builtin >= 0)
+ list = chain_head;
+ else
+ list = chain_head->next;
+
+ for (entry = NULL; list != chain_tail->prev; list = list->next) {
+ struct connman_iptables_entry *tmp;
+ struct ipt_entry *tmp_e;
+
+ tmp = list->data;
+ tmp_e = tmp->entry;
+
+ if (is_same_ipt_entry(entry_test, tmp_e) == FALSE)
+ continue;
+
+ if (xt_t != NULL) {
+ struct xt_entry_target *tmp_xt_e_t;
+
+ tmp_xt_e_t = ipt_get_target(tmp_e);
+
+ if (!is_same_target(tmp_xt_e_t, xt_e_t))
+ continue;
+ }
+
+ if (xt_m != NULL) {
+ struct xt_entry_match *tmp_xt_e_m;
+
+ tmp_xt_e_m = (struct xt_entry_match *)tmp_e->elems;
+
+ if (!is_same_match(tmp_xt_e_m, xt_e_m))
+ continue;
+ }
+
+ entry = tmp;
+ break;
+ }
+
+ if (entry == NULL) {
+ g_free(entry_test);
+ return -EINVAL;
+ }
+
+ /* We have deleted a rule,
+ * all references should be bumped accordingly */
+ if (list->next != NULL)
+ update_targets_reference(table, list->next->data,
+ list->data, TRUE);
+
+ removed += remove_table_entry(table, entry);
+
+ if (builtin >= 0) {
+ list = list->next;
+ if (list) {
+ entry = list->data;
+ entry->builtin = builtin;
+ }
+
+ table->underflow[builtin] -= removed;
+ for (list = chain_tail; list; list = list->next) {
+ entry = list->data;
+
+ builtin = entry->builtin;
+ if (builtin < 0)
+ continue;
+
+ table->hook_entry[builtin] -= removed;
+ table->underflow[builtin] -= removed;
+ }
+ }
+
+ update_offsets(table);
+
+ return 0;
+}
+
+static int iptables_change_policy(struct connman_iptables *table,
+ char *chain_name, char *policy)
+{
+ GList *chain_head;
+ struct connman_iptables_entry *entry;
+ struct xt_entry_target *target;
+ struct xt_standard_target *t;
+ int verdict;
+
+ verdict = target_to_verdict(policy);
+ if (verdict == 0)
+ return -EINVAL;
+
+ chain_head = find_chain_head(table, chain_name);
+ if (chain_head == NULL)
+ return -EINVAL;
+
+ entry = chain_head->data;
+ if (entry->builtin < 0)
+ return -EINVAL;
+
+ target = ipt_get_target(entry->entry);
+
+ t = (struct xt_standard_target *)target;
+ t->verdict = verdict;
+
+ return 0;
+}
+
+static struct ipt_replace *iptables_blob(struct connman_iptables *table)
{
struct ipt_replace *r;
GList *list;
static struct connman_iptables *iptables_init(char *table_name)
{
- struct connman_iptables *table;
+ struct connman_iptables *table = NULL;
+ char *module = NULL;
socklen_t s;
DBG("%s", table_name);
+ if (xtables_insmod("ip_tables", NULL, TRUE) != 0)
+ goto err;
+
+ module = g_strconcat("iptable_", table_name, NULL);
+ if (module == NULL)
+ goto err;
+
+ if (xtables_insmod(module, NULL, TRUE) != 0)
+ goto err;
+
+ g_free(module);
+ module = NULL;
+
table = g_hash_table_lookup(table_hash, table_name);
if (table != NULL)
return table;
if (table->info == NULL)
goto err;
- table->ipt_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+ table->ipt_sock = socket(AF_INET, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_RAW);
if (table->ipt_sock < 0)
goto err;
return table;
err:
+ g_free(module);
table_cleanup(table);
static struct option iptables_opts[] = {
{.name = "append", .has_arg = 1, .val = 'A'},
+ {.name = "delete", .has_arg = 1, .val = 'D'},
{.name = "flush-chain", .has_arg = 1, .val = 'F'},
+ {.name = "insert", .has_arg = 1, .val = 'I'},
{.name = "list", .has_arg = 2, .val = 'L'},
{.name = "new-chain", .has_arg = 1, .val = 'N'},
+ {.name = "policy", .has_arg = 1, .val = 'P'},
+ {.name = "delete-chain", .has_arg = 1, .val = 'X'},
{.name = "destination", .has_arg = 1, .val = 'd'},
{.name = "in-interface", .has_arg = 1, .val = 'i'},
{.name = "jump", .has_arg = 1, .val = 'j'},
.orig_opts = iptables_opts,
};
+static struct xtables_target *prepare_target(struct connman_iptables *table,
+ char *target_name)
+{
+ struct xtables_target *xt_t = NULL;
+ gboolean is_builtin, is_user_defined;
+ GList *chain_head = NULL;
+ size_t target_size;
+
+ is_builtin = FALSE;
+ is_user_defined = FALSE;
+
+ if (is_builtin_target(target_name))
+ is_builtin = TRUE;
+ else {
+ chain_head = find_chain_head(table, target_name);
+ if (chain_head != NULL && chain_head->next != NULL)
+ is_user_defined = TRUE;
+ }
+
+ if (is_builtin || is_user_defined)
+ xt_t = xtables_find_target(IPT_STANDARD_TARGET,
+ XTF_LOAD_MUST_SUCCEED);
+ else
+ xt_t = xtables_find_target(target_name, XTF_TRY_LOAD);
+
+ if (xt_t == NULL)
+ return NULL;
+
+ target_size = ALIGN(sizeof(struct ipt_entry_target)) + xt_t->size;
+
+ xt_t->t = g_try_malloc0(target_size);
+ if (xt_t->t == NULL)
+ return NULL;
+
+ xt_t->t->u.target_size = target_size;
+
+ if (is_builtin || is_user_defined) {
+ struct xt_standard_target *target;
+
+ target = (struct xt_standard_target *)(xt_t->t);
+ strcpy(target->target.u.user.name, IPT_STANDARD_TARGET);
+
+ if (is_builtin == TRUE)
+ target->verdict = target_to_verdict(target_name);
+ else if (is_user_defined == TRUE) {
+ struct connman_iptables_entry *target_rule;
+
+ if (chain_head == NULL) {
+ g_free(xt_t->t);
+ return NULL;
+ }
+
+ target_rule = chain_head->next->data;
+ target->verdict = target_rule->offset;
+ }
+ } else {
+ strcpy(xt_t->t->u.user.name, target_name);
+ xt_t->t->u.user.revision = xt_t->revision;
+ if (xt_t->init != NULL)
+ xt_t->init(xt_t->t);
+ }
+
+#if XTABLES_VERSION_CODE > 5
+ if (xt_t->x6_options != NULL)
+ iptables_globals.opts =
+ xtables_options_xfrm(
+ iptables_globals.orig_opts,
+ iptables_globals.opts,
+ xt_t->x6_options,
+ &xt_t->option_offset);
+ else
+#endif
+ iptables_globals.opts =
+ xtables_merge_options(
+#if XTABLES_VERSION_CODE > 5
+ iptables_globals.orig_opts,
+#endif
+ iptables_globals.opts,
+ xt_t->extra_opts,
+ &xt_t->option_offset);
+
+ if (iptables_globals.opts == NULL) {
+ g_free(xt_t->t);
+ xt_t = NULL;
+ }
+
+ return xt_t;
+}
+
+static struct xtables_match *prepare_matches(struct connman_iptables *table,
+ struct xtables_rule_match **xt_rm, char *match_name)
+{
+ struct xtables_match *xt_m;
+ size_t match_size;
+
+ if (match_name == NULL)
+ return NULL;
+
+ xt_m = xtables_find_match(match_name, XTF_LOAD_MUST_SUCCEED, xt_rm);
+ match_size = ALIGN(sizeof(struct ipt_entry_match)) + xt_m->size;
+
+ xt_m->m = g_try_malloc0(match_size);
+ if (xt_m->m == NULL)
+ return NULL;
+
+ xt_m->m->u.match_size = match_size;
+ strcpy(xt_m->m->u.user.name, xt_m->name);
+ xt_m->m->u.user.revision = xt_m->revision;
+
+ if (xt_m->init != NULL)
+ xt_m->init(xt_m->m);
+
+ if (xt_m == xt_m->next)
+ goto done;
+
+#if XTABLES_VERSION_CODE > 5
+ if (xt_m->x6_options != NULL)
+ iptables_globals.opts =
+ xtables_options_xfrm(
+ iptables_globals.orig_opts,
+ iptables_globals.opts,
+ xt_m->x6_options,
+ &xt_m->option_offset);
+ else
+#endif
+ iptables_globals.opts =
+ xtables_merge_options(
+#if XTABLES_VERSION_CODE > 5
+ iptables_globals.orig_opts,
+#endif
+ iptables_globals.opts,
+ xt_m->extra_opts,
+ &xt_m->option_offset);
+
+ if (iptables_globals.opts == NULL) {
+ g_free(xt_m->m);
+ xt_m = NULL;
+ }
+
+done:
+ return xt_m;
+}
+
static int iptables_command(int argc, char *argv[])
{
struct connman_iptables *table;
- struct xtables_match *xt_m;
+ struct xtables_rule_match *xt_rm, *tmp_xt_rm;
+ struct xtables_match *xt_m, *xt_m_t;
struct xtables_target *xt_t;
struct ipt_ip ip;
char *table_name, *chain, *new_chain, *match_name, *target_name;
- char *flush_chain;
+ char *flush_chain, *delete_chain, *policy;
int c, ret, in_len, out_len;
- size_t size;
- gboolean dump, invert;
+ gboolean dump, invert, insert, delete;
struct in_addr src, dst;
if (argc == 0)
dump = FALSE;
invert = FALSE;
+ insert = FALSE;
+ delete = FALSE;
table_name = chain = new_chain = match_name = target_name = NULL;
- flush_chain = NULL;
+ flush_chain = delete_chain = policy = NULL;
memset(&ip, 0, sizeof(struct ipt_ip));
table = NULL;
+ xt_rm = NULL;
xt_m = NULL;
xt_t = NULL;
ret = 0;
+ /* extension's options will generate false-positives errors */
+ opterr = 0;
+
optind = 0;
- while ((c = getopt_long(argc, argv,
- "-A:F:L::N:d:j:i:m:o:s:t:", iptables_globals.opts, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "-A:F:I:L::N:P:X:d:j:i:m:o:s:t:",
+ iptables_globals.opts, NULL)) != -1) {
switch (c) {
case 'A':
+ /* It is either -A, -D or -I at once */
+ if (chain)
+ goto out;
+
chain = optarg;
break;
+ case 'D':
+ /* It is either -A, -D or -I at once */
+ if (chain)
+ goto out;
+
+ chain = optarg;
+ delete = TRUE;
+ break;
+
case 'F':
flush_chain = optarg;
break;
+ case 'I':
+ /* It is either -A, -D or -I at once */
+ if (chain)
+ goto out;
+
+ chain = optarg;
+ insert = TRUE;
+ break;
+
case 'L':
dump = TRUE;
break;
new_chain = optarg;
break;
+ case 'P':
+ chain = optarg;
+ if (optind < argc)
+ policy = argv[optind++];
+ else
+ goto out;
+
+ break;
+
+ case 'X':
+ delete_chain = optarg;
+ break;
+
case 'd':
if (!inet_pton(AF_INET, optarg, &dst))
break;
case 'j':
target_name = optarg;
- xt_t = xtables_find_target(target_name, XTF_TRY_LOAD);
-
+ xt_t = prepare_target(table, target_name);
if (xt_t == NULL)
- break;
-
- size = ALIGN(sizeof(struct ipt_entry_target)) +
- xt_t->size;
-
- xt_t->t = g_try_malloc0(size);
- if (xt_t->t == NULL)
- goto out;
- xt_t->t->u.target_size = size;
- strcpy(xt_t->t->u.user.name, target_name);
- xt_t->t->u.user.revision = xt_t->revision;
- if (xt_t->init != NULL)
- xt_t->init(xt_t->t);
- iptables_globals.opts =
- xtables_merge_options(
-#if XTABLES_VERSION_CODE > 5
- iptables_globals.orig_opts,
-#endif
- iptables_globals.opts,
- xt_t->extra_opts,
- &xt_t->option_offset);
- if (iptables_globals.opts == NULL)
goto out;
break;
case 'm':
match_name = optarg;
-
- xt_m = xtables_find_match(optarg, XTF_LOAD_MUST_SUCCEED, NULL);
- size = ALIGN(sizeof(struct ipt_entry_match)) +
- xt_m->size;
- xt_m->m = g_try_malloc0(size);
+ xt_m = prepare_matches(table, &xt_rm, match_name);
if (xt_m == NULL)
goto out;
- xt_m->m->u.match_size = size;
- strcpy(xt_m->m->u.user.name, xt_m->name);
- xt_m->m->u.user.revision = xt_m->revision;
- if (xt_m->init != NULL)
- xt_m->init(xt_m->m);
- if (xt_m != xt_m->next) {
- iptables_globals.opts =
- xtables_merge_options(
-#if XTABLES_VERSION_CODE > 5
- iptables_globals.orig_opts,
-#endif
- iptables_globals.opts,
- xt_m->extra_opts,
- &xt_m->option_offset);
- if (iptables_globals.opts == NULL)
- goto out;
- }
break;
case 't':
table_name = optarg;
+
+ table = iptables_init(table_name);
+ if (table == NULL) {
+ ret = -EINVAL;
+ goto out;
+ }
+
break;
case 1:
goto out;
default:
- if (xt_t == NULL || xt_t->parse == NULL ||
- !xt_t->parse(c - xt_t->option_offset, argv, invert,
- &xt_t->tflags, NULL, &xt_t->t)) {
- if (xt_m == NULL || xt_m->parse == NULL)
- break;
+#if XTABLES_VERSION_CODE > 5
+ if (xt_t != NULL && (xt_t->x6_parse != NULL ||
+ xt_t->parse != NULL) &&
+ (c >= (int) xt_t->option_offset &&
+ c < (int) xt_t->option_offset +
+ XT_OPTION_OFFSET_SCALE)) {
+ xtables_option_tpcall(c, argv,
+ invert, xt_t, NULL);
- xt_m->parse(c - xt_m->option_offset, argv,
- invert, &xt_m->mflags, NULL, &xt_m->m);
+ break;
}
+ for (tmp_xt_rm = xt_rm; tmp_xt_rm != NULL;
+ tmp_xt_rm = tmp_xt_rm->next) {
+ xt_m_t = tmp_xt_rm->match;
+
+ if (tmp_xt_rm->completed ||
+ (xt_m_t->x6_parse == NULL &&
+ xt_m_t->parse == NULL))
+ continue;
+
+ if (c < (int) xt_m_t->option_offset ||
+ c >= (int) xt_m_t->option_offset
+ + XT_OPTION_OFFSET_SCALE)
+ continue;
+
+ xtables_option_mpcall(c, argv,
+ invert, xt_m_t, NULL);
+
+ break;
+ }
+#else
+ if (xt_t == NULL || xt_t->parse == NULL ||
+ !xt_t->parse(c - xt_t->option_offset,
+ argv, invert, &xt_t->tflags, NULL, &xt_t->t)) {
+
+ for (tmp_xt_rm = xt_rm; tmp_xt_rm != NULL;
+ tmp_xt_rm = tmp_xt_rm->next) {
+ xt_m_t = tmp_xt_rm->match;
+
+ if (tmp_xt_rm->completed ||
+ xt_m_t->parse == NULL)
+ continue;
+
+ if (xt_m->parse(c - xt_m->option_offset,
+ argv, invert, &xt_m->mflags,
+ NULL, &xt_m->m))
+ break;
+ }
+ }
+#endif
break;
}
invert = FALSE;
}
- if (table_name == NULL)
- table_name = "filter";
+#if XTABLES_VERSION_CODE > 5
+ for (tmp_xt_rm = xt_rm; tmp_xt_rm != NULL;
+ tmp_xt_rm = tmp_xt_rm->next)
+ xtables_option_mfcall(tmp_xt_rm->match);
+
+ if (xt_t != NULL)
+ xtables_option_tfcall(xt_t);
+#else
+ for (tmp_xt_rm = xt_rm; tmp_xt_rm != NULL;
+ tmp_xt_rm = tmp_xt_rm->next)
+ if (tmp_xt_rm->match->final_check != NULL)
+ tmp_xt_rm->match->final_check(
+ tmp_xt_rm->match->mflags);
+
+ if (xt_t != NULL && xt_t->final_check != NULL)
+ xt_t->final_check(xt_t->tflags);
+#endif
- table = iptables_init(table_name);
if (table == NULL) {
- ret = -EINVAL;
+ table_name = "filter";
+
+ table = iptables_init(table_name);
+ if (table == NULL) {
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+
+ if (delete_chain != NULL) {
+ printf("Delete chain %s\n", delete_chain);
+
+ iptables_delete_chain(table, delete_chain);
+
goto out;
}
}
if (chain) {
- if (target_name == NULL)
- return -1;
+ if (policy != NULL) {
+ printf("Changing policy of %s to %s\n", chain, policy);
+
+ iptables_change_policy(table, chain, policy);
- DBG("Adding %s to %s (match %s)",
- target_name, chain, match_name);
+ goto out;
+ }
- ret = iptables_add_rule(table, &ip, chain, target_name, xt_t,
- match_name, xt_m);
+ if (xt_t == NULL)
+ goto out;
- goto out;
+ if (delete == TRUE) {
+ DBG("Deleting %s to %s (match %s)\n",
+ target_name, chain, match_name);
+
+ ret = iptables_delete_rule(table, &ip, chain,
+ target_name, xt_t, xt_m, xt_rm);
+
+ goto out;
+ }
+
+ if (insert == TRUE) {
+ DBG("Inserting %s to %s (match %s)",
+ target_name, chain, match_name);
+
+ ret = iptables_insert_rule(table, &ip, chain,
+ target_name, xt_t, xt_rm);
+
+ goto out;
+ } else {
+ DBG("Adding %s to %s (match %s)",
+ target_name, chain, match_name);
+
+ ret = iptables_append_rule(table, &ip, chain,
+ target_name, xt_t, xt_rm);
+
+ goto out;
+ }
}
out:
+++ /dev/null
-/*
- *
- * Connection Manager
- *
- * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <errno.h>
-
-#include "connman.h"
-
-struct connman_location {
- gint refcount;
- struct connman_service *service;
- enum connman_location_result result;
-
- struct connman_location_driver *driver;
- void *driver_data;
-};
-
-/**
- * connman_location_ref:
- * @location: Location structure
- *
- * Increase reference counter of location
- */
-struct connman_location *connman_location_ref(struct connman_location *location)
-{
- g_atomic_int_inc(&location->refcount);
-
- return location;
-}
-
-/**
- * connman_location_unref:
- * @location: Location structure
- *
- * Decrease reference counter of location
- */
-void connman_location_unref(struct connman_location *location)
-{
- if (g_atomic_int_dec_and_test(&location->refcount) == FALSE)
- return;
-
- if (location->driver) {
- location->driver->finish(location);
- location->driver = NULL;
- }
-
- g_free(location);
-}
-
-/**
- * connman_location_get_type:
- * @location: Location structure
- *
- * Get the service type of location
- */
-enum connman_service_type connman_location_get_type(struct connman_location *location)
-{
- if (location == NULL)
- return CONNMAN_SERVICE_TYPE_UNKNOWN;
-
- return connman_service_get_type(location->service);
-}
-
-/**
- * connman_location_get_interface:
- * @location: location structure
- *
- * Get network interface of location
- */
-char *connman_location_get_interface(struct connman_location *location)
-{
- if (location == NULL)
- return NULL;
-
- return connman_service_get_interface(location->service);
-}
-
-struct connman_service *connman_location_get_service(
- struct connman_location *location)
-{
- return location->service;
-}
-/**
- * connman_location_get_data:
- * @location: Location structure
- *
- * Get private location data pointer
- */
-void *connman_location_get_data(struct connman_location *location)
-{
- return location->driver_data;
-}
-
-/**
- * connman_location_set_data:
- * @location: Location structure
- * @data: data pointer
- *
- * Set private location data pointer
- */
-void connman_location_set_data(struct connman_location *location, void *data)
-{
- location->driver_data = data;
-}
-
-static GSList *driver_list = NULL;
-
-static gint compare_priority(gconstpointer a, gconstpointer b)
-{
- const struct connman_location_driver *driver1 = a;
- const struct connman_location_driver *driver2 = b;
-
- return driver2->priority - driver1->priority;
-}
-
-/**
- * connman_location_driver_register:
- * @driver: Location driver definition
- *
- * Register a new Location driver
- *
- * Returns: %0 on success
- */
-int connman_location_driver_register(struct connman_location_driver *driver)
-{
- DBG("driver %p name %s", driver, driver->name);
-
- driver_list = g_slist_insert_sorted(driver_list, driver,
- compare_priority);
-
- return 0;
-}
-
-/**
- * connman_location_driver_unregister:
- * @driver: Location driver definition
- *
- * Remove a previously registered Location driver
- */
-void connman_location_driver_unregister(struct connman_location_driver *driver)
-{
- DBG("driver %p name %s", driver, driver->name);
-
- driver_list = g_slist_remove(driver_list, driver);
-}
-
-/**
- * connman_location_report_result:
- * @location: location structure
- * @result: result information
- *
- * Report result of a location detection
- */
-void connman_location_report_result(struct connman_location *location,
- enum connman_location_result result)
-{
- DBG("location %p result %d", location, result);
-
- if (location == NULL)
- return;
-
- if (location->result == result)
- return;
-
- location->result = result;
-
- switch (location->result) {
- case CONNMAN_LOCATION_RESULT_UNKNOWN:
- return;
- case CONNMAN_LOCATION_RESULT_PORTAL:
- __connman_service_request_login(location->service);
- break;
- case CONNMAN_LOCATION_RESULT_ONLINE:
- __connman_service_ipconfig_indicate_state(location->service,
- CONNMAN_SERVICE_STATE_ONLINE,
- CONNMAN_IPCONFIG_TYPE_IPV4);
- break;
- }
-}
-
-struct connman_location *__connman_location_create(struct connman_service *service)
-{
- struct connman_location *location;
-
- DBG("service %p", service);
-
- if (service == NULL)
- return NULL;
-
- location = g_try_new0(struct connman_location, 1);
- if (location == NULL)
- return NULL;
-
- DBG("location %p", location);
-
- location->refcount = 1;
-
- location->service = service;
- location->result = CONNMAN_LOCATION_RESULT_UNKNOWN;
-
- return location;
-}
-
-int __connman_location_detect(struct connman_service *service)
-{
- struct connman_location *location;
- GSList *list;
-
- DBG("service %p", service);
-
- location = __connman_service_get_location(service);
- if (location == NULL)
- return -EINVAL;
-
- if (location->driver) {
- location->result = CONNMAN_LOCATION_RESULT_UNKNOWN;
- location->driver->finish(location);
-
- if (location->driver->detect(location) == 0)
- return 0;
-
- location->driver = NULL;
- }
-
- for (list = driver_list; list; list = list->next) {
- struct connman_location_driver *driver = list->data;
-
- DBG("driver %p name %s", driver, driver->name);
-
- if (driver->detect(location) == 0) {
- location->driver = driver;
- break;
- }
- }
-
- if (location->driver == NULL)
- connman_location_report_result(location,
- CONNMAN_LOCATION_RESULT_ONLINE);
-
- return 0;
-}
-
-int __connman_location_finish(struct connman_service *service)
-{
- struct connman_location *location;
-
- DBG("service %p", service);
-
- location = __connman_service_get_location(service);
- if (location == NULL)
- return -EINVAL;
-
- location->result = CONNMAN_LOCATION_RESULT_UNKNOWN;
-
- if (location->driver) {
- location->driver->finish(location);
- location->driver = NULL;
- }
-
- return 0;
-}
-
-int __connman_location_init(void)
-{
- DBG("");
-
- return 0;
-}
-
-void __connman_location_cleanup(void)
-{
- DBG("");
-}
#endif
#define _GNU_SOURCE
+#include <stdio.h>
+#include <unistd.h>
#include <stdarg.h>
-#include <syslog.h>
#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
#include <execinfo.h>
#include <dlfcn.h>
#include "connman.h"
+static const char *program_exec;
+static const char *program_path;
+
#if defined TIZEN_EXT
-#include <stdio.h>
-#include <unistd.h>
#include <sys/stat.h>
#define LOG_FILE_PATH "/var/log/connman.log"
}
#if !defined TIZEN_EXT
-static void signal_handler(int signo)
+static void print_backtrace(unsigned int offset)
{
- void *frames[64];
- char **symbols;
+ void *frames[99];
size_t n_ptrs;
unsigned int i;
+ int outfd[2], infd[2];
+ int pathlen;
+ pid_t pid;
+
+ if (program_exec == NULL)
+ return;
+
+ pathlen = strlen(program_path);
n_ptrs = backtrace(frames, G_N_ELEMENTS(frames));
- symbols = backtrace_symbols(frames, n_ptrs);
- if (symbols == NULL) {
- connman_error("No backtrace symbols");
- exit(1);
+ if (n_ptrs < offset)
+ return;
+
+ if (pipe(outfd) < 0)
+ return;
+
+ if (pipe(infd) < 0) {
+ close(outfd[0]);
+ close(outfd[1]);
+ return;
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ close(outfd[0]);
+ close(outfd[1]);
+ close(infd[0]);
+ close(infd[1]);
+ return;
+ }
+
+ if (pid == 0) {
+ close(outfd[1]);
+ close(infd[0]);
+
+ dup2(outfd[0], STDIN_FILENO);
+ dup2(infd[1], STDOUT_FILENO);
+
+ execlp("addr2line", "-C", "-f", "-e", program_exec, NULL);
+
+ exit(EXIT_FAILURE);
}
- connman_error("Aborting (signal %d)", signo);
+ close(outfd[0]);
+ close(infd[1]);
+
connman_error("++++++++ backtrace ++++++++");
- for (i = 1; i < n_ptrs; i++)
- connman_error("[%d]: %s", i - 1, symbols[i]);
+ for (i = offset; i < n_ptrs - 1; i++) {
+ Dl_info info;
+ char addr[20], buf[PATH_MAX * 2];
+ int len, written;
+ char *ptr, *pos;
+
+ dladdr(frames[i], &info);
+
+ len = snprintf(addr, sizeof(addr), "%p\n", frames[i]);
+ if (len < 0)
+ break;
+
+ written = write(outfd[1], addr, len);
+ if (written < 0)
+ break;
+
+ len = read(infd[0], buf, sizeof(buf));
+ if (len < 0)
+ break;
+
+ buf[len] = '\0';
+
+ pos = strchr(buf, '\n');
+ *pos++ = '\0';
+
+ if (strcmp(buf, "??") == 0) {
+ connman_error("#%-2u %p in %s", i - offset,
+ frames[i], info.dli_fname);
+ continue;
+ }
+
+ ptr = strchr(pos, '\n');
+ *ptr++ = '\0';
+
+ if (strncmp(pos, program_path, pathlen) == 0)
+ pos += pathlen + 1;
+
+ connman_error("#%-2u %p in %s() at %s", i - offset,
+ frames[i], buf, pos);
+ }
connman_error("+++++++++++++++++++++++++++");
- g_free(symbols);
- exit(1);
+ kill(pid, SIGTERM);
+
+ close(outfd[1]);
+ close(infd[0]);
+}
+
+static void signal_handler(int signo)
+{
+ connman_error("Aborting (signal %d) [%s]", signo, program_exec);
+
+ print_backtrace(2);
+
+ exit(EXIT_FAILURE);
}
static void signal_setup(sighandler_t handler)
}
}
-int __connman_log_init(const char *debug, connman_bool_t detach)
+int __connman_log_init(const char *program, const char *debug,
+ connman_bool_t detach)
{
+ static char path[PATH_MAX];
int option = LOG_NDELAY | LOG_PID;
+ program_exec = program;
+ program_path = getcwd(path, sizeof(path));
+
if (debug != NULL)
enabled = g_strsplit_set(debug, ":, ", 0);
signal_setup(signal_handler);
#endif
- openlog("connmand", option, LOG_DAEMON);
+ openlog(basename(program), option, LOG_DAEMON);
syslog(LOG_INFO, "Connection Manager version %s", VERSION);
perror("Failed to create storage directory");
}
- if (mkdir(STORAGEDIR "/stats", S_IRUSR | S_IWUSR | S_IXUSR |
- S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) {
- if (errno != EEXIST)
- perror("Failed to create statistics directory");
- }
-
umask(0077);
main_loop = g_main_loop_new(NULL, FALSE);
g_dbus_set_disconnect_function(conn, disconnect_callback, NULL, NULL);
- __connman_log_init(option_debug, option_detach);
+ __connman_log_init(argv[0], option_debug, option_detach);
__connman_dbus_init(conn);
parse_config(config);
- __connman_storage_init();
+ __connman_storage_migrate();
__connman_technology_init();
__connman_notifier_init();
- __connman_location_init();
__connman_service_init();
__connman_provider_init();
__connman_network_init();
__connman_tethering_init();
__connman_counter_init();
__connman_manager_init();
- __connman_profile_init();
__connman_config_init();
__connman_stats_init();
__connman_clock_init();
__connman_plugin_init(option_plugin, option_noplugin);
- __connman_storage_init_profile();
-
__connman_rtnl_start();
__connman_dhcp_init();
__connman_wpad_init();
__connman_proxy_cleanup();
__connman_task_cleanup();
__connman_rtnl_cleanup();
- __connman_ipconfig_cleanup();
__connman_resolver_cleanup();
__connman_clock_cleanup();
__connman_stats_cleanup();
__connman_config_cleanup();
- __connman_profile_cleanup();
__connman_manager_cleanup();
__connman_counter_cleanup();
__connman_agent_cleanup();
__connman_device_cleanup();
__connman_network_cleanup();
__connman_service_cleanup();
- __connman_location_cleanup();
+ __connman_ipconfig_cleanup();
__connman_notifier_cleanup();
__connman_technology_cleanup();
- __connman_storage_cleanup();
__connman_dbus_cleanup();
if (config)
g_key_file_free(config);
+ g_free(option_debug);
+
return 0;
}
connman_dbus_dict_open(&array, &dict);
- str = __connman_profile_active_path();
- if (str != NULL)
- connman_dbus_dict_append_basic(&dict, "ActiveProfile",
- DBUS_TYPE_OBJECT_PATH, &str);
-
connman_dbus_dict_append_array(&dict, "Services",
DBUS_TYPE_OBJECT_PATH, __connman_service_list, NULL);
connman_dbus_dict_append_array(&dict, "Technologies",
connman_dbus_dict_append_basic(&dict, "State",
DBUS_TYPE_STRING, &str);
- offlinemode = __connman_profile_get_offlinemode();
+ offlinemode = __connman_technology_get_offlinemode();
connman_dbus_dict_append_basic(&dict, "OfflineMode",
DBUS_TYPE_BOOLEAN, &offlinemode);
dbus_message_iter_get_basic(&value, &offlinemode);
- __connman_profile_set_offlinemode(offlinemode, TRUE);
-
- __connman_profile_save_default();
- } else if (g_str_equal(name, "ActiveProfile") == TRUE) {
- const char *str;
-
- dbus_message_iter_get_basic(&value, &str);
-
- return __connman_error_not_supported(msg);
+ __connman_technology_set_offlinemode(offlinemode);
} else if (g_str_equal(name, "SessionMode") == TRUE) {
connman_bool_t sessionmode;
__connman_session_set_mode(sessionmode);
- if (connman_state_idle == FALSE) {
+ if (sessionmode == TRUE && connman_state_idle == FALSE) {
session_mode_pending = msg;
return NULL;
}
static DBusConnection *connection = NULL;
-static enum connman_service_type technology_type;
-static connman_bool_t technology_enabled;
-static DBusMessage *technology_pending = NULL;
-static guint technology_timeout = 0;
-
-static void technology_reply(int error)
-{
- DBG("");
-
- if (technology_timeout > 0) {
- g_source_remove(technology_timeout);
- technology_timeout = 0;
- }
-
- if (technology_pending != NULL) {
- if (error > 0) {
- DBusMessage *reply;
-
- reply = __connman_error_failed(technology_pending,
- error);
- if (reply != NULL)
- g_dbus_send_message(connection, reply);
- } else
- g_dbus_send_reply(connection, technology_pending,
- DBUS_TYPE_INVALID);
-
- dbus_message_unref(technology_pending);
- technology_pending = NULL;
- }
-
- technology_type = CONNMAN_SERVICE_TYPE_UNKNOWN;
-}
-
-static gboolean technology_abort(gpointer user_data)
-{
- DBG("");
-
- technology_timeout = 0;
-
- technology_reply(ETIMEDOUT);
-
- return FALSE;
-}
-
-static void technology_notify(enum connman_service_type type,
- connman_bool_t enabled)
-{
- DBG("type %d enabled %d", type, enabled);
-
- if (type == technology_type && enabled == technology_enabled)
- technology_reply(0);
-}
-
static void session_mode_notify(void)
{
DBusMessage *reply;
static struct connman_notifier technology_notifier = {
.name = "manager",
.priority = CONNMAN_NOTIFIER_PRIORITY_HIGH,
- .service_enabled= technology_notify,
.idle_state = idle_state,
};
{
enum connman_service_type type;
const char *str;
- int err;
DBG("conn %p", conn);
- if (technology_pending != NULL)
- return __connman_error_in_progress(msg);
-
dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
DBUS_TYPE_INVALID);
if (__connman_notifier_is_enabled(type) == TRUE)
return __connman_error_already_enabled(msg);
- technology_type = type;
- technology_enabled = TRUE;
- technology_pending = dbus_message_ref(msg);
-
-#if defined TIZEN_EXT
- __connman_device_enable_technology(type);
-#else
- err = __connman_device_enable_technology(type);
- if (err < 0 && err != -EINPROGRESS)
- technology_reply(-err);
- else
- technology_timeout = g_timeout_add_seconds(15,
- technology_abort, NULL);
-#endif
+ __connman_technology_enable(type, msg);
return NULL;
}
{
enum connman_service_type type;
const char *str;
- int err;
DBG("conn %p", conn);
- if (technology_pending != NULL)
- return __connman_error_in_progress(msg);
-
dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
DBUS_TYPE_INVALID);
if (__connman_notifier_is_enabled(type) == FALSE)
return __connman_error_already_disabled(msg);
- technology_type = type;
- technology_enabled = FALSE;
- technology_pending = dbus_message_ref(msg);
-
- err = __connman_device_disable_technology(type);
- if (err < 0 && err != -EINPROGRESS)
- technology_reply(-err);
- else
- technology_timeout = g_timeout_add_seconds(10,
- technology_abort, NULL);
+ __connman_technology_disable(type, msg);
return NULL;
}
{
DBG("");
- connman_notifier_unregister(&technology_notifier);
-
if (connection == NULL)
return;
+ connman_notifier_unregister(&technology_notifier);
+
g_dbus_unregister_interface(connection, CONNMAN_MANAGER_PATH,
CONNMAN_MANAGER_INTERFACE);
static GSList *driver_list = NULL;
struct connman_network {
- gint refcount;
+ int refcount;
enum connman_network_type type;
connman_bool_t available;
connman_bool_t connected;
if (network->driver == NULL)
return;
+ connman_network_set_connected(network, FALSE);
+
switch (network->type) {
case CONNMAN_NETWORK_TYPE_UNKNOWN:
case CONNMAN_NETWORK_TYPE_VENDOR:
struct connman_network *connman_network_ref(struct connman_network *network)
{
DBG("network %p name %s refcount %d", network, network->name,
- g_atomic_int_get(&network->refcount) + 1);
+ network->refcount + 1);
- g_atomic_int_inc(&network->refcount);
+ __sync_fetch_and_add(&network->refcount, 1);
return network;
}
void connman_network_unref(struct connman_network *network)
{
DBG("network %p name %s refcount %d", network, network->name,
- g_atomic_int_get(&network->refcount) - 1);
+ network->refcount - 1);
- if (g_atomic_int_dec_and_test(&network->refcount) == FALSE)
+ if (__sync_fetch_and_sub(&network->refcount, 1) != 1)
return;
network_list = g_slist_remove(network_list, network);
{
struct connman_service *service;
- if (network->associating == FALSE)
- return ;
-
- network->associating = FALSE;
-
service = __connman_service_lookup_from_network(network);
- __connman_service_ipconfig_indicate_state(service,
- CONNMAN_SERVICE_STATE_FAILURE,
- CONNMAN_IPCONFIG_TYPE_IPV4);
+ __connman_service_indicate_error(service,
+ CONNMAN_SERVICE_ERROR_CONNECT_FAILED);
}
static void set_configure_error(struct connman_network *network)
{
struct connman_service *service;
- network->connecting = FALSE;
-
service = __connman_service_lookup_from_network(network);
- __connman_service_ipconfig_indicate_state(service,
- CONNMAN_SERVICE_STATE_FAILURE,
- CONNMAN_IPCONFIG_TYPE_IPV4);
+ __connman_service_indicate_error(service,
+ CONNMAN_SERVICE_ERROR_CONNECT_FAILED);
}
static void set_invalid_key_error(struct connman_network *network)
DBG("nework %p, error %d", network, error);
network->connecting = FALSE;
+ network->associating = FALSE;
switch (error) {
case CONNMAN_NETWORK_ERROR_UNKNOWN:
DBG("network %p", network);
+ if (network->device == NULL)
+ return;
+
__connman_device_set_network(network->device, network);
connman_device_set_disconnected(network->device, FALSE);
}
} else {
- struct connman_service *service;
+ enum connman_service_state state;
__connman_device_set_network(network->device, NULL);
- service = __connman_service_lookup_from_network(network);
-
switch (ipv4_method) {
case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
case CONNMAN_IPCONFIG_METHOD_OFF:
break;
}
- __connman_service_ipconfig_indicate_state(service,
+ /*
+ * We only set the disconnect state if we were not in idle
+ * or in failure. It does not make sense to go to disconnect
+ * state if we were not connected.
+ */
+ state = __connman_service_ipconfig_get_state(service,
+ CONNMAN_IPCONFIG_TYPE_IPV4);
+ if (state != CONNMAN_SERVICE_STATE_IDLE &&
+ state != CONNMAN_SERVICE_STATE_FAILURE)
+ __connman_service_ipconfig_indicate_state(service,
CONNMAN_SERVICE_STATE_DISCONNECT,
CONNMAN_IPCONFIG_TYPE_IPV4);
- __connman_service_ipconfig_indicate_state(service,
+ state = __connman_service_ipconfig_get_state(service,
+ CONNMAN_IPCONFIG_TYPE_IPV6);
+ if (state != CONNMAN_SERVICE_STATE_IDLE &&
+ state != CONNMAN_SERVICE_STATE_FAILURE)
+ __connman_service_ipconfig_indicate_state(service,
CONNMAN_SERVICE_STATE_DISCONNECT,
CONNMAN_IPCONFIG_TYPE_IPV6);
__connman_service_ipconfig_indicate_state(service,
CONNMAN_SERVICE_STATE_IDLE,
CONNMAN_IPCONFIG_TYPE_IPV6);
-
#if defined TIZEN_EXT
if (connman_service_get_type(service) ==
CONNMAN_SERVICE_TYPE_CELLULAR)
enum connman_ipconfig_method method;
int ret;
+ if (network == NULL)
+ return -EINVAL;
+
if (ipconfig_ipv6) {
method = __connman_ipconfig_get_method(ipconfig_ipv6);
const char *nameservers)
{
struct connman_service *service;
- char **nameservers_array = NULL;
+ char **nameservers_array;
int i;
DBG("network %p nameservers %s", network, nameservers);
__connman_service_nameserver_clear(service);
- if (nameservers != NULL)
- nameservers_array = g_strsplit(nameservers, " ", 0);
+ if (nameservers == NULL)
+ return 0;
+
+ nameservers_array = g_strsplit(nameservers, " ", 0);
for (i = 0; nameservers_array[i] != NULL; i++) {
__connman_service_nameserver_append(service,
- nameservers_array[i]);
+ nameservers_array[i], FALSE);
}
g_strfreev(nameservers_array);
int connman_network_set_string(struct connman_network *network,
const char *key, const char *value)
{
-// DBG("network %p key %s value %s", network, key, value);
+ DBG("network %p key %s value %s", network, key, value);
if (g_strcmp0(key, "Name") == 0)
return connman_network_set_name(network, value);
int connman_network_set_blob(struct connman_network *network,
const char *key, const void *data, unsigned int size)
{
-// DBG("network %p key %s size %d", network, key, size);
+ DBG("network %p key %s size %d", network, key, size);
if (g_str_equal(key, "WiFi.SSID") == TRUE) {
g_free(network->wifi.ssid);
const void *connman_network_get_blob(struct connman_network *network,
const char *key, unsigned int *size)
{
-// DBG("network %p key %s", network, key);
+ DBG("network %p key %s", network, key);
if (g_str_equal(key, "WiFi.SSID") == TRUE) {
if (size != NULL)
#define MAX_TECHNOLOGIES 10
-static volatile gint registered[MAX_TECHNOLOGIES];
-static volatile gint enabled[MAX_TECHNOLOGIES];
-static volatile gint connected[MAX_TECHNOLOGIES];
+static volatile int registered[MAX_TECHNOLOGIES];
+static volatile int enabled[MAX_TECHNOLOGIES];
+static volatile int connected[MAX_TECHNOLOGIES];
void __connman_notifier_list_registered(DBusMessageIter *iter, void *user_data)
{
int i;
+ __sync_synchronize();
for (i = 0; i < MAX_TECHNOLOGIES; i++) {
const char *type = __connman_service_type2string(i);
if (type == NULL)
continue;
- if (g_atomic_int_get(®istered[i]) > 0)
+ if (registered[i] > 0)
dbus_message_iter_append_basic(iter,
DBUS_TYPE_STRING, &type);
}
{
int i;
+ __sync_synchronize();
for (i = 0; i < MAX_TECHNOLOGIES; i++) {
const char *type = __connman_service_type2string(i);
if (type == NULL)
continue;
- if (g_atomic_int_get(&enabled[i]) > 0)
+ if (enabled[i] > 0)
dbus_message_iter_append_basic(iter,
DBUS_TYPE_STRING, &type);
}
{
int i;
+ __sync_synchronize();
for (i = 0; i < MAX_TECHNOLOGIES; i++) {
const char *type = __connman_service_type2string(i);
if (type == NULL)
continue;
- if (g_atomic_int_get(&connected[i]) > 0)
+ if (connected[i] > 0)
dbus_message_iter_append_basic(iter,
DBUS_TYPE_STRING, &type);
}
{
unsigned int i, count = 0;
+ __sync_synchronize();
for (i = 0; i < MAX_TECHNOLOGIES; i++) {
- if (g_atomic_int_get(&connected[i]) > 0)
+ if (connected[i] > 0)
count++;
}
return "offline";
}
-static void state_changed(void)
+static void state_changed(connman_bool_t connected)
{
unsigned int count = __connman_notifier_count_connected();
char *state = "offline";
if (count > 1)
return;
- if (count > 0)
+ if (count == 1) {
+ if (connected == FALSE)
+ return;
+
state = "online";
+ }
connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
CONNMAN_MANAGER_INTERFACE, "State",
CONNMAN_MANAGER_INTERFACE, "ConnectedTechnologies",
DBUS_TYPE_STRING, __connman_notifier_list_connected, NULL);
- state_changed();
+ state_changed(connected);
}
void __connman_notifier_register(enum connman_service_type type)
break;
}
- if (g_atomic_int_exchange_and_add(®istered[type], 1) == 0)
+ if (__sync_fetch_and_add(®istered[type], 1) == 0)
technology_registered(type, TRUE);
}
{
DBG("type %d", type);
- if (g_atomic_int_get(®istered[type]) == 0) {
+ __sync_synchronize();
+ if (registered[type] == 0) {
connman_error("notifier unregister underflow");
return;
}
break;
}
- if (g_atomic_int_dec_and_test(®istered[type]) == TRUE)
- technology_registered(type, FALSE);
+ if (__sync_fetch_and_sub(®istered[type], 1) != 1)
+ return;
+
+ technology_registered(type, FALSE);
}
void __connman_notifier_enable(enum connman_service_type type)
break;
}
- if (g_atomic_int_exchange_and_add(&enabled[type], 1) == 0)
+ if (__sync_fetch_and_add(&enabled[type], 1) == 0)
technology_enabled(type, TRUE);
}
{
DBG("type %d", type);
- if (g_atomic_int_get(&enabled[type]) == 0) {
+ __sync_synchronize();
+ if (enabled[type] == 0) {
connman_error("notifier disable underflow");
return;
}
break;
}
- if (g_atomic_int_dec_and_test(&enabled[type]) == TRUE)
- technology_enabled(type, FALSE);
+ if (__sync_fetch_and_sub(&enabled[type], 1) != 1)
+ return;
+
+ technology_enabled(type, FALSE);
}
void __connman_notifier_connect(enum connman_service_type type)
break;
}
- if (g_atomic_int_exchange_and_add(&connected[type], 1) == 0)
+ if (__sync_fetch_and_add(&connected[type], 1) == 0)
technology_connected(type, TRUE);
}
{
DBG("type %d", type);
- if (g_atomic_int_get(&connected[type]) == 0) {
+ __sync_synchronize();
+ if (connected[type] == 0) {
connman_error("notifier disconnect underflow");
return;
}
break;
}
- DBG("connected type(%d) cnt (%d)", type, g_atomic_int_get(&connected[type]) );
-
- if (g_atomic_int_dec_and_test(&connected[type]) == TRUE)
- technology_connected(type, FALSE);
+ if (__sync_fetch_and_sub(&connected[type], 1) != 1)
+ return;
+
+ technology_connected(type, FALSE);
}
static void technology_default(enum connman_service_type type)
DBG("enabled %d", enabled);
- __connman_profile_changed(FALSE);
-
offlinemode_changed(enabled);
for (list = notifier_list; list; list = list->next) {
switch (state) {
case CONNMAN_SERVICE_STATE_UNKNOWN:
+ case CONNMAN_SERVICE_STATE_FAILURE:
case CONNMAN_SERVICE_STATE_DISCONNECT:
case CONNMAN_SERVICE_STATE_IDLE:
if (found == FALSE)
case CONNMAN_SERVICE_STATE_CONFIGURATION:
case CONNMAN_SERVICE_STATE_READY:
case CONNMAN_SERVICE_STATE_ONLINE:
- case CONNMAN_SERVICE_STATE_FAILURE:
if (found == TRUE)
break;
if (technology_supported(type) == FALSE)
return FALSE;
- if (g_atomic_int_get(®istered[type]) > 0)
+ __sync_synchronize();
+ if (registered[type] > 0)
return TRUE;
return FALSE;
if (technology_supported(type) == FALSE)
return FALSE;
- if (g_atomic_int_get(&enabled[type]) > 0)
+ __sync_synchronize();
+ if (enabled[type] > 0)
return TRUE;
return FALSE;
--- /dev/null
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+
+#include <glib.h>
+
+#include <gweb/gresolv.h>
+
+#include "connman.h"
+
+struct ntp_short {
+ uint16_t seconds;
+ uint16_t fraction;
+} __attribute__ ((packed));
+
+struct ntp_time {
+ uint32_t seconds;
+ uint32_t fraction;
+} __attribute__ ((packed));
+
+struct ntp_msg {
+ uint8_t flags; /* Mode, version and leap indicator */
+ uint8_t stratum; /* Stratum details */
+ int8_t poll; /* Maximum interval in log2 seconds */
+ int8_t precision; /* Clock precision in log2 seconds */
+ struct ntp_short rootdelay; /* Root delay */
+ struct ntp_short rootdisp; /* Root dispersion */
+ uint32_t refid; /* Reference ID */
+ struct ntp_time reftime; /* Reference timestamp */
+ struct ntp_time orgtime; /* Origin timestamp */
+ struct ntp_time rectime; /* Receive timestamp */
+ struct ntp_time xmttime; /* Transmit timestamp */
+} __attribute__ ((packed));
+
+#define OFFSET_1900_1970 2208988800UL /* 1970 - 1900 in seconds */
+
+#define STEPTIME_MIN_OFFSET 0.128
+
+#define LOGTOD(a) ((a) < 0 ? 1. / (1L << -(a)) : 1L << (int)(a))
+
+static struct timeval transmit_timeval;
+static char *transmit_server;
+static int transmit_fd;
+static guint transmit_delay = 16;
+
+static void send_packet(int fd, const char *server)
+{
+ struct ntp_msg msg;
+ struct sockaddr_in addr;
+ ssize_t len;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.flags = 0x23;
+ msg.poll = 4; // min
+ msg.poll = 10; // max
+ msg.xmttime.seconds = random();
+ msg.xmttime.fraction = random();
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(123);
+ addr.sin_addr.s_addr = inet_addr(server);
+
+ gettimeofday(&transmit_timeval, NULL);
+
+ len = sendto(fd, &msg, sizeof(msg), MSG_DONTWAIT,
+ &addr, sizeof(addr));
+ if (len < 0) {
+ connman_error("Time request for server %s failed", server);
+ return;
+ }
+
+ if (len != sizeof(msg)) {
+ connman_error("Broken time request for server %s", server);
+ return;
+ }
+}
+
+static gboolean next_request(gpointer user_data)
+{
+ DBG("server %s", transmit_server);
+
+ send_packet(transmit_fd, transmit_server);
+
+ return FALSE;
+}
+
+static void decode_msg(void *base, size_t len, struct timeval *tv)
+{
+ struct ntp_msg *msg = base;
+ double org, rec, xmt, dst;
+ double delay, offset;
+
+ if (len < sizeof(*msg)) {
+ connman_error("Invalid response from time server");
+ return;
+ }
+
+ if (tv == NULL) {
+ connman_error("Invalid packet timestamp from time server");
+ return;
+ }
+
+ DBG("flags : 0x%02x", msg->flags);
+ DBG("stratum : %u", msg->stratum);
+ DBG("poll : %f seconds (%d)",
+ LOGTOD(msg->poll), msg->poll);
+ DBG("precision : %f seconds (%d)",
+ LOGTOD(msg->precision), msg->precision);
+ DBG("root delay : %u seconds (fraction %u)",
+ msg->rootdelay.seconds, msg->rootdelay.fraction);
+ DBG("root disp. : %u seconds (fraction %u)",
+ msg->rootdisp.seconds, msg->rootdisp.fraction);
+ DBG("reference : 0x%04x", msg->refid);
+
+ transmit_delay = LOGTOD(msg->poll);
+
+ if (msg->flags != 0x24)
+ return;
+
+ org = transmit_timeval.tv_sec +
+ (1.0e-6 * transmit_timeval.tv_usec) + OFFSET_1900_1970;
+ rec = ntohl(msg->rectime.seconds) +
+ ((double) ntohl(msg->rectime.fraction) / UINT_MAX);
+ xmt = ntohl(msg->xmttime.seconds) +
+ ((double) ntohl(msg->xmttime.fraction) / UINT_MAX);
+ dst = tv->tv_sec + (1.0e-6 * tv->tv_usec) + OFFSET_1900_1970;
+
+ DBG("org=%f rec=%f xmt=%f dst=%f", org, rec, xmt, dst);
+
+ offset = ((rec - org) + (xmt - dst)) / 2;
+ delay = (dst - org) - (xmt - rec);
+
+ DBG("offset=%f delay=%f", offset, delay);
+
+ if (offset < STEPTIME_MIN_OFFSET && offset > -STEPTIME_MIN_OFFSET) {
+ struct timeval adj;
+
+ adj.tv_sec = (long) offset;
+ adj.tv_usec = (offset - adj.tv_sec) * 1000000;
+
+ DBG("adjusting time");
+
+ if (adjtime(&adj, &adj) < 0) {
+ connman_error("Failed to adjust time");
+ return;
+ }
+
+ DBG("%lu seconds, %lu msecs", adj.tv_sec, adj.tv_usec);
+ } else {
+ struct timeval cur;
+ double dtime;
+
+ gettimeofday(&cur, NULL);
+ dtime = offset + cur.tv_sec + 1.0e-6 * cur.tv_usec;
+ cur.tv_sec = (long) dtime;
+ cur.tv_usec = (dtime - cur.tv_sec) * 1000000;
+
+ DBG("setting time");
+
+ if (settimeofday(&cur, NULL) < 0) {
+ connman_error("Failed to set time");
+ return;
+ }
+
+ DBG("%lu seconds, %lu msecs", cur.tv_sec, cur.tv_usec);
+ }
+}
+
+static guint channel_watch = 0;
+
+static gboolean received_data(GIOChannel *channel, GIOCondition condition,
+ gpointer user_data)
+{
+ unsigned char buf[128];
+ struct msghdr msg;
+ struct iovec iov;
+ struct cmsghdr *cmsg;
+ struct timeval *tv;
+ char aux[128];
+ ssize_t len;
+ int fd;
+
+ if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+ connman_error("Problem with timer server channel");
+ channel_watch = 0;
+ return FALSE;
+ }
+
+ fd = g_io_channel_unix_get_fd(channel);
+
+ iov.iov_base = buf;
+ iov.iov_len = sizeof(buf);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = aux;
+ msg.msg_controllen = sizeof(aux);
+
+ len = recvmsg(fd, &msg, MSG_DONTWAIT);
+ if (len < 0)
+ return TRUE;
+
+ tv = NULL;
+
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level != SOL_SOCKET)
+ continue;
+
+ switch (cmsg->cmsg_type) {
+ case SCM_TIMESTAMP:
+ tv = (struct timeval *) CMSG_DATA(cmsg);
+ break;
+ }
+ }
+
+ decode_msg(iov.iov_base, iov.iov_len, tv);
+
+ g_timeout_add_seconds(transmit_delay, next_request, NULL);
+
+ return TRUE;
+}
+
+static void start_ntp(const char *server)
+{
+ GIOChannel *channel;
+ struct sockaddr_in addr;
+ int fd, tos = IPTOS_LOWDELAY, timestamp = 1;
+
+ DBG("server %s", server);
+
+ if (channel_watch > 0)
+ return;
+
+ fd = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (fd < 0) {
+ connman_error("Failed to open time server socket");
+ return;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+
+ if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ connman_error("Failed to bind time server socket");
+ close(fd);
+ return;
+ }
+
+ if (setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {
+ connman_error("Failed to set type of service option");
+ close(fd);
+ return;
+ }
+
+ if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMP, ×tamp,
+ sizeof(timestamp)) < 0) {
+ connman_error("Failed to enable timestamp support");
+ close(fd);
+ return;
+ }
+
+ channel = g_io_channel_unix_new(fd);
+ if (channel == NULL) {
+ close(fd);
+ return;
+ }
+
+ g_io_channel_set_encoding(channel, NULL, NULL);
+ g_io_channel_set_buffered(channel, FALSE);
+
+ g_io_channel_set_close_on_unref(channel, TRUE);
+
+ channel_watch = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ received_data, NULL, NULL);
+
+ g_io_channel_unref(channel);
+
+ transmit_fd = fd;
+ transmit_server = g_strdup(server);
+
+ send_packet(fd, server);
+}
+
+static void resolv_debug(const char *str, void *data)
+{
+ connman_info("%s: %s\n", (const char *) data, str);
+}
+
+static GResolv *resolv = NULL;
+static guint resolv_lookup = 0;
+
+static void resolv_result(GResolvResultStatus status,
+ char **results, gpointer user_data)
+{
+ int i;
+
+ resolv_lookup = 0;
+
+ if (results != NULL) {
+ for (i = 0; results[i]; i++)
+ DBG("result: %s", results[i]);
+
+ if (results[0] != NULL)
+ start_ntp(results[0]);
+ }
+}
+
+int __connman_ntp_start(const char *interface, const char *resolver,
+ const char *server)
+{
+ DBG("interface %s server %s", interface, server);
+
+ resolv = g_resolv_new(0);
+ if (resolv == NULL)
+ return -ENOMEM;
+
+ if (getenv("CONNMAN_RESOLV_DEBUG"))
+ g_resolv_set_debug(resolv, resolv_debug, "RESOLV");
+
+ if (resolver != NULL)
+ g_resolv_add_nameserver(resolv, resolver, 53, 0);
+
+ g_resolv_lookup_hostname(resolv, server, resolv_result, NULL);
+
+ return 0;
+}
+
+void __connman_ntp_stop(const char *interface)
+{
+ DBG("interface %s", interface);
+
+ if (resolv == NULL)
+ return;
+
+ if (resolv_lookup > 0) {
+ g_resolv_cancel_lookup(resolv, resolv_lookup);
+ resolv_lookup = 0;
+ }
+
+ if (channel_watch > 0) {
+ g_source_remove(channel_watch);
+ channel_watch = 0;
+ }
+
+ g_resolv_unref(resolv);
+}
+++ /dev/null
-/*
- *
- * Connection Manager
- *
- * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <errno.h>
-#include <string.h>
-
-#include <glib.h>
-#include <gdbus.h>
-
-#include "connman.h"
-
-#define PROFILE_DEFAULT_IDENT "default"
-
-struct connman_profile {
- char *ident;
- char *path;
- char *name;
- connman_bool_t offlinemode;
-};
-
-static struct connman_profile *default_profile = NULL;
-
-static DBusConnection *connection = NULL;
-
-static void offlinemode_changed(struct connman_profile *profile)
-{
- connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
- CONNMAN_MANAGER_INTERFACE, "OfflineMode",
- DBUS_TYPE_BOOLEAN, &profile->offlinemode);
-}
-
-connman_bool_t __connman_profile_get_offlinemode(void)
-{
- if (default_profile == NULL)
- return FALSE;
-
- DBG("offlinemode %d", default_profile->offlinemode);
-
- return default_profile->offlinemode;
-}
-
-int __connman_profile_set_offlinemode(connman_bool_t offlinemode,
- connman_bool_t all_devices)
-{
- DBG("offlinemode %d", offlinemode);
-
- if (default_profile == NULL)
- return -EINVAL;
-
- if (default_profile->offlinemode == offlinemode)
- return -EALREADY;
-
- default_profile->offlinemode = offlinemode;
- offlinemode_changed(default_profile);
-
- if (all_devices)
- __connman_device_set_offlinemode(offlinemode);
-
- return 0;
-}
-
-int __connman_profile_save_default(void)
-{
- DBG("");
-
- if (default_profile != NULL)
- __connman_storage_save_profile(default_profile);
-
- return 0;
-}
-
-const char *__connman_profile_active_ident(void)
-{
- DBG("");
-
- return PROFILE_DEFAULT_IDENT;
-}
-
-const char *__connman_profile_active_path(void)
-{
- DBG("");
-
- if (default_profile == NULL)
- return NULL;
-
- return default_profile->path;
-}
-
-static guint changed_timeout = 0;
-
-static gboolean services_changed(gpointer user_data)
-{
- changed_timeout = 0;
-
- if (default_profile == NULL)
- return FALSE;
-
- connman_dbus_property_changed_array(CONNMAN_MANAGER_PATH,
- CONNMAN_MANAGER_INTERFACE, "Services",
- DBUS_TYPE_OBJECT_PATH, __connman_service_list,
- NULL);
-
- return FALSE;
-}
-
-void __connman_profile_changed(gboolean delayed)
-{
- DBG("");
-
- if (changed_timeout > 0) {
- g_source_remove(changed_timeout);
- changed_timeout = 0;
- }
-
- if (__connman_connection_update_gateway() == TRUE) {
- services_changed(NULL);
- return;
- }
-
- if (delayed == FALSE) {
- services_changed(NULL);
- return;
- }
-
- changed_timeout = g_timeout_add_seconds(1, services_changed, NULL);
-}
-
-static void free_profile(struct connman_profile *profile)
-{
- g_free(profile->name);
- g_free(profile->path);
- g_free(profile->ident);
- g_free(profile);
-}
-
-static int profile_init(void)
-{
- DBG("");
-
- default_profile = g_try_new0(struct connman_profile, 1);
- if (default_profile == NULL)
- return -ENOMEM;
-
- default_profile->ident = g_strdup(PROFILE_DEFAULT_IDENT);
- default_profile->path = g_strdup_printf("/profile/%s",
- PROFILE_DEFAULT_IDENT);
-
- if (default_profile->ident == NULL || default_profile->path == NULL) {
- free_profile(default_profile);
- return -ENOMEM;
- }
-
- default_profile->name = g_strdup("Default");
-
- __connman_storage_load_profile(default_profile);
-
- connman_info("Adding default profile");
-
- DBG("profile %p path %s", default_profile, default_profile->path);
-
- return 0;
-}
-
-static int profile_load(struct connman_profile *profile)
-{
- GKeyFile *keyfile;
- GError *error = NULL;
- connman_bool_t offlinemode;
- char *name;
-
- DBG("profile %p", profile);
-
- keyfile = __connman_storage_open_profile(profile->ident);
- if (keyfile == NULL)
- return -EIO;
-
- name = g_key_file_get_string(keyfile, "global", "Name", NULL);
- if (name != NULL) {
- g_free(profile->name);
- profile->name = name;
- }
-
- offlinemode = g_key_file_get_boolean(keyfile, "global",
- "OfflineMode", &error);
- if (error == NULL)
- profile->offlinemode = offlinemode;
- g_clear_error(&error);
-
- __connman_storage_close_profile(profile->ident, keyfile, FALSE);
-
- return 0;
-}
-
-static int profile_save(struct connman_profile *profile)
-{
- GKeyFile *keyfile;
-
- DBG("profile %p", profile);
-
- keyfile = __connman_storage_open_profile(profile->ident);
- if (keyfile == NULL)
- return -EIO;
-
- if (profile->name != NULL)
- g_key_file_set_string(keyfile, "global",
- "Name", profile->name);
-
- g_key_file_set_boolean(keyfile, "global",
- "OfflineMode", profile->offlinemode);
-
- __connman_storage_close_profile(profile->ident, keyfile, TRUE);
-
- return 0;
-}
-
-static struct connman_storage profile_storage = {
- .name = "profile",
- .priority = CONNMAN_STORAGE_PRIORITY_LOW,
- .profile_init = profile_init,
- .profile_load = profile_load,
- .profile_save = profile_save,
-};
-
-int __connman_profile_init(void)
-{
- DBG("");
-
- connection = connman_dbus_get_connection();
- if (connection == NULL)
- return -1;
-
- if (connman_storage_register(&profile_storage) < 0)
- connman_error("Failed to register profile storage");
-
- return 0;
-}
-
-void __connman_profile_cleanup(void)
-{
- DBG("");
-
- if (connection == NULL)
- return;
-
- connman_storage_unregister(&profile_storage);
-
- dbus_connection_unref(connection);
-}
};
struct connman_provider {
- gint refcount;
+ int refcount;
struct connman_service *vpn_service;
int index;
char *identifier;
&provider->type);
}
+static int connman_provider_load(struct connman_provider *provider)
+{
+ gsize idx = 0;
+ GKeyFile *keyfile;
+ gchar **settings;
+ gchar *key, *value;
+ gsize length;
+
+ DBG("provider %p", provider);
+
+ keyfile = __connman_storage_load_provider(provider->identifier);
+ if (keyfile == NULL)
+ return -ENOENT;
+
+ settings = g_key_file_get_keys(keyfile, provider->identifier, &length,
+ NULL);
+ if (settings == NULL) {
+ g_key_file_free(keyfile);
+ return -ENOENT;
+ }
+
+ while (idx < length) {
+ key = settings[idx];
+ DBG("found key %s", key);
+ if (key != NULL) {
+ value = g_key_file_get_string(keyfile,
+ provider->identifier,
+ key, NULL);
+ connman_provider_set_string(provider, key, value);
+ g_free(value);
+ }
+ idx += 1;
+ }
+ g_strfreev(settings);
+
+ g_key_file_free(keyfile);
+ return 0;
+}
+
+static int connman_provider_save(struct connman_provider *provider)
+{
+ GKeyFile *keyfile;
+
+ DBG("provider %p", provider);
+
+ keyfile = g_key_file_new();
+ if (keyfile == NULL)
+ return -ENOMEM;
+
+ g_key_file_set_string(keyfile, provider->identifier,
+ "Name", provider->name);
+ g_key_file_set_string(keyfile, provider->identifier,
+ "Type", provider->type);
+ g_key_file_set_string(keyfile, provider->identifier,
+ "Host", provider->host);
+ g_key_file_set_string(keyfile, provider->identifier,
+ "VPN.Domain", provider->domain);
+
+ if (provider->driver != NULL && provider->driver->save != NULL)
+ provider->driver->save(provider, keyfile);
+
+ __connman_storage_save_provider(keyfile, provider->identifier);
+ g_key_file_free(keyfile);
+
+ return 0;
+}
+
static struct connman_provider *connman_provider_lookup(const char *identifier)
{
struct connman_provider *provider = NULL;
static int provider_register(struct connman_provider *provider)
{
+ connman_provider_load(provider);
return provider_probe(provider);
}
struct connman_provider *connman_provider_ref(struct connman_provider *provider)
{
- DBG("provider %p", provider);
+ DBG("provider %p refcount %d", provider, provider->refcount + 1);
- g_atomic_int_inc(&provider->refcount);
+ __sync_fetch_and_add(&provider->refcount, 1);
return provider;
}
void connman_provider_unref(struct connman_provider *provider)
{
- DBG("provider %p", provider);
+ DBG("provider %p refcount %d", provider, provider->refcount - 1);
- if (g_atomic_int_dec_and_test(&provider->refcount) == FALSE)
+ if (__sync_fetch_and_sub(&provider->refcount, 1) != 1)
return;
provider_remove(provider);
enum connman_provider_error error)
{
enum connman_service_error service_error;
+ const char *path;
+ int ret;
switch (error) {
case CONNMAN_PROVIDER_ERROR_LOGIN_FAILED:
break;
}
- return __connman_service_indicate_error(provider->vpn_service,
+ ret = __connman_service_indicate_error(provider->vpn_service,
service_error);
+ path = __connman_service_get_path(provider->vpn_service);
+ __connman_provider_remove(path);
+
+ return ret;
}
static void unregister_provider(gpointer data)
provider->host = g_strdup(host);
provider->domain = g_strdup(domain);
+ g_free(provider->name);
provider->name = g_strdup(name);
provider->type = g_strdup(type);
err = -EOPNOTSUPP;
goto unref;
}
- }
- err = __connman_service_connect(provider->vpn_service);
- if (err < 0 && err != -EINPROGRESS)
- goto failed;
+ err = __connman_service_connect(provider->vpn_service);
+ if (err < 0 && err != -EINPROGRESS)
+ goto failed;
+ } else
+ DBG("provider already connected");
+ connman_provider_save(provider);
service_path = __connman_service_get_path(provider->vpn_service);
g_dbus_send_reply(connection, msg,
DBUS_TYPE_OBJECT_PATH, &service_path,
for (i = 0; nameservers_array[i] != NULL; i++) {
__connman_service_nameserver_append(provider->vpn_service,
- nameservers_array[i]);
+ nameservers_array[i], FALSE);
}
g_strfreev(nameservers_array);
const char *connman_provider_get_driver_name(struct connman_provider *provider)
{
+ if (provider->driver == NULL)
+ return NULL;
+
return provider->driver->name;
}
+const char *connman_provider_get_save_group(struct connman_provider *provider)
+{
+ return provider->identifier;
+}
+
static gint compare_priority(gconstpointer a, gconstpointer b)
{
return 0;
#include <config.h>
#endif
+#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
* Description: /etc path is read-only in SLP
* /opt/etc/resolve.conf rather than /etc/resolve.conf
*/
- fd = open("/opt/etc/resolv.conf", O_RDWR | O_CREAT,
+ fd = open("/opt/etc/resolv.conf", O_RDWR | O_CREAT | O_CLOEXEC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
#else
- fd = open("/etc/resolv.conf", O_RDWR | O_CREAT,
+ fd = open("/etc/resolv.conf", O_RDWR | O_CREAT | O_CLOEXEC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
#endif
if (fd < 0) {
{
struct entry_data *entry = user_data;
GSList *list;
+ int index;
DBG("interface %s domain %s server %s",
entry->interface, entry->domain, entry->server);
list = g_slist_append(NULL, entry);
+
+ index = connman_inet_ifindex(entry->interface);
+ if (index >= 0) {
+ struct connman_service *service;
+ service = __connman_service_lookup_from_index(index);
+ if (service != NULL)
+ __connman_service_nameserver_remove(service,
+ entry->server, TRUE);
+ }
+
remove_entries(list);
return FALSE;
entry->domain = g_strdup(domain);
entry->server = g_strdup(server);
entry->flags = flags;
- if (lifetime)
+ if (lifetime) {
+ int index;
entry->timeout = g_timeout_add_seconds(lifetime,
resolver_expire_cb, entry);
+ /*
+ * We update the service only for those nameservers
+ * that are automagically added via netlink (lifetime > 0)
+ */
+ index = connman_inet_ifindex(interface);
+ if (index >= 0) {
+ struct connman_service *service;
+ service = __connman_service_lookup_from_index(index);
+ if (service != NULL)
+ __connman_service_nameserver_append(service,
+ server, TRUE);
+ }
+ }
entry_list = g_slist_append(entry_list, entry);
if (dnsproxy_enabled == TRUE)
int connman_resolver_append(const char *interface, const char *domain,
const char *server)
{
+ GSList *list, *matches = NULL;
+
DBG("interface %s domain %s server %s", interface, domain, server);
+ if (server == NULL && domain == NULL)
+ return -EINVAL;
+
+ for (list = entry_list; list; list = list->next) {
+ struct entry_data *entry = list->data;
+
+ if (entry->timeout > 0 ||
+ g_strcmp0(entry->interface, interface) != 0 ||
+ g_strcmp0(entry->domain, domain) != 0 ||
+ g_strcmp0(entry->server, server) != 0)
+ continue;
+
+ matches = g_slist_append(matches, entry);
+ }
+
+ if (matches != NULL)
+ remove_entries(matches);
+
return append_resolver(interface, domain, server, 0, 0);
}
continue;
g_source_remove(entry->timeout);
+
+ if (lifetime == 0) {
+ resolver_expire_cb(entry);
+ return 0;
+ }
+
entry->timeout = g_timeout_add_seconds(lifetime,
resolver_expire_cb, entry);
return 0;
#include <config.h>
#endif
+#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
RFKILL_TYPE_WWAN,
RFKILL_TYPE_GPS,
RFKILL_TYPE_FM,
+ NUM_RFKILL_TYPES,
};
enum rfkill_operation {
return CONNMAN_SERVICE_TYPE_UNKNOWN;
}
+static enum rfkill_type convert_service_type(enum connman_service_type type)
+{
+ switch (type) {
+ case CONNMAN_SERVICE_TYPE_WIFI:
+ return RFKILL_TYPE_WLAN;
+ case CONNMAN_SERVICE_TYPE_BLUETOOTH:
+ return RFKILL_TYPE_BLUETOOTH;
+ case CONNMAN_SERVICE_TYPE_WIMAX:
+ return RFKILL_TYPE_WIMAX;
+ case CONNMAN_SERVICE_TYPE_CELLULAR:
+ return RFKILL_TYPE_WWAN;
+ case CONNMAN_SERVICE_TYPE_GPS:
+ return RFKILL_TYPE_GPS;
+ case CONNMAN_SERVICE_TYPE_SYSTEM:
+ case CONNMAN_SERVICE_TYPE_ETHERNET:
+ case CONNMAN_SERVICE_TYPE_VPN:
+ case CONNMAN_SERVICE_TYPE_GADGET:
+ case CONNMAN_SERVICE_TYPE_UNKNOWN:
+ return NUM_RFKILL_TYPES;
+ }
+
+ return NUM_RFKILL_TYPES;
+}
+
static GIOStatus rfkill_process(GIOChannel *chan)
{
unsigned char buf[32];
event->type, event->op,
event->soft, event->hard);
+ type = convert_type(event->type);
+
switch (event->op) {
case RFKILL_OP_ADD:
- type = convert_type(event->type);
__connman_technology_add_rfkill(event->idx, type,
event->soft, event->hard);
break;
case RFKILL_OP_DEL:
- __connman_technology_remove_rfkill(event->idx);
+ __connman_technology_remove_rfkill(event->idx, type);
break;
case RFKILL_OP_CHANGE:
- __connman_technology_update_rfkill(event->idx, event->soft,
- event->hard);
+ __connman_technology_update_rfkill(event->idx, type,
+ event->soft, event->hard);
break;
default:
break;
static GIOChannel *channel = NULL;
+int __connman_rfkill_block(enum connman_service_type type, connman_bool_t block)
+{
+ uint8_t rfkill_type;
+ struct rfkill_event event;
+ ssize_t len;
+ int fd;
+
+ DBG("type %d block %d", type, block);
+
+#if defined TIZEN_EXT
+ DBG("try to set rfkill block %d, but it's not permitted", block);
+#else
+ rfkill_type = convert_service_type(type);
+ if (rfkill_type == NUM_RFKILL_TYPES)
+ return -EINVAL;
+
+ fd = open("/dev/rfkill", O_RDWR | O_CLOEXEC);
+ if (fd < 0)
+ return fd;
+
+ memset(&event, 0, sizeof(event));
+ event.op = RFKILL_OP_CHANGE_ALL;
+ event.type = rfkill_type;
+ event.soft = block;
+
+ len = write(fd, &event, sizeof(event));
+ if (len < 0)
+ connman_error("Failed to change RFKILL state");
+
+ close(fd);
+#endif
+
+ return 0;
+}
+
int __connman_rfkill_init(void)
{
GIOFlags flags;
DBG("");
- fd = open("/dev/rfkill", O_RDWR);
+ fd = open("/dev/rfkill", O_RDWR | O_CLOEXEC);
if (fd < 0) {
connman_error("Failed to open RFKILL control device");
return -EIO;
struct iwreq wrq;
int fd, err;
- fd = socket(PF_INET, SOCK_DGRAM, 0);
+ fd = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (fd < 0)
return FALSE;
* Description: SLP requires ARPHRD_PPP PPP type device
*/
case ARPHRD_PPP:
+ DBG("interface index(%d)", index);
#endif
__connman_ipconfig_dellink(index, &stats);
break;
}
- DBG("interface index(%d)", index);
g_hash_table_remove(interface_list, GINT_TO_POINTER(index));
}
interface_list = g_hash_table_new_full(g_direct_hash, g_direct_equal,
NULL, free_interface);
- sk = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ sk = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_ROUTE);
if (sk < 0)
return -1;
#include <netdb.h>
#include <gdbus.h>
+#include <connman/storage.h>
+
#include "connman.h"
#define CONNECT_TIMEOUT 120
};
struct connman_service {
- gint refcount;
- gint session_usage_count;
+ int refcount;
+ int session_usage_count;
char *identifier;
char *path;
enum connman_service_type type;
char *name;
char *passphrase;
char *agent_passphrase;
- char *profile;
connman_bool_t roaming;
connman_bool_t login_required;
connman_bool_t network_created;
struct connman_provider *provider;
char **nameservers;
char **nameservers_config;
+ char **nameservers_auto;
char **domains;
char *domainname;
char **timeservers;
char *phase2;
DBusMessage *pending;
guint timeout;
- struct connman_location *location;
struct connman_stats stats;
struct connman_stats stats_roaming;
GHashTable *counter_table;
return CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
}
-static enum connman_service_state combine_state(
- enum connman_service_state state_a,
- enum connman_service_state state_b)
+static int service_load(struct connman_service *service)
{
- enum connman_service_state result;
+ GKeyFile *keyfile;
+ GError *error = NULL;
+ gsize length;
+ gchar *str;
+ connman_bool_t autoconnect;
+ unsigned int ssid_len;
+ int err = 0;
- if (state_a == state_b) {
- result = state_a;
- goto done;
- }
+ DBG("service %p", service);
- if (state_a == CONNMAN_SERVICE_STATE_UNKNOWN) {
- result = state_b;
- goto done;
- }
+ keyfile = connman_storage_load_service(service->identifier);
+ if (keyfile == NULL)
+ return -EIO;
- if (state_b == CONNMAN_SERVICE_STATE_UNKNOWN) {
- result = state_a;
- goto done;
- }
+ switch (service->type) {
+ case CONNMAN_SERVICE_TYPE_UNKNOWN:
+ case CONNMAN_SERVICE_TYPE_SYSTEM:
+ case CONNMAN_SERVICE_TYPE_ETHERNET:
+ case CONNMAN_SERVICE_TYPE_GPS:
+ case CONNMAN_SERVICE_TYPE_VPN:
+ case CONNMAN_SERVICE_TYPE_GADGET:
+#if defined TIZEN_EXT
+ case CONNMAN_SERVICE_TYPE_CELLULAR:
+#endif
+ break;
+ case CONNMAN_SERVICE_TYPE_WIFI:
+ if (service->name == NULL) {
+ gchar *name;
- if (state_a == CONNMAN_SERVICE_STATE_IDLE) {
- result = state_b;
- goto done;
- }
+ name = g_key_file_get_string(keyfile,
+ service->identifier, "Name", NULL);
+ if (name != NULL) {
+ g_free(service->name);
+ service->name = name;
+ }
- if (state_b == CONNMAN_SERVICE_STATE_IDLE) {
- result = state_a;
- goto done;
- }
+ if (service->network != NULL)
+ connman_network_set_name(service->network,
+ name);
+ }
- if (state_a == CONNMAN_SERVICE_STATE_ASSOCIATION) {
- if (state_b == CONNMAN_SERVICE_STATE_CONFIGURATION ||
- state_b == CONNMAN_SERVICE_STATE_ONLINE ||
- state_b == CONNMAN_SERVICE_STATE_READY)
- result = state_b;
- else
- result = state_a;
- goto done;
- }
+ if (service->network &&
+ connman_network_get_blob(service->network,
+ "WiFi.SSID", &ssid_len) == NULL) {
+ gchar *hex_ssid;
- if (state_b == CONNMAN_SERVICE_STATE_ASSOCIATION) {
- if (state_a == CONNMAN_SERVICE_STATE_CONFIGURATION ||
- state_a == CONNMAN_SERVICE_STATE_ONLINE ||
- state_a == CONNMAN_SERVICE_STATE_READY)
- result = state_a;
- else
- result = state_b;
- goto done;
- }
+ hex_ssid = g_key_file_get_string(keyfile,
+ service->identifier,
+ "SSID", NULL);
- if (state_a == CONNMAN_SERVICE_STATE_CONFIGURATION) {
- if (state_b == CONNMAN_SERVICE_STATE_ONLINE ||
- state_b == CONNMAN_SERVICE_STATE_READY)
- result = state_b;
- else
- result = state_a;
- goto done;
- }
+ if (hex_ssid != NULL) {
+ gchar *ssid;
+ unsigned int i, j = 0, hex;
+ size_t hex_ssid_len = strlen(hex_ssid);
- if (state_b == CONNMAN_SERVICE_STATE_CONFIGURATION) {
- if (state_a == CONNMAN_SERVICE_STATE_ONLINE ||
- state_a == CONNMAN_SERVICE_STATE_READY)
- result = state_a;
- else
- result = state_b;
- goto done;
- }
+ ssid = g_try_malloc0(hex_ssid_len / 2);
+ if (ssid == NULL) {
+ g_free(hex_ssid);
+ err = -ENOMEM;
+ goto done;
+ }
- if (state_a == CONNMAN_SERVICE_STATE_READY) {
- if (state_b == CONNMAN_SERVICE_STATE_ONLINE ||
- state_b == CONNMAN_SERVICE_STATE_DISCONNECT)
- result = state_b;
- else
- result = state_a;
- goto done;
- }
+ for (i = 0; i < hex_ssid_len; i += 2) {
+ sscanf(hex_ssid + i, "%02x", &hex);
+ ssid[j++] = hex;
+ }
- if (state_b == CONNMAN_SERVICE_STATE_READY) {
- if (state_a == CONNMAN_SERVICE_STATE_ONLINE ||
- state_a == CONNMAN_SERVICE_STATE_DISCONNECT)
- result = state_a;
- else
- result = state_b;
- goto done;
+ connman_network_set_blob(service->network,
+ "WiFi.SSID", ssid, hex_ssid_len / 2);
+ }
+
+ g_free(hex_ssid);
+ }
+ /* fall through */
+
+ case CONNMAN_SERVICE_TYPE_WIMAX:
+ case CONNMAN_SERVICE_TYPE_BLUETOOTH:
+#if !defined TIZEN_EXT
+ case CONNMAN_SERVICE_TYPE_CELLULAR:
+#endif
+ service->favorite = g_key_file_get_boolean(keyfile,
+ service->identifier, "Favorite", NULL);
+
+ autoconnect = g_key_file_get_boolean(keyfile,
+ service->identifier, "AutoConnect", &error);
+ if (error == NULL)
+ service->autoconnect = autoconnect;
+ g_clear_error(&error);
+
+ str = g_key_file_get_string(keyfile,
+ service->identifier, "Failure", NULL);
+ if (str != NULL) {
+ if (service->favorite == FALSE)
+ service->state_ipv4 = service->state_ipv6 =
+ CONNMAN_SERVICE_STATE_FAILURE;
+ service->error = string2error(str);
+ g_free(str);
+ }
+ break;
}
- if (state_a == CONNMAN_SERVICE_STATE_ONLINE) {
- if (state_b == CONNMAN_SERVICE_STATE_DISCONNECT)
- result = state_b;
- else
- result = state_a;
- goto done;
+ str = g_key_file_get_string(keyfile,
+ service->identifier, "Modified", NULL);
+ if (str != NULL) {
+ g_time_val_from_iso8601(str, &service->modified);
+ g_free(str);
}
- if (state_b == CONNMAN_SERVICE_STATE_ONLINE) {
- if (state_a == CONNMAN_SERVICE_STATE_DISCONNECT)
- result = state_a;
- else
- result = state_b;
- goto done;
+ str = g_key_file_get_string(keyfile,
+ service->identifier, "Passphrase", NULL);
+ if (str != NULL) {
+ g_free(service->passphrase);
+ service->passphrase = str;
}
- if (state_a == CONNMAN_SERVICE_STATE_DISCONNECT) {
- result = state_a;
- goto done;
+ if (service->ipconfig_ipv4 != NULL)
+ __connman_ipconfig_load(service->ipconfig_ipv4, keyfile,
+ service->identifier, "IPv4.");
+
+ if (service->ipconfig_ipv6 != NULL)
+ __connman_ipconfig_load(service->ipconfig_ipv6, keyfile,
+ service->identifier, "IPv6.");
+
+ service->nameservers_config = g_key_file_get_string_list(keyfile,
+ service->identifier, "Nameservers", &length, NULL);
+ if (service->nameservers_config != NULL && length == 0) {
+ g_strfreev(service->nameservers_config);
+ service->nameservers_config = NULL;
}
- if (state_b == CONNMAN_SERVICE_STATE_DISCONNECT) {
- result = state_b;
- goto done;
+ service->domains = g_key_file_get_string_list(keyfile,
+ service->identifier, "Domains", &length, NULL);
+ if (service->domains != NULL && length == 0) {
+ g_strfreev(service->domains);
+ service->domains = NULL;
}
- result = CONNMAN_SERVICE_STATE_FAILURE;
+ str = g_key_file_get_string(keyfile,
+ service->identifier, "Proxy.Method", NULL);
+ if (str != NULL)
+ service->proxy_config = string2proxymethod(str);
-done:
- return result;
-}
+ g_free(str);
-static connman_bool_t is_connecting_state(struct connman_service *service,
- enum connman_service_state state)
-{
- switch (state) {
- case CONNMAN_SERVICE_STATE_UNKNOWN:
- case CONNMAN_SERVICE_STATE_IDLE:
- case CONNMAN_SERVICE_STATE_FAILURE:
- if (service->network != NULL)
- return connman_network_get_connecting(service->network);
- case CONNMAN_SERVICE_STATE_DISCONNECT:
- case CONNMAN_SERVICE_STATE_READY:
- case CONNMAN_SERVICE_STATE_ONLINE:
- break;
- case CONNMAN_SERVICE_STATE_ASSOCIATION:
- case CONNMAN_SERVICE_STATE_CONFIGURATION:
- return TRUE;
+ service->proxies = g_key_file_get_string_list(keyfile,
+ service->identifier, "Proxy.Servers", &length, NULL);
+ if (service->proxies != NULL && length == 0) {
+ g_strfreev(service->proxies);
+ service->proxies = NULL;
}
- return FALSE;
-}
+ service->excludes = g_key_file_get_string_list(keyfile,
+ service->identifier, "Proxy.Excludes", &length, NULL);
+ if (service->excludes != NULL && length == 0) {
+ g_strfreev(service->excludes);
+ service->excludes = NULL;
+ }
-static connman_bool_t is_connected_state(const struct connman_service *service,
- enum connman_service_state state)
-{
- switch (state) {
- case CONNMAN_SERVICE_STATE_UNKNOWN:
- case CONNMAN_SERVICE_STATE_IDLE:
- case CONNMAN_SERVICE_STATE_ASSOCIATION:
- case CONNMAN_SERVICE_STATE_CONFIGURATION:
- case CONNMAN_SERVICE_STATE_DISCONNECT:
- case CONNMAN_SERVICE_STATE_FAILURE:
- break;
- case CONNMAN_SERVICE_STATE_READY:
- case CONNMAN_SERVICE_STATE_ONLINE:
- return TRUE;
+ str = g_key_file_get_string(keyfile,
+ service->identifier, "Proxy.URL", NULL);
+ if (str != NULL) {
+ g_free(service->pac);
+ service->pac = str;
}
- return FALSE;
-}
+done:
+ g_key_file_free(keyfile);
-static connman_bool_t is_connecting(struct connman_service *service)
-{
- return is_connecting_state(service, service->state);
+ return err;
}
-static connman_bool_t is_connected(struct connman_service *service)
+static int service_save(struct connman_service *service)
{
- return is_connected_state(service, service->state);
-}
+ GKeyFile *keyfile;
+ gchar *str;
+ guint freq;
+ const char *cst_str = NULL;
+ int err = 0;
-static void update_nameservers(struct connman_service *service)
-{
- const char *ifname;
+ DBG("service %p", service);
- if (service->ipconfig_ipv4)
- ifname = connman_ipconfig_get_ifname(service->ipconfig_ipv4);
- else if (service->ipconfig_ipv6)
- ifname = connman_ipconfig_get_ifname(service->ipconfig_ipv6);
+ keyfile = __connman_storage_open_service(service->identifier);
+ if (keyfile == NULL)
+ return -EIO;
+
+ if (service->name != NULL)
+ g_key_file_set_string(keyfile, service->identifier,
+ "Name", service->name);
+
+ switch (service->type) {
+ case CONNMAN_SERVICE_TYPE_UNKNOWN:
+ case CONNMAN_SERVICE_TYPE_SYSTEM:
+ case CONNMAN_SERVICE_TYPE_ETHERNET:
+ case CONNMAN_SERVICE_TYPE_GPS:
+ case CONNMAN_SERVICE_TYPE_VPN:
+ case CONNMAN_SERVICE_TYPE_GADGET:
+ break;
+ case CONNMAN_SERVICE_TYPE_WIFI:
+ if (service->network) {
+ const unsigned char *ssid;
+ unsigned int ssid_len = 0;
+
+ ssid = connman_network_get_blob(service->network,
+ "WiFi.SSID", &ssid_len);
+
+ if (ssid != NULL && ssid_len > 0 && ssid[0] != '\0') {
+ char *identifier = service->identifier;
+ GString *str;
+ unsigned int i;
+
+ str = g_string_sized_new(ssid_len * 2);
+ if (str == NULL) {
+ err = -ENOMEM;
+ goto done;
+ }
+
+ for (i = 0; i < ssid_len; i++)
+ g_string_append_printf(str,
+ "%02x", ssid[i]);
+
+ g_key_file_set_string(keyfile, identifier,
+ "SSID", str->str);
+
+ g_string_free(str, TRUE);
+ }
+
+ freq = connman_network_get_frequency(service->network);
+ g_key_file_set_integer(keyfile, service->identifier,
+ "Frequency", freq);
+ }
+ /* fall through */
+
+ case CONNMAN_SERVICE_TYPE_WIMAX:
+ case CONNMAN_SERVICE_TYPE_BLUETOOTH:
+ case CONNMAN_SERVICE_TYPE_CELLULAR:
+ g_key_file_set_boolean(keyfile, service->identifier,
+ "Favorite", service->favorite);
+
+ if (service->favorite == TRUE)
+ g_key_file_set_boolean(keyfile, service->identifier,
+ "AutoConnect", service->autoconnect);
+
+ if (service->state_ipv4 == CONNMAN_SERVICE_STATE_FAILURE ||
+ service->state_ipv6 == CONNMAN_SERVICE_STATE_FAILURE) {
+ const char *failure = error2string(service->error);
+ if (failure != NULL)
+ g_key_file_set_string(keyfile,
+ service->identifier,
+ "Failure", failure);
+ } else {
+ g_key_file_remove_key(keyfile, service->identifier,
+ "Failure", NULL);
+ }
+ break;
+ }
+
+ str = g_time_val_to_iso8601(&service->modified);
+ if (str != NULL) {
+ g_key_file_set_string(keyfile, service->identifier,
+ "Modified", str);
+ g_free(str);
+ }
+
+ if (service->passphrase != NULL && strlen(service->passphrase) > 0)
+ g_key_file_set_string(keyfile, service->identifier,
+ "Passphrase", service->passphrase);
+ else
+ g_key_file_remove_key(keyfile, service->identifier,
+ "Passphrase", NULL);
+
+ if (service->ipconfig_ipv4 != NULL)
+ __connman_ipconfig_save(service->ipconfig_ipv4, keyfile,
+ service->identifier, "IPv4.");
+
+ if (service->ipconfig_ipv6 != NULL)
+ __connman_ipconfig_save(service->ipconfig_ipv6, keyfile,
+ service->identifier, "IPv6.");
+
+ if (service->nameservers_config != NULL) {
+ guint len = g_strv_length(service->nameservers_config);
+
+ g_key_file_set_string_list(keyfile, service->identifier,
+ "Nameservers",
+ (const gchar **) service->nameservers_config, len);
+ } else
+ g_key_file_remove_key(keyfile, service->identifier,
+ "Nameservers", NULL);
+
+ if (service->domains != NULL) {
+ guint len = g_strv_length(service->domains);
+
+ g_key_file_set_string_list(keyfile, service->identifier,
+ "Domains",
+ (const gchar **) service->domains, len);
+ } else
+ g_key_file_remove_key(keyfile, service->identifier,
+ "Domains", NULL);
+
+ cst_str = proxymethod2string(service->proxy_config);
+ if (cst_str != NULL)
+ g_key_file_set_string(keyfile, service->identifier,
+ "Proxy.Method", cst_str);
+
+ if (service->proxies != NULL) {
+ guint len = g_strv_length(service->proxies);
+
+ g_key_file_set_string_list(keyfile, service->identifier,
+ "Proxy.Servers",
+ (const gchar **) service->proxies, len);
+ } else
+ g_key_file_remove_key(keyfile, service->identifier,
+ "Proxy.Servers", NULL);
+
+ if (service->excludes != NULL) {
+ guint len = g_strv_length(service->excludes);
+
+ g_key_file_set_string_list(keyfile, service->identifier,
+ "Proxy.Excludes",
+ (const gchar **) service->excludes, len);
+ } else
+ g_key_file_remove_key(keyfile, service->identifier,
+ "Proxy.Excludes", NULL);
+
+ if (service->pac != NULL && strlen(service->pac) > 0)
+ g_key_file_set_string(keyfile, service->identifier,
+ "Proxy.URL", service->pac);
+ else
+ g_key_file_remove_key(keyfile, service->identifier,
+ "Proxy.URL", NULL);
+
+done:
+ __connman_storage_save_service(keyfile, service->identifier);
+
+ g_key_file_free(keyfile);
+
+ return err;
+}
+
+static guint changed_timeout = 0;
+
+static gboolean notify_services_changed(gpointer user_data)
+{
+ changed_timeout = 0;
+
+ connman_dbus_property_changed_array(CONNMAN_MANAGER_PATH,
+ CONNMAN_MANAGER_INTERFACE, "Services",
+ DBUS_TYPE_OBJECT_PATH, __connman_service_list,
+ NULL);
+
+ return FALSE;
+}
+
+static void services_changed(gboolean delayed)
+{
+ DBG("");
+
+ if (changed_timeout > 0) {
+ g_source_remove(changed_timeout);
+ changed_timeout = 0;
+ }
+
+ if (__connman_connection_update_gateway() == TRUE) {
+ notify_services_changed(NULL);
+ return;
+ }
+
+ if (delayed == FALSE) {
+ notify_services_changed(NULL);
+ return;
+ }
+
+ changed_timeout = g_timeout_add_seconds(1, notify_services_changed,
+ NULL);
+}
+
+static enum connman_service_state combine_state(
+ enum connman_service_state state_a,
+ enum connman_service_state state_b)
+{
+ enum connman_service_state result;
+
+ if (state_a == state_b) {
+ result = state_a;
+ goto done;
+ }
+
+ if (state_a == CONNMAN_SERVICE_STATE_UNKNOWN) {
+ result = state_b;
+ goto done;
+ }
+
+ if (state_b == CONNMAN_SERVICE_STATE_UNKNOWN) {
+ result = state_a;
+ goto done;
+ }
+
+ if (state_a == CONNMAN_SERVICE_STATE_IDLE) {
+ result = state_b;
+ goto done;
+ }
+
+ if (state_b == CONNMAN_SERVICE_STATE_IDLE) {
+ result = state_a;
+ goto done;
+ }
+
+ if (state_a == CONNMAN_SERVICE_STATE_ONLINE) {
+ result = state_a;
+ goto done;
+ }
+
+ if (state_b == CONNMAN_SERVICE_STATE_ONLINE) {
+ result = state_b;
+ goto done;
+ }
+
+ if (state_a == CONNMAN_SERVICE_STATE_READY) {
+ result = state_a;
+ goto done;
+ }
+
+ if (state_b == CONNMAN_SERVICE_STATE_READY) {
+ result = state_b;
+ goto done;
+ }
+
+ if (state_a == CONNMAN_SERVICE_STATE_CONFIGURATION) {
+ result = state_a;
+ goto done;
+ }
+
+ if (state_b == CONNMAN_SERVICE_STATE_CONFIGURATION) {
+ result = state_b;
+ goto done;
+ }
+
+ if (state_a == CONNMAN_SERVICE_STATE_ASSOCIATION) {
+ result = state_a;
+ goto done;
+ }
+
+ if (state_b == CONNMAN_SERVICE_STATE_ASSOCIATION) {
+ result = state_b;
+ goto done;
+ }
+
+ if (state_a == CONNMAN_SERVICE_STATE_DISCONNECT) {
+ result = state_a;
+ goto done;
+ }
+
+ if (state_b == CONNMAN_SERVICE_STATE_DISCONNECT) {
+ result = state_b;
+ goto done;
+ }
+
+ result = CONNMAN_SERVICE_STATE_FAILURE;
+
+done:
+ return result;
+}
+
+static connman_bool_t is_connecting_state(struct connman_service *service,
+ enum connman_service_state state)
+{
+ switch (state) {
+ case CONNMAN_SERVICE_STATE_UNKNOWN:
+ case CONNMAN_SERVICE_STATE_IDLE:
+ case CONNMAN_SERVICE_STATE_FAILURE:
+ if (service->network != NULL)
+ return connman_network_get_connecting(service->network);
+ case CONNMAN_SERVICE_STATE_DISCONNECT:
+ case CONNMAN_SERVICE_STATE_READY:
+ case CONNMAN_SERVICE_STATE_ONLINE:
+ break;
+ case CONNMAN_SERVICE_STATE_ASSOCIATION:
+ case CONNMAN_SERVICE_STATE_CONFIGURATION:
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static connman_bool_t is_connected_state(const struct connman_service *service,
+ enum connman_service_state state)
+{
+ switch (state) {
+ case CONNMAN_SERVICE_STATE_UNKNOWN:
+ case CONNMAN_SERVICE_STATE_IDLE:
+ case CONNMAN_SERVICE_STATE_ASSOCIATION:
+ case CONNMAN_SERVICE_STATE_CONFIGURATION:
+ case CONNMAN_SERVICE_STATE_DISCONNECT:
+ case CONNMAN_SERVICE_STATE_FAILURE:
+ break;
+ case CONNMAN_SERVICE_STATE_READY:
+ case CONNMAN_SERVICE_STATE_ONLINE:
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static connman_bool_t is_connecting(struct connman_service *service)
+{
+ return is_connecting_state(service, service->state);
+}
+
+static connman_bool_t is_connected(struct connman_service *service)
+{
+ return is_connected_state(service, service->state);
+}
+
+static void update_nameservers(struct connman_service *service)
+{
+ const char *ifname;
+
+ if (service->ipconfig_ipv4)
+ ifname = connman_ipconfig_get_ifname(service->ipconfig_ipv4);
+ else if (service->ipconfig_ipv6)
+ ifname = connman_ipconfig_get_ifname(service->ipconfig_ipv6);
else
ifname = NULL;
break;
}
- connman_resolver_remove_all(ifname);
-
if (service->nameservers_config != NULL) {
int i;
connman_resolver_flush();
}
+/*
+ * The is_auto variable is set to true when IPv6 autoconf nameservers are
+ * inserted to resolver via netlink message (see rtnl.c:rtnl_newnduseropt()
+ * for details) and not through service.c
+ */
int __connman_service_nameserver_append(struct connman_service *service,
- const char *nameserver)
+ const char *nameserver, gboolean is_auto)
{
- int len;
+ char **nameservers;
+ int len, i;
- DBG("service %p nameserver %s", service, nameserver);
+ DBG("service %p nameserver %s auto %d", service, nameserver, is_auto);
if (nameserver == NULL)
return -EINVAL;
- if (service->nameservers != NULL) {
- int i;
+ if (is_auto == TRUE)
+ nameservers = service->nameservers_auto;
+ else
+ nameservers = service->nameservers;
- for (i = 0; service->nameservers[i] != NULL; i++)
- if (g_strcmp0(service->nameservers[i], nameserver) == 0)
- return -EEXIST;
+ for (i = 0; nameservers != NULL && nameservers[i] != NULL; i++)
+ if (g_strcmp0(nameservers[i], nameserver) == 0)
+ return -EEXIST;
- len = g_strv_length(service->nameservers);
- service->nameservers = g_try_renew(char *, service->nameservers,
- len + 2);
+ if (nameservers != NULL) {
+ len = g_strv_length(nameservers);
+ nameservers = g_try_renew(char *, nameservers, len + 2);
} else {
len = 0;
- service->nameservers = g_try_new0(char *, len + 2);
+ nameservers = g_try_new0(char *, len + 2);
}
- if (service->nameservers == NULL)
+ if (nameservers == NULL)
return -ENOMEM;
- service->nameservers[len] = g_strdup(nameserver);
- service->nameservers[len + 1] = NULL;
+ nameservers[len] = g_strdup(nameserver);
+ if (nameservers[len] == NULL)
+ return -ENOMEM;
- update_nameservers(service);
+ nameservers[len + 1] = NULL;
+
+ if (is_auto == TRUE) {
+ service->nameservers_auto = nameservers;
+ } else {
+ service->nameservers = nameservers;
+ update_nameservers(service);
+ }
return 0;
}
int __connman_service_nameserver_remove(struct connman_service *service,
- const char *nameserver)
+ const char *nameserver, gboolean is_auto)
{
- char **servers;
+ char **servers, **nameservers;
+ gboolean found = FALSE;
int len, i, j;
- DBG("service %p nameserver %s", service, nameserver);
+ DBG("service %p nameserver %s auto %d", service, nameserver, is_auto);
if (nameserver == NULL)
return -EINVAL;
- if (service->nameservers == NULL)
+ if (is_auto == TRUE)
+ nameservers = service->nameservers_auto;
+ else
+ nameservers = service->nameservers;
+
+ if (nameservers == NULL)
return 0;
- len = g_strv_length(service->nameservers);
- if (len == 1) {
- if (g_strcmp0(service->nameservers[0], nameserver) != 0)
- return 0;
+ for (i = 0; nameservers != NULL && nameservers[i] != NULL; i++)
+ if (g_strcmp0(nameservers[i], nameserver) == 0) {
+ found = TRUE;
+ break;
+ }
+
+ if (found == FALSE)
+ return 0;
- g_strfreev(service->nameservers);
- service->nameservers = NULL;
+ len = g_strv_length(nameservers);
+
+ if (len == 1) {
+ g_strfreev(nameservers);
+ if (is_auto == TRUE)
+ service->nameservers_auto = NULL;
+ else
+ service->nameservers = NULL;
return 0;
}
return -ENOMEM;
for (i = 0, j = 0; i < len; i++) {
- if (g_strcmp0(service->nameservers[i], nameserver) != 0) {
- servers[j] = g_strdup(service->nameservers[i]);
+ if (g_strcmp0(nameservers[i], nameserver) != 0) {
+ servers[j] = g_strdup(nameservers[i]);
+ if (servers[j] == NULL)
+ return -ENOMEM;
j++;
}
}
servers[len - 1] = NULL;
- g_strfreev(service->nameservers);
- service->nameservers = servers;
+ g_strfreev(nameservers);
+ nameservers = servers;
- update_nameservers(service);
+ if (is_auto == TRUE) {
+ service->nameservers_auto = nameservers;
+ } else {
+ service->nameservers = nameservers;
+ update_nameservers(service);
+ }
return 0;
}
dbus_message_iter_append_basic(iter,
DBUS_TYPE_STRING, &str);
- str = "wps";
- if (service->wps == TRUE)
- dbus_message_iter_append_basic(iter,
- DBUS_TYPE_STRING, &str);
+ /*
+ * Some access points incorrectly advertise WPS even when they
+ * are configured as open or no security, so filter
+ * appropriately.
+ */
+ if (service->wps == TRUE) {
+ switch (service->security) {
+ case CONNMAN_SERVICE_SECURITY_PSK:
+ case CONNMAN_SERVICE_SECURITY_WPA:
+ case CONNMAN_SERVICE_SECURITY_RSN:
+ str = "wps";
+ dbus_message_iter_append_basic(iter,
+ DBUS_TYPE_STRING, &str);
+ break;
+ case CONNMAN_SERVICE_SECURITY_UNKNOWN:
+ case CONNMAN_SERVICE_SECURITY_NONE:
+ case CONNMAN_SERVICE_SECURITY_WEP:
+ case CONNMAN_SERVICE_SECURITY_8021X:
+ break;
+ }
+ }
}
static void append_ethernet(DBusMessageIter *iter, void *user_data)
if (service->nameservers_config != NULL) {
append_nameserver(iter, &service->nameservers_config);
return;
- } else if (service->nameservers != NULL) {
- append_nameserver(iter, &service->nameservers);
- return;
+ } else {
+ if (service->nameservers != NULL)
+ append_nameserver(iter, &service->nameservers);
+
+ if (service->nameservers_auto != NULL)
+ append_nameserver(iter, &service->nameservers_auto);
}
}
void __connman_service_session_inc(struct connman_service *service)
{
DBG("service %p ref count %d", service,
- g_atomic_int_get(&service->session_usage_count) + 1);
+ service->session_usage_count + 1);
- g_atomic_int_inc(&service->session_usage_count);
+ __sync_fetch_and_add(&service->session_usage_count, 1);
}
connman_bool_t __connman_service_session_dec(struct connman_service *service)
{
DBG("service %p ref count %d", service,
- g_atomic_int_get(&service->session_usage_count) - 1);
+ service->session_usage_count - 1);
- if (g_atomic_int_dec_and_test(&service->session_usage_count) == FALSE)
+ if (__sync_fetch_and_sub(&service->session_usage_count, 1) != 1)
return FALSE;
return TRUE;
connman_dbus_dict_append_basic(dict, "Roaming",
DBUS_TYPE_BOOLEAN, &service->roaming);
- required = FALSE;
- connman_dbus_dict_append_basic(dict, "SetupRequired",
- DBUS_TYPE_BOOLEAN, &required);
connman_dbus_dict_append_dict(dict, "Ethernet",
append_ethernet, service);
break;
"WiFi.Passphrase",
service->passphrase);
- __connman_storage_save_service(service);
+ service_save(service);
}
void __connman_service_set_agent_passphrase(struct connman_service *service,
autoconnect_changed(service);
- __connman_storage_save_service(service);
+ service_save(service);
} else if (g_str_equal(name, "Passphrase") == TRUE) {
const char *passphrase;
update_nameservers(service);
dns_configuration_changed(service);
- __connman_storage_save_service(service);
+ service_save(service);
} else if (g_str_equal(name, "Domains.Configuration") == TRUE) {
DBusMessageIter entry;
GString *str;
update_nameservers(service);
domain_configuration_changed(service);
- __connman_storage_save_service(service);
+ service_save(service);
} else if (g_str_equal(name, "Proxy.Configuration") == TRUE) {
int err;
__connman_notifier_proxy_changed(service);
- __connman_storage_save_service(service);
+ service_save(service);
} else if (g_str_equal(name, "IPv4.Configuration") == TRUE ||
g_str_equal(name, "IPv6.Configuration")) {
__connman_network_set_ipconfig(service->network,
ipv4, ipv6);
- __connman_storage_save_service(service);
+ service_save(service);
} else
return __connman_error_invalid_property(msg);
set_idle(service);
g_get_current_time(&service->modified);
- __connman_storage_save_service(service);
+ service_save(service);
} else if (g_str_equal(name, "Passphrase") == TRUE) {
if (service->immutable == TRUE)
return __connman_error_not_supported(msg);
passphrase_changed(service);
- __connman_storage_save_service(service);
+ service_save(service);
} else
return __connman_error_invalid_property(msg);
__connman_device_set_reconnect(device, reconnect);
}
-static connman_bool_t get_reconnect_state(struct connman_service *service)
-{
- struct connman_device *device;
-
- if (service->network == NULL)
- return FALSE;
-
- device = connman_network_get_device(service->network);
- if (device == NULL)
- return FALSE;
-
- return __connman_device_get_reconnect(device);
-}
-
-static void request_input_cb (struct connman_service *service,
- const char *identity, const char *passphrase,
- void *user_data)
-{
- DBG ("RequestInput return, %p", service);
-
- if (identity == NULL && passphrase == NULL && service->wps == FALSE)
- return;
-
- if (identity != NULL)
- __connman_service_set_agent_identity(service, identity);
+static connman_bool_t get_reconnect_state(struct connman_service *service)
+{
+ struct connman_device *device;
- if (passphrase != NULL) {
- switch (service->security) {
- case CONNMAN_SERVICE_SECURITY_WEP:
- case CONNMAN_SERVICE_SECURITY_PSK:
- __connman_service_set_passphrase(service, passphrase);
- break;
- case CONNMAN_SERVICE_SECURITY_8021X:
- __connman_service_set_agent_passphrase(service,
- passphrase);
- break;
- case CONNMAN_SERVICE_SECURITY_UNKNOWN:
- case CONNMAN_SERVICE_SECURITY_NONE:
- case CONNMAN_SERVICE_SECURITY_WPA:
- case CONNMAN_SERVICE_SECURITY_RSN:
- DBG("service security '%s' not handled",
- security2string(service->security));
- break;
- }
- }
+ if (service->network == NULL)
+ return FALSE;
- __connman_service_connect(service);
+ device = connman_network_get_device(service->network);
+ if (device == NULL)
+ return FALSE;
- /* Never cache agent provided credentials */
- __connman_service_set_agent_identity(service, NULL);
- __connman_service_set_agent_passphrase(service, NULL);
+ return __connman_device_get_reconnect(device);
}
static DBusMessage *connect_service(DBusConnection *conn,
CONNMAN_SERVICE_STATE_FAILURE)
return __connman_error_not_supported(msg);
- if (service->network != NULL) {
- set_reconnect_state(service, FALSE);
+ set_reconnect_state(service, FALSE);
- __connman_network_disconnect(service->network);
- }
+ __connman_service_disconnect(service);
g_free(service->passphrase);
service->passphrase = NULL;
set_idle(service);
__connman_service_set_favorite(service, FALSE);
- __connman_storage_save_service(service);
+ service_save(service);
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
return a == b;
}
+static void downgrade_state(struct connman_service *service)
+{
+ if (service == NULL)
+ return;
+
+ DBG("service %p state4 %d state6 %d", service, service->state_ipv4,
+ service->state_ipv6);
+
+ if (service->state_ipv4 == CONNMAN_SERVICE_STATE_ONLINE)
+ __connman_service_ipconfig_indicate_state(service,
+ CONNMAN_SERVICE_STATE_READY,
+ CONNMAN_IPCONFIG_TYPE_IPV4);
+
+ if (service->state_ipv6 == CONNMAN_SERVICE_STATE_ONLINE)
+ __connman_service_ipconfig_indicate_state(service,
+ CONNMAN_SERVICE_STATE_READY,
+ CONNMAN_IPCONFIG_TYPE_IPV6);
+}
+
+static void apply_relevant_default_downgrade(struct connman_service *service)
+{
+ struct connman_service *def_service;
+
+ def_service = get_default();
+ if (def_service == NULL)
+ return;
+
+ if (def_service == service &&
+ def_service->state == CONNMAN_SERVICE_STATE_ONLINE)
+ def_service->state = CONNMAN_SERVICE_STATE_READY;
+}
+
static DBusMessage *move_service(DBusConnection *conn,
DBusMessage *msg, void *user_data,
gboolean before)
return __connman_error_not_supported(msg);
target = find_service(path);
- if (target == NULL || target->favorite == FALSE || target == service)
+ if (target == NULL || target->favorite == FALSE || target == service ||
+ target->type == CONNMAN_SERVICE_TYPE_VPN)
return __connman_error_invalid_service(msg);
target4 = __connman_ipconfig_get_method(target->ipconfig_ipv4);
}
g_get_current_time(&service->modified);
- __connman_storage_save_service(service);
+ service_save(service);
src = g_hash_table_lookup(service_hash, service->identifier);
dst = g_hash_table_lookup(service_hash, target->identifier);
- before ? g_sequence_move(src, dst) : g_sequence_move(dst, src);
+ /*
+ * If the service which goes down is the default service and is
+ * online, we downgrade directly its state to ready so:
+ * the service which goes up, needs to recompute its state which
+ * is triggered via downgrading it - if relevant - to state ready.
+ */
+ if (before == TRUE) {
+ apply_relevant_default_downgrade(target);
+ g_sequence_move(src, dst);
+ downgrade_state(service);
+ } else {
+ apply_relevant_default_downgrade(service);
+ g_sequence_move(dst, src);
+ downgrade_state(target);
+ }
- __connman_profile_changed(FALSE);
+ services_changed(FALSE);
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
__connman_notifier_service_remove(service);
stats_stop(service);
- __connman_storage_save_service(service);
service->path = NULL;
if (path != NULL) {
- __connman_profile_changed(FALSE);
+ services_changed(FALSE);
g_dbus_unregister_interface(connection, path,
CONNMAN_SERVICE_INTERFACE);
service->ipconfig_ipv6 = NULL;
}
- if (service->location != NULL)
- connman_location_unref(service->location);
-
g_strfreev(service->nameservers);
g_strfreev(service->nameservers_config);
+ g_strfreev(service->nameservers_auto);
g_strfreev(service->domains);
g_strfreev(service->proxies);
g_strfreev(service->excludes);
g_free(service->domainname);
g_free(service->pac);
- g_free(service->profile);
g_free(service->name);
g_free(service->passphrase);
g_free(service->agent_passphrase);
*/
void __connman_service_put(struct connman_service *service)
{
+ GSequenceIter *iter;
+
DBG("service %p", service);
- if (g_atomic_int_dec_and_test(&service->refcount) == TRUE) {
- GSequenceIter *iter;
+ if (__sync_fetch_and_sub(&service->refcount, 1) != 1)
+ return;
- iter = g_hash_table_lookup(service_hash, service->identifier);
- if (iter != NULL) {
- reply_pending(service, ECONNABORTED);
+ iter = g_hash_table_lookup(service_hash, service->identifier);
+ if (iter != NULL) {
+ reply_pending(service, ECONNABORTED);
- __connman_service_disconnect(service);
+ __connman_service_disconnect(service);
- g_sequence_remove(iter);
- } else
- service_free(service);
+ g_sequence_remove(iter);
+ } else {
+ service_free(service);
}
}
service_initialize(service);
- service->location = __connman_location_create(service);
-
return service;
}
-struct connman_location *__connman_service_get_location(struct connman_service *service)
-{
- return service->location;
-}
-
/**
* connman_service_ref:
* @service: service structure
{
DBG("%p", service);
- g_atomic_int_inc(&service->refcount);
+ __sync_fetch_and_add(&service->refcount, 1);
return service;
}
g_sequence_sort_changed(iter, service_compare, NULL);
- __connman_profile_changed(FALSE);
+ services_changed(FALSE);
#if defined TIZEN_EXT
{
__connman_service_auto_connect();
g_get_current_time(&service->modified);
- __connman_storage_save_service(service);
+ service_save(service);
}
static void report_error_cb(struct connman_service *service,
__connman_service_connect(service);
else {
service_complete(service);
- __connman_profile_changed(FALSE);
+ services_changed(FALSE);
__connman_device_request_scan(CONNMAN_DEVICE_TYPE_UNKNOWN);
}
}
+static void request_input_cb (struct connman_service *service,
+ const char *identity, const char *passphrase,
+ void *user_data)
+{
+ DBG ("RequestInput return, %p", service);
+
+ if (identity == NULL && passphrase == NULL && service->wps == FALSE) {
+ service_complete(service);
+ services_changed(FALSE);
+ __connman_device_request_scan(CONNMAN_DEVICE_TYPE_UNKNOWN);
+ return;
+ }
+
+ if (identity != NULL)
+ __connman_service_set_agent_identity(service, identity);
+
+ if (passphrase != NULL) {
+ switch (service->security) {
+ case CONNMAN_SERVICE_SECURITY_WEP:
+ case CONNMAN_SERVICE_SECURITY_PSK:
+ __connman_service_set_passphrase(service, passphrase);
+ break;
+ case CONNMAN_SERVICE_SECURITY_8021X:
+ __connman_service_set_agent_passphrase(service,
+ passphrase);
+ break;
+ case CONNMAN_SERVICE_SECURITY_UNKNOWN:
+ case CONNMAN_SERVICE_SECURITY_NONE:
+ case CONNMAN_SERVICE_SECURITY_WPA:
+ case CONNMAN_SERVICE_SECURITY_RSN:
+ DBG("service security '%s' not handled",
+ security2string(service->security));
+ break;
+ }
+ }
+
+ __connman_service_connect(service);
+
+ /* Never cache agent provided credentials */
+ __connman_service_set_agent_identity(service, NULL);
+ __connman_service_set_agent_passphrase(service, NULL);
+}
+
+static void downgrade_connected_services(void)
+{
+ struct connman_service *up_service;
+ GSequenceIter *iter;
+
+ iter = g_sequence_get_begin_iter(service_list);
+ while (g_sequence_iter_is_end(iter) == FALSE) {
+ up_service = g_sequence_get(iter);
+
+ if (is_connected(up_service) == FALSE) {
+ iter = g_sequence_iter_next(iter);
+ continue;
+ }
+
+ if (up_service->state == CONNMAN_SERVICE_STATE_ONLINE)
+ return;
+
+ downgrade_state(up_service);
+
+ iter = g_sequence_iter_next(iter);
+ }
+}
+
#if defined TIZEN_EXT
static connman_bool_t __connman_service_can_drop_cellular(
struct connman_service *cellular)
g_slist_free(services);
}
-static int __connman_service_indicate_state(struct connman_service *service)
+static int service_indicate_state(struct connman_service *service)
{
enum connman_service_state old_state, new_state;
+ struct connman_service *def_service;
GSequenceIter *iter;
if (service == NULL)
old_state = service->state;
new_state = combine_state(service->state_ipv4, service->state_ipv6);
- if (old_state == new_state)
- return -EALREADY;
-
DBG("service %p old %s - new %s/%s => %s",
service,
state2string(old_state),
state2string(service->state_ipv6),
state2string(new_state));
+ if (old_state == new_state)
+ return -EALREADY;
+
+ def_service = get_default();
+
+ if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
+ if (def_service != NULL && def_service != service &&
+ def_service->state == CONNMAN_SERVICE_STATE_ONLINE)
+ return -EALREADY;
+ }
+
service->state = new_state;
state_changed(service);
old_state != CONNMAN_SERVICE_STATE_DISCONNECT) {
#if !defined TIZEN_EXT
/*
- * Dec. 7th, 2011. TIZEN
- *
- * 'service->pending' should be cleared whenever connection is finished regardless success or failure.
- * If the service is disconnected in configuration state by dhcp failure or by the other part of connman,
- * new state is 'idle' but old state is 'disconnect'. So it's not cleared.
+ * Description: 'service->pending' should be cleared whenever connection is finished regardless success or failure.
+ * If the service is disconnected in configuration state by dhcp failure or by the other part of connman,
+ * new state is 'idle' but old state is 'disconnect'. So it's not cleared.
*/
reply_pending(service, ECONNABORTED);
#endif
+
__connman_service_disconnect(service);
}
service->userconnect = FALSE;
g_get_current_time(&service->modified);
- __connman_storage_save_service(service);
+ service_save(service);
update_nameservers(service);
dns_changed(service);
service_single_connection(service);
} else if (new_state == CONNMAN_SERVICE_STATE_DISCONNECT) {
- struct connman_service *def_service = get_default();
+ def_service = get_default();
if (__connman_notifier_count_connected() == 0 &&
def_service != NULL &&
def_service->provider != NULL)
__connman_provider_disconnect(def_service->provider);
- __connman_location_finish(service);
-
default_changed();
+ __connman_wispr_stop(service);
+
__connman_wpad_stop(service);
update_nameservers(service);
domain_changed(service);
__connman_notifier_disconnect(service->type);
+
+ /*
+ * Previous services which are connected and which states
+ * are set to online should reset relevantly ipconfig_state
+ * to ready so wispr/portal will be rerun on those
+ */
+ downgrade_connected_services();
}
if (new_state == CONNMAN_SERVICE_STATE_FAILURE) {
if (iter != NULL)
g_sequence_sort_changed(iter, service_compare, NULL);
- __connman_profile_changed(FALSE);
+ services_changed(FALSE);
if (new_state == CONNMAN_SERVICE_STATE_ONLINE)
default_changed();
default_changed();
- __connman_location_detect(service);
-
return 0;
}
+enum connman_service_state __connman_service_ipconfig_get_state(
+ struct connman_service *service,
+ enum connman_ipconfig_type type)
+{
+ if (service == NULL)
+ return CONNMAN_SERVICE_STATE_UNKNOWN;
+
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
+ return service->state_ipv4;
+
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
+ return service->state_ipv6;
+
+ return CONNMAN_SERVICE_STATE_UNKNOWN;
+}
+
static void check_proxy_setup(struct connman_service *service)
{
/*
*/
if (service->proxy != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN)
- return;
+ goto done;
if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN &&
(service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_AUTO ||
service->pac != NULL))
- return;
+ goto done;
if (__connman_wpad_start(service) < 0) {
service->proxy = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
__connman_notifier_proxy_changed(service);
+ goto done;
+ }
+
+ return;
+
+done:
+ __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
+}
+
+/*
+ * How many networks are connected at the same time. If more than 1,
+ * then set the rp_filter setting properly (loose mode routing) so that network
+ * connectivity works ok. This is only done for IPv4 networks as IPv6
+ * does not have rp_filter knob.
+ */
+static int connected_networks_count;
+static int original_rp_filter;
+
+static void service_rp_filter(struct connman_service *service,
+ gboolean connected)
+{
+ enum connman_ipconfig_method method;
+
+ method = __connman_ipconfig_get_method(service->ipconfig_ipv4);
+
+ switch (method) {
+ case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
+ case CONNMAN_IPCONFIG_METHOD_OFF:
+ case CONNMAN_IPCONFIG_METHOD_AUTO:
+ return;
+ case CONNMAN_IPCONFIG_METHOD_FIXED:
+ case CONNMAN_IPCONFIG_METHOD_MANUAL:
+ case CONNMAN_IPCONFIG_METHOD_DHCP:
+ break;
+ }
+
+ if (connected == TRUE) {
+ if (connected_networks_count == 1) {
+ int filter_value;
+ filter_value = __connman_ipconfig_set_rp_filter();
+ if (filter_value < 0)
+ return;
+
+ original_rp_filter = filter_value;
+ }
+ connected_networks_count++;
+
+ } else {
+ if (connected_networks_count == 2)
+ __connman_ipconfig_unset_rp_filter(original_rp_filter);
+
+ connected_networks_count--;
+ if (connected_networks_count < 0)
+ connected_networks_count = 0;
}
+
+ DBG("%s %s ipconfig %p method %d count %d filter %d",
+ connected ? "connected" : "disconnected", service->identifier,
+ service->ipconfig_ipv4, method,
+ connected_networks_count, original_rp_filter);
}
int __connman_service_ipconfig_indicate_state(struct connman_service *service,
{
struct connman_ipconfig *ipconfig = NULL;
enum connman_service_state old_state;
+ int ret;
if (service == NULL)
return -EINVAL;
case CONNMAN_SERVICE_STATE_READY:
update_nameservers(service);
- if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
check_proxy_setup(service);
+ service_rp_filter(service, TRUE);
+ } else
+ __connman_wispr_start(service, type);
break;
case CONNMAN_SERVICE_STATE_ONLINE:
break;
case CONNMAN_SERVICE_STATE_DISCONNECT:
if (service->state == CONNMAN_SERVICE_STATE_IDLE)
return -EINVAL;
+
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
+ service_rp_filter(service, FALSE);
+
break;
case CONNMAN_SERVICE_STATE_FAILURE:
break;
else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
service->state_ipv6 = new_state;
- return __connman_service_indicate_state(service);
+ ret = service_indicate_state(service);
+
+ /*
+ * If the ipconfig method is OFF, then we set the state to IDLE
+ * so that it will not affect the combined state in the future.
+ */
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
+ enum connman_ipconfig_method method;
+ method = __connman_ipconfig_get_method(service->ipconfig_ipv4);
+ if (method == CONNMAN_IPCONFIG_METHOD_OFF ||
+ method == CONNMAN_IPCONFIG_METHOD_UNKNOWN) {
+ service->state_ipv4 = CONNMAN_SERVICE_STATE_IDLE;
+ ret = service_indicate_state(service);
+ }
+
+ } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
+ enum connman_ipconfig_method method;
+ method = __connman_ipconfig_get_method(service->ipconfig_ipv6);
+ if (method == CONNMAN_IPCONFIG_METHOD_OFF ||
+ method == CONNMAN_IPCONFIG_METHOD_UNKNOWN) {
+ service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
+ ret = service_indicate_state(service);
+ }
+ }
+
+ return ret;
}
int __connman_service_request_login(struct connman_service *service)
case CONNMAN_SERVICE_SECURITY_PSK:
case CONNMAN_SERVICE_SECURITY_WPA:
case CONNMAN_SERVICE_SECURITY_RSN:
- DBG("service->wps : %d", service->wps);
if (service->passphrase == NULL) {
if (service->network == NULL)
return -EOPNOTSUPP;
+
#if defined TIZEN_EXT
if(service->wps == TRUE)
{
}
break;
case CONNMAN_SERVICE_SECURITY_8021X:
- DBG("service->eap : %s", service->eap);
if (service->eap == NULL)
return -EINVAL;
return err;
}
+
int __connman_service_connect(struct connman_service *service)
{
int err;
if (service->userconnect == TRUE) {
if (err == -ENOKEY) {
- if (__connman_agent_request_input(service,
+ if (__connman_agent_request_passphrase_input(service,
request_input_cb,
NULL) == -EIO)
return -EINPROGRESS;
}
- reply_pending(service, -err);
+ reply_pending(service, err);
}
return err;
int __connman_service_disconnect_all(void)
{
GSequenceIter *iter;
+ GSList *services = NULL, *list;
DBG("");
while (g_sequence_iter_is_end(iter) == FALSE) {
struct connman_service *service = g_sequence_get(iter);
+ services = g_slist_prepend(services, service);
+
+ iter = g_sequence_iter_next(iter);
+ }
+
+ for (list = services; list != NULL; list = list->next) {
+ struct connman_service *service = list->data;
+
service->ignore = TRUE;
set_reconnect_state(service, FALSE);
__connman_service_disconnect(service);
-
- iter = g_sequence_iter_next(iter);
}
+ g_slist_free(list);
+
return 0;
}
{
GHashTableIter iter;
gpointer key, value;
+ struct connman_device *device;
+ const char *ifname;
g_hash_table_iter_init(&iter, service_hash);
*path = (const char *) service->path;
return 0;
}
+
+ if (service->network == NULL)
+ continue;
+
+ device = connman_network_get_device(service->network);
+ if (device == NULL)
+ continue;
+
+ ifname = connman_device_get_string(device, "Interface");
+ if (ifname != NULL && g_strcmp0(ifname, pattern) == 0) {
+ *path = (const char *) service->path;
+ return 0;
+ }
+
}
return -ENXIO;
{
GSequenceIter *iter;
- DBG("ident %s", identifier);
iter = g_hash_table_lookup(service_hash, identifier);
if (iter != NULL)
return g_sequence_get(iter);
DBusMessageIter iter, array;
const char *mode = "managed", *security = "none", *group_security;
const char *type = NULL, *ssid = NULL, *passphrase = NULL;
+ connman_bool_t network_created = FALSE;
unsigned int ssid_len = 0;
const char *ident;
char *name, *group;
service = lookup_by_identifier(name);
- if (service != NULL)
- goto done;
-
- network = create_hidden_wifi(device, ssid, mode, security, group);
- if (network != NULL)
- connman_network_set_group(network, group);
+ if (service == NULL) {
+ network = create_hidden_wifi(device, ssid,
+ mode, security, group);
+ if (network != NULL) {
+ connman_network_set_group(network, group);
+ network_created = TRUE;
+ }
- service = lookup_by_identifier(name);
+ service = lookup_by_identifier(name);
+ }
-done:
g_free(name);
g_free(group);
goto failed;
}
- service->network_created = TRUE;
+ service->network_created = network_created;
if (is_connected(service) == TRUE) {
err = -EISCONN;
service->identifier = g_strdup(identifier);
- service->profile = g_strdup(__connman_profile_active_ident());
-
iter = g_sequence_insert_sorted(service_list, service,
service_compare, NULL);
static int service_register(struct connman_service *service)
{
- const char *path = __connman_profile_active_path();
GSequenceIter *iter;
DBG("service %p", service);
if (service->path != NULL)
return -EALREADY;
- service->path = g_strdup_printf("%s/%s", path, service->identifier);
+ service->path = g_strdup_printf("%s/service/%s", CONNMAN_PATH,
+ service->identifier);
DBG("path %s", service->path);
__connman_config_provision_service(service);
- __connman_storage_load_service(service);
+ service_load(service);
g_dbus_register_interface(connection, service->path,
CONNMAN_SERVICE_INTERFACE,
if (iter != NULL)
g_sequence_sort_changed(iter, service_compare, NULL);
- __connman_profile_changed(TRUE);
+ services_changed(TRUE);
return 0;
}
DBG("%s lower down", connman_ipconfig_get_ifname(ipconfig));
stats_stop(service);
- __connman_storage_save_service(service);
+ service_save(service);
}
static void service_ip_bound(struct connman_ipconfig *ipconfig)
static void setup_ip4config(struct connman_service *service, int index,
enum connman_ipconfig_method method)
{
-#if !defined TIZEN_EXT
- if (index < 0)
- return;
-#endif
-
service->ipconfig_ipv4 = connman_ipconfig_create(index,
CONNMAN_IPCONFIG_TYPE_IPV4);
if (service->ipconfig_ipv4 == NULL)
static void setup_ip6config(struct connman_service *service, int index)
{
- if (index < 0)
- return;
-
service->ipconfig_ipv6 = connman_ipconfig_create(index,
CONNMAN_IPCONFIG_TYPE_IPV6);
if (service->ipconfig_ipv6 == NULL)
}
void __connman_service_read_ip4config(struct connman_service *service)
-{
- const char *ident = service->profile;
- GKeyFile *keyfile;
-
- if (ident == NULL)
- return;
+{
+ GKeyFile *keyfile;
if (service->ipconfig_ipv4 == NULL)
return;
- keyfile = __connman_storage_open_profile(ident);
+ keyfile = connman_storage_load_service(service->identifier);
if (keyfile == NULL)
return;
void __connman_service_read_ip6config(struct connman_service *service)
{
- const char *ident = service->profile;
GKeyFile *keyfile;
- if (ident == NULL)
- return;
if (service->ipconfig_ipv6 == NULL)
return;
- keyfile = __connman_storage_open_profile(ident);
-
+ keyfile = connman_storage_load_service(service->identifier);
if (keyfile == NULL)
return;
return;
setup_ip6config(service, index);
+
__connman_service_read_ip6config(service);
}
DBG("network %p", network);
+ if (network == NULL)
+ return NULL;
+
ident = __connman_network_get_ident(network);
if (ident == NULL)
return NULL;
}
static void update_from_network(struct connman_service *service,
- struct connman_network *network)
-{
- connman_uint8_t strength = service->strength;
- GSequenceIter *iter;
- const char *str;
-
- DBG("service %p network %p", service, network);
-
- if (is_connected(service) == TRUE)
- return;
-
- if (is_connecting(service) == TRUE)
- return;
-
- str = connman_network_get_string(network, "Name");
- if (str != NULL) {
- g_free(service->name);
- service->name = g_strdup(str);
- service->hidden = FALSE;
- } else {
- g_free(service->name);
- service->name = NULL;
- service->hidden = TRUE;
- }
-
- service->strength = connman_network_get_strength(network);
- service->roaming = connman_network_get_bool(network, "Roaming");
-
- if (service->strength == 0) {
- /*
- * Filter out 0-values; it's unclear what they mean
- * and they cause anomalous sorting of the priority list.
- */
- service->strength = strength;
- }
-
- str = connman_network_get_string(network, "WiFi.Security");
- service->security = convert_wifi_security(str);
-
- if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
- service->wps = connman_network_get_bool(network, "WiFi.WPS");
-
- if (service->strength > strength && service->network != NULL) {
- service->network = network;
-
- strength_changed(service);
- }
-
- if (service->network == NULL)
- service->network = network;
-
- iter = g_hash_table_lookup(service_hash, service->identifier);
- if (iter != NULL)
- g_sequence_sort_changed(iter, service_compare, NULL);
-}
-
-/**
- * __connman_service_create_from_network:
- * @network: network structure
- *
- * Look up service by network and if not found, create one
- */
-struct connman_service * __connman_service_create_from_network(struct connman_network *network)
-{
- struct connman_service *service;
- struct connman_device *device;
- const char *ident, *group;
- char *name;
- int index;
-
- DBG("network %p", network);
-
- ident = __connman_network_get_ident(network);
- if (ident == NULL)
- return NULL;
-
- group = connman_network_get_group(network);
- if (group == NULL)
- return NULL;
-
- name = g_strdup_printf("%s_%s_%s",
- __connman_network_get_type(network), ident, group);
- service = service_get(name);
- g_free(name);
-
- if (service == NULL)
- return NULL;
-
- if (__connman_network_get_weakness(network) == TRUE)
- return service;
-
- if (service->path != NULL) {
- update_from_network(service, network);
- __connman_profile_changed(TRUE);
- return service;
- }
-
- service->type = convert_network_type(network);
-
- switch (service->type) {
- case CONNMAN_SERVICE_TYPE_UNKNOWN:
- case CONNMAN_SERVICE_TYPE_SYSTEM:
- case CONNMAN_SERVICE_TYPE_ETHERNET:
- case CONNMAN_SERVICE_TYPE_WIMAX:
- case CONNMAN_SERVICE_TYPE_BLUETOOTH:
- case CONNMAN_SERVICE_TYPE_GPS:
- case CONNMAN_SERVICE_TYPE_VPN:
- case CONNMAN_SERVICE_TYPE_GADGET:
- service->autoconnect = FALSE;
- break;
- case CONNMAN_SERVICE_TYPE_WIFI:
- case CONNMAN_SERVICE_TYPE_CELLULAR:
- service->autoconnect = TRUE;
- break;
- }
-
- service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
- service->state = combine_state(service->state_ipv4, service->state_ipv6);
-
- update_from_network(service, network);
-
- index = connman_network_get_index(network);
-
- if (service->ipconfig_ipv4 == NULL)
- setup_ip4config(service, index, CONNMAN_IPCONFIG_METHOD_DHCP);
-
- if (service->ipconfig_ipv6 == NULL)
- setup_ip6config(service, index);
-
- service_register(service);
-
- if (service->favorite == TRUE) {
- device = connman_network_get_device(service->network);
- if (device && __connman_device_scanning(device) == FALSE)
- __connman_service_auto_connect();
- }
-
- __connman_notifier_service_add(service, service->name);
-
- return service;
-}
-
-void __connman_service_update_from_network(struct connman_network *network)
-{
- struct connman_service *service;
- connman_uint8_t strength;
- connman_bool_t roaming;
- GSequenceIter *iter;
- const char *name;
- connman_bool_t stats_enable;
-
- DBG("network %p", network);
-
- service = __connman_service_lookup_from_network(network);
- if (service == NULL)
- return;
-
- if (service->network == NULL)
- return;
-
- name = connman_network_get_string(service->network, "Name");
- if (g_strcmp0(service->name, name) != 0) {
- g_free(service->name);
- service->name = g_strdup(name);
- connman_dbus_property_changed_basic(service->path,
- CONNMAN_SERVICE_INTERFACE, "Name",
- DBUS_TYPE_STRING, &service->name);
- }
-
- if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
- service->wps = connman_network_get_bool(network, "WiFi.WPS");
-
- strength = connman_network_get_strength(service->network);
- if (strength == service->strength)
- goto roaming;
-
- service->strength = strength;
-
- strength_changed(service);
-
-roaming:
- roaming = connman_network_get_bool(service->network, "Roaming");
- if (roaming == service->roaming)
- return;
-
- stats_enable = stats_enabled(service);
- if (stats_enable == TRUE)
- stats_stop(service);
-
- service->roaming = roaming;
-
- if (stats_enable == TRUE)
- stats_start(service);
-
- roaming_changed(service);
-
- iter = g_hash_table_lookup(service_hash, service->identifier);
- if (iter != NULL)
- g_sequence_sort_changed(iter, service_compare, NULL);
-}
-
-void __connman_service_remove_from_network(struct connman_network *network)
-{
- struct connman_service *service;
-
- DBG("network %p", network);
-
- service = __connman_service_lookup_from_network(network);
- if (service == NULL)
- return;
-
- __connman_connection_gateway_remove(service, CONNMAN_IPCONFIG_TYPE_ALL);
-
-#if defined TIZEN_EXT
- __connman_service_ipconfig_indicate_state(service,
- CONNMAN_SERVICE_STATE_DISCONNECT,
- CONNMAN_IPCONFIG_TYPE_IPV4);
-
- __connman_service_ipconfig_indicate_state(service,
- CONNMAN_SERVICE_STATE_DISCONNECT,
- CONNMAN_IPCONFIG_TYPE_IPV6);
-#endif
-
- __connman_service_put(service);
-}
-
-/**
- * __connman_service_create_from_provider:
- * @provider: provider structure
- *
- * Look up service by provider and if not found, create one
- */
-struct connman_service *
-__connman_service_create_from_provider(struct connman_provider *provider)
-{
- struct connman_service *service;
- const char *ident, *str;
- char *name;
- int index = connman_provider_get_index(provider);
-
- DBG("provider %p", provider);
-
- ident = __connman_provider_get_ident(provider);
- if (ident == NULL)
- return NULL;
-
- name = g_strdup_printf("vpn_%s", ident);
- service = service_get(name);
- g_free(name);
+ struct connman_network *network)
+{
+ connman_uint8_t strength = service->strength;
+ GSequenceIter *iter;
+ const char *str;
- if (service == NULL)
- return NULL;
+ DBG("service %p network %p", service, network);
- service->type = CONNMAN_SERVICE_TYPE_VPN;
- service->provider = connman_provider_ref(provider);
- service->autoconnect = FALSE;
+ if (is_connected(service) == TRUE)
+ return;
- service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
+ if (is_connecting(service) == TRUE)
+ return;
- str = connman_provider_get_string(provider, "Name");
+ str = connman_network_get_string(network, "Name");
if (str != NULL) {
g_free(service->name);
service->name = g_strdup(str);
service->hidden = TRUE;
}
- service->strength = 0;
-
- if (service->ipconfig_ipv4 == NULL)
- setup_ip4config(service, index, CONNMAN_IPCONFIG_METHOD_MANUAL);
-
- if (service->ipconfig_ipv6 == NULL)
- setup_ip6config(service, index);
-
- service_register(service);
+ service->strength = connman_network_get_strength(network);
+ service->roaming = connman_network_get_bool(network, "Roaming");
- __connman_notifier_service_add(service, service->name);
+ if (service->strength == 0) {
+ /*
+ * Filter out 0-values; it's unclear what they mean
+ * and they cause anomalous sorting of the priority list.
+ */
+ service->strength = strength;
+ }
- return service;
-}
+ str = connman_network_get_string(network, "WiFi.Security");
+ service->security = convert_wifi_security(str);
-void __connman_service_downgrade_state(struct connman_service *service)
-{
-#if defined TIZEN_EXT
- if (service == NULL || service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
- return;
-#else
- if (service == NULL)
- return;
+ if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
+ service->wps = connman_network_get_bool(network, "WiFi.WPS");
-#endif
+ if (service->strength > strength && service->network != NULL) {
+ service->network = network;
- DBG("service %p state4 %d state6 %d", service, service->state_ipv4,
- service->state_ipv6);
+ strength_changed(service);
+ }
- if (service->state_ipv4 == CONNMAN_SERVICE_STATE_ONLINE)
- __connman_service_ipconfig_indicate_state(service,
- CONNMAN_SERVICE_STATE_READY,
- CONNMAN_IPCONFIG_TYPE_IPV4);
+ if (service->network == NULL)
+ service->network = network;
- if (service->state_ipv6 == CONNMAN_SERVICE_STATE_ONLINE)
- __connman_service_ipconfig_indicate_state(service,
- CONNMAN_SERVICE_STATE_READY,
- CONNMAN_IPCONFIG_TYPE_IPV6);
+ iter = g_hash_table_lookup(service_hash, service->identifier);
+ if (iter != NULL)
+ g_sequence_sort_changed(iter, service_compare, NULL);
}
-static int service_load(struct connman_service *service)
+/**
+ * __connman_service_create_from_network:
+ * @network: network structure
+ *
+ * Look up service by network and if not found, create one
+ */
+struct connman_service * __connman_service_create_from_network(struct connman_network *network)
{
- const char *ident = service->profile;
- GKeyFile *keyfile;
- GError *error = NULL;
- gchar *pathname, *data = NULL;
- gsize length;
- gchar *str;
- connman_bool_t autoconnect;
- unsigned int ssid_len;
- int err = 0;
+ struct connman_service *service;
+ struct connman_device *device;
+ const char *ident, *group;
+ char *name;
+ int index;
- DBG("service %p", service);
+ DBG("network %p", network);
+
+ if (network == NULL)
+ return NULL;
+ ident = __connman_network_get_ident(network);
if (ident == NULL)
- return -EINVAL;
+ return NULL;
- pathname = g_strdup_printf("%s/%s.profile", STORAGEDIR, ident);
- if (pathname == NULL)
- return -ENOMEM;
+ group = connman_network_get_group(network);
+ if (group == NULL)
+ return NULL;
- keyfile = g_key_file_new();
+ name = g_strdup_printf("%s_%s_%s",
+ __connman_network_get_type(network), ident, group);
+ service = service_get(name);
+ g_free(name);
- if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
- g_free(pathname);
- return -ENOENT;
- }
+ if (service == NULL)
+ return NULL;
- g_free(pathname);
+ if (__connman_network_get_weakness(network) == TRUE)
+ return service;
- if (g_key_file_load_from_data(keyfile, data, length,
- 0, NULL) == FALSE) {
- g_free(data);
- return -EILSEQ;
+ if (service->path != NULL) {
+ update_from_network(service, network);
+ services_changed(TRUE);
+ return service;
}
- g_free(data);
+ service->type = convert_network_type(network);
switch (service->type) {
case CONNMAN_SERVICE_TYPE_UNKNOWN:
case CONNMAN_SERVICE_TYPE_SYSTEM:
case CONNMAN_SERVICE_TYPE_ETHERNET:
+ case CONNMAN_SERVICE_TYPE_WIMAX:
+ case CONNMAN_SERVICE_TYPE_BLUETOOTH:
case CONNMAN_SERVICE_TYPE_GPS:
case CONNMAN_SERVICE_TYPE_VPN:
case CONNMAN_SERVICE_TYPE_GADGET:
+ service->autoconnect = FALSE;
break;
case CONNMAN_SERVICE_TYPE_WIFI:
- if (service->name == NULL) {
- gchar *name;
-
- name = g_key_file_get_string(keyfile,
- service->identifier, "Name", NULL);
- if (name != NULL) {
- g_free(service->name);
- service->name = name;
- }
-
- if (service->network != NULL)
- connman_network_set_name(service->network,
- name);
- }
-
- if (service->network &&
- connman_network_get_blob(service->network,
- "WiFi.SSID", &ssid_len) == NULL) {
- gchar *hex_ssid;
-
- hex_ssid = g_key_file_get_string(keyfile,
- service->identifier,
- "SSID", NULL);
-
- if (hex_ssid != NULL) {
- gchar *ssid;
- unsigned int i, j = 0, hex;
- size_t hex_ssid_len = strlen(hex_ssid);
-
- ssid = g_try_malloc0(hex_ssid_len / 2);
- if (ssid == NULL) {
- g_free(hex_ssid);
- err = -ENOMEM;
- goto done;
- }
-
- for (i = 0; i < hex_ssid_len; i += 2) {
- sscanf(hex_ssid + i, "%02x", &hex);
- ssid[j++] = hex;
- }
-
- connman_network_set_blob(service->network,
- "WiFi.SSID", ssid, hex_ssid_len / 2);
- }
-
- g_free(hex_ssid);
- }
- /* fall through */
-
- case CONNMAN_SERVICE_TYPE_WIMAX:
- case CONNMAN_SERVICE_TYPE_BLUETOOTH:
-#if !defined TIZEN_EXT
case CONNMAN_SERVICE_TYPE_CELLULAR:
-#endif
- service->favorite = g_key_file_get_boolean(keyfile,
- service->identifier, "Favorite", NULL);
-
- autoconnect = g_key_file_get_boolean(keyfile,
- service->identifier, "AutoConnect", &error);
- if (error == NULL)
- service->autoconnect = autoconnect;
- g_clear_error(&error);
-
- str = g_key_file_get_string(keyfile,
- service->identifier, "Failure", NULL);
- if (str != NULL) {
- if (service->favorite == FALSE)
- service->state_ipv4 = service->state_ipv6 =
- CONNMAN_SERVICE_STATE_FAILURE;
- service->error = string2error(str);
- }
-
+ service->autoconnect = TRUE;
break;
}
- str = g_key_file_get_string(keyfile,
- service->identifier, "Modified", NULL);
- if (str != NULL) {
- g_time_val_from_iso8601(str, &service->modified);
- g_free(str);
- }
-
- str = g_key_file_get_string(keyfile,
- service->identifier, "Passphrase", NULL);
- if (str != NULL) {
- g_free(service->passphrase);
- service->passphrase = str;
- }
-
- if (service->ipconfig_ipv4 != NULL)
- __connman_ipconfig_load(service->ipconfig_ipv4, keyfile,
- service->identifier, "IPv4.");
-
- if (service->ipconfig_ipv6 != NULL)
- __connman_ipconfig_load(service->ipconfig_ipv6, keyfile,
- service->identifier, "IPv6.");
-
- service->nameservers_config = g_key_file_get_string_list(keyfile,
- service->identifier, "Nameservers", &length, NULL);
- if (service->nameservers_config != NULL && length == 0) {
- g_strfreev(service->nameservers_config);
- service->nameservers_config = NULL;
- }
-
- service->domains = g_key_file_get_string_list(keyfile,
- service->identifier, "Domains", &length, NULL);
- if (service->domains != NULL && length == 0) {
- g_strfreev(service->domains);
- service->domains = NULL;
- }
+ service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
+ service->state = combine_state(service->state_ipv4, service->state_ipv6);
- str = g_key_file_get_string(keyfile,
- service->identifier, "Proxy.Method", NULL);
- if (str != NULL)
- service->proxy_config = string2proxymethod(str);
+ update_from_network(service, network);
- g_free(str);
+ index = connman_network_get_index(network);
- service->proxies = g_key_file_get_string_list(keyfile,
- service->identifier, "Proxy.Servers", &length, NULL);
- if (service->proxies != NULL && length == 0) {
- g_strfreev(service->proxies);
- service->proxies = NULL;
- }
+ if (service->ipconfig_ipv4 == NULL)
+ setup_ip4config(service, index, CONNMAN_IPCONFIG_METHOD_DHCP);
- service->excludes = g_key_file_get_string_list(keyfile,
- service->identifier, "Proxy.Excludes", &length, NULL);
- if (service->excludes != NULL && length == 0) {
- g_strfreev(service->excludes);
- service->excludes = NULL;
- }
+ if (service->ipconfig_ipv6 == NULL)
+ setup_ip6config(service, index);
- str = g_key_file_get_string(keyfile,
- service->identifier, "Proxy.URL", NULL);
- if (str != NULL) {
- g_free(service->pac);
- service->pac = str;
+ service_register(service);
+
+ if (service->favorite == TRUE) {
+ device = connman_network_get_device(service->network);
+ if (device && __connman_device_scanning(device) == FALSE)
+ __connman_service_auto_connect();
}
-done:
- g_key_file_free(keyfile);
+ __connman_notifier_service_add(service, service->name);
- return err;
+ return service;
}
-static int service_save(struct connman_service *service)
+void __connman_service_update_from_network(struct connman_network *network)
{
- const char *ident = service->profile;
- GKeyFile *keyfile;
- gchar *pathname, *data = NULL;
- gsize length;
- gchar *str;
- const char *cst_str = NULL;
- int err = 0;
-
- DBG("service %p", service);
-
- if (ident == NULL)
- return -EINVAL;
+ connman_bool_t need_sort = FALSE;
+ struct connman_service *service;
+ connman_uint8_t strength;
+ connman_bool_t roaming;
+ GSequenceIter *iter;
+ const char *name;
+ connman_bool_t stats_enable;
- pathname = g_strdup_printf("%s/%s.profile", STORAGEDIR, ident);
- if (pathname == NULL)
- return -ENOMEM;
+ DBG("network %p", network);
- keyfile = g_key_file_new();
+ service = __connman_service_lookup_from_network(network);
+ if (service == NULL)
+ return;
- if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
- goto update;
+ if (service->network == NULL)
+ return;
- if (length > 0) {
- if (g_key_file_load_from_data(keyfile, data, length,
- 0, NULL) == FALSE)
- goto done;
+ name = connman_network_get_string(service->network, "Name");
+ if (g_strcmp0(service->name, name) != 0) {
+ g_free(service->name);
+ service->name = g_strdup(name);
+ connman_dbus_property_changed_basic(service->path,
+ CONNMAN_SERVICE_INTERFACE, "Name",
+ DBUS_TYPE_STRING, &service->name);
}
- g_free(data);
-
-update:
- if (service->name != NULL)
- g_key_file_set_string(keyfile, service->identifier,
- "Name", service->name);
-
- switch (service->type) {
- case CONNMAN_SERVICE_TYPE_UNKNOWN:
- case CONNMAN_SERVICE_TYPE_SYSTEM:
- case CONNMAN_SERVICE_TYPE_ETHERNET:
- case CONNMAN_SERVICE_TYPE_GPS:
- case CONNMAN_SERVICE_TYPE_VPN:
- case CONNMAN_SERVICE_TYPE_GADGET:
- break;
- case CONNMAN_SERVICE_TYPE_WIFI:
- if (service->network) {
- const unsigned char *ssid;
- unsigned int ssid_len = 0;
+ if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
+ service->wps = connman_network_get_bool(network, "WiFi.WPS");
- ssid = connman_network_get_blob(service->network,
- "WiFi.SSID", &ssid_len);
+ strength = connman_network_get_strength(service->network);
+ if (strength == service->strength)
+ goto roaming;
- if (ssid != NULL && ssid_len > 0 && ssid[0] != '\0') {
- char *identifier = service->identifier;
- GString *str;
- unsigned int i;
+ service->strength = strength;
+ need_sort = TRUE;
- str = g_string_sized_new(ssid_len * 2);
- if (str == NULL) {
- err = -ENOMEM;
- goto done;
- }
+ strength_changed(service);
- for (i = 0; i < ssid_len; i++)
- g_string_append_printf(str,
- "%02x", ssid[i]);
+roaming:
+ roaming = connman_network_get_bool(service->network, "Roaming");
+ if (roaming == service->roaming)
+ goto sorting;
- g_key_file_set_string(keyfile, identifier,
- "SSID", str->str);
+ stats_enable = stats_enabled(service);
+ if (stats_enable == TRUE)
+ stats_stop(service);
- g_string_free(str, TRUE);
- }
- }
- /* fall through */
+ service->roaming = roaming;
+ need_sort = TRUE;
- case CONNMAN_SERVICE_TYPE_WIMAX:
- case CONNMAN_SERVICE_TYPE_BLUETOOTH:
- case CONNMAN_SERVICE_TYPE_CELLULAR:
- g_key_file_set_boolean(keyfile, service->identifier,
- "Favorite", service->favorite);
+ if (stats_enable == TRUE)
+ stats_start(service);
- if (service->favorite == TRUE)
- g_key_file_set_boolean(keyfile, service->identifier,
- "AutoConnect", service->autoconnect);
+ roaming_changed(service);
- if (service->state_ipv4 == CONNMAN_SERVICE_STATE_FAILURE ||
- service->state_ipv6 == CONNMAN_SERVICE_STATE_FAILURE) {
- const char *failure = error2string(service->error);
- if (failure != NULL)
- g_key_file_set_string(keyfile,
- service->identifier,
- "Failure", failure);
- } else {
- g_key_file_remove_key(keyfile, service->identifier,
- "Failure", NULL);
- }
- break;
+sorting:
+ if (need_sort == TRUE) {
+ iter = g_hash_table_lookup(service_hash, service->identifier);
+ if (iter != NULL)
+ g_sequence_sort_changed(iter, service_compare, NULL);
}
+}
- str = g_time_val_to_iso8601(&service->modified);
- if (str != NULL) {
- g_key_file_set_string(keyfile, service->identifier,
- "Modified", str);
- g_free(str);
- }
+void __connman_service_remove_from_network(struct connman_network *network)
+{
+ struct connman_service *service;
- if (service->passphrase != NULL && strlen(service->passphrase) > 0)
- g_key_file_set_string(keyfile, service->identifier,
- "Passphrase", service->passphrase);
- else
- g_key_file_remove_key(keyfile, service->identifier,
- "Passphrase", NULL);
+ DBG("network %p", network);
- switch (service->state) {
- case CONNMAN_SERVICE_STATE_UNKNOWN:
- case CONNMAN_SERVICE_STATE_IDLE:
- case CONNMAN_SERVICE_STATE_ASSOCIATION:
- break;
- case CONNMAN_SERVICE_STATE_CONFIGURATION:
- case CONNMAN_SERVICE_STATE_READY:
- case CONNMAN_SERVICE_STATE_ONLINE:
- case CONNMAN_SERVICE_STATE_DISCONNECT:
- case CONNMAN_SERVICE_STATE_FAILURE:
- if (service->ipconfig_ipv4 != NULL)
- __connman_ipconfig_save(service->ipconfig_ipv4,
- keyfile, service->identifier,
- "IPv4.");
+ service = __connman_service_lookup_from_network(network);
+ if (service == NULL)
+ return;
- if (service->ipconfig_ipv6 != NULL)
- __connman_ipconfig_save(service->ipconfig_ipv6,
- keyfile, service->identifier,
- "IPv6.");
- }
+ __connman_connection_gateway_remove(service,
+ CONNMAN_IPCONFIG_TYPE_ALL);
+#if defined TIZEN_EXT
+ __connman_service_ipconfig_indicate_state(service,
+ CONNMAN_SERVICE_STATE_DISCONNECT,
+ CONNMAN_IPCONFIG_TYPE_IPV4);
- if (service->nameservers_config != NULL) {
- guint len = g_strv_length(service->nameservers_config);
+ __connman_service_ipconfig_indicate_state(service,
+ CONNMAN_SERVICE_STATE_DISCONNECT,
+ CONNMAN_IPCONFIG_TYPE_IPV6);
+#endif
- g_key_file_set_string_list(keyfile, service->identifier,
- "Nameservers",
- (const gchar **) service->nameservers_config, len);
- } else
- g_key_file_remove_key(keyfile, service->identifier,
- "Nameservers", NULL);
+ __connman_service_put(service);
+}
- if (service->domains != NULL) {
- guint len = g_strv_length(service->domains);
+/**
+ * __connman_service_create_from_provider:
+ * @provider: provider structure
+ *
+ * Look up service by provider and if not found, create one
+ */
+struct connman_service *
+__connman_service_create_from_provider(struct connman_provider *provider)
+{
+ struct connman_service *service;
+ const char *ident, *str;
+ char *name;
+ int index = connman_provider_get_index(provider);
- g_key_file_set_string_list(keyfile, service->identifier,
- "Domains",
- (const gchar **) service->domains, len);
- } else
- g_key_file_remove_key(keyfile, service->identifier,
- "Domains", NULL);
+ DBG("provider %p", provider);
- cst_str = proxymethod2string(service->proxy_config);
- if (cst_str != NULL)
- g_key_file_set_string(keyfile, service->identifier,
- "Proxy.Method", cst_str);
+ ident = __connman_provider_get_ident(provider);
+ if (ident == NULL)
+ return NULL;
- if (service->proxies != NULL) {
- guint len = g_strv_length(service->proxies);
+ name = g_strdup_printf("vpn_%s", ident);
+ service = service_get(name);
+ g_free(name);
- g_key_file_set_string_list(keyfile, service->identifier,
- "Proxy.Servers",
- (const gchar **) service->proxies, len);
- } else
- g_key_file_remove_key(keyfile, service->identifier,
- "Proxy.Servers", NULL);
+ if (service == NULL)
+ return NULL;
- if (service->excludes != NULL) {
- guint len = g_strv_length(service->excludes);
+ service->type = CONNMAN_SERVICE_TYPE_VPN;
+ service->provider = connman_provider_ref(provider);
+ service->autoconnect = FALSE;
+ service->userconnect = TRUE;
- g_key_file_set_string_list(keyfile, service->identifier,
- "Proxy.Excludes",
- (const gchar **) service->excludes, len);
- } else
- g_key_file_remove_key(keyfile, service->identifier,
- "Proxy.Excludes", NULL);
+ service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
- if (service->pac != NULL && strlen(service->pac) > 0)
- g_key_file_set_string(keyfile, service->identifier,
- "Proxy.URL", service->pac);
- else
- g_key_file_remove_key(keyfile, service->identifier,
- "Proxy.URL", NULL);
+ str = connman_provider_get_string(provider, "Name");
+ if (str != NULL) {
+ g_free(service->name);
+ service->name = g_strdup(str);
+ service->hidden = FALSE;
+ } else {
+ g_free(service->name);
+ service->name = NULL;
+ service->hidden = TRUE;
+ }
- data = g_key_file_to_data(keyfile, &length, NULL);
+ service->strength = 0;
- if (g_file_set_contents(pathname, data, length, NULL) == FALSE)
- connman_error("Failed to store service information");
+ if (service->ipconfig_ipv4 == NULL)
+ setup_ip4config(service, index, CONNMAN_IPCONFIG_METHOD_MANUAL);
-done:
- g_free(data);
+ if (service->ipconfig_ipv6 == NULL)
+ setup_ip6config(service, index);
- g_key_file_free(keyfile);
+ service_register(service);
- g_free(pathname);
+ __connman_notifier_service_add(service, service->name);
- return err;
+ return service;
}
-static struct connman_storage service_storage = {
- .name = "service",
- .priority = CONNMAN_STORAGE_PRIORITY_LOW,
- .service_load = service_load,
- .service_save = service_save,
-};
-
int __connman_service_init(void)
{
DBG("");
connection = connman_dbus_get_connection();
- if (connman_storage_register(&service_storage) < 0)
- connman_error("Failed to register service storage");
-
service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, NULL);
g_slist_free(counter_list);
counter_list = NULL;
- connman_storage_unregister(&service_storage);
-
dbus_connection_unref(connection);
}
static DBusConnection *connection;
static GHashTable *session_hash;
static connman_bool_t sessionmode;
-static struct connman_session *ecall_session;
+static struct session_info *ecall_info;
enum connman_session_trigger {
CONNMAN_SESSION_TRIGGER_UNKNOWN = 0,
enum connman_session_reason {
CONNMAN_SESSION_REASON_UNKNOWN = 0,
CONNMAN_SESSION_REASON_CONNECT = 1,
- CONNMAN_SESSION_REASON_FREE_RIDE = 2,
- CONNMAN_SESSION_REASON_PERIODIC = 3,
+ CONNMAN_SESSION_REASON_DISCONNECT = 2,
+ CONNMAN_SESSION_REASON_FREE_RIDE = 3,
+ CONNMAN_SESSION_REASON_PERIODIC = 4,
};
enum connman_session_roaming_policy {
struct connman_service *service;
char *ifname;
const char *bearer;
+ GSList *pending_timeouts;
};
struct session_info {
return "unknown";
case CONNMAN_SESSION_REASON_CONNECT:
return "connect";
+ case CONNMAN_SESSION_REASON_DISCONNECT:
+ return "disconnect";
case CONNMAN_SESSION_REASON_FREE_RIDE:
return "free-ride";
case CONNMAN_SESSION_REASON_PERIODIC:
return CONNMAN_SERVICE_TYPE_WIMAX;
else if (g_strcmp0(bearer, "bluetooth") == 0)
return CONNMAN_SERVICE_TYPE_BLUETOOTH;
- else if (g_strcmp0(bearer, "3g") == 0)
+ else if (g_strcmp0(bearer, "cellular") == 0)
return CONNMAN_SERVICE_TYPE_CELLULAR;
else if (g_strcmp0(bearer, "vpn") == 0)
return CONNMAN_SERVICE_TYPE_VPN;
case CONNMAN_SERVICE_TYPE_BLUETOOTH:
return "bluetooth";
case CONNMAN_SERVICE_TYPE_CELLULAR:
- return "3g";
+ return "cellular";
case CONNMAN_SERVICE_TYPE_VPN:
return "vpn";
case CONNMAN_SERVICE_TYPE_UNKNOWN:
g_dbus_send_message(connection, msg);
- session->info_dirty = FALSE;
-
return FALSE;
}
* 1. Ethernet
* 2. Bluetooth
* 3. WiFi/WiMAX
- * 4. GSM/UTMS/3G
+ * 4. Cellular
*/
switch (type) {
switch (reason) {
case CONNMAN_SESSION_REASON_UNKNOWN:
case CONNMAN_SESSION_REASON_FREE_RIDE:
+ case CONNMAN_SESSION_REASON_DISCONNECT:
break;
case CONNMAN_SESSION_REASON_CONNECT:
case CONNMAN_SESSION_REASON_PERIODIC:
return FALSE;
}
-static connman_bool_t explicit_disconnect(struct connman_session *session)
+static connman_bool_t explicit_disconnect(struct session_info *info)
{
- struct session_info *info = session->info;
-
if (info->entry == NULL)
return FALSE;
- DBG("session %p, reason %s service %p state %d",
- session, reason2string(info->entry->reason),
+ DBG("reason %s service %p state %d",
+ reason2string(info->entry->reason),
info->entry->service, info->entry->state);
if (info->entry->reason == CONNMAN_SESSION_REASON_UNKNOWN)
if (__connman_service_session_dec(info->entry->service) == FALSE)
return FALSE;
- if (ecall_session != NULL && ecall_session != session)
+ if (ecall_info != NULL && ecall_info != info)
return FALSE;
return TRUE;
}
+struct pending_data {
+ unsigned int timeout;
+ struct service_entry *entry;
+ gboolean (*cb)(gpointer);
+};
+
+static void pending_timeout_free(gpointer data, gpointer user_data)
+{
+ struct pending_data *pending = data;
+
+ DBG("pending %p timeout %d", pending, pending->timeout);
+ g_source_remove(pending->timeout);
+ g_free(pending);
+}
+
+static void pending_timeout_remove_all(struct service_entry *entry)
+{
+ DBG("");
+
+ g_slist_foreach(entry->pending_timeouts, pending_timeout_free, NULL);
+ g_slist_free(entry->pending_timeouts);
+ entry->pending_timeouts = NULL;
+}
+
+static gboolean pending_timeout_cb(gpointer data)
+{
+ struct pending_data *pending = data;
+ struct service_entry *entry = pending->entry;
+ gboolean ret;
+
+ DBG("pending %p timeout %d", pending, pending->timeout);
+
+ ret = pending->cb(pending->entry);
+ if (ret == FALSE) {
+ entry->pending_timeouts =
+ g_slist_remove(entry->pending_timeouts,
+ pending);
+ g_free(pending);
+ }
+ return ret;
+}
+
+static connman_bool_t pending_timeout_add(unsigned int seconds,
+ gboolean (*cb)(gpointer),
+ struct service_entry *entry)
+{
+ struct pending_data *pending = g_try_new0(struct pending_data, 1);
+
+ if (pending == NULL || cb == NULL || entry == NULL) {
+ g_free(pending);
+ return FALSE;
+ }
+
+ pending->cb = cb;
+ pending->entry = entry;
+ pending->timeout = g_timeout_add_seconds(seconds, pending_timeout_cb,
+ pending);
+ entry->pending_timeouts = g_slist_prepend(entry->pending_timeouts,
+ pending);
+
+ DBG("pending %p entry %p timeout id %d", pending, entry,
+ pending->timeout);
+
+ return TRUE;
+}
+
static gboolean call_disconnect(gpointer user_data)
{
- struct connman_service *service = user_data;
+ struct service_entry *entry = user_data;
+ struct connman_service *service = entry->service;
/*
* TODO: We should mark this entry as pending work. In case
static gboolean call_connect(gpointer user_data)
{
- struct connman_service *service = user_data;
+ struct service_entry *entry = user_data;
+ struct connman_service *service = entry->service;
DBG("connect service %p", service);
__connman_service_connect(service);
return FALSE;
}
-static void test_and_disconnect(struct connman_session *session)
+static connman_bool_t deselect_service(struct session_info *info)
{
- struct session_info *info = session->info;
- struct connman_service *service;
- connman_bool_t disconnect;
+ struct service_entry *entry;
+ connman_bool_t disconnect, online;
+
+ DBG("");
if (info->entry == NULL)
- return;
+ return FALSE;
- disconnect = explicit_disconnect(session);
+ disconnect = explicit_disconnect(info);
+
+ online = is_connecting(info->entry->state) == TRUE ||
+ is_online(info->entry->state) == TRUE;
info->online = FALSE;
- info->reason = CONNMAN_SESSION_REASON_UNKNOWN;
info->entry->reason = CONNMAN_SESSION_REASON_UNKNOWN;
- service = info->entry->service;
+ entry = info->entry;
info->entry = NULL;
- if (disconnect == TRUE)
- g_timeout_add_seconds(0, call_disconnect, service);
+ DBG("disconnect %d online %d", disconnect, online);
+
+ if (disconnect == TRUE && online == TRUE)
+ pending_timeout_add(0, call_disconnect, entry);
+
+ return TRUE;
+}
+
+static void deselect_and_disconnect(struct connman_session *session,
+ enum connman_session_reason reason)
+{
+ struct session_info *info = session->info;
+
+ session->info_dirty |= deselect_service(info);
+
+ info->reason = reason;
+}
+
+static connman_bool_t select_online_service(struct session_info *info,
+ struct service_entry *entry)
+{
+ info->online = TRUE;
+
+ info->entry = entry;
+ info->entry->reason = info->reason;
+
+ if (explicit_connect(info->reason) == FALSE)
+ return TRUE;
+
+ __connman_service_session_inc(info->entry->service);
+
+ return TRUE;
+}
+
+static connman_bool_t select_offline_service(struct session_info *info,
+ struct service_entry *entry)
+{
+ if (explicit_connect(info->reason) == FALSE)
+ return FALSE;
+
+ info->online = FALSE;
+
+ info->entry = entry;
+ info->entry->reason = info->reason;
+
+ __connman_service_session_inc(info->entry->service);
+ pending_timeout_add(0, call_connect, entry);
+
+ return TRUE;
+}
+
+static connman_bool_t select_service(struct session_info *info,
+ struct service_entry *entry)
+{
+ DBG("service %p", entry->service);
+
+ if (is_online(entry->state) == TRUE)
+ return select_online_service(info, entry);
+ else
+ return select_offline_service(info, entry);
}
static void select_and_connect(struct connman_session *session,
struct session_info *info = session->info;
struct service_entry *entry = NULL;
GSequenceIter *iter;
- connman_bool_t do_connect = FALSE;
DBG("session %p reason %s", session, reason2string(reason));
case CONNMAN_SERVICE_STATE_CONFIGURATION:
case CONNMAN_SERVICE_STATE_READY:
case CONNMAN_SERVICE_STATE_ONLINE:
- /* connecting or connected */
- break;
case CONNMAN_SERVICE_STATE_IDLE:
case CONNMAN_SERVICE_STATE_DISCONNECT:
- if (explicit_connect(reason) == TRUE)
- do_connect = TRUE;
- break;
+ session->info_dirty |=
+ select_service(info, entry);
+ return;
case CONNMAN_SERVICE_STATE_UNKNOWN:
case CONNMAN_SERVICE_STATE_FAILURE:
- entry = NULL;
break;
}
- if (entry != NULL)
- break;
-
iter = g_sequence_iter_next(iter);
}
+}
- if (info->entry != NULL && info->entry != entry)
- test_and_disconnect(session);
+static struct service_entry *create_service_entry(struct connman_service *service,
+ const char *name,
+ enum connman_service_state state)
+{
+ struct service_entry *entry;
+ enum connman_service_type type;
+ int idx;
- if (entry == NULL) {
- info->entry = NULL;
- return;
- }
+ entry = g_try_new0(struct service_entry, 1);
+ if (entry == NULL)
+ return entry;
- info->entry = entry;
- info->entry->reason = reason;
-
- if (do_connect == TRUE) {
- __connman_service_session_inc(info->entry->service);
- g_timeout_add_seconds(0, call_connect, info->entry->service);
- } else if (reason == CONNMAN_SESSION_REASON_CONNECT) {
- /* session is already online take ref */
- __connman_service_session_inc(info->entry->service);
- }
+ entry->reason = CONNMAN_SESSION_REASON_UNKNOWN;
+ entry->state = state;
+ if (name != NULL)
+ entry->name = name;
+ else
+ entry->name = "";
+ entry->service = service;
+
+ idx = __connman_service_get_index(entry->service);
+ entry->ifname = connman_inet_ifname(idx);
+ if (entry->ifname == NULL)
+ entry->ifname = g_strdup("");
+
+ type = connman_service_get_type(entry->service);
+ entry->bearer = service2bearer(type);
+
+ return entry;
+}
+
+static void destroy_service_entry(gpointer data)
+{
+ struct service_entry *entry = data;
+
+ pending_timeout_remove_all(entry);
+ g_free(entry->ifname);
+
+ g_free(entry);
+}
+
+static void populate_service_list(struct connman_session *session)
+{
+ struct service_entry *entry;
+ GSequenceIter *iter;
+
+ session->service_hash =
+ g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, NULL);
+ session->service_list = __connman_service_get_list(session,
+ service_match,
+ create_service_entry,
+ destroy_service_entry);
+
+ g_sequence_sort(session->service_list, sort_services, session);
+
+ iter = g_sequence_get_begin_iter(session->service_list);
- info->online = is_online(entry->state);
+ while (g_sequence_iter_is_end(iter) == FALSE) {
+ entry = g_sequence_get(iter);
+
+ DBG("service %p type %s name %s", entry->service,
+ service2bearer(connman_service_get_type(entry->service)),
+ entry->name);
+
+ g_hash_table_replace(session->service_hash,
+ entry->service, iter);
+
+ iter = g_sequence_iter_next(iter);
+ }
}
static void session_changed(struct connman_session *session,
{
struct session_info *info = session->info;
struct session_info *info_last = session->info_last;
- GSequenceIter *iter;
+ GSequenceIter *service_iter = NULL, *service_iter_last = NULL;
+ GSequence *service_list_last;
+ GHashTable *service_hash_last;
/*
* TODO: This only a placeholder for the 'real' algorithm to
* play a bit around. So we are going to improve it step by step.
*/
- DBG("session %p trigger %s", session, trigger2string(trigger));
+ DBG("session %p trigger %s reason %s", session, trigger2string(trigger),
+ reason2string(info->reason));
+
+ if (info->entry != NULL) {
+ info->online = is_online(info->entry->state);
+ if (info_last->online != info->online)
+ session->info_dirty = TRUE;
+ }
switch (trigger) {
case CONNMAN_SESSION_TRIGGER_UNKNOWN:
DBG("ignore session changed event");
return;
case CONNMAN_SESSION_TRIGGER_SETTING:
- if (info->entry != NULL) {
- iter = g_hash_table_lookup(session->service_hash,
+ if (info->allowed_bearers != info_last->allowed_bearers) {
+
+ service_hash_last = session->service_hash;
+ service_list_last = session->service_list;
+
+ populate_service_list(session);
+
+ if (info->entry != NULL) {
+ service_iter_last = g_hash_table_lookup(
+ service_hash_last,
info->entry->service);
- if (iter == NULL) {
+ service_iter = g_hash_table_lookup(
+ session->service_hash,
+ info->entry->service);
+ }
+
+ if (service_iter == NULL && service_iter_last != NULL) {
/*
- * This service is not part of this
- * session anymore.
+ * The currently selected service is
+ * not part of this session anymore.
*/
- test_and_disconnect(session);
+ deselect_and_disconnect(session, info->reason);
}
+
+ g_hash_table_remove_all(service_hash_last);
+ g_sequence_free(service_list_last);
}
if (info->online == FALSE) {
break;
}
+ if (info->entry != NULL &&
+ is_connecting(info->entry->state) == TRUE) {
+ break;
+ }
+
select_and_connect(session,
CONNMAN_SESSION_REASON_CONNECT);
break;
case CONNMAN_SESSION_TRIGGER_DISCONNECT:
- test_and_disconnect(session);
+ deselect_and_disconnect(session,
+ CONNMAN_SESSION_REASON_DISCONNECT);
break;
case CONNMAN_SESSION_TRIGGER_PERIODIC:
break;
case CONNMAN_SESSION_TRIGGER_SERVICE:
- switch (info->reason) {
- case CONNMAN_SESSION_REASON_CONNECT:
- if (info->entry != NULL &&
- (is_connecting(info->entry->state) == TRUE ||
+ if (info->entry != NULL &&
+ (is_connecting(info->entry->state) == TRUE ||
is_online(info->entry->state) == TRUE)) {
- break;
- }
-
- /*
- * We are not online, we are not connecting, that
- * means we could still have a valid info->entry.
- * Though something has changed from the service layer.
- * Therefore we want to restart the algorithm. Before we
- * can do that we have to cleanup a potientional old entry.
- */
- test_and_disconnect(session);
- info->reason = CONNMAN_SESSION_REASON_CONNECT; /* restore value */
-
- DBG("Retry to find a matching session");
- /*
- * The user called Connect() but there was no
- * matching session available at this point.
- * Now there might be a new one. Let's retry
- * to select and connect
- */
- select_and_connect(session,
- CONNMAN_SESSION_REASON_CONNECT);
- break;
- case CONNMAN_SESSION_REASON_PERIODIC:
- case CONNMAN_SESSION_REASON_FREE_RIDE:
- if (info->stay_connected == TRUE) {
- DBG("StayConnected");
- select_and_connect(session,
- CONNMAN_SESSION_REASON_CONNECT);
- } else {
- select_and_connect(session,
- CONNMAN_SESSION_REASON_FREE_RIDE);
- }
- break;
- case CONNMAN_SESSION_REASON_UNKNOWN:
break;
}
+
+ deselect_and_disconnect(session, info->reason);
+
+ if (info->reason == CONNMAN_SESSION_REASON_FREE_RIDE ||
+ info->stay_connected == TRUE) {
+ select_and_connect(session, info->reason);
+ }
+
break;
case CONNMAN_SESSION_TRIGGER_ECALL:
- if (info->online == FALSE && info->entry->service != NULL)
- test_and_disconnect(session);
+ if (info->online == FALSE && info->entry != NULL &&
+ info->entry->service != NULL) {
+ deselect_and_disconnect(session, info->reason);
+ }
break;
}
- if (info->entry != info_last->entry)
- session->info_dirty = TRUE;
-
session_notify(session);
}
DBusMessage *msg, void *user_data)
{
struct connman_session *session = user_data;
+ struct session_info *info = session->info;
DBG("session %p", session);
- if (ecall_session != NULL && ecall_session != session)
+ if (ecall_info != NULL && ecall_info != info)
return __connman_error_failed(msg, EBUSY);
session_changed(session, CONNMAN_SESSION_TRIGGER_CONNECT);
DBusMessage *msg, void *user_data)
{
struct connman_session *session = user_data;
+ struct session_info *info = session->info;
DBG("session %p", session);
- if (ecall_session != NULL && ecall_session != session)
+ if (ecall_info != NULL && ecall_info != info)
return __connman_error_failed(msg, EBUSY);
session_changed(session, CONNMAN_SESSION_TRIGGER_DISCONNECT);
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
-static struct service_entry *create_service_entry(struct connman_service *service,
- const char *name,
- enum connman_service_state state)
-{
- struct service_entry *entry;
- enum connman_service_type type;
- int idx;
-
- entry = g_try_new0(struct service_entry, 1);
- if (entry == NULL)
- return entry;
-
- entry->reason = CONNMAN_SESSION_REASON_UNKNOWN;
- entry->state = state;
- if (name != NULL)
- entry->name = name;
- else
- entry->name = "";
- entry->service = service;
-
- idx = __connman_service_get_index(entry->service);
- entry->ifname = connman_inet_ifname(idx);
- if (entry->ifname == NULL)
- entry->ifname = g_strdup("");
-
- type = connman_service_get_type(entry->service);
- entry->bearer = service2bearer(type);
-
- return entry;
-}
-
-static void destroy_service_entry(gpointer data)
-{
- struct service_entry *entry = data;
-
- g_free(entry->ifname);
-
- g_free(entry);
-}
-
-static void update_allowed_bearers(struct connman_session *session)
-{
- struct service_entry *entry;
- GSequenceIter *iter;
-
- if (session->service_list != NULL) {
- g_hash_table_remove_all(session->service_hash);
- g_sequence_free(session->service_list);
- }
-
- session->service_list = __connman_service_get_list(session,
- service_match,
- create_service_entry,
- destroy_service_entry);
-
- g_sequence_sort(session->service_list, sort_services, session);
-
- iter = g_sequence_get_begin_iter(session->service_list);
-
- while (g_sequence_iter_is_end(iter) == FALSE) {
- entry = g_sequence_get(iter);
-
- DBG("service %p type %s name %s", entry->service,
- service2bearer(connman_service_get_type(entry->service)),
- entry->name);
-
- g_hash_table_replace(session->service_hash,
- entry->service, iter);
-
- iter = g_sequence_iter_next(iter);
- }
-
- session->info_dirty = TRUE;
-}
-
static void update_ecall_sessions(struct connman_session *session)
{
struct session_info *info = session->info;
struct session_info *info = session->info;
struct session_info *info_last = session->info_last;
- DBG("session %p ecall_session %p ecall %d -> %d", session,
- ecall_session, info_last->ecall, info->ecall);
+ DBG("session %p ecall_info %p ecall %d -> %d", session,
+ ecall_info, info_last->ecall, info->ecall);
- if (ecall_session == NULL) {
+ if (ecall_info == NULL) {
if (!(info_last->ecall == FALSE && info->ecall == TRUE))
goto err;
- ecall_session = session;
- } else if (ecall_session == session) {
+ ecall_info = info;
+ } else if (ecall_info == info) {
if (!(info_last->ecall == TRUE && info->ecall == FALSE))
goto err;
- ecall_session = NULL;
+ ecall_info = NULL;
} else {
goto err;
}
info->allowed_bearers = allowed_bearers;
- update_allowed_bearers(session);
+ session->info_dirty = TRUE;
} else {
goto err;
}
g_dbus_unregister_interface(connection, session->session_path,
CONNMAN_SESSION_INTERFACE);
- test_and_disconnect(session);
+ deselect_and_disconnect(session,
+ CONNMAN_SESSION_REASON_DISCONNECT);
g_hash_table_remove(session_hash, session->session_path);
DBusMessage *msg, void *user_data)
{
struct connman_session *session = user_data;
+ struct session_info *info = session->info;
DBG("session %p", session);
+ if (ecall_info != NULL && ecall_info != info)
+ return __connman_error_failed(msg, EBUSY);
+
+ session_disconnect(session);
+
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
DBG("owner %s", owner);
- if (ecall_session != NULL) {
+ if (ecall_info != NULL) {
/*
* If there is an emergency call already going on,
* ignore session creation attempt
g_dbus_add_disconnect_watch(connection, session->owner,
owner_disconnect, session, NULL);
- session->service_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
- NULL, NULL);
-
info->online = FALSE;
info->priority = priority;
info->avoid_handover = avoid_handover;
DBUS_TYPE_INVALID);
- update_allowed_bearers(session);
+ populate_service_list(session);
if (info->ecall == TRUE) {
- ecall_session = session;
+ ecall_info = info;
update_ecall_sessions(session);
}
{
GHashTableIter iter;
gpointer key, value;
- struct connman_session *session;
- struct session_info *info, *info_last;
DBG("service %p state %d", service, state);
g_hash_table_iter_init(&iter, session_hash);
while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
+ struct connman_session *session = value;
GSequenceIter *service_iter;
- session = value;
- info = session->info;
- info_last = session->info_last;
-
service_iter = g_hash_table_lookup(session->service_hash, service);
if (service_iter != NULL) {
struct service_entry *entry;
entry = g_sequence_get(service_iter);
entry->state = state;
-
- if (info->entry == entry) {
- info->online = is_online(entry->state);
- if (info_last->online != info->online)
- session->info_dirty = TRUE;
- }
}
session_changed(session,
#include <unistd.h>
#include <string.h>
#include <limits.h>
+#include <sys/stat.h>
#include "connman.h"
+#define MODE (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | \
+ S_IXGRP | S_IROTH | S_IXOTH)
+
#ifdef TEMP_FAILURE_RETRY
#define TFR TEMP_FAILURE_RETRY
#else
file->name = g_strdup(name);
- file->fd = TFR(open(file->name, O_RDWR | O_CREAT, 0644));
+ file->fd = TFR(open(file->name, O_RDWR | O_CREAT | O_CLOEXEC, 0644));
if (file->fd < 0) {
connman_error("open error %s for %s",
strerror(errno), file->name);
static int stats_open_temp(struct stats_file *file)
{
- file->name = g_strdup_printf("%s/stats/stats.XXXXXX.tmp",
+ file->name = g_strdup_printf("%s/stats.XXXXXX.tmp",
STORAGEDIR);
file->fd = g_mkstemp_full(file->name, O_RDWR | O_CREAT, 0644);
if (file->fd < 0) {
int __connman_stats_service_register(struct connman_service *service)
{
struct stats_file *file;
- char *name;
+ char *name, *dir;
int err;
DBG("service %p", service);
return -EALREADY;
}
- name = g_strdup_printf("%s/stats/%s.data", STORAGEDIR,
+ dir = g_strdup_printf("%s/%s", STORAGEDIR,
+ __connman_service_get_ident(service));
+
+ /* If the dir doesn't exist, create it */
+ if (!g_file_test(dir, G_FILE_TEST_IS_DIR)) {
+ if(mkdir(dir, MODE) < 0) {
+ if (errno != EEXIST) {
+ g_free(dir);
+
+ err = -errno;
+ goto err;
+ }
+ }
+ }
+
+ g_free(dir);
+
+ name = g_strdup_printf("%s/%s/data", STORAGEDIR,
__connman_service_get_ident(service));
- file->history_name = g_strdup_printf("%s/stats/%s.history", STORAGEDIR,
+ file->history_name = g_strdup_printf("%s/%s/history", STORAGEDIR,
__connman_service_get_ident(service));
/* TODO: Use a global config file instead of hard coded value. */
#include <errno.h>
#include <unistd.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+#include <connman/storage.h>
#include "connman.h"
-#define PROFILE_SUFFIX "profile"
-#define CONFIG_SUFFIX "config"
+#define SETTINGS "settings"
+#define DEFAULT "default.profile"
-static GSList *storage_list = NULL;
+#define MODE (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | \
+ S_IXGRP | S_IROTH | S_IXOTH)
-static gint compare_priority(gconstpointer a, gconstpointer b)
+static GKeyFile *storage_load(const char *pathname)
{
- const struct connman_storage *storage1 = a;
- const struct connman_storage *storage2 = b;
+ GKeyFile *keyfile = NULL;
+ GError *error = NULL;
+
+ DBG("Loading %s", pathname);
+
+ keyfile = g_key_file_new();
+
+ if (!g_key_file_load_from_file(keyfile, pathname, 0, &error)) {
+ DBG("Unable to load %s: %s", pathname, error->message);
+ g_clear_error(&error);
- return storage2->priority - storage1->priority;
+ g_key_file_free(keyfile);
+ keyfile = NULL;
+ }
+
+ return keyfile;
}
-/**
- * connman_storage_register:
- * @storage: storage module
- *
- * Register a new storage module
- *
- * Returns: %0 on success
- */
-int connman_storage_register(struct connman_storage *storage)
+static void storage_save(GKeyFile *keyfile, char *pathname)
{
- DBG("storage %p name %s", storage, storage->name);
+ gchar *data = NULL;
+ gsize length = 0;
+ GError *error = NULL;
- storage_list = g_slist_insert_sorted(storage_list, storage,
- compare_priority);
+ data = g_key_file_to_data(keyfile, &length, NULL);
- return 0;
+ if (!g_file_set_contents(pathname, data, length, &error)) {
+ DBG("Failed to store information: %s", error->message);
+ g_free(error);
+ }
+
+ g_free(data);
}
-/**
- * connman_storage_unregister:
- * @storage: storage module
- *
- * Remove a previously registered storage module
- */
-void connman_storage_unregister(struct connman_storage *storage)
+static void storage_delete(const char *pathname)
{
- DBG("storage %p name %s", storage, storage->name);
+ DBG("file path %s", pathname);
- storage_list = g_slist_remove(storage_list, storage);
+ if (unlink(pathname) < 0)
+ connman_error("Failed to remove %s", pathname);
}
-GKeyFile *__connman_storage_open(const char *ident, const char *suffix)
+GKeyFile *__connman_storage_load_global()
{
- GKeyFile *keyfile;
- gchar *pathname, *data = NULL;
- gboolean result;
- gsize length;
-
- DBG("ident %s suffix %s", ident, suffix);
+ gchar *pathname;
+ GKeyFile *keyfile = NULL;
- pathname = g_strdup_printf("%s/%s.%s", STORAGEDIR, ident, suffix);
- if (pathname == NULL)
+ pathname = g_strdup_printf("%s/%s", STORAGEDIR, SETTINGS);
+ if(pathname == NULL)
return NULL;
- result = g_file_get_contents(pathname, &data, &length, NULL);
+ keyfile = storage_load(pathname);
g_free(pathname);
- keyfile = g_key_file_new();
-
- if (result == FALSE)
- goto done;
+ return keyfile;
+}
- if (length > 0)
- g_key_file_load_from_data(keyfile, data, length, 0, NULL);
+void __connman_storage_save_global(GKeyFile *keyfile)
+{
+ gchar *pathname;
- g_free(data);
+ pathname = g_strdup_printf("%s/%s", STORAGEDIR, SETTINGS);
+ if(pathname == NULL)
+ return;
-done:
- DBG("keyfile %p", keyfile);
+ storage_save(keyfile, pathname);
- return keyfile;
+ g_free(pathname);
}
-void __connman_storage_close(const char *ident, const char *suffix,
- GKeyFile *keyfile, gboolean save)
+void __connman_storage_delete_global()
{
- gchar *pathname, *data = NULL;
- gsize length = 0;
-
- DBG("ident %s suffix %s keyfile %p save %d",
- ident, suffix, keyfile, save);
+ gchar *pathname;
- if (save == FALSE) {
- g_key_file_free(keyfile);
+ pathname = g_strdup_printf("%s/%s", STORAGEDIR, SETTINGS);
+ if(pathname == NULL)
return;
- }
- pathname = g_strdup_printf("%s/%s.%s", STORAGEDIR, ident, suffix);
- if (pathname == NULL)
- return;
+ storage_delete(pathname);
- data = g_key_file_to_data(keyfile, &length, NULL);
+ g_free(pathname);
+}
- if (g_file_set_contents(pathname, data, length, NULL) == FALSE)
- connman_error("Failed to store information");
+GKeyFile *__connman_storage_load_config(const char *ident)
+{
+ gchar *pathname;
+ GKeyFile *keyfile = NULL;
- g_free(data);
+ pathname = g_strdup_printf("%s/%s.config", STORAGEDIR, ident);
+ if(pathname == NULL)
+ return NULL;
+
+ keyfile = storage_load(pathname);
g_free(pathname);
- g_key_file_free(keyfile);
+ return keyfile;
}
-void __connman_storage_delete(const char *ident, const char *suffix)
+void __connman_storage_save_config(GKeyFile *keyfile, const char *ident)
{
gchar *pathname;
- DBG("ident %s suffix %s", ident, suffix);
-
- pathname = g_strdup_printf("%s/%s.%s", STORAGEDIR, ident, suffix);
- if (pathname == NULL)
+ pathname = g_strdup_printf("%s/%s.config", STORAGEDIR, ident);
+ if(pathname == NULL)
return;
- if (unlink(pathname) < 0)
- connman_error("Failed to remove %s", pathname);
+ storage_save(keyfile, pathname);
}
-GKeyFile *__connman_storage_open_profile(const char *ident)
+void __connman_storage_delete_config(const char *ident)
{
- return __connman_storage_open(ident, PROFILE_SUFFIX);
-}
+ gchar *pathname;
-void __connman_storage_close_profile(const char *ident,
- GKeyFile *keyfile, gboolean save)
-{
- __connman_storage_close(ident, PROFILE_SUFFIX, keyfile, save);
-}
+ pathname = g_strdup_printf("%s/%s.config", STORAGEDIR, ident);
+ if(pathname == NULL)
+ return;
-void __connman_storage_delete_profile(const char *ident)
-{
- __connman_storage_delete(ident, PROFILE_SUFFIX);
-}
+ storage_delete(pathname);
-GKeyFile *__connman_storage_open_config(const char *ident)
-{
- return __connman_storage_open(ident, CONFIG_SUFFIX);
+ g_free(pathname);
}
-void __connman_storage_close_config(const char *ident,
- GKeyFile *keyfile, gboolean save)
+GKeyFile *__connman_storage_open_service(const char *service_id)
{
- __connman_storage_close(ident, CONFIG_SUFFIX, keyfile, save);
-}
+ gchar *pathname;
+ GKeyFile *keyfile = NULL;
-void __connman_storage_delete_config(const char *ident)
-{
- __connman_storage_delete(ident, CONFIG_SUFFIX);
+ pathname = g_strdup_printf("%s/%s/%s", STORAGEDIR, service_id, SETTINGS);
+ if(pathname == NULL)
+ return NULL;
+
+ keyfile = storage_load(pathname);
+ if (keyfile) {
+ g_free(pathname);
+ return keyfile;
+ }
+
+ g_free(pathname);
+
+ keyfile = g_key_file_new();
+
+ return keyfile;
}
-int __connman_storage_init_profile(void)
+gchar **connman_storage_get_services()
{
- GSList *list;
+ struct dirent *d;
+ gchar *str;
+ DIR *dir;
+ GString *result;
+ gchar **services = NULL;
+ struct stat buf;
+ int ret;
+
+ dir = opendir(STORAGEDIR);
+ if (dir == NULL)
+ return NULL;
- DBG("");
+ result = g_string_new(NULL);
+
+ while ((d = readdir(dir))) {
+ if (strcmp(d->d_name, ".") == 0 ||
+ strcmp(d->d_name, "..") == 0 ||
+ strncmp(d->d_name, "provider_", 9) == 0)
+ continue;
+
+ switch (d->d_type) {
+ case DT_DIR:
+ /*
+ * If the settings file is not found, then
+ * assume this directory is not a services dir.
+ */
+ str = g_strdup_printf("%s/%s/settings", STORAGEDIR,
+ d->d_name);
+ ret = stat(str, &buf);
+ g_free(str);
+ if (ret < 0)
+ continue;
+
+ g_string_append_printf(result, "%s/", d->d_name);
+ break;
+ }
+ }
- for (list = storage_list; list; list = list->next) {
- struct connman_storage *storage = list->data;
+ closedir(dir);
- if (storage->profile_init) {
- if (storage->profile_init() == 0)
- return 0;
- }
+ str = g_string_free(result, FALSE);
+ if (str) {
+ str[strlen(str) - 1] = '\0';
+ services = g_strsplit(str, "/", -1);
}
+ g_free(str);
- return -ENOENT;
+ return services;
}
-int __connman_storage_load_profile(struct connman_profile *profile)
+GKeyFile *connman_storage_load_service(const char *service_id)
{
- GSList *list;
+ gchar *pathname;
+ GKeyFile *keyfile = NULL;
- DBG("profile %p", profile);
+ pathname = g_strdup_printf("%s/%s/%s", STORAGEDIR, service_id, SETTINGS);
+ if(pathname == NULL)
+ return NULL;
- for (list = storage_list; list; list = list->next) {
- struct connman_storage *storage = list->data;
+ keyfile = storage_load(pathname);
+ g_free(pathname);
+ if (keyfile)
+ return keyfile;
- if (storage->profile_load) {
- if (storage->profile_load(profile) == 0)
- return 0;
- }
- }
+ pathname = g_strdup_printf("%s/%s", STORAGEDIR, DEFAULT);
+ if(pathname == NULL)
+ return NULL;
- return -ENOENT;
+ keyfile = storage_load(pathname);
+
+ g_free(pathname);
+
+ return keyfile;
}
-int __connman_storage_save_profile(struct connman_profile *profile)
+void __connman_storage_save_service(GKeyFile *keyfile, const char *service_id)
{
- GSList *list;
+ gchar *pathname, *dirname;
- DBG("profile %p", profile);
-
- for (list = storage_list; list; list = list->next) {
- struct connman_storage *storage = list->data;
+ dirname = g_strdup_printf("%s/%s", STORAGEDIR, service_id);
+ if(dirname == NULL)
+ return;
- if (storage->profile_save) {
- if (storage->profile_save(profile) == 0)
- return 0;
+ /* If the dir doesn't exist, create it */
+ if (!g_file_test(dirname, G_FILE_TEST_IS_DIR)) {
+ if(mkdir(dirname, MODE) < 0) {
+ if (errno != EEXIST) {
+ g_free(dirname);
+ return;
+ }
}
}
- return -ENOENT;
+ pathname = g_strdup_printf("%s/%s", dirname, SETTINGS);
+
+ g_free(dirname);
+
+ storage_save(keyfile, pathname);
+
+ g_free(pathname);
}
-int __connman_storage_load_service(struct connman_service *service)
+GKeyFile *__connman_storage_load_provider(const char *identifier)
{
- GSList *list;
+ gchar *pathname;
+ GKeyFile *keyfile;
- DBG("service %p", service);
+ pathname = g_strdup_printf("%s/%s_%s/%s", STORAGEDIR, "provider",
+ identifier, SETTINGS);
+ if (pathname == NULL)
+ return NULL;
- for (list = storage_list; list; list = list->next) {
- struct connman_storage *storage = list->data;
+ keyfile = storage_load(pathname);
+ g_free(pathname);
- if (storage->service_load) {
- if (storage->service_load(service) == 0)
- return 0;
- }
+ return keyfile;
+}
+
+void __connman_storage_save_provider(GKeyFile *keyfile, const char *identifier)
+{
+ gchar *pathname, *dirname;
+
+ dirname = g_strdup_printf("%s/%s_%s", STORAGEDIR,
+ "provider", identifier);
+ if (dirname == NULL)
+ return;
+
+ if (g_file_test(dirname, G_FILE_TEST_IS_DIR) == FALSE &&
+ mkdir(dirname, MODE) < 0) {
+ g_free(dirname);
+ return;
}
- return -ENOENT;
+ pathname = g_strdup_printf("%s/%s", dirname, SETTINGS);
+ g_free(dirname);
+
+ storage_save(keyfile, pathname);
+ g_free(pathname);
}
-int __connman_storage_save_service(struct connman_service *service)
+/*
+ * This function migrates keys from default.profile to settings file.
+ * This can be removed once the migration is over.
+*/
+void __connman_storage_migrate()
{
- GSList *list;
+ gchar *pathname;
+ GKeyFile *keyfile_def = NULL;
+ GKeyFile *keyfile = NULL;
+ GError *error = NULL;
+ connman_bool_t val;
+
+ /* If setting file exists, migration has been done. */
+ keyfile = __connman_storage_load_global();
+ if (keyfile) {
+ g_key_file_free(keyfile);
+ return;
+ }
- DBG("service %p", service);
+ pathname = g_strdup_printf("%s/%s", STORAGEDIR, DEFAULT);
+ if(pathname == NULL)
+ return;
- for (list = storage_list; list; list = list->next) {
- struct connman_storage *storage = list->data;
+ /* Copy global settings from default.profile to settings. */
+ keyfile = g_key_file_new();
- if (storage->service_save) {
- if (storage->service_save(service) == 0)
- return 0;
- }
+ /* If default.profile doesn't exists, create settings with defaults. */
+ keyfile_def = storage_load(pathname);
+ if (keyfile_def == NULL) {
+ g_key_file_set_boolean(keyfile, "global",
+ "OfflineMode", FALSE);
+
+ g_key_file_set_boolean(keyfile, "WiFi",
+ "Enable", FALSE);
+
+ g_key_file_set_boolean(keyfile, "Bluetooth",
+ "Enable", FALSE);
+
+ g_key_file_set_boolean(keyfile, "Wired",
+ "Enable", FALSE);
+
+ g_key_file_set_boolean(keyfile, "3G",
+ "Enable", FALSE);
+
+ g_key_file_set_boolean(keyfile, "WiMAX",
+ "Enable", FALSE);
+
+ goto done;
}
- return -ENOENT;
-}
+ /* offline mode */
+ val = g_key_file_get_boolean(keyfile_def, "global",
+ "OfflineMode", &error);
+ if (error != NULL) {
+ g_clear_error(&error);
+ val = FALSE;
+ }
-int __connman_storage_load_device(struct connman_device *device)
-{
- GSList *list;
+ g_key_file_set_boolean(keyfile, "global",
+ "OfflineMode", val);
- DBG("device %p", device);
+ /* wifi */
+ val = g_key_file_get_boolean(keyfile_def, "WiFi",
+ "Enable", &error);
+ if (error != NULL) {
+ g_clear_error(&error);
+ val = FALSE;
+ }
- for (list = storage_list; list; list = list->next) {
- struct connman_storage *storage = list->data;
+ g_key_file_set_boolean(keyfile, "WiFi",
+ "Enable", val);
- if (storage->device_load) {
- if (storage->device_load(device) == 0)
- return 0;
- }
+ /* bluetooth */
+ val = g_key_file_get_boolean(keyfile_def, "Bluetooth",
+ "Enable", &error);
+ if (error != NULL) {
+ g_clear_error(&error);
+ val = FALSE;
}
- return -ENOENT;
-}
+ g_key_file_set_boolean(keyfile, "Bluetooth",
+ "Enable", val);
-int __connman_storage_save_device(struct connman_device *device)
-{
- GSList *list;
+ /* wired */
+ val = g_key_file_get_boolean(keyfile_def, "Wired",
+ "Enable", &error);
+ if (error != NULL) {
+ g_clear_error(&error);
+ val = FALSE;
+ }
- DBG("device %p", device);
+ g_key_file_set_boolean(keyfile, "Wired",
+ "Enable", val);
- for (list = storage_list; list; list = list->next) {
- struct connman_storage *storage = list->data;
+ /* 3G */
+ val = g_key_file_get_boolean(keyfile_def, "3G",
+ "Enable", &error);
+ if (error != NULL) {
+ g_clear_error(&error);
+ val = FALSE;
+ }
- if (storage->device_save) {
- if (storage->device_save(device) == 0)
- return 0;
- }
+ g_key_file_set_boolean(keyfile, "3G",
+ "Enable", val);
+
+ /* WiMAX */
+ val = g_key_file_get_boolean(keyfile_def, "WiMAX",
+ "Enable", &error);
+ if (error != NULL) {
+ g_clear_error(&error);
+ val = FALSE;
}
- return -ENOENT;
-}
+ g_key_file_set_boolean(keyfile, "WiMAX",
+ "Enable", val);
-int __connman_storage_init(void)
-{
- DBG("");
+done:
+ __connman_storage_save_global(keyfile);
- return 0;
-}
+ g_key_file_free(keyfile);
-void __connman_storage_cleanup(void)
-{
- DBG("");
+ if (keyfile_def)
+ g_key_file_free(keyfile_def);
+
+ g_free(pathname);
}
static GHashTable *task_hash = NULL;
-static volatile gint task_counter;
+static volatile int task_counter;
static DBusConnection *connection;
if (task == NULL)
return NULL;
- counter = g_atomic_int_exchange_and_add(&task_counter, 1);
+ counter = __sync_fetch_and_add(&task_counter, 1);
task->path = g_strdup_printf("/task/%d", counter);
task->pid = -1;
return 0;
}
+static gboolean force_kill_timeout(gpointer user_data)
+{
+ pid_t pid = GPOINTER_TO_INT(user_data);
+ if (pid > 0) {
+ if (kill(pid, SIGKILL) == 0)
+ connman_warn("killing pid %d by force", pid);
+ }
+
+ return FALSE;
+}
+
+static gboolean kill_timeout(gpointer user_data)
+{
+ pid_t pid = GPOINTER_TO_INT(user_data);
+ if (pid > 0) {
+ if (kill(pid, SIGINT) == 0)
+ g_timeout_add_seconds(1, force_kill_timeout,
+ GINT_TO_POINTER(pid));
+ }
+
+ return FALSE;
+}
+
+static gboolean check_kill(gpointer user_data)
+{
+ pid_t pid = GPOINTER_TO_INT(user_data);
+ if (pid > 0) {
+ if (kill(pid, 0) == 0) {
+ connman_info("pid %d was not killed, "
+ "retrying after 2 sec", pid);
+ g_timeout_add_seconds(2, kill_timeout,
+ GINT_TO_POINTER(pid));
+ }
+ }
+
+ return FALSE;
+}
+
/**
* connman_task_stop:
* @task: task structure
{
DBG("task %p", task);
- if (task->pid > 0)
+ if (task->pid > 0) {
kill(task->pid, SIGTERM);
+ g_timeout_add_seconds(0, check_kill,
+ GINT_TO_POINTER(task->pid));
+ }
+
return 0;
}
struct connman_task *task;
struct notify_data *notify;
const char *path, *member;
+ DBusMessage *reply = NULL;
if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
if (task == NULL)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- if (dbus_message_get_no_reply(message) == FALSE) {
- DBusMessage *reply;
+ member = dbus_message_get_member(message);
+ if (member == NULL)
+ goto send_reply;
+
+ notify = g_hash_table_lookup(task->notify, member);
+ if (notify == NULL)
+ goto send_reply;
+
+ if (notify->func)
+ reply = notify->func(task, message, notify->data);
+
+send_reply:
+ if (dbus_message_get_no_reply(message) == FALSE &&
+ reply == NULL) {
reply = dbus_message_new_method_return(message);
if (reply == NULL)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ }
+ if (reply != NULL) {
dbus_connection_send(connection, reply, NULL);
dbus_message_unref(reply);
}
- member = dbus_message_get_member(message);
- if (member == NULL)
- return DBUS_HANDLER_RESULT_HANDLED;
-
- notify = g_hash_table_lookup(task->notify, member);
- if (notify == NULL)
- return DBUS_HANDLER_RESULT_HANDLED;
-
- if (notify->func)
- notify->func(task, message, notify->data);
-
return DBUS_HANDLER_RESULT_HANDLED;
}
dbus_connection_add_filter(connection, task_filter, NULL, NULL);
- g_atomic_int_set(&task_counter, 0);
+ task_counter = 0;
+ __sync_synchronize();
task_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, free_task);
static DBusConnection *connection;
-static GHashTable *rfkill_table;
-static GHashTable *device_table;
static GSList *technology_list = NULL;
+static connman_bool_t global_offlinemode;
+
struct connman_rfkill {
unsigned int index;
enum connman_service_type type;
enum connman_technology_state {
CONNMAN_TECHNOLOGY_STATE_UNKNOWN = 0,
CONNMAN_TECHNOLOGY_STATE_OFFLINE = 1,
- CONNMAN_TECHNOLOGY_STATE_AVAILABLE = 2,
- CONNMAN_TECHNOLOGY_STATE_ENABLED = 3,
- CONNMAN_TECHNOLOGY_STATE_CONNECTED = 4,
+ CONNMAN_TECHNOLOGY_STATE_ENABLED = 2,
+ CONNMAN_TECHNOLOGY_STATE_CONNECTED = 3,
};
struct connman_technology {
- gint refcount;
+ int refcount;
enum connman_service_type type;
enum connman_technology_state state;
char *path;
GHashTable *rfkill_list;
GSList *device_list;
- gint enabled;
- gint blocked;
+ int enabled;
char *regdom;
connman_bool_t tethering;
char *tethering_ident;
char *tethering_passphrase;
+ connman_bool_t enable_persistent; /* Save the tech state */
+
struct connman_technology_driver *driver;
void *driver_data;
+
+ DBusMessage *pending_reply;
+ guint pending_timeout;
};
static GSList *driver_list = NULL;
void connman_technology_tethering_notify(struct connman_technology *technology,
connman_bool_t enabled)
{
+ GSList *list;
+
DBG("technology %p enabled %u", technology, enabled);
if (technology->tethering == enabled)
if (enabled == TRUE)
__connman_tethering_set_enabled();
- else
- __connman_tethering_set_disabled();
+ else {
+ for (list = technology_list; list; list = list->next) {
+ struct connman_technology *other_tech = list->data;
+ if (other_tech->tethering == TRUE)
+ break;
+ }
+ if (list == NULL)
+ __connman_tethering_set_disabled();
+ }
}
static int set_tethering(struct connman_technology *technology,
- const char *bridge, connman_bool_t enabled)
+ connman_bool_t enabled)
{
- const char *ident, *passphrase;
+ const char *ident, *passphrase, *bridge;
ident = technology->tethering_ident;
passphrase = technology->tethering_passphrase;
technology->driver->set_tethering == NULL)
return -EOPNOTSUPP;
+ bridge = __connman_tethering_get_bridge();
+ if (bridge == NULL)
+ return -EOPNOTSUPP;
+
if (technology->type == CONNMAN_SERVICE_TYPE_WIFI &&
(ident == NULL || passphrase == NULL))
return -EINVAL;
break;
case CONNMAN_TECHNOLOGY_STATE_OFFLINE:
return "offline";
- case CONNMAN_TECHNOLOGY_STATE_AVAILABLE:
- return "available";
case CONNMAN_TECHNOLOGY_STATE_ENABLED:
return "enabled";
case CONNMAN_TECHNOLOGY_STATE_CONNECTED:
return NULL;
}
+static void load_state(struct connman_technology *technology)
+{
+ GKeyFile *keyfile;
+ gchar *identifier;
+ GError *error = NULL;
+ connman_bool_t enable;
+
+ DBG("technology %p", technology);
+
+ keyfile = __connman_storage_load_global();
+ /* Fallback on disabling technology if file not found. */
+ if (keyfile == NULL) {
+ technology->enable_persistent = FALSE;
+ return;
+ }
+
+ identifier = g_strdup_printf("%s", get_name(technology->type));
+ if (identifier == NULL)
+ goto done;
+
+ enable = g_key_file_get_boolean(keyfile, identifier, "Enable", &error);
+ if (error == NULL)
+ technology->enable_persistent = enable;
+ else {
+ technology->enable_persistent = FALSE;
+ g_clear_error(&error);
+ }
+done:
+ g_free(identifier);
+
+ g_key_file_free(keyfile);
+
+ return;
+}
+
+static void save_state(struct connman_technology *technology)
+{
+ GKeyFile *keyfile;
+ gchar *identifier;
+
+ DBG("technology %p", technology);
+
+ keyfile = __connman_storage_load_global();
+ if (keyfile == NULL)
+ keyfile = g_key_file_new();
+
+ identifier = g_strdup_printf("%s", get_name(technology->type));
+ if (identifier == NULL)
+ goto done;
+
+ g_key_file_set_boolean(keyfile, identifier, "Enable",
+ technology->enable_persistent);
+
+done:
+ g_free(identifier);
+
+ __connman_storage_save_global(keyfile);
+
+ g_key_file_free(keyfile);
+
+ return;
+}
+
+connman_bool_t __connman_technology_get_offlinemode(void)
+{
+ return global_offlinemode;
+}
+
+static void connman_technology_save_offlinemode()
+{
+ GKeyFile *keyfile;
+
+ keyfile = __connman_storage_load_global();
+ if (keyfile == NULL)
+ keyfile = g_key_file_new();
+
+ g_key_file_set_boolean(keyfile, "global",
+ "OfflineMode", global_offlinemode);
+
+ __connman_storage_save_global(keyfile);
+
+ g_key_file_free(keyfile);
+
+ return;
+}
+
+static connman_bool_t connman_technology_load_offlinemode()
+{
+ GKeyFile *keyfile;
+ GError *error = NULL;
+ connman_bool_t offlinemode;
+
+ /* If there is a error, we enable offlinemode */
+ keyfile = __connman_storage_load_global();
+ if (keyfile == NULL)
+ return TRUE;
+
+ offlinemode = g_key_file_get_boolean(keyfile, "global",
+ "OfflineMode", &error);
+ if (error != NULL) {
+ offlinemode = TRUE;
+ g_clear_error(&error);
+ }
+
+ g_key_file_free(keyfile);
+
+ return offlinemode;
+}
+
static DBusMessage *get_properties(DBusConnection *conn,
DBusMessage *message, void *user_data)
{
if (g_str_equal(name, "Tethering") == TRUE) {
int err;
connman_bool_t tethering;
- const char *bridge;
if (type != DBUS_TYPE_BOOLEAN)
return __connman_error_invalid_arguments(msg);
if (technology->tethering == tethering)
return __connman_error_in_progress(msg);
- bridge = __connman_tethering_get_bridge();
- if (bridge == NULL)
- return __connman_error_not_supported(msg);
-
- err = set_tethering(technology, bridge, tethering);
+ err = set_tethering(technology, tethering);
if (err < 0)
return __connman_error_failed(msg, -err);
static struct connman_technology *technology_get(enum connman_service_type type)
{
struct connman_technology *technology;
+ struct connman_technology_driver *driver = NULL;
const char *str;
GSList *list;
+ int err;
DBG("type %d", type);
+ str = __connman_service_type2string(type);
+ if (str == NULL)
+ return NULL;
+
technology = technology_find(type);
- if (technology != NULL) {
- g_atomic_int_inc(&technology->refcount);
- goto done;
+ if (technology != NULL)
+ return technology;
+
+ /* First check if we have a driver for this technology type */
+ for (list = driver_list; list; list = list->next) {
+ driver = list->data;
+
+ if (driver->type == type)
+ break;
+ else
+ driver = NULL;
}
- str = __connman_service_type2string(type);
- if (str == NULL)
+ if (driver == NULL) {
+ DBG("No matching driver found for %s.",
+ __connman_service_type2string(type));
return NULL;
+ }
technology = g_try_new0(struct connman_technology, 1);
if (technology == NULL)
NULL, free_rfkill);
technology->device_list = NULL;
+ technology->pending_reply = NULL;
technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
+ load_state(technology);
+
if (g_dbus_register_interface(connection, technology->path,
CONNMAN_TECHNOLOGY_INTERFACE,
technology_methods, technology_signals,
technologies_changed();
- if (technology->driver != NULL)
- goto done;
-
- for (list = driver_list; list; list = list->next) {
- struct connman_technology_driver *driver = list->data;
-
- DBG("driver %p name %s", driver, driver->name);
-
- if (driver->type != technology->type)
- continue;
-
- if (driver->probe(technology) == 0) {
- technology->driver = driver;
- break;
- }
- }
+ technology->driver = driver;
+ err = driver->probe(technology);
+ if (err != 0)
+ DBG("Driver probe failed for technology %p", technology);
-done:
DBG("technology %p", technology);
return technology;
{
DBG("technology %p", technology);
- if (g_atomic_int_dec_and_test(&technology->refcount) == FALSE)
+ if (__sync_fetch_and_sub(&technology->refcount, 1) != 1)
return;
if (technology->driver) {
{
struct connman_technology *technology;
- DBG("type(%d)", type);
-
switch (type) {
case CONNMAN_SERVICE_TYPE_UNKNOWN:
case CONNMAN_SERVICE_TYPE_SYSTEM:
{
struct connman_technology *technology;
- DBG("type(%d)", type);
-
switch (type) {
case CONNMAN_SERVICE_TYPE_UNKNOWN:
case CONNMAN_SERVICE_TYPE_SYSTEM:
technology_put(technology);
}
-static void unregister_technology(gpointer data)
-{
- struct connman_technology *technology = data;
-
- technology_put(technology);
-}
-
int __connman_technology_add_device(struct connman_device *device)
{
struct connman_technology *technology;
if (technology == NULL)
return -ENXIO;
- g_hash_table_insert(device_table, device, technology);
-
- if (g_atomic_int_get(&technology->blocked))
- goto done;
-
- technology->state = CONNMAN_TECHNOLOGY_STATE_AVAILABLE;
-
- state_changed(technology);
-
-done:
+ if (technology->enable_persistent && !global_offlinemode)
+ __connman_device_enable(device);
+ /* if technology persistent state is offline */
+ if (!technology->enable_persistent)
+ __connman_device_disable(device);
technology->device_list = g_slist_append(technology->device_list,
device);
type = __connman_device_get_service_type(device);
__connman_notifier_unregister(type);
- technology = g_hash_table_lookup(device_table, device);
+ technology = technology_find(type);
if (technology == NULL)
return -ENXIO;
state_changed(technology);
}
- g_hash_table_remove(device_table, device);
-
return 0;
}
-int __connman_technology_enable(enum connman_service_type type)
+static gboolean technology_pending_reply(gpointer user_data)
+{
+ struct connman_technology *technology = user_data;
+ DBusMessage *reply;
+
+ /* Power request timedout, send ETIMEDOUT. */
+ if (technology->pending_reply != NULL) {
+ reply = __connman_error_failed(technology->pending_reply, ETIMEDOUT);
+ if (reply != NULL)
+ g_dbus_send_message(connection, reply);
+
+ dbus_message_unref(technology->pending_reply);
+ technology->pending_reply = NULL;
+ technology->pending_timeout = 0;
+ }
+
+ return FALSE;
+}
+
+int __connman_technology_enabled(enum connman_service_type type)
{
struct connman_technology *technology;
if (technology == NULL)
return -ENXIO;
- if (g_atomic_int_get(&technology->blocked))
- return -ERFKILL;
-
- __connman_notifier_enable(type);
-
- if (g_atomic_int_exchange_and_add(&technology->enabled, 1) == 0) {
+ if (__sync_fetch_and_add(&technology->enabled, 1) == 0) {
+ __connman_notifier_enable(type);
technology->state = CONNMAN_TECHNOLOGY_STATE_ENABLED;
state_changed(technology);
}
+ if (technology->pending_reply != NULL) {
+ g_dbus_send_reply(connection, technology->pending_reply, DBUS_TYPE_INVALID);
+ dbus_message_unref(technology->pending_reply);
+ g_source_remove(technology->pending_timeout);
+ technology->pending_reply = NULL;
+ technology->pending_timeout = 0;
+ }
+
return 0;
}
-int __connman_technology_disable(enum connman_service_type type)
+int __connman_technology_enable(enum connman_service_type type, DBusMessage *msg)
{
struct connman_technology *technology;
GSList *list;
+ int err = 0;
+ int ret = -ENODEV;
+ DBusMessage *reply;
+
+ DBG("type %d enable", type);
technology = technology_find(type);
- if (technology == NULL)
- return -ENXIO;
+ if (technology == NULL) {
+ err = -ENXIO;
+ goto done;
+ }
- if (g_atomic_int_dec_and_test(&technology->enabled) == TRUE) {
- __connman_notifier_disable(type);
+ if (technology->pending_reply != NULL) {
+ err = -EBUSY;
+ goto done;
+ }
- technology->state = CONNMAN_TECHNOLOGY_STATE_AVAILABLE;
- state_changed(technology);
+ if (msg != NULL) {
+ /*
+ * This is a bit of a trick. When msg is not NULL it means
+ * thats technology_enable was invoked from the manager API. Hence we save
+ * the state here.
+ */
+ technology->enable_persistent = TRUE;
+ save_state(technology);
}
+ __connman_rfkill_block(technology->type, FALSE);
+
+ /*
+ * An empty device list means that devices in the technology
+ * were rfkill blocked. The unblock above will enable the devs.
+ */
+ if (technology->device_list == NULL)
+ return 0;
+
for (list = technology->device_list; list; list = list->next) {
struct connman_device *device = list->data;
- if (__connman_device_get_blocked(device) == FALSE)
- return 0;
+ err = __connman_device_enable(device);
+ /*
+ * err = 0 : Device was enabled right away.
+ * If atleast one device gets enabled, we consider
+ * the technology to be enabled.
+ */
+ if (err == 0)
+ ret = 0;
+ }
+
+done:
+ if (ret == 0) {
+ if (msg != NULL)
+ g_dbus_send_reply(connection, msg, DBUS_TYPE_INVALID);
+ return ret;
+ }
+
+ if (msg != NULL) {
+ if (err == -EINPROGRESS) {
+ technology->pending_reply = dbus_message_ref(msg);
+ technology->pending_timeout = g_timeout_add_seconds(10,
+ technology_pending_reply, technology);
+ } else {
+ reply = __connman_error_failed(msg, -err);
+ if (reply != NULL)
+ g_dbus_send_message(connection, reply);
+ }
+ }
+
+ return err;
+}
+
+int __connman_technology_disabled(enum connman_service_type type)
+{
+ struct connman_technology *technology;
+
+ technology = technology_find(type);
+ if (technology == NULL)
+ return -ENXIO;
+
+ if (technology->pending_reply != NULL) {
+ g_dbus_send_reply(connection, technology->pending_reply, DBUS_TYPE_INVALID);
+ dbus_message_unref(technology->pending_reply);
+ g_source_remove(technology->pending_timeout);
+ technology->pending_reply = NULL;
+ technology->pending_timeout = 0;
}
+ if (__sync_fetch_and_sub(&technology->enabled, 1) != 1)
+ return 0;
+
+ __connman_notifier_disable(type);
technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
state_changed(technology);
return 0;
}
-static void technology_blocked(struct connman_technology *technology,
- connman_bool_t blocked)
+int __connman_technology_disable(enum connman_service_type type, DBusMessage *msg)
{
+ struct connman_technology *technology;
GSList *list;
+ int err = 0;
+ int ret = -ENODEV;
+ DBusMessage *reply;
+
+ DBG("type %d disable", type);
+
+ technology = technology_find(type);
+ if (technology == NULL) {
+ err = -ENXIO;
+ goto done;
+ }
+
+ if (technology->pending_reply != NULL) {
+ err = -EBUSY;
+ goto done;
+ }
+
+ if (technology->tethering == TRUE)
+ set_tethering(technology, FALSE);
+
+ if (msg != NULL) {
+ technology->enable_persistent = FALSE;
+ save_state(technology);
+ }
+
+ __connman_rfkill_block(technology->type, TRUE);
for (list = technology->device_list; list; list = list->next) {
struct connman_device *device = list->data;
- __connman_device_set_blocked(device, blocked);
+ err = __connman_device_disable(device);
+ if (err == 0)
+ ret = 0;
}
+
+done:
+ if (ret == 0) {
+ if (msg != NULL)
+ g_dbus_send_reply(connection, msg, DBUS_TYPE_INVALID);
+ return ret;
+ }
+
+ if (msg != NULL) {
+ if (err == -EINPROGRESS) {
+ technology->pending_reply = dbus_message_ref(msg);
+ technology->pending_timeout = g_timeout_add_seconds(10,
+ technology_pending_reply, technology);
+ } else {
+ reply = __connman_error_failed(msg, -err);
+ if (reply != NULL)
+ g_dbus_send_message(connection, reply);
+ }
+ }
+
+ return err;
+}
+
+int __connman_technology_set_offlinemode(connman_bool_t offlinemode)
+{
+ GSList *list;
+ int err = -EINVAL;
+
+ if (global_offlinemode == offlinemode)
+ return 0;
+
+ DBG("offlinemode %s", offlinemode ? "On" : "Off");
+
+ /*
+ * This is a bit tricky. When you set offlinemode, there is no
+ * way to differentiate between attempting offline mode and
+ * resuming offlinemode from last saved profile. We need that
+ * information in rfkill_update, otherwise it falls back on the
+ * technology's persistent state. Hence we set the offline mode here
+ * but save it & call the notifier only if its successful.
+ */
+
+ global_offlinemode = offlinemode;
+
+ /* Traverse technology list, enable/disable each technology. */
+ for (list = technology_list; list; list = list->next) {
+ struct connman_technology *technology = list->data;
+
+ if (offlinemode)
+ err = __connman_technology_disable(technology->type, NULL);
+
+ if (!offlinemode && technology->enable_persistent)
+ err = __connman_technology_enable(technology->type, NULL);
+ }
+
+ if (err == 0 || err == -EINPROGRESS || err == -EALREADY) {
+ connman_technology_save_offlinemode();
+ __connman_notifier_offlinemode(offlinemode);
+ } else
+ global_offlinemode = connman_technology_load_offlinemode();
+
+ return err;
}
int __connman_technology_add_rfkill(unsigned int index,
{
struct connman_technology *technology;
struct connman_rfkill *rfkill;
- connman_bool_t blocked;
DBG("index %u type %d soft %u hard %u", index, type,
softblock, hardblock);
if (rfkill == NULL)
return -ENOMEM;
+ __connman_notifier_register(type);
+
rfkill->index = index;
rfkill->type = type;
rfkill->softblock = softblock;
rfkill->hardblock = hardblock;
- g_hash_table_replace(rfkill_table, &rfkill->index, technology);
-
g_hash_table_replace(technology->rfkill_list, &rfkill->index, rfkill);
- blocked = (softblock || hardblock) ? TRUE : FALSE;
- if (blocked == FALSE)
+ if (hardblock) {
+ DBG("%s is switched off.", get_name(type));
return 0;
+ }
- if (g_atomic_int_exchange_and_add(&technology->blocked, 1) == 0) {
- technology_blocked(technology, TRUE);
-
- technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
- state_changed(technology);
+ /*
+ * If Offline mode is on, we softblock the device if it isnt already.
+ * If Offline mode is off, we rely on the persistent state of tech.
+ */
+ if (global_offlinemode) {
+ if (!softblock)
+ return __connman_rfkill_block(type, TRUE);
+ } else {
+ if (technology->enable_persistent && softblock)
+ return __connman_rfkill_block(type, FALSE);
+ /* if technology persistent state is offline */
+ if (!technology->enable_persistent && !softblock)
+ return __connman_rfkill_block(type, TRUE);
}
return 0;
}
int __connman_technology_update_rfkill(unsigned int index,
+ enum connman_service_type type,
connman_bool_t softblock,
connman_bool_t hardblock)
{
struct connman_technology *technology;
struct connman_rfkill *rfkill;
- connman_bool_t blocked, old_blocked;
DBG("index %u soft %u hard %u", index, softblock, hardblock);
- technology = g_hash_table_lookup(rfkill_table, &index);
+ technology = technology_find(type);
if (technology == NULL)
return -ENXIO;
if (rfkill == NULL)
return -ENXIO;
- old_blocked = (rfkill->softblock || rfkill->hardblock) ? TRUE : FALSE;
- blocked = (softblock || hardblock) ? TRUE : FALSE;
+ if (rfkill->softblock == softblock &&
+ rfkill->hardblock == hardblock)
+ return 0;
rfkill->softblock = softblock;
rfkill->hardblock = hardblock;
- if (blocked == old_blocked)
+ if (hardblock) {
+ DBG("%s is switched off.", get_name(type));
return 0;
+ }
- if (blocked) {
- guint n_blocked;
-
- n_blocked =
- g_atomic_int_exchange_and_add(&technology->blocked, 1);
- if (n_blocked != g_hash_table_size(technology->rfkill_list) - 1)
- return 0;
-
- technology_blocked(technology, blocked);
- technology->state = CONNMAN_TECHNOLOGY_STATE_OFFLINE;
- state_changed(technology);
- } else {
- if (g_atomic_int_dec_and_test(&technology->blocked) == FALSE)
- return 0;
-
- technology_blocked(technology, blocked);
- technology->state = CONNMAN_TECHNOLOGY_STATE_AVAILABLE;
- state_changed(technology);
+ if (!global_offlinemode) {
+ if (technology->enable_persistent && softblock)
+ return __connman_rfkill_block(type, FALSE);
+ if (!technology->enable_persistent && !softblock)
+ return __connman_rfkill_block(type, TRUE);
}
return 0;
}
-int __connman_technology_remove_rfkill(unsigned int index)
+int __connman_technology_remove_rfkill(unsigned int index,
+ enum connman_service_type type)
{
struct connman_technology *technology;
struct connman_rfkill *rfkill;
- connman_bool_t blocked;
DBG("index %u", index);
- technology = g_hash_table_lookup(rfkill_table, &index);
+ technology = technology_find(type);
if (technology == NULL)
return -ENXIO;
if (rfkill == NULL)
return -ENXIO;
- blocked = (rfkill->softblock || rfkill->hardblock) ? TRUE : FALSE;
-
g_hash_table_remove(technology->rfkill_list, &index);
- g_hash_table_remove(rfkill_table, &index);
-
- if (blocked &&
- g_atomic_int_dec_and_test(&technology->blocked) == TRUE) {
- technology_blocked(technology, FALSE);
- technology->state = CONNMAN_TECHNOLOGY_STATE_AVAILABLE;
- state_changed(technology);
- }
+ technology_put(technology);
return 0;
}
-connman_bool_t __connman_technology_get_blocked(enum connman_service_type type)
-{
- struct connman_technology *technology;
-
- technology = technology_find(type);
- if (technology == NULL)
- return FALSE;
-
- if (g_atomic_int_get(&technology->blocked))
- return TRUE;
-
- return FALSE;
-}
-
int __connman_technology_init(void)
{
DBG("");
connection = connman_dbus_get_connection();
- rfkill_table = g_hash_table_new_full(g_int_hash, g_int_equal,
- NULL, unregister_technology);
- device_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
- NULL, unregister_technology);
+ global_offlinemode = connman_technology_load_offlinemode();
return 0;
}
{
DBG("");
- g_hash_table_destroy(device_table);
- g_hash_table_destroy(rfkill_table);
-
dbus_connection_unref(connection);
}
#define PRIVATE_NETWORK_SECONDARY_DNS "8.8.4.4"
static char *default_interface = NULL;
-static volatile gint tethering_enabled;
+static volatile int tethering_enabled;
static GDHCPServer *tethering_dhcp_server = NULL;
static DBusConnection *connection;
static GHashTable *pn_hash;
DBG("name %s", name);
- sk = socket(AF_INET, SOCK_STREAM, 0);
+ sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return -EOPNOTSUPP;
- err = ioctl(sk, SIOCBRADDBR, name);
-
- if (err < 0)
- return -EOPNOTSUPP;
+ if (ioctl(sk, SIOCBRADDBR, name) == -1) {
+ err = -errno;
+ if (err != -EEXIST)
+ return -EOPNOTSUPP;
+ }
err = set_forward_delay(name, 0);
DBG("name %s", name);
- sk = socket(AF_INET, SOCK_STREAM, 0);
+ sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return -EOPNOTSUPP;
void __connman_tethering_set_enabled(void)
{
int err;
+ const char *dns;
DBG("enabled %d", tethering_enabled + 1);
- if (g_atomic_int_exchange_and_add(&tethering_enabled, 1) == 0) {
- const char *dns;
+ if (__sync_fetch_and_add(&tethering_enabled, 1) != 0)
+ return;
- err = create_bridge(BRIDGE_NAME);
- if (err < 0)
- return;
+ err = create_bridge(BRIDGE_NAME);
+ if (err < 0)
+ return;
- err = enable_bridge(BRIDGE_NAME);
- if (err < 0) {
- remove_bridge(BRIDGE_NAME);
- return;
- }
+ err = enable_bridge(BRIDGE_NAME);
+ if (err < 0 && err != -EALREADY) {
+ remove_bridge(BRIDGE_NAME);
+ return;
+ }
- dns = BRIDGE_IP;
- if (__connman_dnsproxy_add_listener(BRIDGE_NAME) < 0) {
- connman_error("Can't add listener %s to DNS proxy",
+ dns = BRIDGE_IP;
+ if (__connman_dnsproxy_add_listener(BRIDGE_NAME) < 0) {
+ connman_error("Can't add listener %s to DNS proxy",
BRIDGE_NAME);
- dns = BRIDGE_DNS;
- }
-
- tethering_dhcp_server =
- dhcp_server_start(BRIDGE_NAME,
- BRIDGE_IP, BRIDGE_SUBNET,
- BRIDGE_IP_START, BRIDGE_IP_END,
- 24 * 3600, dns);
- if (tethering_dhcp_server == NULL) {
- disable_bridge(BRIDGE_NAME);
- remove_bridge(BRIDGE_NAME);
- return;
- }
-
- enable_nat(default_interface);
-
- DBG("tethering started");
+ dns = BRIDGE_DNS;
+ }
+
+ tethering_dhcp_server =
+ dhcp_server_start(BRIDGE_NAME,
+ BRIDGE_IP, BRIDGE_SUBNET,
+ BRIDGE_IP_START, BRIDGE_IP_END,
+ 24 * 3600, dns);
+ if (tethering_dhcp_server == NULL) {
+ disable_bridge(BRIDGE_NAME);
+ remove_bridge(BRIDGE_NAME);
+ return;
}
+
+ enable_nat(default_interface);
+
+ DBG("tethering started");
}
void __connman_tethering_set_disabled(void)
__connman_dnsproxy_remove_listener(BRIDGE_NAME);
- if (g_atomic_int_dec_and_test(&tethering_enabled) == TRUE) {
- disable_nat(default_interface);
+ if (__sync_fetch_and_sub(&tethering_enabled, 1) != 1)
+ return;
+
+ disable_nat(default_interface);
- dhcp_server_stop(tethering_dhcp_server);
+ dhcp_server_stop(tethering_dhcp_server);
- disable_bridge(BRIDGE_NAME);
+ tethering_dhcp_server = NULL;
- remove_bridge(BRIDGE_NAME);
+ disable_bridge(BRIDGE_NAME);
- DBG("tethering stopped");
- }
+ remove_bridge(BRIDGE_NAME);
+
+ DBG("tethering stopped");
}
void __connman_tethering_update_interface(const char *interface)
default_interface = g_strdup(interface);
- if (!g_atomic_int_get(&tethering_enabled))
+ __sync_synchronize();
+ if (tethering_enabled == 0)
return;
enable_nat(interface);
{
DBG("");
- if (g_atomic_int_get(&tethering_enabled)) {
+ __sync_synchronize();
+ if (tethering_enabled == 0) {
if (tethering_dhcp_server)
dhcp_server_stop(tethering_dhcp_server);
disable_bridge(BRIDGE_NAME);
#include <config.h>
#endif
+#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
off_t ptrlen, keylen;
int fd;
- fd = open(pathname, O_RDONLY);
+ fd = open(pathname, O_RDONLY | O_CLOEXEC);
if (fd < 0)
return NULL;
void *dst_map;
int fd, result;
- fd = open(pathname, O_RDONLY);
+ fd = open(pathname, O_RDONLY | O_CLOEXEC);
if (fd < 0)
return -1;
subpath, d->d_name);
if (compare_file(src_map, src_st, pathname) == 0) {
- closedir(dir);
- return g_strdup_printf("%s/%s",
+ str = g_strdup_printf("%s/%s",
subpath, d->d_name);
+ closedir(dir);
+ return str;
}
break;
case DT_DIR:
DBG("sysconfig zone %s", zone);
- fd = open(ETC_LOCALTIME, O_RDONLY);
+ fd = open(ETC_LOCALTIME, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
g_free(zone);
return NULL;
unlink(pathname);
}
- fd = open(pathname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ fd = open(pathname, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
if (fd < 0)
return -EIO;
snprintf(pathname, PATH_MAX, "%s/%s", USR_SHARE_ZONEINFO, zone);
- fd = open(pathname, O_RDONLY);
+ fd = open(pathname, O_RDONLY | O_CLOEXEC);
if (fd < 0)
return -EINVAL;
dirname = g_path_get_dirname(ETC_LOCALTIME);
wd = inotify_add_watch(fd, dirname, IN_DONT_FOLLOW |
- IN_MODIFY | IN_MOVED_TO);
+ IN_CLOSE_WRITE | IN_MOVED_TO);
g_free(dirname);
#include <config.h>
#endif
+#include <errno.h>
+#include <stdlib.h>
+
+#include <gweb/gweb.h>
+
#include "connman.h"
+#define STATUS_URL_IPV4 "http://ipv4.connman.net/online/status.html"
+#define STATUS_URL_IPV6 "http://ipv6.connman.net/online/status.html"
+
+struct connman_wispr_message {
+ gboolean has_error;
+ const char *current_element;
+ int message_type;
+ int response_code;
+ char *login_url;
+ char *abort_login_url;
+ char *logoff_url;
+ char *access_procedure;
+ char *access_location;
+ char *location_name;
+};
+
+enum connman_wispr_result {
+ CONNMAN_WISPR_RESULT_UNKNOWN = 0,
+ CONNMAN_WISPR_RESULT_LOGIN = 1,
+ CONNMAN_WISPR_RESULT_ONLINE = 2,
+ CONNMAN_WISPR_RESULT_FAILED = 3,
+};
+
+struct connman_wispr_portal_context {
+ struct connman_service *service;
+ enum connman_ipconfig_type type;
+
+ /* Portal/WISPr common */
+ GWeb *web;
+ unsigned int token;
+ guint request_id;
+
+ const char *status_url;
+
+ /* WISPr specific */
+ GWebParser *wispr_parser;
+ struct connman_wispr_message wispr_msg;
+
+ char *wispr_username;
+ char *wispr_password;
+ char *wispr_formdata;
+
+ enum connman_wispr_result wispr_result;
+};
+
+struct connman_wispr_portal {
+ struct connman_wispr_portal_context *ipv4_context;
+ struct connman_wispr_portal_context *ipv6_context;
+};
+
+static gboolean wispr_portal_web_result(GWebResult *result, gpointer user_data);
+
+static GHashTable *wispr_portal_list = NULL;
+
+static void connman_wispr_message_init(struct connman_wispr_message *msg)
+{
+ DBG("");
+
+ msg->has_error = FALSE;
+ msg->current_element = NULL;
+
+ msg->message_type = -1;
+ msg->response_code = -1;
+
+ g_free(msg->login_url);
+ msg->login_url = NULL;
+
+ g_free(msg->abort_login_url);
+ msg->abort_login_url = NULL;
+
+ g_free(msg->logoff_url);
+ msg->logoff_url = NULL;
+
+ g_free(msg->access_procedure);
+ msg->access_procedure = NULL;
+
+ g_free(msg->access_location);
+ msg->access_location = NULL;
+
+ g_free(msg->location_name);
+ msg->location_name = NULL;
+}
+
+static void free_connman_wispr_portal_context(struct connman_wispr_portal_context *wp_context)
+{
+ DBG("");
+
+ if (wp_context == NULL)
+ return;
+
+ connman_service_unref(wp_context->service);
+
+ if (wp_context->token > 0)
+ connman_proxy_lookup_cancel(wp_context->token);
+
+ if (wp_context->request_id > 0)
+ g_web_cancel_request(wp_context->web, wp_context->request_id);
+
+ g_web_unref(wp_context->web);
+
+ g_web_parser_unref(wp_context->wispr_parser);
+ connman_wispr_message_init(&wp_context->wispr_msg);
+
+ g_free(wp_context->wispr_username);
+ g_free(wp_context->wispr_password);
+ g_free(wp_context->wispr_formdata);
+
+ g_free(wp_context);
+}
+
+static void free_connman_wispr_portal(gpointer data)
+{
+ struct connman_wispr_portal *wispr_portal = data;
+
+ DBG("");
+
+ if (wispr_portal == NULL)
+ return;
+
+ free_connman_wispr_portal_context(wispr_portal->ipv4_context);
+ free_connman_wispr_portal_context(wispr_portal->ipv6_context);
+
+ g_free(wispr_portal);
+}
+
+static const char *message_type_to_string(int message_type)
+{
+ switch (message_type) {
+ case 100:
+ return "Initial redirect message";
+ case 110:
+ return "Proxy notification";
+ case 120:
+ return "Authentication notification";
+ case 130:
+ return "Logoff notification";
+ case 140:
+ return "Response to Authentication Poll";
+ case 150:
+ return "Response to Abort Login";
+ }
+
+ return NULL;
+}
+
+static const char *response_code_to_string(int response_code)
+{
+ switch (response_code) {
+ case 0:
+ return "No error";
+ case 50:
+ return "Login succeeded";
+ case 100:
+ return "Login failed";
+ case 102:
+ return "RADIUS server error/timeout";
+ case 105:
+ return "RADIUS server not enabled";
+ case 150:
+ return "Logoff succeeded";
+ case 151:
+ return "Login aborted";
+ case 200:
+ return "Proxy detection/repeat operation";
+ case 201:
+ return "Authentication pending";
+ case 255:
+ return "Access gateway internal error";
+ }
+
+ return NULL;
+}
+
+static struct {
+ const char *str;
+ enum {
+ WISPR_ELEMENT_NONE = 0,
+ WISPR_ELEMENT_ACCESS_PROCEDURE = 1,
+ WISPR_ELEMENT_ACCESS_LOCATION = 2,
+ WISPR_ELEMENT_LOCATION_NAME = 3,
+ WISPR_ELEMENT_LOGIN_URL = 4,
+ WISPR_ELEMENT_ABORT_LOGIN_URL = 5,
+ WISPR_ELEMENT_MESSAGE_TYPE = 6,
+ WISPR_ELEMENT_RESPONSE_CODE = 7,
+ WISPR_ELEMENT_NEXT_URL = 8,
+ WISPR_ELEMENT_DELAY = 9,
+ WISPR_ELEMENT_REPLY_MESSAGE = 10,
+ WISPR_ELEMENT_LOGIN_RESULTS_URL = 11,
+ WISPR_ELEMENT_LOGOFF_URL = 12,
+ } element;
+} wispr_element_map[] = {
+ { "AccessProcedure", WISPR_ELEMENT_ACCESS_PROCEDURE },
+ { "AccessLocation", WISPR_ELEMENT_ACCESS_LOCATION },
+ { "LocationName", WISPR_ELEMENT_LOCATION_NAME },
+ { "LoginURL", WISPR_ELEMENT_LOGIN_URL },
+ { "AbortLoginURL", WISPR_ELEMENT_ABORT_LOGIN_URL },
+ { "MessageType", WISPR_ELEMENT_MESSAGE_TYPE },
+ { "ResponseCode", WISPR_ELEMENT_RESPONSE_CODE },
+ { "NextURL", WISPR_ELEMENT_NEXT_URL },
+ { "Delay", WISPR_ELEMENT_DELAY },
+ { "ReplyMessage", WISPR_ELEMENT_REPLY_MESSAGE },
+ { "LoginResultsURL", WISPR_ELEMENT_LOGIN_RESULTS_URL },
+ { "LogoffURL", WISPR_ELEMENT_LOGOFF_URL },
+ { NULL, WISPR_ELEMENT_NONE },
+};
+
+static void xml_wispr_start_element_handler(GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data, GError **error)
+{
+ struct connman_wispr_message *msg = user_data;
+
+ msg->current_element = element_name;
+}
+
+static void xml_wispr_end_element_handler(GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data, GError **error)
+{
+ struct connman_wispr_message *msg = user_data;
+
+ msg->current_element = NULL;
+}
+
+static void xml_wispr_text_handler(GMarkupParseContext *context,
+ const gchar *text, gsize text_len,
+ gpointer user_data, GError **error)
+{
+ struct connman_wispr_message *msg = user_data;
+ int i;
+
+ if (msg->current_element == NULL)
+ return;
+
+ for (i = 0; wispr_element_map[i].str; i++) {
+ if (g_str_equal(wispr_element_map[i].str,
+ msg->current_element) == FALSE)
+ continue;
+
+ switch (wispr_element_map[i].element) {
+ case WISPR_ELEMENT_NONE:
+ case WISPR_ELEMENT_ACCESS_PROCEDURE:
+ g_free(msg->access_procedure);
+ msg->access_procedure = g_strdup(text);
+ break;
+ case WISPR_ELEMENT_ACCESS_LOCATION:
+ g_free(msg->access_location);
+ msg->access_location = g_strdup(text);
+ break;
+ case WISPR_ELEMENT_LOCATION_NAME:
+ g_free(msg->location_name);
+ msg->location_name = g_strdup(text);
+ break;
+ case WISPR_ELEMENT_LOGIN_URL:
+ g_free(msg->login_url);
+ msg->login_url = g_strdup(text);
+ break;
+ case WISPR_ELEMENT_ABORT_LOGIN_URL:
+ g_free(msg->abort_login_url);
+ msg->abort_login_url = g_strdup(text);
+ break;
+ case WISPR_ELEMENT_MESSAGE_TYPE:
+ msg->message_type = atoi(text);
+ break;
+ case WISPR_ELEMENT_RESPONSE_CODE:
+ msg->response_code = atoi(text);
+ break;
+ case WISPR_ELEMENT_NEXT_URL:
+ case WISPR_ELEMENT_DELAY:
+ case WISPR_ELEMENT_REPLY_MESSAGE:
+ case WISPR_ELEMENT_LOGIN_RESULTS_URL:
+ break;
+ case WISPR_ELEMENT_LOGOFF_URL:
+ g_free(msg->logoff_url);
+ msg->logoff_url = g_strdup(text);
+ break;
+ }
+ }
+}
+
+static void xml_wispr_error_handler(GMarkupParseContext *context,
+ GError *error, gpointer user_data)
+{
+ struct connman_wispr_message *msg = user_data;
+
+ msg->has_error = TRUE;
+}
+
+static const GMarkupParser xml_wispr_parser_handlers = {
+ xml_wispr_start_element_handler,
+ xml_wispr_end_element_handler,
+ xml_wispr_text_handler,
+ NULL,
+ xml_wispr_error_handler,
+};
+
+static void xml_wispr_parser_callback(const char *str, gpointer user_data)
+{
+ struct connman_wispr_portal_context *wp_context = user_data;
+ GMarkupParseContext *parser_context = NULL;
+ gboolean result;
+
+ DBG("");
+
+ parser_context = g_markup_parse_context_new(&xml_wispr_parser_handlers,
+ G_MARKUP_TREAT_CDATA_AS_TEXT,
+ &(wp_context->wispr_msg), NULL);
+
+ result = g_markup_parse_context_parse(parser_context,
+ str, strlen(str), NULL);
+ if (result == TRUE)
+ result = g_markup_parse_context_end_parse(parser_context, NULL);
+
+ g_markup_parse_context_free(parser_context);
+}
+
+static void web_debug(const char *str, void *data)
+{
+ connman_info("%s: %s\n", (const char *) data, str);
+}
+
+static void wispr_portal_error(struct connman_wispr_portal_context *wp_context)
+{
+ DBG("Failed to proceed wispr/portal web request");
+
+ wp_context->wispr_result = CONNMAN_WISPR_RESULT_FAILED;
+}
+
+static void portal_manage_status(GWebResult *result,
+ struct connman_wispr_portal_context *wp_context)
+{
+ const char *str = NULL;
+
+ DBG("");
+
+ /* We currently don't do anything with this info */
+ if (g_web_result_get_header(result, "X-ConnMan-Client-IP",
+ &str) == TRUE)
+ connman_info("Client-IP: %s", str);
+
+ if (g_web_result_get_header(result, "X-ConnMan-Client-Country",
+ &str) == TRUE)
+ connman_info("Client-Country: %s", str);
+
+ if (g_web_result_get_header(result, "X-ConnMan-Client-Region",
+ &str) == TRUE)
+ connman_info("Client-Region: %s", str);
+
+ __connman_service_ipconfig_indicate_state(wp_context->service,
+ CONNMAN_SERVICE_STATE_ONLINE,
+ wp_context->type);
+}
+
+static void wispr_portal_request_portal(struct connman_wispr_portal_context *wp_context)
+{
+ DBG("");
+
+ wp_context->request_id = g_web_request_get(wp_context->web,
+ wp_context->status_url,
+ wispr_portal_web_result, wp_context);
+
+ if (wp_context->request_id == 0)
+ wispr_portal_error(wp_context);
+}
+
+static gboolean wispr_input(const guint8 **data, gsize *length,
+ gpointer user_data)
+{
+ struct connman_wispr_portal_context *wp_context = user_data;
+ GString *buf;
+ gsize count;
+
+ DBG("");
+
+ buf = g_string_sized_new(100);
+
+ g_string_append(buf, "button=Login&UserName=");
+ g_string_append_uri_escaped(buf, wp_context->wispr_username,
+ NULL, FALSE);
+ g_string_append(buf, "&Password=");
+ g_string_append_uri_escaped(buf, wp_context->wispr_password,
+ NULL, FALSE);
+ g_string_append(buf, "&FNAME=0&OriginatingServer=");
+ g_string_append_uri_escaped(buf, wp_context->status_url, NULL, FALSE);
+
+ count = buf->len;
+
+ g_free(wp_context->wispr_formdata);
+ wp_context->wispr_formdata = g_string_free(buf, FALSE);
+
+ *data = (guint8 *) wp_context->wispr_formdata;
+ *length = count;
+
+ return FALSE;
+}
+
+static void wispr_portal_request_wispr_login(struct connman_service *service,
+ const char *username, const char *password,
+ void *user_data)
+{
+ struct connman_wispr_portal_context *wp_context = user_data;
+
+ DBG("");
+
+ g_free(wp_context->wispr_username);
+ wp_context->wispr_username = g_strdup(username);
+
+ g_free(wp_context->wispr_password);
+ wp_context->wispr_password = g_strdup(password);
+
+ wp_context->request_id = g_web_request_post(wp_context->web,
+ wp_context->wispr_msg.login_url,
+ "application/x-www-form-urlencoded",
+ wispr_input, wispr_portal_web_result,
+ wp_context);
+
+ connman_wispr_message_init(&wp_context->wispr_msg);
+}
+
+static gboolean wispr_manage_message(GWebResult *result,
+ struct connman_wispr_portal_context *wp_context)
+{
+ DBG("Message type: %s (%d)",
+ message_type_to_string(wp_context->wispr_msg.message_type),
+ wp_context->wispr_msg.message_type);
+ DBG("Response code: %s (%d)",
+ response_code_to_string(wp_context->wispr_msg.response_code),
+ wp_context->wispr_msg.response_code);
+
+ if (wp_context->wispr_msg.access_procedure != NULL)
+ DBG("Access procedure: %s",
+ wp_context->wispr_msg.access_procedure);
+ if (wp_context->wispr_msg.access_location != NULL)
+ DBG("Access location: %s",
+ wp_context->wispr_msg.access_location);
+ if (wp_context->wispr_msg.location_name != NULL)
+ DBG("Location name: %s",
+ wp_context->wispr_msg.location_name);
+ if (wp_context->wispr_msg.login_url != NULL)
+ DBG("Login URL: %s", wp_context->wispr_msg.login_url);
+ if (wp_context->wispr_msg.abort_login_url != NULL)
+ DBG("Abort login URL: %s",
+ wp_context->wispr_msg.abort_login_url);
+ if (wp_context->wispr_msg.logoff_url != NULL)
+ DBG("Logoff URL: %s", wp_context->wispr_msg.logoff_url);
+
+ switch (wp_context->wispr_msg.message_type) {
+ case 100:
+ DBG("Login required");
+
+ wp_context->wispr_result = CONNMAN_WISPR_RESULT_LOGIN;
+
+ __connman_service_request_login(wp_context->service);
+
+ if (__connman_agent_request_login_input(wp_context->service,
+ wispr_portal_request_wispr_login,
+ wp_context) != -EIO)
+ wispr_portal_error(wp_context);
+
+ break;
+ case 120: /* Falling down */
+ case 140:
+ if (wp_context->wispr_msg.response_code == 50) {
+ wp_context->wispr_result = CONNMAN_WISPR_RESULT_ONLINE;
+
+ g_free(wp_context->wispr_username);
+ wp_context->wispr_username = NULL;
+
+ g_free(wp_context->wispr_password);
+ wp_context->wispr_password = NULL;
+
+ g_free(wp_context->wispr_formdata);
+ wp_context->wispr_formdata = NULL;
+
+ wispr_portal_request_portal(wp_context);
+
+ return TRUE;
+ } else
+ wispr_portal_error(wp_context);
+
+ break;
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static gboolean wispr_portal_web_result(GWebResult *result, gpointer user_data)
+{
+ struct connman_wispr_portal_context *wp_context = user_data;
+ const char *redirect = NULL;
+ const guint8 *chunk = NULL;
+ const char *str = NULL;
+ guint16 status;
+ gsize length;
+
+ DBG("");
+
+ if (wp_context->request_id == 0)
+ return FALSE;
+
+ if (wp_context->wispr_result != CONNMAN_WISPR_RESULT_ONLINE) {
+ g_web_result_get_chunk(result, &chunk, &length);
+
+ if (length > 0) {
+ g_web_parser_feed_data(wp_context->wispr_parser,
+ chunk, length);
+ return TRUE;
+ }
+
+ g_web_parser_end_data(wp_context->wispr_parser);
+
+ if (wp_context->wispr_msg.message_type >= 0) {
+ if (wispr_manage_message(result, wp_context) == TRUE)
+ goto done;
+ }
+ }
+
+ status = g_web_result_get_status(result);
+
+ DBG("status: %03u", status);
+
+ switch (status) {
+ case 200:
+ if (wp_context->wispr_msg.message_type >= 0)
+ break;
+
+ if (g_web_result_get_header(result, "X-ConnMan-Status",
+ &str) == TRUE)
+ portal_manage_status(result, wp_context);
+ else
+ __connman_service_request_login(wp_context->service);
+
+ break;
+ case 302:
+ if (g_web_result_get_header(result, "Location",
+ &redirect) == FALSE)
+ break;
+
+ DBG("Redirect URL: %s", redirect);
+
+ wp_context->request_id = g_web_request_get(wp_context->web,
+ redirect, wispr_portal_web_result, wp_context);
+
+ goto done;
+ case 404:
+ wispr_portal_error(wp_context);
+
+ break;
+ default:
+ break;
+ }
+
+ wp_context->request_id = 0;
+done:
+ wp_context->wispr_msg.message_type = -1;
+ return FALSE;
+}
+
+static void proxy_callback(const char *proxy, void *user_data)
+{
+ struct connman_wispr_portal_context *wp_context = user_data;
+
+ DBG("proxy %s", proxy);
+
+ wp_context->token = 0;
+
+ if (proxy == NULL)
+ proxy = getenv("http_proxy");
+
+ if (getenv("CONNMAN_WEB_DEBUG"))
+ g_web_set_debug(wp_context->web, web_debug, "WEB");
+
+ if (proxy != NULL && g_strcmp0(proxy, "DIRECT") != 0)
+ g_web_set_proxy(wp_context->web, proxy);
+
+ g_web_set_accept(wp_context->web, NULL);
+ g_web_set_user_agent(wp_context->web, "ConnMan/%s wispr", VERSION);
+ g_web_set_close_connection(wp_context->web, TRUE);
+
+ connman_wispr_message_init(&wp_context->wispr_msg);
+
+ wp_context->wispr_parser = g_web_parser_new(
+ "<WISPAccessGatewayParam",
+ "WISPAccessGatewayParam>",
+ xml_wispr_parser_callback, wp_context);
+
+ wispr_portal_request_portal(wp_context);
+}
+
+static int wispr_portal_detect(struct connman_wispr_portal_context *wp_context)
+{
+ enum connman_service_type service_type;
+ char *interface = NULL;
+ int if_index;
+ int err = 0;
+
+ DBG("wispr/portal context %p", wp_context);
+ DBG("service %p", wp_context->service);
+
+ service_type = connman_service_get_type(wp_context->service);
+
+ switch (service_type) {
+ case CONNMAN_SERVICE_TYPE_ETHERNET:
+ case CONNMAN_SERVICE_TYPE_WIFI:
+ case CONNMAN_SERVICE_TYPE_WIMAX:
+ case CONNMAN_SERVICE_TYPE_BLUETOOTH:
+ case CONNMAN_SERVICE_TYPE_CELLULAR:
+ break;
+ case CONNMAN_SERVICE_TYPE_UNKNOWN:
+ case CONNMAN_SERVICE_TYPE_SYSTEM:
+ case CONNMAN_SERVICE_TYPE_GPS:
+ case CONNMAN_SERVICE_TYPE_VPN:
+ case CONNMAN_SERVICE_TYPE_GADGET:
+ return -EOPNOTSUPP;
+ }
+
+ interface = connman_service_get_interface(wp_context->service);
+ if (interface == NULL)
+ return -EINVAL;
+
+ DBG("interface %s", interface);
+
+ if_index = connman_inet_ifindex(interface);
+ if (if_index < 0)
+ return -EINVAL;
+
+ wp_context->web = g_web_new(if_index);
+ if (wp_context->web == NULL) {
+ err = -ENOMEM;
+ goto done;
+ }
+
+ if (wp_context->type == CONNMAN_IPCONFIG_TYPE_IPV4) {
+ g_web_set_address_family(wp_context->web, AF_INET);
+ wp_context->status_url = STATUS_URL_IPV4;
+ } else {
+ g_web_set_address_family(wp_context->web, AF_INET6);
+ wp_context->status_url = STATUS_URL_IPV6;
+ }
+
+ wp_context->token = connman_proxy_lookup(interface,
+ wp_context->status_url,
+ wp_context->service,
+ proxy_callback, wp_context);
+ if (wp_context->token == 0)
+ err = -EINVAL;
+
+done:
+ g_free(interface);
+ return err;
+}
+
+int __connman_wispr_start(struct connman_service *service,
+ enum connman_ipconfig_type type)
+{
+ struct connman_wispr_portal_context *wp_context = NULL;
+ struct connman_wispr_portal *wispr_portal = NULL;
+ int index;
+
+ DBG("service %p", service);
+
+ if (wispr_portal_list == NULL)
+ return -EINVAL;
+
+ index = __connman_service_get_index(service);
+ if (index < 0)
+ return -EINVAL;
+
+ wispr_portal = g_hash_table_lookup(wispr_portal_list,
+ GINT_TO_POINTER(index));
+ if (wispr_portal == NULL) {
+ wispr_portal = g_try_new0(struct connman_wispr_portal, 1);
+ if (wispr_portal == NULL)
+ return -ENOMEM;
+
+ g_hash_table_replace(wispr_portal_list,
+ GINT_TO_POINTER(index), wispr_portal);
+ }
+
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
+ wp_context = wispr_portal->ipv4_context;
+ else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
+ wp_context = wispr_portal->ipv6_context;
+ else
+ return -EINVAL;
+
+ /* If there is already an existing context, we wipe it */
+ if (wp_context != NULL)
+ free_connman_wispr_portal_context(wp_context);
+
+ wp_context = g_try_new0(struct connman_wispr_portal_context, 1);
+ if (wp_context == NULL)
+ return -ENOMEM;
+
+ connman_service_ref(service);
+
+ wp_context->service = service;
+ wp_context->type = type;
+
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
+ wispr_portal->ipv4_context = wp_context;
+ else
+ wispr_portal->ipv6_context = wp_context;
+
+ return wispr_portal_detect(wp_context);
+}
+
+void __connman_wispr_stop(struct connman_service *service)
+{
+ int index;
+
+ DBG("service %p", service);
+
+ if (wispr_portal_list == NULL)
+ return;
+
+ index = __connman_service_get_index(service);
+ if (index < 0)
+ return;
+
+ g_hash_table_remove(wispr_portal_list, GINT_TO_POINTER(index));
+}
+
int __connman_wispr_init(void)
{
DBG("");
+ wispr_portal_list = g_hash_table_new_full(g_direct_hash,
+ g_direct_equal, NULL,
+ free_connman_wispr_portal);
+
return 0;
}
void __connman_wispr_cleanup(void)
{
DBG("");
+
+ g_hash_table_destroy(wispr_portal_list);
+ wispr_portal_list = NULL;
}
g_free(url);
+ __connman_wispr_start(wpad->service,
+ CONNMAN_IPCONFIG_TYPE_IPV4);
+
return;
}
failed:
connman_service_set_proxy_method(wpad->service,
CONNMAN_SERVICE_PROXY_METHOD_DIRECT);
+
+ __connman_wispr_start(wpad->service,
+ CONNMAN_IPCONFIG_TYPE_IPV4);
}
int __connman_wpad_start(struct connman_service *service)
g_resolv_lookup_hostname(wpad->resolv, wpad->hostname,
wpad_result, wpad);
+ connman_service_ref(service);
g_hash_table_replace(wpad_list, GINT_TO_POINTER(index), wpad);
return 0;
if (index < 0)
return;
- g_hash_table_remove(wpad_list, GINT_TO_POINTER(index));
+ if (g_hash_table_remove(wpad_list, GINT_TO_POINTER(index)) == TRUE)
+ connman_service_unref(service);
}
int __connman_wpad_init(void)
print " type: openconnect"
print " <name> <host> <domain> <cookie> [servercert]"
print " type: openvpn"
- print " <name> <host> <domain> <cafile> <certfile> <keyfile>"
+ print " <name> <host> <domain> [<cafile> <certfile> <keyfile>]"
+ print " type: pptp"
+ print " <name> <host> <domain> <user> <password>"
+ print " type: l2tp"
+ print " <name> <host> <domain> <user> <password>"
sys.exit(1)
bus = dbus.SystemBus()
"VPN.Domain": sys.argv[4],
"OpenConnect.Cookie": sys.argv[5]}))
elif sys.argv[1] == "openvpn":
- path = manager.ConnectProvider(({ "Type": "openvpn",
+ if (len(sys.argv) < 6):
+ path = manager.ConnectProvider(({ "Type": "openvpn",
+ "Name": sys.argv[2],
+ "Host": sys.argv[3],
+ "VPN.Domain": sys.argv[4] }))
+ else:
+ path = manager.ConnectProvider(({ "Type": "openvpn",
+ "Name": sys.argv[2],
+ "Host": sys.argv[3],
+ "VPN.Domain": sys.argv[4],
+ "OpenVPN.CACert": sys.argv[5],
+ "OpenVPN.Cert": sys.argv[6],
+ "OpenVPN.Key": sys.argv[7]}))
+
+elif sys.argv[1] == "pptp":
+ path = manager.ConnectProvider(({ "Type": "pptp",
+ "Name": sys.argv[2],
+ "Host": sys.argv[3],
+ "VPN.Domain": sys.argv[4],
+ "PPTP.User": sys.argv[5],
+ "PPTP.Password": sys.argv[6]}))
+elif sys.argv[1] == "l2tp":
+ path = manager.ConnectProvider(({ "Type": "l2tp",
"Name": sys.argv[2],
"Host": sys.argv[3],
"VPN.Domain": sys.argv[4],
- "OpenVPN.CACert": sys.argv[5],
- "OpenVPN.Cert": sys.argv[6],
- "OpenVPN.Key": sys.argv[7]}))
+ "L2TP.User": sys.argv[5],
+ "L2TP.Password": sys.argv[6]}))
+
else:
print "Unknown VPN type"
sys.exit(1)
"Security"]:
val = extract_list(properties[key])
elif key in ["Favorite", "Immutable", "AutoConnect",
- "SetupRequired", "PassphraseRequired"]:
+ "PassphraseRequired"]:
if properties[key] == dbus.Boolean(1):
val = "true"
else:
"Security"]:
val = extract_list(properties[key])
elif key in ["Favorite", "Immutable", "AutoConnect",
- "LoginRequired", "SetupRequired",
- "PassphraseRequired"]:
+ "LoginRequired", "PassphraseRequired"]:
if properties[key] == dbus.Boolean(1):
val = "true"
else:
sys.exit(1)
bus = dbus.SystemBus()
-path = "/profile/default/" + sys.argv[1]
+path = "/net/connman/service/" + sys.argv[1]
service = dbus.Interface(bus.get_object('net.connman', path),
'net.connman.Service')
-path2 = "/profile/default/" + sys.argv[2]
+path2 = "/net/connman/service/" + sys.argv[2]
service2 = dbus.Interface(bus.get_object('net.connman', path2),
'net.connman.Service')
sys.exit(1)
bus = dbus.SystemBus()
-path = "/profile/default/" + sys.argv[1]
+path = "/net/connman/service/" + sys.argv[1]
service = dbus.Interface(bus.get_object('net.connman', path),
'net.connman.Service')
sys.exit(1)
bus = dbus.SystemBus()
-path = "/profile/default/" + sys.argv[1]
+path = "/net/connman/service/" + sys.argv[1]
service = dbus.Interface(bus.get_object('net.connman', path),
'net.connman.Service')
sys.exit(1)
bus = dbus.SystemBus()
-path = "/profile/default/" + sys.argv[1]
+path = "/net/connman/service/" + sys.argv[1]
service = dbus.Interface(bus.get_object('net.connman', path),
'net.connman.Service')
sys.exit(1)
bus = dbus.SystemBus()
-path = "/profile/default/" + sys.argv[1]
+path = "/net/connman/service/" + sys.argv[1]
service = dbus.Interface(bus.get_object('net.connman', path),
'net.connman.Service')
sys.exit(1)
bus = dbus.SystemBus()
-path = "/profile/default/" + sys.argv[1]
+path = "/net/connman/service/" + sys.argv[1]
service = dbus.Interface(bus.get_object('net.connman', path),
'net.connman.Service')
identity = None
passphrase = None
wpspin = None
+ username = None
+ password = None
@dbus.service.method("net.connman.Agent",
in_signature='', out_signature='')
print("Release")
mainloop.quit()
- @dbus.service.method("net.connman.Agent",
- in_signature='oa{sv}',
- out_signature='a{sv}')
- def RequestInput(self, path, fields):
- print "RequestInput (%s,%s)" % (path, fields)
-
+ def input_passphrase(self):
response = {}
if not self.identity and not self.passphrase and not self.wpspin:
if arg.startswith("Identity="):
identity = arg.replace("Identity=", "", 1)
response["Identity"] = identity
- break
if arg.startswith("Passphrase="):
passphrase = arg.replace("Passphrase=", "", 1)
response["Passphrase"] = passphrase
- break
if arg.startswith("WPS="):
wpspin = arg.replace("WPS=", "", 1)
response["WPS"] = wpspin
if self.wpspin:
response["WPS"] = self.wpspin
+ return response
+
+ def input_username(self):
+ response = {}
+
+ if not self.username and not self.password:
+ args = raw_input('Answer: ')
+
+ for arg in args.split():
+ if arg.startswith("Username="):
+ username = arg.replace("Username=", "", 1)
+ response["Username"] = username
+ if arg.startswith("Password="):
+ password = arg.replace("Password=", "", 1)
+ response["Password"] = password
+ else:
+ if self.username:
+ response["Username"] = self.username
+ if self.password:
+ response["Password"] = self.password
+
+ return response
+
+ @dbus.service.method("net.connman.Agent",
+ in_signature='oa{sv}',
+ out_signature='a{sv}')
+ def RequestInput(self, path, fields):
+ print "RequestInput (%s,%s)" % (path, fields)
+
+ response = None
+
+ if fields.has_key("Passphrase"):
+ response = self.input_passphrase()
+ elif fields.has_key("Username"):
+ response = self.input_username()
+ else:
+ print "No method to answer the input request"
+
print "returning (%s)" % (response)
return response
print "Cancel"
def print_usage():
- print "Usage: %s Identity=<identity> Passphrase=<passphrase> WPS=<wpspin>" % (sys.argv[0])
- print "Help: %s help" % (sys.ar[0])
+ print "Usage:"
+ print "For EAP/WPA input:"
+ print "%s Identity=<identity> Passphrase=<passphrase> WPS=<wpspin>" % (sys.argv[0])
+ print "For WISPr login input:"
+ print "%s Username=<username> Password=<password>" % (sys.argv[0])
+ print "Help: %s help" % (sys.argv[0])
sys.exit(1)
if __name__ == '__main__':
object.passphrase = arg.replace("Passphrase=", "", 1)
elif arg.startswith("WPS="):
object.wpspin = arg.replace("WPS=", "", 1)
+ elif arg.startswith("Username="):
+ object.username = arg.replace("Username=", "", 1)
+ elif arg.startswith("Password="):
+ object.password = arg.replace("Password=", "", 1)
else:
print_usage()
print "Need at least service parameter"
sys.exit(1)
- path = "/profile/default/" + sys.argv[2]
+ path = "/net/connman/service/" + sys.argv[2]
service = dbus.Interface(bus.get_object("net.connman", path),
"net.connman.Service")
print "Need at least service parameter"
sys.exit(1)
- path = "/profile/default/" + sys.argv[2]
+ path = "/net/connman/service/" + sys.argv[2]
service = dbus.Interface(bus.get_object("net.connman", path),
"net.connman.Service")
print "Need at least service parameter"
sys.exit(1)
- path = "/profile/default/" + sys.argv[2]
+ path = "/net/connman/service/" + sys.argv[2]
service = dbus.Interface(bus.get_object("net.connman", path),
"net.connman.Service")
print "Need at least service parameter"
sys.exit(1)
- path = "/profile/default/" + sys.argv[2]
+ path = "/net/connman/service/" + sys.argv[2]
service = dbus.Interface(bus.get_object("net.connman", path),
"net.connman.Service")
print "Need at least service parameter"
sys.exit(1)
- path = "/profile/default/" + sys.argv[2]
+ path = "/net/connman/service/" + sys.argv[2]
service = dbus.Interface(bus.get_object("net.connman", path),
"net.connman.Service")
elif key in ["Powered", "Scanning", "Connected",
"Available", "Remember", "Default",
"Favorite", "Immutable", "AutoConnect",
- "LoginRequired", "SetupRequired",
+ "LoginRequired",
"PassphraseRequired"]:
if properties[key] == dbus.Boolean(1):
val = "true"
@dbus.service.method("net.connman.Notification",
in_signature='', out_signature='')
def Release(self):
- print("Release")
- self.app.release()
+ print "Release %s" % (self._object_path)
+ session_name = self._object_path.split('/')[-1]
+ self.app.release(session_name)
@dbus.service.method("net.connman.Notification",
in_signature='a{sv}', out_signature='')
def Update(self, settings):
- print "Update called"
+ print "Update called at %s" % (self._object_path)
try:
for key in settings.keys():
dbus.service.Object.__init__(self, bus, object_path)
self.manager = None
- self.notify_path = object_path + "/notify"
- self.notify = None
- self.session_path = None
self.mainloop = mainloop
- self.session = None
- self.settings = { }
+ self.sessions = {}
try:
bus = dbus.SystemBus()
else:
print "connman disappeared on D-Bus"
self.manager = None
- self.session = None
- if self.notify:
- self.notify.remove_from_connection()
- self.notify = None
+ for s in self.sessions.keys():
+ self.sessions[s]['notify'].remove_from_connection()
+ self.sessions[s]['notify'] = None
+
+ self.sessions = {}
except dbus.DBusException:
traceback.print_exc()
exit(1)
- def release(self):
- if self.session:
- self.manager.DestroySession(self.session_path)
- self.session = None
- if self.notify:
- self.notify.remove_from_connection()
- self.notify = None
+ def release(self, session_name):
+ s = self.find_session(session_name)
+ if not s:
+ return
+ if s['session']:
+ s['session'].Destroy()
+ s['session'] = None
+ if s['notify']:
+ s['notify'].remove_from_connection()
+ s['notify'] = None
+ del self.sessions[session_name]
def type_convert(self, key, value):
if key in [ "AllowedBearers", "RoamingPolicy" ]:
return value
+ def find_session(self, session_name):
+ if not session_name in self.sessions.keys():
+ return None
+ return self.sessions[session_name]
+
@dbus.service.method("com.example.TestSession",
in_signature='', out_signature='')
- def CreateSession(self):
+ def CreateSession(self, session_name):
print "Create session"
- if self.session:
- print "already running a session -> drop reqest"
+ s = self.find_session(session_name)
+ if s and s['session'] :
+ print "Session %s already created-> drop reqest" % (session_name)
return
try:
bus = dbus.SystemBus()
- self.notify = Notification(bus, self, self.notify_path)
- self.notify.add_to_connection(bus, self.notify_path)
-
- self.session_path = self.manager.CreateSession(self.settings, self.notify_path)
-
- print "notify path %s" % (self.notify_path)
- print "session path %s" % (self.session_path)
-
- self.session = dbus.Interface(bus.get_object("net.connman", self.session_path),
+ if s == None:
+ s = {}
+ s['notify_path'] = self._object_path + "/" + session_name
+ s['notify'] = Notification(bus, self, s['notify_path'])
+ s['notify'].add_to_connection(bus, s['notify_path'])
+ if not 'settings' in s.keys():
+ s['settings'] = {};
+ s['session_path'] = self.manager.CreateSession(s['settings'], s['notify_path'])
+ print "notify path %s" % (s['notify_path'])
+ print "session path %s" % (s['session_path'])
+ s['session'] = dbus.Interface(bus.get_object("net.connman", s['session_path']),
"net.connman.Session")
+ self.sessions[session_name] = s
except dbus.DBusException, e:
if e.get_dbus_name() in ['net.connman.Error.Failed']:
@dbus.service.method("com.example.TestSession",
in_signature='', out_signature='')
- def DestroySession(self):
+ def DestroySession(self, session_name):
print "Destroy session"
- if self.session == None:
- print "no session running -> drop request"
+ s = self.find_session(session_name)
+ if s == None or s['session'] == None:
+ print "The session is not running -> drop request"
return
try:
- self.release()
+ self.release(session_name)
except dbus.DBusException:
traceback.print_exc()
exit(1)
@dbus.service.method("com.example.TestSession",
in_signature='', out_signature='')
- def Connect(self):
+ def Connect(self, session_name):
print "Connect session"
- if self.session == None:
- print "no session running -> drop request"
+ s = self.find_session(session_name)
+ if s == None or s['session'] == None:
+ print "The session is not running -> drop request"
return
try:
- self.session.Connect()
+ s['session'].Connect()
except dbus.DBusException, e:
if e.get_dbus_name() in ['net.connman.Error.Failed']:
print e.get_dbus_message()
@dbus.service.method("com.example.TestSession",
in_signature='', out_signature='')
- def Disconnect(self):
+ def Disconnect(self, session_name):
print "Disconnect session"
- if self.session == None:
- print "no session running -> drop request"
+ s = self.find_session(session_name)
+ if s == None or s['session'] == None:
+ print "The session is not running -> drop request"
return
try:
- self.session.Disconnect()
+ s['session'].Disconnect()
except dbus.DBusException, e:
if e.get_dbus_name() in ['net.connman.Error.Failed']:
print e.get_dbus_message()
exit(1)
@dbus.service.method("com.example.TestSession",
- in_signature='sv', out_signature='')
- def Change(self, key, value):
+ in_signature='', out_signature='')
+ def Change(self, session_name, key, value):
print "Update session settings"
- if self.session == None:
- print "no session running -> drop request"
+ s = self.find_session(session_name)
+ if s == None or s['session'] == None:
+ print "The session is not running -> drop request"
return
try:
val = self.type_convert(key, value)
- self.session.Change(key, val)
+ s['session'].Change(key, val)
except dbus.DBusException, e:
if e.get_dbus_name() in ['net.connman.Error.Failed']:
print e.get_dbus_message()
exit(1)
@dbus.service.method("com.example.TestSession",
- in_signature='sv', out_signature='')
- def Configure(self, key, value):
+ in_signature='', out_signature='')
+ def Configure(self, session_name, key, value):
print "Configure session settings"
+ s = self.find_session(session_name)
+ if s == None:
+ s = {}
+ s['notify_path'] = None
+ s['notify'] = None
+ if not 'settings' in s.keys():
+ s['settings'] = {};
+ s['session_path'] = None
+ s['session'] = None
+ self.sessions[session_name] = s
+ if s and s['session']:
+ print "The session is running, use change -> drop request"
+ return
val = self.type_convert(key, value)
- self.settings[key] = val
+ s['settings'][key] = val
def main():
if len(sys.argv) < 2:
print ""
print " enable"
print " disable"
- print " create <app_path>"
- print " destroy <app_path>"
- print " connect <app_path>"
- print " disconnect <app_path>"
- print " change <app_path> <key> <value>"
- print " configure <app_path> <key> <value>"
+ print " create <app_path> <session_name>"
+ print " destroy <app_path> <session_name>"
+ print " connect <app_path> <session_name>"
+ print " disconnect <app_path> <session_name>"
+ print " change <app_path> <session_name> <key> <value>"
+ print " configure <app_path> <session_name> <key> <value>"
print ""
print " run <app_path>"
sys.exit(1)
"com.example.TestSession")
if sys.argv[1] == "create":
- app.CreateSession()
+ app.CreateSession(sys.argv[3])
elif sys.argv[1] == "destroy":
- app.DestroySession()
+ app.DestroySession(sys.argv[3])
elif sys.argv[1] == "connect":
- app.Connect()
+ app.Connect(sys.argv[3])
elif sys.argv[1] == "disconnect":
- app.Disconnect()
+ app.Disconnect(sys.argv[3])
elif sys.argv[1] == "change":
if len(sys.argv) < 5:
print "Arguments missing"
sys.exit(1)
- app.Change(sys.argv[3], sys.argv[4:])
+ app.Change(sys.argv[3], sys.argv[4], sys.argv[5:])
elif sys.argv[1] == "configure":
if len(sys.argv) < 5:
print "Arguments missing"
sys.exit(1)
- app.Configure(sys.argv[3], sys.argv[4:])
+ app.Configure(sys.argv[3], sys.argv[4], sys.argv[5:])
else:
print "Unknown command '%s'" % sys.argv[1]
#include <config.h>
#endif
+#define _GNU_SOURCE
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
struct stat st;
int fd;
- fd = open(pathname, O_RDONLY);
+ fd = open(pathname, O_RDONLY | O_CLOEXEC);
if (fd < 0)
return -1;
};
int sk, nsk;
- sk = socket(PF_ALG, SOCK_SEQPACKET, 0);
+ sk = socket(PF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
if (sk < 0) {
perror("Failed to create socket");
return -1;
/*
* Connection Manager
*
- * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
+ * Copyright (C) 2007-2011 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include <unistd.h>
#include <sys/errno.h>
#include <sys/socket.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
#include <xtables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#define LABEL_QUEUE "QUEUE"
#define LABEL_RETURN "RETURN"
+#define XT_OPTION_OFFSET_SCALE 256
+
/* fn returns 0 to continue iteration */
#define _XT_ENTRY_ITERATE_CONTINUE(type, entries, size, n, fn, args...) \
({ \
type *__entry; \
\
for (__i = 0, __n = 0; __i < (size); \
- __i += __entry->next_offset, __n++) { \
+ __i += __entry->next_offset, __n++) { \
__entry = (void *)(entries) + __i; \
if (__n < n) \
continue; \
char *chain_name)
{
GList *chain_head, *list;
- struct connman_iptables_entry *head, *tail;
- struct ipt_entry *entry;
- struct xt_entry_target *target;
- int builtin;
-
- /* First we look for the head */
- for (list = table->entries; list; list = list->next) {
- head = list->data;
- entry = head->entry;
-
- /* Buit-in chain */
- builtin = head->builtin;
- if (builtin >= 0 && !strcmp(hooknames[builtin], chain_name))
- break;
+ struct connman_iptables_entry *tail;
- /* User defined chain */
- target = ipt_get_target(entry);
- if (!strcmp(target->u.user.name, IPT_ERROR_TARGET) &&
- !strcmp((char *)target->data, chain_name))
- break;
- }
-
- if (list == NULL)
+ chain_head = find_chain_head(table, chain_name);
+ if (chain_head == NULL)
return NULL;
- chain_head = list;
-
/* Then we look for the next chain */
for (list = chain_head->next; list; list = list->next) {
tail = list->data;
- entry = tail->entry;
if (is_chain(table, tail))
return list;
}
}
+static void update_targets_reference(struct connman_iptables *table,
+ struct connman_iptables_entry *entry_before,
+ struct connman_iptables_entry *modified_entry,
+ gboolean is_removing)
+{
+ struct connman_iptables_entry *tmp;
+ struct xt_standard_target *t;
+ GList *list;
+ int offset;
+
+ offset = modified_entry->entry->next_offset;
+
+ for (list = table->entries; list; list = list->next) {
+ tmp = list->data;
+
+ if (!is_jump(tmp))
+ continue;
+
+ t = (struct xt_standard_target *)ipt_get_target(tmp->entry);
+
+ if (is_removing == TRUE) {
+ if (t->verdict >= entry_before->offset)
+ t->verdict -= offset;
+ } else {
+ if (t->verdict > entry_before->offset)
+ t->verdict += offset;
+ }
+ }
+}
+
static int connman_add_entry(struct connman_iptables *table,
struct ipt_entry *entry, GList *before,
int builtin)
{
- GList *list;
- struct connman_iptables_entry *e, *tmp, *entry_before;
- struct xt_standard_target *t;
+ struct connman_iptables_entry *e, *entry_before;
if (table == NULL)
return -1;
entry_before = before->data;
/*
- * We've just insterted a new entry. All references before it
+ * We've just appended/insterted a new entry. All references
* should be bumped accordingly.
*/
- for (list = table->entries; list != before; list = list->next) {
- tmp = list->data;
+ update_targets_reference(table, entry_before, e, FALSE);
- if (!is_jump(tmp))
- continue;
+ update_offsets(table);
- t = (struct xt_standard_target *)ipt_get_target(tmp->entry);
+ return 0;
+}
- if (t->verdict >= entry_before->offset)
- t->verdict += entry->next_offset;
- }
+static int remove_table_entry(struct connman_iptables *table,
+ struct connman_iptables_entry *entry)
+{
+ int removed = 0;
- update_offsets(table);
+ table->num_entries--;
+ table->size -= entry->entry->next_offset;
+ removed = entry->entry->next_offset;
- return 0;
+ g_free(entry->entry);
+
+ table->entries = g_list_remove(table->entries, entry);
+
+ return removed;
}
static int connman_iptables_flush_chain(struct connman_iptables *table,
entry = list->data;
next = g_list_next(list);
- table->num_entries--;
- table->size -= entry->entry->next_offset;
- removed += entry->entry->next_offset;
-
- table->entries = g_list_remove(table->entries, list->data);
+ removed += remove_table_entry(table, entry);
list = next;
}
static int connman_iptables_delete_chain(struct connman_iptables *table,
char *name)
{
- GList *chain_head, *chain_tail, *list, *next;
+ GList *chain_head, *chain_tail;
struct connman_iptables_entry *entry;
chain_head = find_chain_head(table, name);
if (chain_head == NULL)
return -EINVAL;
+ entry = chain_head->data;
+
+ /* We cannot remove builtin chain */
+ if (entry->builtin >= 0)
+ return -EINVAL;
+
chain_tail = find_chain_tail(table, name);
if (chain_tail == NULL)
return -EINVAL;
- list = chain_head;
-
- while (list != chain_tail) {
- entry = list->data;
- next = g_list_next(list);
-
- table->num_entries--;
- table->size -= entry->entry->next_offset;
+ /* Chain must be flushed */
+ if (chain_head->next != chain_tail->prev)
+ return -EINVAL;
- table->entries = g_list_remove(table->entries, list->data);
+ remove_table_entry(table, entry);
- list = next;
- }
+ entry = chain_tail->prev->data;
+ remove_table_entry(table, entry);
update_offsets(table);
return -ENOMEM;
}
-static struct ipt_entry *
-new_rule(struct connman_iptables *table,
- char *target_name, struct xtables_target *xt_t,
- char *match_name, struct xtables_match *xt_m)
+static struct ipt_entry *new_rule(struct ipt_ip *ip,
+ char *target_name, struct xtables_target *xt_t,
+ struct xtables_rule_match *xt_rm)
{
+ struct xtables_rule_match *tmp_xt_rm;
struct ipt_entry *new_entry;
size_t match_size, target_size;
- int is_builtin = is_builtin_target(target_name);
- if (xt_m)
- match_size = xt_m->m->u.match_size;
- else
- match_size = 0;
+ match_size = 0;
+ for (tmp_xt_rm = xt_rm; tmp_xt_rm != NULL; tmp_xt_rm = tmp_xt_rm->next)
+ match_size += tmp_xt_rm->match->m->u.match_size;
if (xt_t)
target_size = ALIGN(xt_t->t->u.target_size);
if (new_entry == NULL)
return NULL;
+ memcpy(&new_entry->ip, ip, sizeof(struct ipt_ip));
+
new_entry->target_offset = sizeof(struct ipt_entry) + match_size;
new_entry->next_offset = sizeof(struct ipt_entry) + target_size +
match_size;
- if (xt_m) {
- struct xt_entry_match *entry_match;
- entry_match = (struct xt_entry_match *)new_entry->elems;
- memcpy(entry_match, xt_m->m, match_size);
+ match_size = 0;
+ for (tmp_xt_rm = xt_rm; tmp_xt_rm != NULL;
+ tmp_xt_rm = tmp_xt_rm->next) {
+ memcpy(new_entry->elems + match_size, tmp_xt_rm->match->m,
+ tmp_xt_rm->match->m->u.match_size);
+ match_size += tmp_xt_rm->match->m->u.match_size;
}
if (xt_t) {
struct xt_entry_target *entry_target;
- if (is_builtin) {
- struct xt_standard_target *target;
-
- target = (struct xt_standard_target *)(xt_t->t);
- strcpy(target->target.u.user.name, IPT_STANDARD_TARGET);
- target->verdict = target_to_verdict(target_name);
- }
-
entry_target = ipt_get_target(new_entry);
memcpy(entry_target, xt_t->t, target_size);
- } else {
- struct connman_iptables_entry *target_rule;
- struct xt_standard_target *target;
- GList *chain_head;
-
- /*
- * This is a user defined target, i.e. a chain jump.
- * We search for the chain head, and the target verdict
- * is the first rule's offset on this chain.
- * The offset is from the beginning of the table.
- */
-
- chain_head = find_chain_head(table, target_name);
- if (chain_head == NULL || chain_head->next == NULL) {
- g_free(new_entry);
- return NULL;
- }
-
- target_rule = chain_head->next->data;
-
- target = (struct xt_standard_target *)ipt_get_target(new_entry);
- strcpy(target->target.u.user.name, IPT_STANDARD_TARGET);
- target->target.u.user.target_size = target_size;
- target->verdict = target_rule->offset;
}
return new_entry;
}
-static void update_hooks(struct connman_iptables *table, GList *chain_head, struct ipt_entry *entry)
+static void update_hooks(struct connman_iptables *table, GList *chain_head,
+ struct ipt_entry *entry)
{
GList *list;
struct connman_iptables_entry *head, *e;
}
}
-static int
-connman_iptables_add_rule(struct connman_iptables *table, char *chain_name,
+static struct ipt_entry *prepare_rule_inclusion(struct connman_iptables *table,
+ struct ipt_ip *ip, char *chain_name,
char *target_name, struct xtables_target *xt_t,
- char *match_name, struct xtables_match *xt_m)
+ int *builtin, struct xtables_rule_match *xt_rm)
{
GList *chain_tail, *chain_head;
struct ipt_entry *new_entry;
struct connman_iptables_entry *head;
- int builtin = -1;
chain_head = find_chain_head(table, chain_name);
if (chain_head == NULL)
- return -EINVAL;
+ return NULL;
chain_tail = find_chain_tail(table, chain_name);
if (chain_tail == NULL)
- return -EINVAL;
+ return NULL;
- new_entry = new_rule(table,
- target_name, xt_t,
- match_name, xt_m);
+ new_entry = new_rule(ip, target_name, xt_t, xt_rm);
if (new_entry == NULL)
- return -EINVAL;
+ return NULL;
update_hooks(table, chain_head, new_entry);
*/
head = chain_head->data;
if (head->builtin < 0)
- builtin = -1;
+ *builtin = -1;
else if (chain_head == chain_tail->prev) {
- builtin = head->builtin;
+ *builtin = head->builtin;
head->builtin = -1;
}
- return connman_add_entry(table, new_entry, chain_tail->prev, builtin);
+ return new_entry;
+}
+
+static int connman_iptables_append_rule(struct connman_iptables *table,
+ struct ipt_ip *ip, char *chain_name,
+ char *target_name, struct xtables_target *xt_t,
+ struct xtables_rule_match *xt_rm)
+{
+ GList *chain_tail;
+ struct ipt_entry *new_entry;
+ int builtin = -1, ret;
+
+ chain_tail = find_chain_tail(table, chain_name);
+ if (chain_tail == NULL)
+ return -EINVAL;
+
+ new_entry = prepare_rule_inclusion(table, ip, chain_name,
+ target_name, xt_t, &builtin, xt_rm);
+ if (new_entry == NULL)
+ return -EINVAL;
+
+ ret = connman_add_entry(table, new_entry, chain_tail->prev, builtin);
+ if (ret < 0)
+ g_free(new_entry);
+
+ return ret;
+}
+
+static int connman_iptables_insert_rule(struct connman_iptables *table,
+ struct ipt_ip *ip, char *chain_name,
+ char *target_name, struct xtables_target *xt_t,
+ struct xtables_rule_match *xt_rm)
+{
+ GList *chain_head;
+ struct ipt_entry *new_entry;
+ int builtin = -1, ret;
+
+ chain_head = find_chain_head(table, chain_name);
+ if (chain_head == NULL)
+ return -EINVAL;
+
+ new_entry = prepare_rule_inclusion(table, ip, chain_name,
+ target_name, xt_t, &builtin, xt_rm);
+ if (new_entry == NULL)
+ return -EINVAL;
+
+ ret = connman_add_entry(table, new_entry, chain_head->next, builtin);
+ if (ret < 0)
+ g_free(new_entry);
+
+ return ret;
+}
+
+static gboolean is_same_ipt_entry(struct ipt_entry *i_e1,
+ struct ipt_entry *i_e2)
+{
+ if (memcmp(&i_e1->ip, &i_e2->ip, sizeof(struct ipt_ip)) != 0)
+ return FALSE;
+
+ if (i_e1->target_offset != i_e2->target_offset)
+ return FALSE;
+
+ if (i_e1->next_offset != i_e2->next_offset)
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean is_same_target(struct xt_entry_target *xt_e_t1,
+ struct xt_entry_target *xt_e_t2)
+{
+ if (xt_e_t1 == NULL || xt_e_t2 == NULL)
+ return FALSE;
+
+ if (strcmp(xt_e_t1->u.user.name, IPT_STANDARD_TARGET) == 0) {
+ struct xt_standard_target *xt_s_t1;
+ struct xt_standard_target *xt_s_t2;
+
+ xt_s_t1 = (struct xt_standard_target *) xt_e_t1;
+ xt_s_t2 = (struct xt_standard_target *) xt_e_t2;
+
+ if (xt_s_t1->verdict != xt_s_t2->verdict)
+ return FALSE;
+ } else {
+ if (xt_e_t1->u.target_size != xt_e_t2->u.target_size)
+ return FALSE;
+
+ if (strcmp(xt_e_t1->u.user.name, xt_e_t2->u.user.name) != 0)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean is_same_match(struct xt_entry_match *xt_e_m1,
+ struct xt_entry_match *xt_e_m2)
+{
+ if (xt_e_m1 == NULL || xt_e_m2 == NULL)
+ return FALSE;
+
+ if (xt_e_m1->u.match_size != xt_e_m2->u.match_size)
+ return FALSE;
+
+ if (xt_e_m1->u.user.revision != xt_e_m2->u.user.revision)
+ return FALSE;
+
+ if (strcmp(xt_e_m1->u.user.name, xt_e_m2->u.user.name) != 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static int connman_iptables_delete_rule(struct connman_iptables *table,
+ struct ipt_ip *ip, char *chain_name,
+ char *target_name, struct xtables_target *xt_t,
+ struct xtables_match *xt_m,
+ struct xtables_rule_match *xt_rm)
+{
+ GList *chain_tail, *chain_head, *list;
+ struct xt_entry_target *xt_e_t = NULL;
+ struct xt_entry_match *xt_e_m = NULL;
+ struct connman_iptables_entry *entry;
+ struct ipt_entry *entry_test;
+ int builtin, removed;
+
+ removed = 0;
+
+ chain_head = find_chain_head(table, chain_name);
+ if (chain_head == NULL)
+ return -EINVAL;
+
+ chain_tail = find_chain_tail(table, chain_name);
+ if (chain_tail == NULL)
+ return -EINVAL;
+
+ if (!xt_t && !xt_m)
+ return -EINVAL;
+
+ entry_test = new_rule(ip, target_name, xt_t, xt_rm);
+ if (entry_test == NULL)
+ return -EINVAL;
+
+ if (xt_t != NULL)
+ xt_e_t = ipt_get_target(entry_test);
+ if (xt_m != NULL)
+ xt_e_m = (struct xt_entry_match *)entry_test->elems;
+
+ entry = chain_head->data;
+ builtin = entry->builtin;
+
+ if (builtin >= 0)
+ list = chain_head;
+ else
+ list = chain_head->next;
+
+ for (entry = NULL; list != chain_tail->prev; list = list->next) {
+ struct connman_iptables_entry *tmp;
+ struct ipt_entry *tmp_e;
+
+ tmp = list->data;
+ tmp_e = tmp->entry;
+
+ if (is_same_ipt_entry(entry_test, tmp_e) == FALSE)
+ continue;
+
+ if (xt_t != NULL) {
+ struct xt_entry_target *tmp_xt_e_t;
+
+ tmp_xt_e_t = ipt_get_target(tmp_e);
+
+ if (!is_same_target(tmp_xt_e_t, xt_e_t))
+ continue;
+ }
+
+ if (xt_m != NULL) {
+ struct xt_entry_match *tmp_xt_e_m;
+
+ tmp_xt_e_m = (struct xt_entry_match *)tmp_e->elems;
+
+ if (!is_same_match(tmp_xt_e_m, xt_e_m))
+ continue;
+ }
+
+ entry = tmp;
+ break;
+ }
+
+ if (entry == NULL) {
+ g_free(entry_test);
+ return -EINVAL;
+ }
+
+ /* We have deleted a rule,
+ * all references should be bumped accordingly */
+ if (list->next != NULL)
+ update_targets_reference(table, list->next->data,
+ list->data, TRUE);
+
+ removed += remove_table_entry(table, entry);
+
+ if (builtin >= 0) {
+ list = list->next;
+ if (list) {
+ entry = list->data;
+ entry->builtin = builtin;
+ }
+
+ table->underflow[builtin] -= removed;
+ for (list = chain_tail; list; list = list->next) {
+ entry = list->data;
+
+ builtin = entry->builtin;
+ if (builtin < 0)
+ continue;
+
+ table->hook_entry[builtin] -= removed;
+ table->underflow[builtin] -= removed;
+ }
+ }
+
+ update_offsets(table);
+
+ return 0;
}
-static struct ipt_replace *
-connman_iptables_blob(struct connman_iptables *table)
+static int connman_iptables_change_policy(struct connman_iptables *table,
+ char *chain_name, char *policy)
+{
+ GList *chain_head;
+ struct connman_iptables_entry *entry;
+ struct xt_entry_target *target;
+ struct xt_standard_target *t;
+ int verdict;
+
+ verdict = target_to_verdict(policy);
+ if (verdict == 0)
+ return -EINVAL;
+
+ chain_head = find_chain_head(table, chain_name);
+ if (chain_head == NULL)
+ return -EINVAL;
+
+ entry = chain_head->data;
+ if (entry->builtin < 0)
+ return -EINVAL;
+
+ target = ipt_get_target(entry->entry);
+
+ t = (struct xt_standard_target *)target;
+ t->verdict = verdict;
+
+ return 0;
+}
+
+static struct ipt_replace *connman_iptables_blob(struct connman_iptables *table)
{
struct ipt_replace *r;
GList *list;
static struct connman_iptables *connman_iptables_init(const char *table_name)
{
- struct connman_iptables *table;
+ struct connman_iptables *table = NULL;
+ char *module = NULL;
socklen_t s;
+ if (xtables_insmod("ip_tables", NULL, TRUE) != 0)
+ goto err;
+
+ module = g_strconcat("iptable_", table_name, NULL);
+ if (module == NULL)
+ goto err;
+
+ if (xtables_insmod(module, NULL, TRUE) != 0)
+ goto err;
+
+ g_free(module);
+ module = NULL;
+
table = g_try_new0(struct connman_iptables, 1);
if (table == NULL)
return NULL;
if (table->info == NULL)
goto err;
- table->ipt_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+ table->ipt_sock = socket(AF_INET, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_RAW);
if (table->ipt_sock < 0)
goto err;
table->blob_entries->size,
add_entry, table);
-
return table;
err:
+ g_free(module);
connman_iptables_cleanup(table);
return NULL;
}
-
static struct option connman_iptables_opts[] = {
{.name = "append", .has_arg = 1, .val = 'A'},
+ {.name = "delete", .has_arg = 1, .val = 'D'},
{.name = "flush-chain", .has_arg = 1, .val = 'F'},
+ {.name = "insert", .has_arg = 1, .val = 'I'},
{.name = "list", .has_arg = 2, .val = 'L'},
{.name = "new-chain", .has_arg = 1, .val = 'N'},
+ {.name = "policy", .has_arg = 1, .val = 'P'},
{.name = "delete-chain", .has_arg = 1, .val = 'X'},
+ {.name = "destination", .has_arg = 1, .val = 'd'},
{.name = "in-interface", .has_arg = 1, .val = 'i'},
{.name = "jump", .has_arg = 1, .val = 'j'},
{.name = "match", .has_arg = 1, .val = 'm'},
{.name = "out-interface", .has_arg = 1, .val = 'o'},
+ {.name = "source", .has_arg = 1, .val = 's'},
{.name = "table", .has_arg = 1, .val = 't'},
{NULL},
};
.orig_opts = connman_iptables_opts,
};
+static struct xtables_target *prepare_target(struct connman_iptables *table,
+ char *target_name)
+{
+ struct xtables_target *xt_t = NULL;
+ gboolean is_builtin, is_user_defined;
+ GList *chain_head = NULL;
+ size_t target_size;
+
+ is_builtin = FALSE;
+ is_user_defined = FALSE;
+
+ if (is_builtin_target(target_name))
+ is_builtin = TRUE;
+ else {
+ chain_head = find_chain_head(table, target_name);
+ if (chain_head != NULL && chain_head->next != NULL)
+ is_user_defined = TRUE;
+ }
+
+ if (is_builtin || is_user_defined)
+ xt_t = xtables_find_target(IPT_STANDARD_TARGET,
+ XTF_LOAD_MUST_SUCCEED);
+ else
+ xt_t = xtables_find_target(target_name, XTF_TRY_LOAD);
+
+ if (xt_t == NULL)
+ return NULL;
+
+ target_size = ALIGN(sizeof(struct ipt_entry_target)) + xt_t->size;
+
+ xt_t->t = g_try_malloc0(target_size);
+ if (xt_t->t == NULL)
+ return NULL;
+
+ xt_t->t->u.target_size = target_size;
+
+ if (is_builtin || is_user_defined) {
+ struct xt_standard_target *target;
+
+ target = (struct xt_standard_target *)(xt_t->t);
+ strcpy(target->target.u.user.name, IPT_STANDARD_TARGET);
+
+ if (is_builtin == TRUE)
+ target->verdict = target_to_verdict(target_name);
+ else if (is_user_defined == TRUE) {
+ struct connman_iptables_entry *target_rule;
+
+ if (chain_head == NULL) {
+ g_free(xt_t->t);
+ return NULL;
+ }
+
+ target_rule = chain_head->next->data;
+ target->verdict = target_rule->offset;
+ }
+ } else {
+ strcpy(xt_t->t->u.user.name, target_name);
+ xt_t->t->u.user.revision = xt_t->revision;
+ if (xt_t->init != NULL)
+ xt_t->init(xt_t->t);
+ }
+
+#if XTABLES_VERSION_CODE > 5
+ if (xt_t->x6_options != NULL)
+ connman_iptables_globals.opts =
+ xtables_options_xfrm(
+ connman_iptables_globals.orig_opts,
+
+ connman_iptables_globals.opts,
+ xt_t->x6_options,
+ &xt_t->option_offset);
+ else
+#endif
+ connman_iptables_globals.opts =
+ xtables_merge_options(
+#if XTABLES_VERSION_CODE > 5
+ connman_iptables_globals.orig_opts,
+#endif
+ connman_iptables_globals.opts,
+ xt_t->extra_opts,
+ &xt_t->option_offset);
+
+ if (connman_iptables_globals.opts == NULL) {
+ g_free(xt_t->t);
+ xt_t = NULL;
+ }
+
+ return xt_t;
+}
+
+static struct xtables_match *prepare_matches(struct connman_iptables *table,
+ struct xtables_rule_match **xt_rm, char *match_name)
+{
+ struct xtables_match *xt_m;
+ size_t match_size;
+
+ if (match_name == NULL)
+ return NULL;
+
+ xt_m = xtables_find_match(match_name, XTF_LOAD_MUST_SUCCEED, xt_rm);
+ match_size = ALIGN(sizeof(struct ipt_entry_match)) + xt_m->size;
+
+ xt_m->m = g_try_malloc0(match_size);
+ if (xt_m->m == NULL)
+ return NULL;
+
+ xt_m->m->u.match_size = match_size;
+ strcpy(xt_m->m->u.user.name, xt_m->name);
+ xt_m->m->u.user.revision = xt_m->revision;
+
+ if (xt_m->init != NULL)
+ xt_m->init(xt_m->m);
+
+ if (xt_m == xt_m->next)
+ goto done;
+
+#if XTABLES_VERSION_CODE > 5
+ if (xt_m->x6_options != NULL)
+ connman_iptables_globals.opts =
+ xtables_options_xfrm(
+ connman_iptables_globals.orig_opts,
+ connman_iptables_globals.opts,
+ xt_m->x6_options,
+ &xt_m->option_offset);
+ else
+#endif
+ connman_iptables_globals.opts =
+ xtables_merge_options(
+#if XTABLES_VERSION_CODE > 5
+ connman_iptables_globals.orig_opts,
+#endif
+ connman_iptables_globals.opts,
+ xt_m->extra_opts,
+ &xt_m->option_offset);
+
+ if (connman_iptables_globals.opts == NULL) {
+ g_free(xt_m->m);
+ xt_m = NULL;
+ }
+
+done:
+ return xt_m;
+}
+
int main(int argc, char *argv[])
{
struct connman_iptables *table;
- struct xtables_match *xt_m;
+ struct xtables_rule_match *xt_rm, *tmp_xt_rm;
+ struct xtables_match *xt_m, *xt_m_t;
struct xtables_target *xt_t;
+ struct ipt_ip ip;
char *table_name, *chain, *new_chain, *match_name, *target_name;
- char *delete_chain, *flush_chain;
- int c;
- size_t size;
- gboolean dump, invert, delete;
+ char *delete_chain, *flush_chain, *policy;
+ int c, in_len, out_len;
+ gboolean dump, invert, delete, insert, delete_rule;
+ struct in_addr src, dst;
xtables_init_all(&connman_iptables_globals, NFPROTO_IPV4);
dump = FALSE;
invert = FALSE;
delete = FALSE;
+ insert = FALSE;
+ delete_rule = FALSE;
table_name = chain = new_chain = match_name = target_name = NULL;
- delete_chain = flush_chain = NULL;
+ delete_chain = flush_chain = policy = NULL;
+ memset(&ip, 0, sizeof(struct ipt_ip));
table = NULL;
+ xt_rm = NULL;
xt_m = NULL;
xt_t = NULL;
- while ((c = getopt_long(argc, argv,
- "-A:F:L::N:X:j:i:m:o:t:", connman_iptables_globals.opts, NULL)) != -1) {
+ /* extension's options will generate false-positives errors */
+ opterr = 0;
+
+ while ((c = getopt_long(argc, argv, "-A:D:F:I:L::N:P:X:d:i:j:m:o:s:t:",
+ connman_iptables_globals.opts, NULL)) != -1) {
switch (c) {
case 'A':
+ /* It is either -A, -D or -I at once */
+ if (chain)
+ goto out;
+
+ chain = optarg;
+ break;
+
+ case 'D':
+ /* It is either -A, -D or -I at once */
+ if (chain)
+ goto out;
+
chain = optarg;
+ delete_rule = TRUE;
break;
case 'F':
flush_chain = optarg;
break;
+ case 'I':
+ /* It is either -A, -D or -I at once */
+ if (chain)
+ goto out;
+
+ chain = optarg;
+ insert = TRUE;
+ break;
+
case 'L':
dump = true;
break;
new_chain = optarg;
break;
+ case 'P':
+ chain = optarg;
+ if (optind < argc)
+ policy = argv[optind++];
+ else
+ goto out;
+
+ break;
+
case 'X':
delete = true;
delete_chain = optarg;
break;
- case 'j':
- target_name = optarg;
- xt_t = xtables_find_target(target_name, XTF_TRY_LOAD);
-
- if (xt_t == NULL)
+ case 'd':
+ if (!inet_pton(AF_INET, optarg, &dst))
break;
- size = ALIGN(sizeof(struct ipt_entry_target)) + xt_t->size;
+ ip.dst = dst;
+ inet_pton(AF_INET, "255.255.255.255", &ip.dmsk);
- xt_t->t = g_try_malloc0(size);
- if (xt_t->t == NULL)
- goto out;
- xt_t->t->u.target_size = size;
- strcpy(xt_t->t->u.user.name, target_name);
- xt_t->t->u.user.revision = xt_t->revision;
- if (xt_t->init != NULL)
- xt_t->init(xt_t->t);
- connman_iptables_globals.opts =
- xtables_merge_options(
-#if XTABLES_VERSION_CODE > 5
- connman_iptables_globals.orig_opts,
-#endif
- connman_iptables_globals.opts,
- xt_t->extra_opts,
- &xt_t->option_offset);
- if (connman_iptables_globals.opts == NULL)
- goto out;
+ if (invert)
+ ip.invflags |= IPT_INV_DSTIP;
break;
case 'i':
+ in_len = strlen(optarg);
+
+ if (in_len + 1 > IFNAMSIZ)
+ break;
+
+ strcpy(ip.iniface, optarg);
+ memset(ip.iniface_mask, 0xff, in_len + 1);
+
+ if (invert)
+ ip.invflags |= IPT_INV_VIA_IN;
+
+ break;
+
+ case 'j':
+ target_name = optarg;
+ xt_t = prepare_target(table, target_name);
+ if (xt_t == NULL)
+ goto out;
+
break;
case 'm':
match_name = optarg;
-
- xt_m = xtables_find_match(optarg, XTF_LOAD_MUST_SUCCEED, NULL);
- size = ALIGN(sizeof(struct ipt_entry_match)) + xt_m->size;
- xt_m->m = g_try_malloc0(size);
+ xt_m = prepare_matches(table, &xt_rm, match_name);
if (xt_m == NULL)
goto out;
- xt_m->m->u.match_size = size;
- strcpy(xt_m->m->u.user.name, xt_m->name);
- xt_m->m->u.user.revision = xt_m->revision;
- if (xt_m->init != NULL)
- xt_m->init(xt_m->m);
- if (xt_m != xt_m->next) {
- connman_iptables_globals.opts =
- xtables_merge_options(
-#if XTABLES_VERSION_CODE > 5
- connman_iptables_globals.orig_opts,
-#endif
- connman_iptables_globals.opts,
- xt_m->extra_opts,
- &xt_m->option_offset);
- if (connman_iptables_globals.opts == NULL)
- goto out;
- }
break;
case 'o':
+ out_len = strlen(optarg);
+
+ if (out_len + 1 > IFNAMSIZ)
+ break;
+
+ strcpy(ip.outiface, optarg);
+ memset(ip.outiface_mask, 0xff, out_len + 1);
+
+ if (invert)
+ ip.invflags |= IPT_INV_VIA_OUT;
+
+ break;
+
+ case 's':
+ if (!inet_pton(AF_INET, optarg, &src))
+ break;
+
+ ip.src = src;
+ inet_pton(AF_INET, "255.255.255.255", &ip.smsk);
+
+ if (invert)
+ ip.invflags |= IPT_INV_SRCIP;
+
break;
case 't':
table_name = optarg;
+
+ table = connman_iptables_init(table_name);
+ if (table == NULL)
+ return -1;
+
break;
case 1:
return -1;
default:
- if (xt_t == NULL || xt_t->parse == NULL ||
- !xt_t->parse(c - xt_t->option_offset, argv, invert,
- &xt_t->tflags, NULL, &xt_t->t)) {
- if (xt_m == NULL || xt_m->parse == NULL)
- break;
+#if XTABLES_VERSION_CODE > 5
+ if (xt_t != NULL && (xt_t->x6_parse != NULL ||
+ xt_t->parse != NULL) &&
+ (c >= (int) xt_t->option_offset &&
+ c < (int) xt_t->option_offset +
+ XT_OPTION_OFFSET_SCALE)) {
+ xtables_option_tpcall(c, argv,
+ invert, xt_t, NULL);
- xt_m->parse(c - xt_m->option_offset, argv,
- invert, &xt_m->mflags, NULL, &xt_m->m);
+ break;
}
+ for (tmp_xt_rm = xt_rm; tmp_xt_rm != NULL;
+ tmp_xt_rm = tmp_xt_rm->next) {
+ xt_m_t = tmp_xt_rm->match;
+
+ if (tmp_xt_rm->completed ||
+ (xt_m_t->x6_parse == NULL &&
+ xt_m_t->parse == NULL))
+ continue;
+
+ if (c < (int) xt_m_t->option_offset ||
+ c >= (int) xt_m_t->option_offset
+ + XT_OPTION_OFFSET_SCALE)
+ continue;
+
+ xtables_option_mpcall(c, argv,
+ invert, xt_m_t, NULL);
+
+ break;
+ }
+#else
+ if (xt_t == NULL || xt_t->parse == NULL ||
+ !xt_t->parse(c - xt_t->option_offset,
+ argv, invert, &xt_t->tflags, NULL, &xt_t->t)) {
+
+ for (tmp_xt_rm = xt_rm; tmp_xt_rm != NULL;
+ tmp_xt_rm = tmp_xt_rm->next) {
+ xt_m_t = tmp_xt_rm->match;
+
+ if (tmp_xt_rm->completed ||
+ xt_m_t->parse == NULL)
+ continue;
+
+ if (xt_m->parse(c - xt_m->option_offset,
+ argv, invert, &xt_m->mflags,
+ NULL, &xt_m->m))
+ break;
+ }
+ }
+#endif
break;
}
+
+ invert = FALSE;
}
- if (table_name == NULL)
+#if XTABLES_VERSION_CODE > 5
+ for (tmp_xt_rm = xt_rm; tmp_xt_rm != NULL;
+ tmp_xt_rm = tmp_xt_rm->next)
+ xtables_option_mfcall(tmp_xt_rm->match);
+
+ if (xt_t != NULL)
+ xtables_option_tfcall(xt_t);
+#else
+ for (tmp_xt_rm = xt_rm; tmp_xt_rm != NULL;
+ tmp_xt_rm = tmp_xt_rm->next)
+ if (tmp_xt_rm->match->final_check != NULL)
+ tmp_xt_rm->match->final_check(
+ tmp_xt_rm->match->mflags);
+
+ if (xt_t != NULL && xt_t->final_check != NULL)
+ xt_t->final_check(xt_t->tflags);
+#endif
+
+ if (table == NULL) {
table_name = "filter";
- table = connman_iptables_init(table_name);
- if (table == NULL)
- return -1;
+ table = connman_iptables_init(table_name);
+ if (table == NULL)
+ return -1;
+ }
if (delete) {
if (delete_chain == NULL)
}
if (chain) {
- if (target_name == NULL)
- return -1;
+ if (policy != NULL) {
+ printf("Changing policy of %s to %s\n", chain, policy);
- printf("Adding %s to %s (match %s)\n", target_name, chain, match_name);
+ connman_iptables_change_policy(table, chain, policy);
- connman_iptables_add_rule(table, chain, target_name, xt_t,
- match_name, xt_m);
+ goto commit;
+ }
- goto commit;
+ if (delete_rule == TRUE) {
+ printf("Deleting %s to %s (match %s)\n", target_name,
+ chain, match_name);
+
+ connman_iptables_delete_rule(table, &ip, chain,
+ target_name, xt_t, xt_m, xt_rm);
+
+ goto commit;
+ }
+
+ if (insert == TRUE) {
+ printf("Inserting %s to %s (match %s)\n", target_name,
+ chain, match_name);
+
+ connman_iptables_insert_rule(table, &ip, chain,
+ target_name, xt_t, xt_rm);
+ } else {
+ printf("Appending %s to %s (match %s)\n", target_name,
+ chain, match_name);
+
+ connman_iptables_append_rule(table, &ip, chain,
+ target_name, xt_t, xt_rm);
+ }
}
commit:
if (name != NULL) {
file->name = g_strdup(name);
- file->fd = TFR(open(file->name, O_RDWR | O_CREAT, 0644));
+ file->fd = TFR(open(file->name,
+ O_RDWR | O_CREAT | O_CLOEXEC, 0644));
if (file->fd == -1) {
fprintf(stderr, "open error %s for %s\n",
strerror(errno), file->name);
#include <config.h>
#endif
+#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
struct ifreq ifr;
int sk, err;
- sk = socket(PF_INET, SOCK_DGRAM, 0);
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return -errno;
struct ifreq ifr;
int fd, val;
- fd = open("/dev/net/tun", O_RDWR);
+ fd = open("/dev/net/tun", O_RDWR | O_CLOEXEC);
if (fd < 0) {
perror("Failed to open TUN/TAP device");
return -1;
#include <config.h>
#endif
+#define _GNU_SOURCE
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
data->user_data = user_data;
data->hidden = hidden;
- data->fd = open("/dev/tty", O_RDWR | O_NOCTTY);
+ data->fd = open("/dev/tty", O_RDWR | O_NOCTTY | O_CLOEXEC);
if (data->fd < 0)
goto error;