--- /dev/null
+From 79fe33b1a73f42592ac98c44b87dc15b52c7d791 Mon Sep 17 00:00:00 2001
+From: Zhang zhengguang <zhengguang.zhang@intel.com>
+Date: Fri, 11 Jul 2014 09:34:05 +0800
+Subject: [PATCH 01/32] Add bootstrap files
+
+Change-Id: Ia3923cb1ff35e7bfbd4e45f13dd18af15ed89f56
+---
+ bootstrap | 7 +++++++
+ bootstrap-configure | 20 ++++++++++++++++++++
+ 2 files changed, 27 insertions(+)
+ create mode 100755 bootstrap
+ create mode 100755 bootstrap-configure
+
+diff --git a/bootstrap b/bootstrap
+new file mode 100755
+index 0000000..0dd71d9
+--- /dev/null
++++ b/bootstrap
+@@ -0,0 +1,7 @@
++#!/bin/sh
++
++aclocal && \
++ autoheader && \
++ libtoolize --automake --copy --force && \
++ automake --add-missing --copy && \
++ autoconf
+diff --git a/bootstrap-configure b/bootstrap-configure
+new file mode 100755
+index 0000000..070c676
+--- /dev/null
++++ b/bootstrap-configure
+@@ -0,0 +1,20 @@
++#!/bin/sh
++
++if [ -f config.status ]; then
++ make maintainer-clean
++fi
++
++./bootstrap && \
++ ./configure --enable-maintainer-mode \
++ --enable-debug \
++ --prefix=/usr \
++ --mandir=/usr/share/man \
++ --localstatedir=/var \
++ --sysconfdir=/etc \
++ --disable-datafiles \
++ --enable-openconnect=builtin \
++ --enable-openvpn=builtin \
++ --enable-vpnc=builtin \
++ --enable-session-policy-local=builtin \
++ --enable-nmcompat \
++ --enable-polkit $*
+--
+1.8.1.4
+
--- /dev/null
+From 88ec373b61d46ef46dcab48fe14d02ab7254763c Mon Sep 17 00:00:00 2001
+From: Zhang zhengguang <zhengguang.zhang@intel.com>
+Date: Fri, 4 Jul 2014 13:45:07 +0800
+Subject: [PATCH 02/32] Add package build spec file
+
+Change-Id: Ia8c78e122998da70565700d895dbf54688e7c8b9
+---
+ packaging/connman.spec | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 97 insertions(+)
+ create mode 100644 packaging/connman.spec
+
+diff --git a/packaging/connman.spec b/packaging/connman.spec
+new file mode 100644
+index 0000000..7da9ddd
+--- /dev/null
++++ b/packaging/connman.spec
+@@ -0,0 +1,97 @@
++Name: connman
++Version: 1.26
++Release: 1
++License: GPL-2.0
++Summary: Connection Manager
++Url: http://connman.net
++Group: Network & Connectivity/Connection Management
++Source0: %{name}-%{version}.tar.gz
++BuildRequires: systemd
++BuildRequires: pkgconfig(dbus-1)
++BuildRequires: pkgconfig(glib-2.0)
++BuildRequires: pkgconfig(libiptc)
++BuildRequires: pkgconfig(xtables)
++BuildRequires: pkgconfig(gnutls)
++BuildRequires: readline-devel
++%systemd_requires
++Requires: iptables
++
++%description
++Connection Manager provides a daemon for managing Internet connections
++within embedded devices running the Linux operating system.
++
++%package test
++Summary: Test Scripts for Connection Manager
++Requires: %{name} = %{version}
++Requires: dbus-python
++Requires: pygobject
++Requires: python-xml
++
++%description test
++Scripts for testing Connman and its functionality
++
++%package devel
++Summary: Development Files for connman
++Requires: %{name} = %{version}
++
++%description devel
++Header files and development files for connman.
++
++%prep
++%setup -q
++
++%build
++CFLAGS+=" -DTIZEN_EXT"
++
++chmod +x bootstrap
++./bootstrap
++%configure \
++ --enable-threads \
++ --enable-client \
++ --enable-pacrunner \
++ --enable-wifi=builtin \
++ --enable-test \
++ --enable-loopback \
++ --enable-ethernet \
++ --with-systemdunitdir=%{_unitdir}
++
++make %{?_smp_mflags}
++
++%install
++%make_install
++
++mkdir -p %{buildroot}%{_sysconfdir}/connman
++cp src/main.conf %{buildroot}%{_sysconfdir}/connman/main.conf
++
++%install_service network.target.wants connman.service
++%install_service multi-user.target.wants connman.service
++
++%post
++systemctl daemon-reload
++systemctl restart connman.service
++
++%preun
++systemctl stop connman.service
++
++%postun
++systemctl daemon-reload
++
++%docs_package
++
++%files
++%license COPYING
++%{_sbindir}/*
++%config %{_sysconfdir}/connman/main.conf
++%config %{_sysconfdir}/dbus-1/system.d/*
++%{_unitdir}/connman.service
++%{_unitdir}/network.target.wants/connman.service
++%{_unitdir}/multi-user.target.wants/connman.service
++
++%files test
++%{_libdir}/%{name}/test/*
++
++%files devel
++%{_includedir}/connman/*.h
++%{_libdir}/pkgconfig/*.pc
++
++%changelog
+--
+1.8.1.4
+
--- /dev/null
+From cdc8865c44bb77e9b7fa664a3669f84f7305718d Mon Sep 17 00:00:00 2001
+From: Zhang zhengguang <zhengguang.zhang@intel.com>
+Date: Fri, 4 Jul 2014 14:12:08 +0800
+Subject: [PATCH 03/32] Add systemd service to manager ConnMan NTP
+
+---
+ packaging/40-connman-ntp.list | 1 +
+ packaging/connman-ntp.service | 13 +++++++++++++
+ 2 files changed, 14 insertions(+)
+ create mode 100644 packaging/40-connman-ntp.list
+ create mode 100644 packaging/connman-ntp.service
+
+diff --git a/packaging/40-connman-ntp.list b/packaging/40-connman-ntp.list
+new file mode 100644
+index 0000000..9b84282
+--- /dev/null
++++ b/packaging/40-connman-ntp.list
+@@ -0,0 +1 @@
++connman-ntp.service
+diff --git a/packaging/connman-ntp.service b/packaging/connman-ntp.service
+new file mode 100644
+index 0000000..6ca46e2
+--- /dev/null
++++ b/packaging/connman-ntp.service
+@@ -0,0 +1,13 @@
++[Unit]
++Description=Connman NTP service
++Requires=connman.service
++After=connman.service
++
++[Service]
++Type=oneshot
++ExecStart=/bin/bash -c "dbus-send --system --type=method_call --print-reply --dest=net.connman / net.connman.Clock.SetProperty string:'TimeUpdates' variant:string:'auto'"
++ExecStop=/bin/bash -c "dbus-send --system --type=method_call --print-reply --dest=net.connman / net.connman.Clock.SetProperty string:'TimeUpdates' variant:string:'manual'"
++RemainAfterExit=yes
++
++[Install]
++WantedBy=multi-user.target
+--
+1.8.1.4
+
--- /dev/null
+From 7923d6ca6ccb144a5b036b03a015a182c3622a92 Mon Sep 17 00:00:00 2001
+From: Zhang zhengguang <zhengguang.zhang@intel.com>
+Date: Fri, 4 Jul 2014 13:50:49 +0800
+Subject: [PATCH 04/32] Set manifest request domain to floor
+
+---
+ packaging/connman.manifest | 5 +++++
+ packaging/connman.spec | 5 +++++
+ 2 files changed, 10 insertions(+)
+ create mode 100644 packaging/connman.manifest
+
+diff --git a/packaging/connman.manifest b/packaging/connman.manifest
+new file mode 100644
+index 0000000..017d22d
+--- /dev/null
++++ b/packaging/connman.manifest
+@@ -0,0 +1,5 @@
++<manifest>
++ <request>
++ <domain name="_"/>
++ </request>
++</manifest>
+diff --git a/packaging/connman.spec b/packaging/connman.spec
+index 7da9ddd..c43deaa 100644
+--- a/packaging/connman.spec
++++ b/packaging/connman.spec
+@@ -6,6 +6,7 @@ Summary: Connection Manager
+ Url: http://connman.net
+ Group: Network & Connectivity/Connection Management
+ Source0: %{name}-%{version}.tar.gz
++Source1001: connman.manifest
+ BuildRequires: systemd
+ BuildRequires: pkgconfig(dbus-1)
+ BuildRequires: pkgconfig(glib-2.0)
+@@ -39,6 +40,7 @@ Header files and development files for connman.
+
+ %prep
+ %setup -q
++cp %{SOURCE1001} .
+
+ %build
+ CFLAGS+=" -DTIZEN_EXT"
+@@ -79,6 +81,7 @@ systemctl daemon-reload
+ %docs_package
+
+ %files
++%manifest %{name}.manifest
+ %license COPYING
+ %{_sbindir}/*
+ %config %{_sysconfdir}/connman/main.conf
+@@ -88,9 +91,11 @@ systemctl daemon-reload
+ %{_unitdir}/multi-user.target.wants/connman.service
+
+ %files test
++%manifest %{name}.manifest
+ %{_libdir}/%{name}/test/*
+
+ %files devel
++%manifest %{name}.manifest
+ %{_includedir}/connman/*.h
+ %{_libdir}/pkgconfig/*.pc
+
+--
+1.8.1.4
+
--- /dev/null
+From 85053773dfe482c81ca1ac87dc6baf2ff6b29df0 Mon Sep 17 00:00:00 2001
+From: Zhang zhengguang <zhengguang.zhang@intel.com>
+Date: Fri, 4 Jul 2014 14:49:18 +0800
+Subject: [PATCH 05/32] Set ConnMan default settings in config files
+
+---
+ src/connman.service.in | 3 ++-
+ src/main.conf | 4 ++++
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/src/connman.service.in b/src/connman.service.in
+index 7b6195e..67d051d 100644
+--- a/src/connman.service.in
++++ b/src/connman.service.in
+@@ -5,10 +5,11 @@ After=dbus.socket
+ Before=remote-fs.target
+
+ [Service]
++EnvironmentFile=-/etc/sysconfig/connman
+ Type=dbus
+ BusName=net.connman
+ Restart=on-failure
+-ExecStart=@prefix@/sbin/connmand -n
++ExecStart=@prefix@/sbin/connmand -n $OPTIONS
+ StandardOutput=null
+
+ [Install]
+diff --git a/src/main.conf b/src/main.conf
+index 93c7a50..c979553 100644
+--- a/src/main.conf
++++ b/src/main.conf
+@@ -19,6 +19,7 @@
+ # the scan list is empty. In that case, a simple backoff
+ # mechanism starting from 10s up to 5 minutes will run.
+ # BackgroundScanning = true
++BackgroundScanning = false
+
+ # List of Fallback timeservers separated by ",".
+ # These timeservers are used for NTP sync when there are
+@@ -26,6 +27,7 @@
+ # These can contain mixed combination of fully qualified
+ # domain names, IPv4 and IPv6 addresses.
+ # FallbackTimeservers =
++FallbackTimeservers = pool.ntp.org
+
+ # List of fallback nameservers separated by "," used if no
+ # nameservers are otherwise provided by the service. The
+@@ -52,6 +54,7 @@
+ # the default route when compared to either a non-preferred
+ # type or a preferred type further down in the list.
+ # PreferredTechnologies =
++PreferredTechnologies = ethernet,wifi
+
+ # List of blacklisted network interfaces separated by ",".
+ # Found interfaces will be compared to the list and will
+@@ -59,6 +62,7 @@
+ # match any of the list entries. Default value is
+ # vmnet,vboxnet,virbr,ifb.
+ # NetworkInterfaceBlacklist = vmnet,vboxnet,virbr,ifb
++NetworkInterfaceBlacklist = vmnet,vboxnet,virbr
+
+ # Allow connman to change the system hostname. This can
+ # happen for example if we receive DHCP hostname option.
+--
+1.8.1.4
+
--- /dev/null
+From 346988b0c78109cce94fec48f8eeb16719426fa3 Mon Sep 17 00:00:00 2001
+From: Zhang zhengguang <zhengguang.zhang@intel.com>
+Date: Fri, 4 Jul 2014 14:33:55 +0800
+Subject: [PATCH 06/32] Enable ConnMan NTP configurable in spec file
+
+---
+ packaging/connman.spec | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+diff --git a/packaging/connman.spec b/packaging/connman.spec
+index c43deaa..5438f4c 100644
+--- a/packaging/connman.spec
++++ b/packaging/connman.spec
+@@ -1,3 +1,5 @@
++%bcond_with connman_ntp
++
+ Name: connman
+ Version: 1.26
+ Release: 1
+@@ -6,6 +8,8 @@ Summary: Connection Manager
+ Url: http://connman.net
+ Group: Network & Connectivity/Connection Management
+ Source0: %{name}-%{version}.tar.gz
++Source10: 40-connman-ntp.list
++Source11: connman-ntp.service
+ Source1001: connman.manifest
+ BuildRequires: systemd
+ BuildRequires: pkgconfig(dbus-1)
+@@ -62,6 +66,14 @@ make %{?_smp_mflags}
+ %install
+ %make_install
+
++%if %{with connman_ntp}
++mkdir -p %{buildroot}/usr/lib/systemd/ntp-units.d
++install -m644 %{SOURCE10} %{buildroot}/usr/lib/systemd/ntp-units.d
++install -m644 %{SOURCE11} %{buildroot}%{_unitdir}
++%install_service network.target.wants connman-ntp.service
++%install_service multi-user.target.wants connman-ntp.service
++%endif
++
+ mkdir -p %{buildroot}%{_sysconfdir}/connman
+ cp src/main.conf %{buildroot}%{_sysconfdir}/connman/main.conf
+
+@@ -89,6 +101,13 @@ systemctl daemon-reload
+ %{_unitdir}/connman.service
+ %{_unitdir}/network.target.wants/connman.service
+ %{_unitdir}/multi-user.target.wants/connman.service
++%if %{with connman_ntp}
++%dir /usr/lib/systemd/ntp-units.d
++%{_unitdir}/connman-ntp.service
++%{_unitdir}/multi-user.target.wants/connman-ntp.service
++%{_unitdir}/network.target.wants/connman-ntp.service
++/usr/lib/systemd/ntp-units.d/40-connman-ntp.list
++%endif
+
+ %files test
+ %manifest %{name}.manifest
+--
+1.8.1.4
+
--- /dev/null
+From 509d88ad3a5d229a5df0e7f349ac70e02148396e Mon Sep 17 00:00:00 2001
+From: Zhang zhengguang <zhengguang.zhang@intel.com>
+Date: Fri, 4 Jul 2014 14:37:58 +0800
+Subject: [PATCH 07/32] Enable ConnMan VPND/OpenVPN/OpenConnect configurable in
+ spec file
+
+---
+ packaging/connman.spec | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 88 insertions(+)
+
+diff --git a/packaging/connman.spec b/packaging/connman.spec
+index 5438f4c..edc1d53 100644
+--- a/packaging/connman.spec
++++ b/packaging/connman.spec
+@@ -1,3 +1,6 @@
++%bcond_with connman_openconnect
++%bcond_with connman_openvpn
++%bcond_with connman_vpnd
+ %bcond_with connman_ntp
+
+ Name: connman
+@@ -17,6 +20,12 @@ BuildRequires: pkgconfig(glib-2.0)
+ BuildRequires: pkgconfig(libiptc)
+ BuildRequires: pkgconfig(xtables)
+ BuildRequires: pkgconfig(gnutls)
++%if %{with connman_openconnect}
++BuildRequires: openconnect
++%endif
++%if %{with connman_openvpn}
++BuildRequires: openvpn
++%endif
+ BuildRequires: readline-devel
+ %systemd_requires
+ Requires: iptables
+@@ -25,6 +34,36 @@ Requires: iptables
+ Connection Manager provides a daemon for managing Internet connections
+ within embedded devices running the Linux operating system.
+
++%if %{with connman_openconnect}
++%package plugin-openconnect
++Summary: Openconnect Support for Connman
++Requires: %{name} = %{version}
++Requires: openconnect
++
++%description plugin-openconnect
++Openconnect Support for Connman.
++%endif
++
++%if %{with connman_openvpn}
++%package plugin-openvpn
++Summary: Openvpn Support for Connman
++Requires: %{name} = %{version}
++Requires: openvpn
++
++%description plugin-openvpn
++OpenVPN support for Connman.
++%endif
++
++%if %{with connman_vpnd}
++%package connman-vpnd
++Summary: VPN Support for Connman
++BuildRequires: %{name} = %{version}
++Requires: %{name} = %{version}
++
++%description connman-vpnd
++Provides VPN support for Connman
++%endif
++
+ %package test
+ Summary: Test Scripts for Connection Manager
+ Requires: %{name} = %{version}
+@@ -56,6 +95,12 @@ chmod +x bootstrap
+ --enable-client \
+ --enable-pacrunner \
+ --enable-wifi=builtin \
++%if %{with connman_openconnect}
++ --enable-openconnect \
++%endif
++%if %{with connman_openvpn}
++ --enable-openvpn \
++%endif
+ --enable-test \
+ --enable-loopback \
+ --enable-ethernet \
+@@ -80,12 +125,23 @@ cp src/main.conf %{buildroot}%{_sysconfdir}/connman/main.conf
+ %install_service network.target.wants connman.service
+ %install_service multi-user.target.wants connman.service
+
++%if %{with connman_vpnd}
++%install_service network.target.wants connman-vpn.service
++%install_service multi-user.target.wants connman-vpn.service
++%endif
++
+ %post
+ systemctl daemon-reload
+ systemctl restart connman.service
++%if %{with connman_vpnd}
++systemctl restart connman-vpn.service
++%endif
+
+ %preun
+ systemctl stop connman.service
++%if %{with connman_vpnd}
++systemctl stop connman-vpn.service
++%endif
+
+ %postun
+ systemctl daemon-reload
+@@ -118,4 +174,36 @@ systemctl daemon-reload
+ %{_includedir}/connman/*.h
+ %{_libdir}/pkgconfig/*.pc
+
++%if %{with connman_openconnect}
++%files plugin-openconnect
++%manifest %{name}.manifest
++%{_unitdir}/connman-vpn.service
++%{_libdir}/connman/plugins-vpn/openconnect.so
++%{_libdir}/connman/scripts/openconnect-script
++%{_datadir}/dbus-1/system-services/net.connman.vpn.service
++%endif
++
++%if %{with connman_openvpn}
++%files plugin-openvpn
++%manifest %{name}.manifest
++%{_unitdir}/connman-vpn.service
++%{_libdir}/%{name}/plugins-vpn/openvpn.so
++%{_libdir}/%{name}/scripts/openvpn-script
++%{_datadir}/dbus-1/system-services/net.connman.vpn.service
++%endif
++
++%if %{with connman_vpnd}
++%files connman-vpnd
++%manifest %{name}.manifest
++%{_sbindir}/connman-vpnd
++%{_unitdir}/connman-vpn.service
++%{_unitdir}/network.target.wants/connman-vpn.service
++%{_unitdir}/multi-user.target.wants/connman-vpn.service
++%dir %{_libdir}/%{name}
++%dir %{_libdir}/%{name}/scripts
++%dir %{_libdir}/%{name}/plugins-vpn
++%config %{_sysconfdir}/dbus-1/system.d/connman-vpn-dbus.conf
++%{_datadir}/dbus-1/system-services/net.connman.vpn.service
++%endif
++
+ %changelog
+--
+1.8.1.4
+
--- /dev/null
+From 8b828d775adb413be2e02a5377d83af9ecb979ed Mon Sep 17 00:00:00 2001
+From: Zhang zhengguang <zhengguang.zhang@intel.com>
+Date: Tue, 19 Aug 2014 09:41:09 +0800
+Subject: [PATCH 08/32] Add connmanctl to the built rpm
+
+Change-Id: I84fb13ea9224985ad9e15b5c3c5f616bcf7431a4
+---
+ Makefile.am | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index a574170..76863cf 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -237,7 +237,7 @@ script_LTLIBRARIES =
+ include Makefile.plugins
+
+ if CLIENT
+-noinst_PROGRAMS += client/connmanctl
++sbin_PROGRAMS += client/connmanctl
+
+ noinst_MANUAL_PAGES = doc/connmanctl.1
+
+--
+1.8.1.4
+
--- /dev/null
+From 98894f533f23fe532a4449ddaafaa69d39441980 Mon Sep 17 00:00:00 2001
+From: Arron Wang <arron.wang@intel.com>
+Date: Mon, 24 Sep 2012 14:18:07 +0800
+Subject: [PATCH 09/32] Tizen: Export more wifi info in ConnMan network API
+
+Network client requires additional wifi specific info
+
+Export the BSSID property
+Export the MaxRate property
+Export the detailed info for encryption mode(mixed,aes,tkip,wep,none)
+
+Export the connman_network get/set method for bssid, maxrate,
+encryption_mode property
+
+Change-Id: Ic5744978282e49cb2f70165aaadc7822dc718dfb
+---
+ gsupplicant/gsupplicant.h | 10 +++++++
+ gsupplicant/supplicant.c | 49 +++++++++++++++++++++++++++++++
+ include/network.h | 17 +++++++++++
+ plugins/wifi.c | 25 +++++++++++++++-
+ src/network.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 173 insertions(+), 1 deletion(-)
+
+diff --git a/gsupplicant/gsupplicant.h b/gsupplicant/gsupplicant.h
+index e49aaa6..27826dc 100644
+--- a/gsupplicant/gsupplicant.h
++++ b/gsupplicant/gsupplicant.h
+@@ -336,6 +336,16 @@ GSupplicantInterface *g_supplicant_peer_get_group_interface(GSupplicantPeer *pee
+ bool g_supplicant_peer_is_client(GSupplicantPeer *peer);
+ bool g_supplicant_peer_has_requested_connection(GSupplicantPeer *peer);
+
++#if defined TIZEN_EXT
++/*
++* Description: Network client requires additional wifi specific info
++*/
++const unsigned char *g_supplicant_network_get_bssid(
++ GSupplicantNetwork *network);
++unsigned int g_supplicant_network_get_maxrate(GSupplicantNetwork *network);
++const char *g_supplicant_network_get_enc_mode(GSupplicantNetwork *network);
++#endif
++
+ struct _GSupplicantCallbacks {
+ void (*system_ready) (void);
+ void (*system_killed) (void);
+diff --git a/gsupplicant/supplicant.c b/gsupplicant/supplicant.c
+index 909a617..d2e4a64 100644
+--- a/gsupplicant/supplicant.c
++++ b/gsupplicant/supplicant.c
+@@ -1169,6 +1169,55 @@ bool g_supplicant_peer_has_requested_connection(GSupplicantPeer *peer)
+ return peer->connection_requested;
+ }
+
++#if defined TIZEN_EXT
++/*
++ * Description: Network client requires additional wifi specific info
++ */
++const unsigned char *g_supplicant_network_get_bssid(GSupplicantNetwork *network)
++{
++ if (network == NULL || network->best_bss == NULL)
++ return NULL;
++
++ return (const unsigned char *)network->best_bss->bssid;
++}
++
++unsigned int g_supplicant_network_get_maxrate(GSupplicantNetwork *network)
++{
++ if (network == NULL || network->best_bss == NULL)
++ return 0;
++
++ return network->best_bss->maxrate;
++}
++
++const char *g_supplicant_network_get_enc_mode(GSupplicantNetwork *network)
++{
++ if (network == NULL || network->best_bss == NULL)
++ return NULL;
++
++ if (network->best_bss->security == G_SUPPLICANT_SECURITY_PSK ||
++ network->best_bss->security == G_SUPPLICANT_SECURITY_IEEE8021X) {
++ unsigned int pairwise;
++
++ pairwise = network->best_bss->rsn_pairwise |
++ network->best_bss->wpa_pairwise;
++
++ if ((pairwise & G_SUPPLICANT_PAIRWISE_CCMP) &&
++ (pairwise & G_SUPPLICANT_PAIRWISE_TKIP))
++ return "mixed";
++ else if (pairwise & G_SUPPLICANT_PAIRWISE_CCMP)
++ return "aes";
++ else if (pairwise & G_SUPPLICANT_PAIRWISE_TKIP)
++ return "tkip";
++
++ } else if (network->best_bss->security == G_SUPPLICANT_SECURITY_WEP)
++ return "wep";
++ else if (network->best_bss->security == G_SUPPLICANT_SECURITY_NONE)
++ return "none";
++
++ return NULL;
++}
++#endif
++
+ static void merge_network(GSupplicantNetwork *network)
+ {
+ GString *str;
+diff --git a/include/network.h b/include/network.h
+index d772699..180f2a2 100644
+--- a/include/network.h
++++ b/include/network.h
+@@ -116,6 +116,23 @@ int connman_network_set_nameservers(struct connman_network *network,
+ const char *nameservers);
+ int connman_network_set_domain(struct connman_network *network,
+ const char *domain);
++#if defined TIZEN_EXT
++/*
++ * Description: Network client requires additional wifi specific info
++ */
++int connman_network_set_bssid(struct connman_network *network,
++ const unsigned char *bssid);
++unsigned char *connman_network_get_bssid(struct connman_network *network);
++
++int connman_network_set_maxrate(struct connman_network *network,
++ unsigned int maxrate);
++unsigned int connman_network_get_maxrate(struct connman_network *network);
++
++int connman_network_set_enc_mode(struct connman_network *network,
++ const char *encryption_mode);
++const char *connman_network_get_enc_mode(struct connman_network *network);
++#endif
++
+ int connman_network_set_name(struct connman_network *network,
+ const char *name);
+ int connman_network_set_strength(struct connman_network *network,
+diff --git a/plugins/wifi.c b/plugins/wifi.c
+index 5f2ebf1..69a0e23 100644
+--- a/plugins/wifi.c
++++ b/plugins/wifi.c
+@@ -2602,7 +2602,14 @@ static void network_added(GSupplicantNetwork *supplicant_network)
+
+ 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_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);
+
+@@ -2658,6 +2665,12 @@ static void network_changed(GSupplicantNetwork *network, const char *property)
+ const char *name, *identifier;
+ struct connman_network *connman_network;
+
++#if defined TIZEN_EXT
++ const unsigned char *bssid;
++ unsigned int maxrate;
++ uint16_t frequency;
++#endif
++
+ interface = g_supplicant_network_get_interface(network);
+ wifi = g_supplicant_interface_get_data(interface);
+ identifier = g_supplicant_network_get_identifier(network);
+@@ -2677,6 +2690,16 @@ static void network_changed(GSupplicantNetwork *network, const char *property)
+ calculate_strength(network));
+ connman_network_update(connman_network);
+ }
++
++#if defined TIZEN_EXT
++ bssid = g_supplicant_network_get_bssid(network);
++ maxrate = g_supplicant_network_get_maxrate(network);
++ frequency = g_supplicant_network_get_frequency(network);
++
++ connman_network_set_bssid(connman_network, bssid);
++ connman_network_set_maxrate(connman_network, maxrate);
++ connman_network_set_frequency(connman_network, frequency);
++#endif
+ }
+
+ static void apply_peer_services(GSupplicantPeer *peer,
+diff --git a/src/network.c b/src/network.c
+index b388995..c40a079 100644
+--- a/src/network.c
++++ b/src/network.c
+@@ -41,6 +41,11 @@
+ */
+ #define RS_REFRESH_TIMEOUT 3
+
++#if defined TIZEN_EXT
++#define WIFI_ENCYPTION_MODE_LEN_MAX 6
++#define WIFI_BSSID_LEN_MAX 6
++#endif
++
+ static GSList *network_list = NULL;
+ static GSList *driver_list = NULL;
+
+@@ -87,6 +92,11 @@ struct connman_network {
+ bool wps;
+ bool use_wps;
+ char *pin_wps;
++#if defined TIZEN_EXT
++ char encryption_mode[WIFI_ENCYPTION_MODE_LEN_MAX];
++ unsigned char bssid[WIFI_BSSID_LEN_MAX];
++ unsigned int maxrate;
++#endif
+ } wifi;
+
+ };
+@@ -1737,6 +1747,69 @@ int connman_network_set_ipaddress(struct connman_network *network,
+ return 0;
+ }
+
++#if defined TIZEN_EXT
++/*
++ * Description: Network client requires additional wifi specific info
++ */
++int connman_network_set_bssid(struct connman_network *network,
++ const unsigned char *bssid)
++{
++ int i = 0;
++
++ if (bssid == NULL)
++ return -EINVAL;
++
++ DBG("network %p bssid %02x:%02x:%02x:%02x:%02x:%02x", network,
++ bssid[0], bssid[1], bssid[2],
++ bssid[3], bssid[4], bssid[5]);
++
++ for (;i < WIFI_BSSID_LEN_MAX;i++)
++ network->wifi.bssid[i] = bssid[i];
++
++ return 0;
++}
++
++unsigned char *connman_network_get_bssid(struct connman_network *network)
++{
++ return (unsigned char *)network->wifi.bssid;
++}
++
++int connman_network_set_maxrate(struct connman_network *network,
++ unsigned int maxrate)
++{
++ DBG("network %p maxrate %d", network, maxrate);
++
++ network->wifi.maxrate = maxrate;
++
++ return 0;
++}
++
++unsigned int connman_network_get_maxrate(struct connman_network *network)
++{
++ return network->wifi.maxrate;
++}
++
++int connman_network_set_enc_mode(struct connman_network *network,
++ const char *encryption_mode)
++{
++ if (encryption_mode == NULL)
++ return -EINVAL;
++
++ DBG("network %p encryption mode %s", network, encryption_mode);
++
++ g_strlcpy(network->wifi.encryption_mode, encryption_mode,
++ WIFI_ENCYPTION_MODE_LEN_MAX);
++
++ return 0;
++}
++
++const char *connman_network_get_enc_mode(struct connman_network *network)
++{
++ return (const char *)network->wifi.encryption_mode;
++}
++
++#endif
++
+ int connman_network_set_nameservers(struct connman_network *network,
+ const char *nameservers)
+ {
+--
+1.8.1.4
+
--- /dev/null
+From d9c8d2e9c9b3d0b7c8c884e74b124895a627d148 Mon Sep 17 00:00:00 2001
+From: Arron Wang <arron.wang@intel.com>
+Date: Mon, 24 Sep 2012 14:42:02 +0800
+Subject: [PATCH 10/32] Tizen: Append extra wifi service property
+
+Append wifi property bssid, maxrate, frequency, encryptionmode to wifi
+service
+
+Change-Id: I1d5987334ab288fc04ff931fda5108f4afe864f0
+---
+ doc/service-api.txt | 26 ++++++++++++++++++++++++++
+ src/service.c | 43 +++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 69 insertions(+)
+
+diff --git a/doc/service-api.txt b/doc/service-api.txt
+index c9dd7e2..74c8345 100644
+--- a/doc/service-api.txt
++++ b/doc/service-api.txt
+@@ -191,6 +191,32 @@ Properties string State [readonly]
+ This property might be only present for WiFi
+ services.
+
++ string BSSID [readonly]
++
++ If the service type is WiFi, then this property
++ indicates the BSSID of the service.
++
++ uint32 MaxRate [readonly]
++
++ If the service type is WiFi, then this property
++ indicates the Maximum speed(bps) of the service.
++
++ uint16 Frequency [readonly]
++
++ If the service type is WiFi, then this property
++ indicates the frequency band(MHz) of the service.
++
++ string EncryptionMode [readonly]
++
++ If the service type is WiFi, then this property
++ indicates the key encryption mode.
++
++ Possible values are "none", "wep", "tkip", "aes"
++ and "mixed".
++
++ This property might be only present for WiFi
++ services.
++
+ uint8 Strength [readonly]
+
+ Indicates the signal strength of the service. This
+diff --git a/src/service.c b/src/service.c
+index 87a2f2c..d3b219f 100644
+--- a/src/service.c
++++ b/src/service.c
+@@ -39,6 +39,10 @@
+
+ #define CONNECT_TIMEOUT 120
+
++#if defined TIZEN_EXT
++#define WIFI_BSSID_STR_LEN 18
++#endif
++
+ static DBusConnection *connection = NULL;
+
+ static GList *service_list = NULL;
+@@ -2252,6 +2256,37 @@ int __connman_service_iterate_services(service_iterate_cb cb, void *user_data)
+ return 0;
+ }
+
++#if defined TIZEN_EXT
++static void append_wifi_ext_info(DBusMessageIter *dict,
++ struct connman_network *network)
++{
++ char bssid_buff[WIFI_BSSID_STR_LEN] = {0,};
++ char *bssid_str = bssid_buff;
++ unsigned char *bssid;
++ unsigned int maxrate;
++ uint16_t frequency;
++ const char *enc_mode;
++
++ bssid = connman_network_get_bssid(network);
++ maxrate = connman_network_get_maxrate(network);
++ frequency = connman_network_get_frequency(network);
++ enc_mode = connman_network_get_enc_mode(network);
++
++ snprintf(bssid_str, WIFI_BSSID_STR_LEN, "%02x:%02x:%02x:%02x:%02x:%02x",
++ bssid[0], bssid[1], bssid[2],
++ bssid[3], bssid[4], bssid[5]);
++
++ connman_dbus_dict_append_basic(dict, "BSSID",
++ DBUS_TYPE_STRING, &bssid_str);
++ connman_dbus_dict_append_basic(dict, "MaxRate",
++ DBUS_TYPE_UINT32, &maxrate);
++ connman_dbus_dict_append_basic(dict, "Frequency",
++ DBUS_TYPE_UINT16, &frequency);
++ connman_dbus_dict_append_basic(dict, "EncryptionMode",
++ DBUS_TYPE_STRING, &enc_mode);
++}
++#endif
++
+ static void append_properties(DBusMessageIter *dict, dbus_bool_t limited,
+ struct connman_service *service)
+ {
+@@ -2317,6 +2352,14 @@ static void append_properties(DBusMessageIter *dict, dbus_bool_t limited,
+ append_ethernet, service);
+ break;
+ case CONNMAN_SERVICE_TYPE_WIFI:
++#if defined TIZEN_EXT
++ if (service->network != NULL)
++ append_wifi_ext_info(dict, service->network);
++
++ connman_dbus_dict_append_dict(dict, "Ethernet",
++ append_ethernet, service);
++ break;
++#endif
+ case CONNMAN_SERVICE_TYPE_ETHERNET:
+ case CONNMAN_SERVICE_TYPE_BLUETOOTH:
+ case CONNMAN_SERVICE_TYPE_GADGET:
+--
+1.8.1.4
+
--- /dev/null
+From 2bbc2b500806c808f54b459615ea4daddef1cf4e Mon Sep 17 00:00:00 2001
+From: Arron Wang <arron.wang@intel.com>
+Date: Tue, 9 Oct 2012 16:20:45 +0800
+Subject: [PATCH 11/32] Tizen: Export network proxy API for telephony plugin
+
+Telephony plug-in requires manual PROXY setting function
+Telephony stack provides proxy address (3G profile).
+
+Change-Id: Iaa02f59465a687961c303667ee09051b419507d2
+---
+ include/network.h | 3 +++
+ src/connman.h | 4 ++++
+ src/network.c | 18 ++++++++++++++++++
+ src/service.c | 16 ++++++++++++++++
+ 4 files changed, 41 insertions(+)
+
+diff --git a/include/network.h b/include/network.h
+index 180f2a2..e433c22 100644
+--- a/include/network.h
++++ b/include/network.h
+@@ -131,6 +131,9 @@ unsigned int connman_network_get_maxrate(struct connman_network *network);
+ int connman_network_set_enc_mode(struct connman_network *network,
+ const char *encryption_mode);
+ const char *connman_network_get_enc_mode(struct connman_network *network);
++
++int connman_network_set_proxy(struct connman_network *network,
++ const char *proxies);
+ #endif
+
+ int connman_network_set_name(struct connman_network *network,
+diff --git a/src/connman.h b/src/connman.h
+index da01215..4d78eab 100644
+--- a/src/connman.h
++++ b/src/connman.h
+@@ -756,6 +756,10 @@ void __connman_service_timeserver_changed(struct connman_service *service,
+ GSList *ts_list);
+ void __connman_service_set_pac(struct connman_service *service,
+ const char *pac);
++#if defined TIZEN_EXT
++void __connman_service_set_proxy(struct connman_service *service,
++ const char *proxies);
++#endif
+ bool __connman_service_is_hidden(struct connman_service *service);
+ bool __connman_service_is_split_routing(struct connman_service *service);
+ bool __connman_service_index_is_split_routing(int index);
+diff --git a/src/network.c b/src/network.c
+index c40a079..8c9fdcb 100644
+--- a/src/network.c
++++ b/src/network.c
+@@ -1808,6 +1808,24 @@ const char *connman_network_get_enc_mode(struct connman_network *network)
+ return (const char *)network->wifi.encryption_mode;
+ }
+
++int connman_network_set_proxy(struct connman_network *network,
++ const char *proxies)
++{
++ struct connman_service *service;
++
++ DBG("network %p proxies %s", network, proxies);
++
++ service = connman_service_lookup_from_network(network);
++ if (service == NULL)
++ return -EINVAL;
++
++ __connman_service_set_proxy(service, proxies);
++
++ connman_service_set_proxy_method(service,
++ CONNMAN_SERVICE_PROXY_METHOD_MANUAL);
++
++ return 0;
++}
+ #endif
+
+ int connman_network_set_nameservers(struct connman_network *network,
+diff --git a/src/service.c b/src/service.c
+index d3b219f..8d3c619 100644
+--- a/src/service.c
++++ b/src/service.c
+@@ -2806,6 +2806,22 @@ void __connman_service_set_pac(struct connman_service *service,
+ proxy_changed(service);
+ }
+
++#if defined TIZEN_EXT
++void __connman_service_set_proxy(struct connman_service *service,
++ const char *proxies)
++{
++ char **proxies_array = NULL;
++
++ g_strfreev(service->proxies);
++ service->proxies = NULL;
++
++ if (proxies != NULL)
++ proxies_array = g_strsplit(proxies, " ", 0);
++
++ service->proxies = proxies_array;
++}
++#endif
++
+ void __connman_service_set_identity(struct connman_service *service,
+ const char *identity)
+ {
+--
+1.8.1.4
+
--- /dev/null
+From f5af9712213cb0da9e5066e0a2fcf8fbedccc075 Mon Sep 17 00:00:00 2001
+From: Arron Wang <arron.wang@intel.com>
+Date: Wed, 10 Oct 2012 09:56:13 +0800
+Subject: [PATCH 12/32] Tizen: Integrate telephony plugin
+
+Change-Id: Ia178f5de981501296573bf3f48e329d5a1355af6
+---
+ Makefile.plugins | 12 +
+ configure.ac | 6 +
+ packaging/connman.spec | 2 +
+ plugins/telephony.c | 1757 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 1777 insertions(+)
+ create mode 100644 plugins/telephony.c
+
+diff --git a/Makefile.plugins b/Makefile.plugins
+index e90ad19..83ad8fb 100644
+--- a/Makefile.plugins
++++ b/Makefile.plugins
+@@ -55,6 +55,18 @@ builtin_modules += dundee
+ builtin_sources += plugins/dundee.c
+ endif
+
++if TELEPHONY
++if TELEPHONY_BUILTIN
++builtin_modules += telephony
++builtin_sources += plugins/telephony.c
++else
++plugin_LTLIBRARIES += plugins/telephony.la
++plugin_objects += $(plugins_telephony_la_OBJECTS)
++plugins_telephony_la_CFLAGS = $(plugin_cflags)
++plugins_telephony_la_LDFLAGS = $(plugin_ldflags)
++endif
++endif
++
+ if VPN
+ builtin_modules += vpn
+ builtin_sources += plugins/vpn.c
+diff --git a/configure.ac b/configure.ac
+index 6f35c78..dee2dcb 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -61,6 +61,12 @@ AC_ARG_ENABLE(hh2serial-gps,
+ AM_CONDITIONAL(HH2SERIAL_GPS, test "${enable_hh2serial_gps}" != "no")
+ AM_CONDITIONAL(HH2SERIAL_GPS_BUILTIN, test "${enable_hh2serial_gps}" = "builtin")
+
++AC_ARG_ENABLE(telephony,
++ AC_HELP_STRING([--enable-telephony], [enable Telephony support]),
++ [enable_telephony=${enableval}], [enable_telephony="yes"])
++AM_CONDITIONAL(TELEPHONY, test "${enable_telephony}" != "no")
++AM_CONDITIONAL(TELEPHONY_BUILTIN, test "${enable_telephony}" = "builtin")
++
+ AC_ARG_WITH(openconnect, AC_HELP_STRING([--with-openconnect=PROGRAM],
+ [specify location of openconnect binary]), [path_openconnect=${withval}])
+
+diff --git a/packaging/connman.spec b/packaging/connman.spec
+index edc1d53..f4faf92 100644
+--- a/packaging/connman.spec
++++ b/packaging/connman.spec
+@@ -152,6 +152,8 @@ systemctl daemon-reload
+ %manifest %{name}.manifest
+ %license COPYING
+ %{_sbindir}/*
++%{_libdir}/connman/plugins/*.so
++%{_datadir}/man/*
+ %config %{_sysconfdir}/connman/main.conf
+ %config %{_sysconfdir}/dbus-1/system.d/*
+ %{_unitdir}/connman.service
+diff --git a/plugins/telephony.c b/plugins/telephony.c
+new file mode 100644
+index 0000000..63e7f6e
+--- /dev/null
++++ b/plugins/telephony.c
+@@ -0,0 +1,1757 @@
++/*
++ *
++ * Connection Manager
++ *
++ * Copyright (C) 2011-2013 Samsung Electronics Co., Ltd. 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 <gdbus.h>
++#include <string.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/log.h>
++
++#define PS_DBUS_SERVICE "com.tcore.ps"
++
++#define PS_MASTER_INTERFACE PS_DBUS_SERVICE ".master"
++#define PS_MODEM_INTERFACE PS_DBUS_SERVICE ".modem"
++#define PS_SERVICE_INTERFACE PS_DBUS_SERVICE ".service"
++#define PS_CONTEXT_INTERFACE PS_DBUS_SERVICE ".context"
++
++/* methods */
++#define GET_MODEMS "GetModems"
++#define GET_SERVICES "GetServices"
++#define GET_CONTEXTS "GetContexts"
++#define ACTIVATE_CONTEXT "Activate"
++#define DEACTIVATE_CONTEXT "Deactivate"
++#define GET_PROPERTIES "GetProperties"
++#define SET_PROPERTY "SetProperties"
++
++/* signals */
++#define MODEM_ADDED "ModemAdded"
++#define MODEM_REMOVED "ModemRemoved"
++#define SERVICE_ADDED "ServiceAdded"
++#define SERVICE_REMOVED "ServiceRemoved"
++#define CONTEXT_ADDED "ContextAdded"
++#define CONTEXT_REMOVED "ContextRemoved"
++#define PROPERTY_CHANGED "PropertyChanged"
++
++#define TIMEOUT 40000
++
++#define STRING2BOOL(a) ((g_str_equal(a, "TRUE")) ? (TRUE):(FALSE))
++
++static DBusConnection *connection;
++static GHashTable *modem_hash;
++static GHashTable *service_hash;
++static GHashTable *network_hash;
++
++struct telephony_service {
++ char *path;
++
++ gpointer p_modem;
++ char *act;
++ gboolean roaming; /* global roaming state */
++ gboolean ps_attached; /* packet service is available */
++};
++
++struct telephony_modem {
++ char *path;
++
++ char *operator;
++ gboolean powered;
++ gboolean sim_init;
++ gboolean flight_mode;
++ gboolean data_allowed;
++ gboolean roaming_allowed;
++
++ struct connman_device *device;
++ struct telephony_service *s_service;
++};
++
++struct telephony_network {
++ char *path;
++ struct connman_network *network;
++
++ enum connman_ipconfig_method ipv4_method;
++ struct connman_ipaddress *ipv4_address;
++
++ enum connman_ipconfig_method ipv6_method;
++ struct connman_ipaddress *ipv6_address;
++};
++
++/* function prototype */
++static void telephony_connect(DBusConnection *connection, void *user_data);
++static void telephony_disconnect(DBusConnection *connection, void *user_data);
++static void __remove_modem(gpointer data);
++static void __remove_service(gpointer data);
++static void __remove_network(gpointer data);
++
++static int __modem_probe(struct connman_device *device);
++static void __modem_remove(struct connman_device *device);
++static int __modem_enable(struct connman_device *device);
++static int __modem_disable(struct connman_device *device);
++
++static int __network_probe(struct connman_network *network);
++static void __network_remove(struct connman_network *network);
++static int __network_connect(struct connman_network *network);
++static int __network_disconnect(struct connman_network *network);
++
++
++/* dbus request and reply */
++static int __dbus_request(const char *path, const char *interface,
++ const char *method,
++ DBusPendingCallNotifyFunction notify, void *user_data,
++ DBusFreeFunction free_function, int type, ...);
++
++static int __request_get_modems(void);
++static void __response_get_modems(DBusPendingCall *call, void *user_data);
++static int __request_get_services(const char *path);
++static void __response_get_services(DBusPendingCall *call, void *user_data);
++static int __request_get_contexts(struct telephony_modem *modem);
++static void __response_get_contexts(DBusPendingCall *call, void *user_data);
++static int __request_network_activate(struct connman_network *network);
++static void __response_network_activate(DBusPendingCall *call, void *user_data);
++static int __request_network_deactivate(struct connman_network *network);
++
++/* telephony internal function */
++static void __add_modem(const char *path, DBusMessageIter *prop);
++static void __add_service(struct telephony_modem *modem,
++ const char *service_path, DBusMessageIter *prop);
++static void __add_connman_device(const char *modem_path, const char *operator);
++static void __remove_connman_device(struct telephony_modem *modem);
++static void __remove_connman_networks(struct connman_device *device);
++static void __set_device_powered(struct telephony_modem *modem,
++ gboolean powered);
++static int __check_device_powered(const char *path, gboolean online);
++static gboolean __check_network_available(struct connman_network *network);
++static void __create_service(struct connman_network *network);
++static int __add_context(struct connman_device *device, const char *path,
++ DBusMessageIter *prop);
++static gboolean __set_network_ipconfig(struct telephony_network *network,
++ DBusMessageIter *dict);
++static void __set_network_connected(struct telephony_network *network,
++ gboolean connected);
++static char *__get_ident(const char *path);
++
++/* signal handler */
++static gboolean __changed_modem(DBusConnection *connection,
++ DBusMessage *message, void *user_data);
++static gboolean __added_modem(DBusConnection *connection,
++ DBusMessage *message, void *user_data);
++static gboolean __removed_modem(DBusConnection *connection,
++ DBusMessage *message, void *user_data);
++static gboolean __changed_service(DBusConnection *connection,
++ DBusMessage *message, void *user_data);
++static gboolean __added_service(DBusConnection *connection,
++ DBusMessage *message, void *user_data);
++static gboolean __removed_service(DBusConnection *connection,
++ DBusMessage *message, void *user_data);
++static gboolean __changed_context(DBusConnection *connection,
++ DBusMessage *message, void *user_data);
++static gboolean __added_context(DBusConnection *connection,
++ DBusMessage *message, void *user_data);
++static gboolean __removed_context(DBusConnection *connection,
++ DBusMessage *message, void *user_data);
++
++/* device driver */
++static struct connman_device_driver modem_driver = {
++ .name = "device",
++ .type = CONNMAN_DEVICE_TYPE_CELLULAR,
++ .probe = __modem_probe,
++ .remove = __modem_remove,
++ .enable = __modem_enable,
++ .disable = __modem_disable,
++};
++
++/* network driver */
++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 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,
++};
++
++/* local function */
++static void telephony_connect(DBusConnection *connection, void *user_data)
++{
++ DBG("connection %p", connection);
++ modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
++ g_free, __remove_modem);
++ service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
++ g_free, __remove_service);
++ network_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
++ g_free, __remove_network);
++ __request_get_modems();
++ return;
++}
++
++static void telephony_disconnect(DBusConnection *connection, void *user_data)
++{
++ DBG("connection %p", connection);
++
++ 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;
++ }
++
++ return;
++}
++
++static void __remove_modem(gpointer data)
++{
++ struct telephony_modem *modem = data;
++
++ __remove_connman_device(modem);
++
++ g_free(modem->path);
++ g_free(modem->operator);
++ g_free(modem);
++}
++
++static void __remove_service(gpointer data)
++{
++ struct telephony_service *service = data;
++
++ g_free(service->path);
++ g_free(service->act);
++ g_free(service);
++}
++
++static void __remove_network(gpointer data)
++{
++ struct telephony_network *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);
++
++ g_free(info->path);
++ connman_ipaddress_free(info->ipv4_address);
++ connman_ipaddress_free(info->ipv6_address);
++ g_free(info);
++}
++
++static int __modem_probe(struct connman_device *device)
++{
++ DBG("device %p", device);
++ return 0;
++}
++
++static void __modem_remove(struct connman_device *device)
++{
++ DBG("device %p", device);
++}
++
++static int __modem_enable(struct connman_device *device)
++{
++ const char *path = connman_device_get_string(device, "Path");
++ DBG("device %p, path, %s", device, path);
++
++ return __check_device_powered(path, TRUE);
++}
++
++static int __modem_disable(struct connman_device *device)
++{
++ const char *path = connman_device_get_string(device, "Path");
++ DBG("device %p, path, %s", device, path);
++
++ return __check_device_powered(path, FALSE);
++}
++
++static int __network_probe(struct connman_network *network)
++{
++ DBG("network_prove network(%p)", network);
++ return 0;
++}
++
++static int __network_connect(struct connman_network *network)
++{
++ struct connman_device *device;
++ struct telephony_modem *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->powered == FALSE)
++ return -ENOLINK;
++
++ return __request_network_activate(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 __request_network_deactivate(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;
++}
++
++static int __dbus_request(const char *path, const char *interface,
++ const char *method,
++ DBusPendingCallNotifyFunction notify, void *user_data,
++ DBusFreeFunction free_function, int type, ...)
++{
++ DBusMessage *message;
++ DBusPendingCall *call;
++ dbus_bool_t ok;
++ va_list va;
++
++ DBG("Telephony request path %s %s.%s", path, interface, method);
++
++ if (path == NULL)
++ return -EINVAL;
++
++ message = dbus_message_new_method_call(PS_DBUS_SERVICE, path,
++ interface, method);
++ if (message == NULL)
++ return -ENOMEM;
++
++ dbus_message_set_auto_start(message, FALSE);
++
++ va_start(va, type);
++ ok = dbus_message_append_args_valist(message, type, va);
++ va_end(va);
++
++ if (!ok)
++ return -ENOMEM;
++
++ 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;
++ }
++
++ if (call == NULL) {
++ connman_error("D-Bus connection not available");
++ dbus_message_unref(message);
++ return -EINVAL;
++ }
++
++ dbus_pending_call_set_notify(call, notify, user_data, free_function);
++
++ dbus_message_unref(message);
++
++ return -EINPROGRESS;
++}
++
++static int __request_get_modems(void)
++{
++ DBG("request get modem");
++ /* call connect master */
++ return __dbus_request("/", PS_MASTER_INTERFACE, GET_MODEMS,
++ __response_get_modems, NULL, NULL, DBUS_TYPE_INVALID);
++}
++
++static void __response_get_modems(DBusPendingCall *call, void *user_data)
++{
++ DBusMessage *reply;
++ DBusError error;
++ DBusMessageIter args, dict;
++
++ DBG("");
++
++ reply = dbus_pending_call_steal_reply(call);
++
++ dbus_error_init(&error);
++
++ if (dbus_set_error_from_message(&error, reply)) {
++ connman_error("GetModems() %s %s", error.name, error.message);
++ dbus_error_free(&error);
++ goto done;
++ }
++
++ DBG("message signature (%s)", dbus_message_get_signature(reply));
++
++ if (dbus_message_iter_init(reply, &args) == FALSE)
++ goto done;
++
++ dbus_message_iter_recurse(&args, &dict);
++
++ while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) {
++ DBusMessageIter entry, property;
++ const char *modem_path;
++
++ dbus_message_iter_recurse(&dict, &entry);
++ dbus_message_iter_get_basic(&entry, &modem_path);
++ DBG("modem path (%s)", modem_path);
++
++ dbus_message_iter_next(&entry);
++ dbus_message_iter_recurse(&entry, &property);
++
++ __add_modem(modem_path, &property);
++
++ dbus_message_iter_next(&dict);
++ }
++
++done:
++ dbus_message_unref(reply);
++ dbus_pending_call_unref(call);
++ return;
++}
++
++static int __request_get_services(const char *path)
++{
++ DBG("request get service");
++ return __dbus_request(path, PS_MODEM_INTERFACE, GET_SERVICES,
++ __response_get_services, g_strdup(path),
++ g_free, DBUS_TYPE_INVALID);
++}
++
++static void __response_get_services(DBusPendingCall *call, void *user_data)
++{
++ DBusMessage *reply;
++ DBusError error;
++ DBusMessageIter args, dict;
++
++ const char *path = user_data;
++ struct telephony_modem *modem;
++
++ modem = g_hash_table_lookup(modem_hash, path);
++ if (modem == NULL)
++ return;
++ if (modem->device == NULL)
++ return;
++
++ DBG("");
++
++ reply = dbus_pending_call_steal_reply(call);
++
++ dbus_error_init(&error);
++
++ if (dbus_set_error_from_message(&error, reply)) {
++ connman_error("GetServices() %s %s", error.name, error.message);
++ dbus_error_free(&error);
++ goto done;
++ }
++
++ DBG("message signature (%s)", dbus_message_get_signature(reply));
++
++ if (dbus_message_iter_init(reply, &args) == FALSE)
++ goto done;
++
++ dbus_message_iter_recurse(&args, &dict);
++
++ while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) {
++ DBusMessageIter entry, property;
++ const char *service_path;
++
++ dbus_message_iter_recurse(&dict, &entry);
++ dbus_message_iter_get_basic(&entry, &service_path);
++ DBG("service path (%s)", service_path);
++
++ dbus_message_iter_next(&entry);
++ dbus_message_iter_recurse(&entry, &property);
++
++ __add_service(modem, service_path, &property);
++
++ dbus_message_iter_next(&dict);
++ }
++
++done:
++ dbus_message_unref(reply);
++ dbus_pending_call_unref(call);
++ return;
++}
++
++static int __request_get_contexts(struct telephony_modem *modem)
++{
++ DBG("request get contexts");
++ return __dbus_request(modem->s_service->path,
++ PS_SERVICE_INTERFACE, GET_CONTEXTS,
++ __response_get_contexts, g_strdup(modem->path),
++ g_free, DBUS_TYPE_INVALID);
++}
++
++static void __response_get_contexts(DBusPendingCall *call, void *user_data)
++{
++ DBusError error;
++ DBusMessage *reply;
++ DBusMessageIter args, dict;
++
++ const char *path = user_data;
++ struct telephony_modem *modem;
++
++ DBG("");
++
++ modem = g_hash_table_lookup(modem_hash, path);
++ if (modem == NULL)
++ return;
++ if (modem->s_service == NULL)
++ return;
++ if (modem->device == NULL)
++ return;
++
++ reply = dbus_pending_call_steal_reply(call);
++
++ dbus_error_init(&error);
++
++ if (dbus_set_error_from_message(&error, reply)) {
++ connman_error("GetContexts() %s %s", error.name, error.message);
++ dbus_error_free(&error);
++ goto done;
++ }
++
++ DBG("message signature (%s)", dbus_message_get_signature(reply));
++
++ if (dbus_message_iter_init(reply, &args) == FALSE)
++ goto done;
++
++ dbus_message_iter_recurse(&args, &dict);
++
++ while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) {
++ DBusMessageIter entry, property;
++ const char *context_path;
++
++ dbus_message_iter_recurse(&dict, &entry);
++ dbus_message_iter_get_basic(&entry, &context_path);
++ DBG("context path (%s)", context_path);
++
++ dbus_message_iter_next(&entry);
++ dbus_message_iter_recurse(&entry, &property);
++
++ __add_context(modem->device, context_path, &property);
++
++ dbus_message_iter_next(&dict);
++ }
++
++done:
++ dbus_message_unref(reply);
++ dbus_pending_call_unref(call);
++ return;
++}
++
++static int __request_network_activate(struct connman_network *network)
++{
++ DBG("request network activate");
++
++ const char *path = connman_network_get_string(network, "Path");
++ DBG("network %p, path %s", network, path);
++
++ return __dbus_request(path, PS_CONTEXT_INTERFACE, ACTIVATE_CONTEXT,
++ __response_network_activate,
++ g_strdup(path), NULL, DBUS_TYPE_INVALID);
++}
++
++static void __response_network_activate(DBusPendingCall *call, void *user_data)
++{
++ DBG("network activation response");
++
++ DBusError error;
++ DBusMessage *reply;
++
++ struct telephony_network *info;
++ const char *path = user_data;
++
++ info = g_hash_table_lookup(network_hash, path);
++ reply = dbus_pending_call_steal_reply(call);
++
++ if (info == NULL)
++ goto done;
++
++ if (!__check_network_available(info->network)) {
++ g_hash_table_remove(network_hash, path);
++ goto done;
++ }
++
++ dbus_error_init(&error);
++ if (dbus_set_error_from_message(&error, reply)) {
++ connman_error("connection activate() %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);
++ goto done;
++ }
++
++done:
++ dbus_message_unref(reply);
++ dbus_pending_call_unref(call);
++ return;
++}
++
++static int __request_network_deactivate(struct connman_network *network)
++{
++ DBG("request network deactivate");
++
++ const char *path = connman_network_get_string(network, "Path");
++ DBG("network %p, path %s", network, path);
++
++ return __dbus_request(path, PS_CONTEXT_INTERFACE, DEACTIVATE_CONTEXT,
++ NULL, NULL, NULL, DBUS_TYPE_INVALID);
++}
++
++static void __add_modem(const char *path, DBusMessageIter *prop)
++{
++ struct telephony_modem *modem;
++
++ modem = g_hash_table_lookup(modem_hash, path);
++ if (modem != NULL)
++ return;
++
++ modem = (struct telephony_modem *)malloc(
++ sizeof(struct telephony_modem));
++ memset(modem, 0, sizeof(struct telephony_modem));
++
++ modem->path = g_strdup(path);
++ modem->device = NULL;
++ modem->s_service = NULL;
++
++ g_hash_table_insert(modem_hash, g_strdup(path), modem);
++
++ while (dbus_message_iter_get_arg_type(prop) != DBUS_TYPE_INVALID) {
++ DBusMessageIter entry;
++ const char *key, *tmp;
++
++ dbus_message_iter_recurse(prop, &entry);
++ dbus_message_iter_get_basic(&entry, &key);
++
++ dbus_message_iter_next(&entry);
++ dbus_message_iter_get_basic(&entry, &tmp);
++
++ DBG("key (%s) value(%s)", key, tmp);
++
++ if (g_str_equal(key, "powered") == TRUE) {
++ modem->powered = STRING2BOOL(tmp);
++ } else if (g_str_equal(key, "operator") == TRUE) {
++ modem->operator = g_strdup(tmp);
++ } else if (g_str_equal(key, "sim_init") == TRUE) {
++ modem->sim_init = STRING2BOOL(tmp);
++ } else if (g_str_equal(key, "flight_mode") == TRUE) {
++ modem->flight_mode = STRING2BOOL(tmp);
++ } else if (g_str_equal(key, "roaming_allowed") == TRUE) {
++ modem->roaming_allowed = STRING2BOOL(tmp);
++ } else if (g_str_equal(key, "data_allowed") == TRUE) {
++ modem->data_allowed = STRING2BOOL(tmp);
++ }
++ dbus_message_iter_next(prop);
++ }
++
++ __add_connman_device(path, modem->operator);
++ __set_device_powered(modem, modem->powered);
++
++ if (modem->powered != TRUE) {
++ DBG("modem is not powered");
++ return;
++ }
++
++ __request_get_services(modem->path);
++
++ return;
++}
++
++static void __add_service(struct telephony_modem *modem,
++ const char *service_path, DBusMessageIter *prop)
++{
++ struct telephony_service *service;
++
++ if (modem->s_service != NULL)
++ return;
++
++ service = (struct telephony_service *)g_try_malloc(
++ sizeof(struct telephony_service));
++ if (service == NULL)
++ return;
++
++ memset(service, 0, sizeof(struct telephony_service));
++
++ service->path = g_strdup(service_path);
++ service->p_modem = modem;
++ g_hash_table_insert(service_hash, g_strdup(service_path), service);
++
++ while (dbus_message_iter_get_arg_type(prop) != DBUS_TYPE_INVALID) {
++ DBusMessageIter entry;
++ const char *key, *tmp;
++
++ dbus_message_iter_recurse(prop, &entry);
++ dbus_message_iter_get_basic(&entry, &key);
++
++ dbus_message_iter_next(&entry);
++ dbus_message_iter_get_basic(&entry, &tmp);
++
++ DBG("key (%s) value(%s)", key, tmp);
++
++ if (g_str_equal(key, "roaming") == TRUE) {
++ service->roaming = STRING2BOOL(tmp);
++ } else if (g_str_equal(key, "act") == TRUE) {
++ service->act = g_strdup(tmp);
++ } else if (g_str_equal(key, "ps_attached") == TRUE) {
++ service->ps_attached = STRING2BOOL(tmp);
++ }
++
++ dbus_message_iter_next(prop);
++ }
++
++ modem->s_service = service;
++ __request_get_contexts(modem);
++
++ return;
++}
++
++static void __add_connman_device(const char *modem_path, const char *operator)
++{
++ struct telephony_modem *modem;
++ struct connman_device *device;
++
++ DBG("path %s operator %s", modem_path, operator);
++
++ if (modem_path == NULL)
++ return;
++
++ if (operator == NULL)
++ return;
++
++ modem = g_hash_table_lookup(modem_hash, modem_path);
++ if (modem == NULL)
++ return;
++
++ if (modem->device) {
++ if (!g_strcmp0(operator,
++ connman_device_get_ident(modem->device)))
++ return;
++
++ __remove_connman_device(modem);
++ }
++
++ if (strlen(operator) == 0)
++ return;
++
++ device = connman_device_create(operator, CONNMAN_DEVICE_TYPE_CELLULAR);
++ if (device == NULL)
++ return;
++
++ connman_device_set_ident(device, operator);
++ connman_device_set_string(device, "Path", modem_path);
++ connman_device_set_data(device, modem);
++
++ if (connman_device_register(device) < 0) {
++ connman_error("Failed to register cellular device");
++ connman_device_unref(device);
++ return;
++ }
++
++ modem->device = device;
++
++ return;
++}
++
++static void __remove_connman_device(struct telephony_modem *modem)
++{
++ DBG("modem %p path %s device %p", modem, modem->path, modem->device);
++
++ if (modem->device == NULL)
++ return;
++
++ __remove_connman_networks(modem->device);
++
++ connman_device_unregister(modem->device);
++ connman_device_unref(modem->device);
++
++ modem->device = NULL;
++
++ return;
++}
++
++static void __remove_connman_networks(struct connman_device *device)
++{
++ GHashTableIter iter;
++ gpointer key, value;
++ GSList *info_list = NULL;
++ GSList *list;
++
++ if (network_hash == NULL)
++ return;
++
++ g_hash_table_iter_init(&iter, network_hash);
++
++ while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
++ struct telephony_network *info = value;
++
++ if (connman_network_get_device(info->network) != device)
++ continue;
++
++ info_list = g_slist_append(info_list, info);
++ }
++
++ for (list = info_list; list != NULL; list = list->next) {
++ struct telephony_network *info = list->data;
++ connman_device_remove_network(device, info->network);
++ }
++
++ g_slist_free(info_list);
++}
++
++static void __set_device_powered(struct telephony_modem *modem,
++ gboolean powered)
++{
++ DBG("set modem(%s) powered(%d)", modem->path, powered);
++
++ if (modem->device)
++ connman_device_set_powered(modem->device, powered);
++
++ return;
++}
++
++static int __check_device_powered(const char *path, gboolean powered)
++{
++ struct telephony_modem *modem = g_hash_table_lookup(modem_hash, path);
++
++ if (modem == NULL)
++ return -ENODEV;
++
++ DBG("check modem (%s) powered (%d)", modem->path, modem->powered);
++
++ if (modem->powered == powered)
++ return -EALREADY;
++
++ return 0;
++}
++
++static gboolean __check_network_available(struct connman_network *network)
++{
++ if (network == NULL || connman_network_get_device(network) == NULL) {
++ DBG("Modem or network was removed");
++ return FALSE;
++ }
++
++ return TRUE;
++}
++
++static int __add_context(struct connman_device *device, const char *path,
++ DBusMessageIter *prop)
++{
++ char *ident;
++ gboolean active = FALSE;
++
++ struct telephony_modem *modem = connman_device_get_data(device);
++ struct connman_network *network;
++ struct telephony_network *info;
++
++ DBG("modem %p device %p path %s", modem, device, path);
++
++ ident = __get_ident(path);
++
++ 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);
++ }
++
++ network = connman_network_create(ident, CONNMAN_NETWORK_TYPE_CELLULAR);
++ if (network == NULL)
++ return -ENOMEM;
++
++ info = (struct telephony_network *)g_try_malloc(
++ sizeof(struct telephony_network));
++ if (info == NULL) {
++ connman_network_unref(network);
++ return -ENOMEM;
++ }
++
++ memset(info, 0, sizeof(struct telephony_network));
++
++ info->path = g_strdup(path);
++
++ connman_ipaddress_clear(info->ipv4_address);
++ connman_ipaddress_clear(info->ipv6_address);
++ info->network = network;
++
++ connman_network_set_string(network, "Path", path);
++ connman_network_set_name(network, path);
++
++ __create_service(network);
++
++ g_hash_table_insert(network_hash, g_strdup(path), info);
++
++ connman_network_set_available(network, TRUE);
++ connman_network_set_index(network, -1);
++ connman_network_set_bool(network, "Roaming", modem->s_service->roaming);
++
++ if (connman_device_add_network(device, network) != 0) {
++ g_hash_table_remove(network_hash, path);
++ return -EIO;
++ }
++
++ active = __set_network_ipconfig(info, prop);
++
++ if (active && (connman_network_get_connecting(network) ||
++ connman_network_get_associating(network)))
++ __set_network_connected(info, active);
++
++ return 0;
++}
++
++static void __create_service(struct connman_network *network)
++{
++ const char *path;
++ char *group;
++
++ DBG("");
++
++ path = connman_network_get_string(network, "Path");
++
++ group = __get_ident(path);
++
++ connman_network_set_group(network, group);
++}
++
++static gboolean __set_network_ipconfig(struct telephony_network *network,
++ DBusMessageIter *dict)
++{
++ DBG("set network info");
++
++ gboolean active = FALSE;
++ char *dev_name = NULL, *proxy_addr = NULL;
++ char *ipv4_addr = NULL, *ipv4_gw = NULL, *ipv4_netmask = NULL,
++ *ipv4_dns1 = NULL, *ipv4_dns2 = NULL;
++ char *ipv6_addr = NULL, *ipv6_gw = NULL, *ipv6_netmask = NULL,
++ *ipv6_dns1 = NULL, *ipv6_dns2 = NULL;
++ int index;
++ int dns_flag = 0;
++
++ while (dbus_message_iter_get_arg_type(dict) != DBUS_TYPE_INVALID) {
++ DBusMessageIter entry;
++ const char *key, *tmp;
++
++ dbus_message_iter_recurse(dict, &entry);
++ dbus_message_iter_get_basic(&entry, &key);
++
++ dbus_message_iter_next(&entry);
++
++ DBG("key (%s)", key);
++
++ if (g_str_equal(key, "dev_name") == TRUE) {
++ dbus_message_iter_get_basic(&entry, &dev_name);
++ DBG("dev_name (%s)", dev_name);
++ } else if (g_str_equal(key, "proxy") == TRUE) {
++ dbus_message_iter_get_basic(&entry, &proxy_addr);
++ } else if (g_str_equal(key, "ipv4_address") == TRUE) {
++ dbus_message_iter_get_basic(&entry, &ipv4_addr);
++ DBG("ipv4 address (%s)", ipv4_addr);
++ } else if (g_str_equal(key, "ipv4_gateway") == TRUE) {
++ dbus_message_iter_get_basic(&entry, &ipv4_gw);
++ } else if (g_str_equal(key, "ipv4_netmask") == TRUE) {
++ dbus_message_iter_get_basic(&entry, &ipv4_netmask);
++ } else if (g_str_equal(key, "ipv4_dns1") == TRUE) {
++ dbus_message_iter_get_basic(&entry, &ipv4_dns1);
++ } else if (g_str_equal(key, "ipv4_dns2") == TRUE) {
++ dbus_message_iter_get_basic(&entry, &ipv4_dns2);
++ } else if (g_str_equal(key, "ipv6_address") == TRUE) {
++ dbus_message_iter_get_basic(&entry, &ipv6_addr);
++ DBG("ipv6 address (%s)", ipv6_addr);
++ } else if (g_str_equal(key, "ipv6_gateway") == TRUE) {
++ dbus_message_iter_get_basic(&entry, &ipv6_gw);
++ } else if (g_str_equal(key, "ipv6_netmask") == TRUE) {
++ dbus_message_iter_get_basic(&entry, &ipv6_netmask);
++ } else if (g_str_equal(key, "ipv6_dns1") == TRUE) {
++ dbus_message_iter_get_basic(&entry, &ipv6_dns1);
++ } else if (g_str_equal(key, "ipv6_dns2") == TRUE) {
++ dbus_message_iter_get_basic(&entry, &ipv6_dns2);
++ } else if (g_str_equal(key, "active") == TRUE) {
++ dbus_message_iter_get_basic(&entry, &tmp);
++ DBG("active (%s)", tmp);
++ active = STRING2BOOL(tmp);
++ }
++
++ dbus_message_iter_next(dict);
++ }
++
++ /* interface index set */
++ if (dev_name == NULL)
++ dev_name = "";
++
++ if (!g_str_equal(dev_name, "")) {
++ index = connman_inet_ifindex(dev_name);
++ DBG("interface %s, index %d", dev_name, index);
++ connman_network_set_index(network->network, index);
++ }
++
++ /* proxy set */
++ if (proxy_addr == NULL)
++ proxy_addr = "";
++
++ DBG("proxy (%s) is set", proxy_addr);
++ connman_network_set_proxy(network->network, proxy_addr);
++
++ /* ipv4 set */
++ if (ipv4_addr == NULL)
++ ipv4_addr = "0.0.0.0";
++
++ if (g_str_equal(ipv4_addr, "0.0.0.0")) {
++ network->ipv4_method = CONNMAN_IPCONFIG_METHOD_OFF;
++ } else {
++ network->ipv4_method = CONNMAN_IPCONFIG_METHOD_FIXED;
++ network->ipv4_address =
++ connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV4);
++ if (network->ipv4_address == NULL)
++ return FALSE;
++
++ connman_ipaddress_set_ipv4(network->ipv4_address, ipv4_addr,
++ ipv4_netmask, ipv4_gw);
++
++ if (ipv4_dns1 == NULL)
++ ipv4_dns1 = "0.0.0.0";
++ if (ipv4_dns2 == NULL)
++ ipv4_dns2 = "0.0.0.0";
++
++ if (g_str_equal(ipv4_dns1, "0.0.0.0"))
++ dns_flag += 1;
++
++ if (g_str_equal(ipv4_dns2, "0.0.0.0"))
++ dns_flag += 2;
++
++ gchar *nameservers = NULL;
++
++ switch (dns_flag) {
++ case 0:
++ nameservers = g_strdup_printf("%s %s", ipv4_dns1,
++ ipv4_dns2);
++ break;
++ case 1:
++ nameservers = g_strdup_printf("%s", ipv4_dns2);
++ break;
++ case 2:
++ nameservers = g_strdup_printf("%s", ipv4_dns1);
++ }
++
++ connman_network_set_nameservers(network->network, nameservers);
++ g_free(nameservers);
++ }
++
++ /* ipv6 set */
++ if (ipv6_addr == NULL)
++ ipv6_addr = "::";
++
++ if (g_str_equal(ipv6_addr, "::")) {
++ network->ipv6_method = CONNMAN_IPCONFIG_METHOD_OFF;
++ } else {
++ network->ipv6_method = CONNMAN_IPCONFIG_METHOD_FIXED;
++ unsigned char prefix_length = 64;
++ network->ipv6_address =
++ connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV6);
++ if (network->ipv6_address == NULL)
++ return FALSE;
++
++ connman_ipaddress_set_ipv6(network->ipv6_address, ipv6_addr,
++ prefix_length, ipv6_gw);
++
++ dns_flag = 0;
++
++ if (ipv6_dns1 == NULL)
++ ipv6_dns1 = "::";
++ if (ipv6_dns2 == NULL)
++ ipv6_dns2 = "::";
++
++ if (g_str_equal(ipv6_dns1, "::"))
++ dns_flag += 1;
++
++ if (g_str_equal(ipv6_dns2, "::"))
++ dns_flag += 2;
++
++ gchar *nameservers = NULL;
++
++ switch (dns_flag) {
++ case 0:
++ nameservers = g_strdup_printf("%s %s", ipv6_dns1,
++ ipv6_dns2);
++ break;
++ case 1:
++ nameservers = g_strdup_printf("%s", ipv6_dns2);
++ break;
++ case 2:
++ nameservers = g_strdup_printf("%s", ipv6_dns1);
++ }
++
++ connman_network_set_nameservers(network->network, nameservers);
++ g_free(nameservers);
++ }
++
++ if (active)
++ connman_network_set_associating(network->network, TRUE);
++
++ return active;
++}
++
++static void __set_network_connected(struct telephony_network *network,
++ gboolean connected)
++{
++ gboolean setip = FALSE;
++
++ DBG("network %p connected %d", network, connected);
++
++ switch (network->ipv4_method) {
++ case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
++ case CONNMAN_IPCONFIG_METHOD_OFF:
++ case CONNMAN_IPCONFIG_METHOD_MANUAL:
++ case CONNMAN_IPCONFIG_METHOD_AUTO:
++ setip = TRUE;
++ break;
++
++ case CONNMAN_IPCONFIG_METHOD_FIXED:
++ connman_network_set_ipv4_method(network->network,
++ network->ipv4_method);
++ connman_network_set_ipaddress(network->network,
++ network->ipv4_address);
++ setip = TRUE;
++ break;
++
++ case CONNMAN_IPCONFIG_METHOD_DHCP:
++ connman_network_set_ipv4_method(network->network,
++ network->ipv4_method);
++ setip = TRUE;
++ break;
++ }
++
++ switch (network->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:
++ DBG("ipv6 not supported");
++ break;
++
++ case CONNMAN_IPCONFIG_METHOD_FIXED:
++ connman_network_set_ipv6_method(network->network,
++ network->ipv6_method);
++ connman_network_set_ipaddress(network->network,
++ network->ipv6_address);
++ setip = TRUE;
++ break;
++ }
++
++ if (setip == TRUE)
++ connman_network_set_connected(network->network, connected);
++
++ return;
++}
++
++static char *__get_ident(const char *path)
++{
++ char *pos;
++
++ if (*path != '/')
++ return NULL;
++
++ pos = strrchr(path, '/');
++ if (pos == NULL)
++ return NULL;
++
++ return pos + 1;
++}
++
++static gboolean __changed_modem(DBusConnection *connection,
++ DBusMessage *message, void *user_data)
++{
++ DBG("modem changed signal");
++
++ DBusMessageIter args, dict;
++ const char *path = dbus_message_get_path(message);
++ struct telephony_modem *modem;
++
++ DBG("modem path %s", path);
++
++ modem = g_hash_table_lookup(modem_hash, path);
++ if (modem == NULL) {
++ DBG("modem object does not exists");
++ return TRUE;
++ }
++
++ DBG("message signature (%s)", dbus_message_get_signature(message));
++
++ if (dbus_message_iter_init(message, &args) == FALSE) {
++ DBG("error to read message");
++ return TRUE;
++ }
++
++ dbus_message_iter_recurse(&args, &dict);
++
++ while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) {
++ DBusMessageIter entry;
++ const char *key, *tmp;
++
++ dbus_message_iter_recurse(&dict, &entry);
++ dbus_message_iter_get_basic(&entry, &key);
++
++ dbus_message_iter_next(&entry);
++ dbus_message_iter_get_basic(&entry, &tmp);
++
++ DBG("key(%s), value(%s)", key, tmp);
++
++ if (g_str_equal(key, "powered") == TRUE) {
++ modem->powered = STRING2BOOL(tmp);
++ } else if (g_str_equal(key, "operator") == TRUE) {
++ modem->operator = g_strdup(tmp);
++ } else if (g_str_equal(key, "sim_init") == TRUE) {
++ modem->sim_init = STRING2BOOL(tmp);
++ } else if (g_str_equal(key, "flight_mode") == TRUE) {
++ modem->flight_mode = STRING2BOOL(tmp);
++ } else if (g_str_equal(key, "roaming_allowed") == TRUE) {
++ modem->roaming_allowed = STRING2BOOL(tmp);
++ } else if (g_str_equal(key, "data_allowed") == TRUE) {
++ modem->data_allowed = STRING2BOOL(tmp);
++ }
++
++ dbus_message_iter_next(&dict);
++ }
++
++ if (modem->device == NULL)
++ __add_connman_device(path, modem->operator);
++
++ __set_device_powered(modem, modem->powered);
++
++ if (modem->powered != TRUE) {
++ DBG("modem is not powered");
++ return TRUE;
++ }
++
++ if (!modem->s_service) {
++ __request_get_services(modem->path);
++ return TRUE;
++ }
++
++ if (modem->flight_mode || !modem->data_allowed) {
++ DBG("modem(%s) flight mode(%d) data allowed(%d)",
++ modem->path, modem->flight_mode, modem->data_allowed);
++ return TRUE;
++ }
++
++ return TRUE;
++}
++
++static gboolean __added_modem(DBusConnection *connection,
++ DBusMessage *message, void *user_data)
++{
++ DBG("modem added signal");
++
++ const char *modem_path = NULL;
++ DBusMessageIter args, dict, tmp;
++
++ DBG("message signature (%s)", dbus_message_get_signature(message));
++ if (dbus_message_iter_init(message, &args) == FALSE) {
++ DBG("error to read message");
++ return TRUE;
++ }
++
++ dbus_message_iter_recurse(&args, &dict);
++ memcpy(&tmp, &dict, sizeof(struct DBusMessageIter));
++
++ while (dbus_message_iter_get_arg_type(&tmp) != DBUS_TYPE_INVALID) {
++ DBusMessageIter entry;
++ const char *key, *value;
++
++ dbus_message_iter_recurse(&tmp, &entry);
++ dbus_message_iter_get_basic(&entry, &key);
++
++ dbus_message_iter_next(&entry);
++ dbus_message_iter_get_basic(&entry, &value);
++
++ DBG("key (%s) value(%s)", key, value);
++
++ if (g_str_equal(key, "path") == TRUE)
++ modem_path = g_strdup(value);
++
++ dbus_message_iter_next(&tmp);
++ }
++
++ if (modem_path != NULL)
++ __add_modem(modem_path, &dict);
++
++ return TRUE;
++}
++
++static gboolean __removed_modem(DBusConnection *connection,
++ DBusMessage *message, void *user_data)
++{
++ DBG("modem removed signal");
++
++ DBusMessageIter iter;
++ const char *modem_path;
++
++ if (dbus_message_iter_init(message, &iter) == FALSE) {
++ DBG("error to read message");
++ return TRUE;
++ }
++
++ dbus_message_iter_get_basic(&iter, &modem_path);
++ g_hash_table_remove(modem_hash, modem_path);
++
++ return TRUE;
++}
++
++static gboolean __changed_service(DBusConnection *connection,
++ DBusMessage *message, void *user_data)
++{
++ DBG("service changed signal");
++
++ DBusMessageIter args, dict;
++ const char *service_path = dbus_message_get_path(message);
++ struct telephony_modem *modem;
++ struct telephony_service *s_service;
++ gboolean roaming_option = TRUE;
++
++ DBG("service path %s", service_path);
++
++ s_service = g_hash_table_lookup(service_hash, service_path);
++ if (s_service == NULL) {
++ DBG("service object does not exists");
++ return TRUE;
++ }
++
++ modem = s_service->p_modem;
++ if (modem == NULL) {
++ DBG("modem object does not exists");
++ return TRUE;
++ }
++
++ DBG("message signature (%s)", dbus_message_get_signature(message));
++
++ if (dbus_message_iter_init(message, &args) == FALSE) {
++ DBG("error to read message");
++ return TRUE;
++ }
++
++ dbus_message_iter_recurse(&args, &dict);
++
++ while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) {
++ DBusMessageIter entry;
++ const char *key, *tmp;
++
++ dbus_message_iter_recurse(&dict, &entry);
++ dbus_message_iter_get_basic(&entry, &key);
++
++ dbus_message_iter_next(&entry);
++ dbus_message_iter_get_basic(&entry, &tmp);
++
++ DBG("key(%s), value(%s)", key, tmp);
++
++ if (g_str_equal(key, "roaming") == TRUE) {
++ s_service->roaming = STRING2BOOL(tmp);
++ } else if (g_str_equal(key, "act") == TRUE) {
++ s_service->act = g_strdup(tmp);
++ } else if (g_str_equal(key, "ps_attached") == TRUE) {
++ s_service->ps_attached = STRING2BOOL(tmp);
++ }
++
++ dbus_message_iter_next(&dict);
++ }
++
++ roaming_option &= (!s_service->roaming && !modem->roaming_allowed)
++ || modem->roaming_allowed;
++
++ return TRUE;
++}
++
++
++static gboolean __added_service(DBusConnection *connection,
++ DBusMessage *message, void *user_data)
++{
++ DBG("service added signal");
++
++ const char *path = dbus_message_get_path(message);
++ const char *service_path = NULL;
++ DBusMessageIter args, dict, tmp;
++ struct telephony_modem *modem;
++
++ modem = g_hash_table_lookup(modem_hash, path);
++ if (modem == NULL || modem->device == NULL)
++ return TRUE;
++
++ DBG("message signature (%s)", dbus_message_get_signature(message));
++ if (dbus_message_iter_init(message, &args) == FALSE) {
++ DBG("error to read message");
++ return TRUE;
++ }
++
++ dbus_message_iter_recurse(&args, &dict);
++ memcpy(&tmp, &dict, sizeof(struct DBusMessageIter));
++
++ while (dbus_message_iter_get_arg_type(&tmp) != DBUS_TYPE_INVALID) {
++ DBusMessageIter entry;
++ const char *key, *value;
++
++ dbus_message_iter_recurse(&tmp, &entry);
++ dbus_message_iter_get_basic(&entry, &key);
++
++ dbus_message_iter_next(&entry);
++ dbus_message_iter_get_basic(&entry, &value);
++
++ DBG("key (%s) value(%s)", key, value);
++
++ if (g_str_equal(key, "path") == TRUE) {
++ service_path = g_strdup(value);
++ }
++
++ dbus_message_iter_next(&tmp);
++ }
++
++ if (service_path != NULL)
++ __add_service(modem, service_path, &dict);
++
++ return TRUE;
++}
++
++static gboolean __removed_service(DBusConnection *connection,
++ DBusMessage *message, void *user_data)
++{
++ DBG("service removed signal");
++
++ DBusMessageIter iter;
++ const char *service_path;
++
++ if (dbus_message_iter_init(message, &iter) == FALSE) {
++ DBG("error to read message");
++ return TRUE;
++ }
++
++ dbus_message_iter_get_basic(&iter, &service_path);
++ g_hash_table_remove(service_hash, service_path);
++
++ return TRUE;
++}
++
++static gboolean __changed_context(DBusConnection *connection,
++ DBusMessage *message, void *user_data)
++{
++ DBG("network changed signal");
++
++ gboolean active = FALSE;
++ const char *path = dbus_message_get_path(message);
++ struct telephony_network *info;
++ DBusMessageIter args, dict;
++
++ DBG("path %s", path);
++ info = g_hash_table_lookup(network_hash, path);
++ if (info == NULL)
++ return TRUE;
++
++ if (!__check_network_available(info->network)) {
++ g_hash_table_remove(network_hash, path);
++ return TRUE;
++ }
++
++ if (dbus_message_iter_init(message, &args) == FALSE) {
++ DBG("error to read message");
++ return TRUE;
++ }
++
++ dbus_message_iter_recurse(&args, &dict);
++
++ active = __set_network_ipconfig(info, &dict);
++
++ if (active == FALSE)
++ __set_network_connected(info, active);
++ else if ((connman_network_get_connecting(info->network) ||
++ connman_network_get_associating(info->network)))
++ __set_network_connected(info, active);
++
++ return TRUE;
++}
++
++static gboolean __added_context(DBusConnection *connection,
++ DBusMessage *message, void *user_data)
++{
++ DBG("network added signal");
++
++ DBusMessageIter args, dict, tmp;
++ const char *path = dbus_message_get_path(message);
++ const char *network_path = NULL;
++ struct telephony_service *service = NULL;
++ struct telephony_modem *modem = NULL;
++
++ service = g_hash_table_lookup(service_hash, path);
++ if (service == NULL || service->p_modem == NULL)
++ return TRUE;
++
++ modem = service->p_modem;
++ if (modem == NULL || modem->device == NULL)
++ return TRUE;
++
++ DBG("message signature (%s)", dbus_message_get_signature(message));
++ if (dbus_message_iter_init(message, &args) == FALSE) {
++ DBG("error to read message");
++ return TRUE;
++ }
++
++ dbus_message_iter_recurse(&args, &dict);
++ memcpy(&tmp, &dict, sizeof(struct DBusMessageIter));
++
++ while (dbus_message_iter_get_arg_type(&tmp) != DBUS_TYPE_INVALID) {
++ DBusMessageIter entry;
++ const char *key, *value;
++
++ dbus_message_iter_recurse(&tmp, &entry);
++ dbus_message_iter_get_basic(&entry, &key);
++
++ dbus_message_iter_next(&entry);
++ dbus_message_iter_get_basic(&entry, &value);
++
++ DBG("key (%s) value(%s)", key, value);
++
++ if (g_str_equal(key, "path") == TRUE)
++ network_path = g_strdup(value);
++
++ dbus_message_iter_next(&tmp);
++ }
++
++ if (network_path != NULL)
++ __add_context(modem->device, network_path, &dict);
++
++ return TRUE;
++}
++
++static gboolean __removed_context(DBusConnection *connection,
++ DBusMessage *message, void *user_data)
++{
++ DBG("network removed signal");
++
++ DBusMessageIter iter;
++ const char *path = dbus_message_get_path(message);
++ const char *network_path = NULL;
++ struct telephony_service *service = NULL;
++
++ service = g_hash_table_lookup(service_hash, path);
++ if (service == NULL || service->p_modem == NULL)
++ return TRUE;
++
++ if (dbus_message_iter_init(message, &iter) == FALSE) {
++ DBG("error to read message");
++ return TRUE;
++ }
++
++ dbus_message_iter_get_basic(&iter, &network_path);
++ g_hash_table_remove(network_hash, network_path);
++
++ return TRUE;
++}
++
++/* telephony initialization */
++static guint watch;
++static guint modem_watch;
++static guint modem_added_watch;
++static guint modem_removed_watch;
++static guint service_watch;
++static guint service_added_watch;
++static guint service_removed_watch;
++static guint context_watch;
++static guint context_added_watch;
++static guint context_removed_watch;
++
++static int telephony_init(void)
++{
++ DBG("telephony plugin");
++ int err;
++
++ connection = connman_dbus_get_connection();
++ if (connection == NULL)
++ return -EIO;
++
++ /* telephony watch */
++ watch = g_dbus_add_service_watch(connection, PS_DBUS_SERVICE,
++ telephony_connect, telephony_disconnect,
++ NULL, NULL);
++
++ modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
++ PS_MODEM_INTERFACE,
++ PROPERTY_CHANGED,
++ __changed_modem, NULL, NULL);
++
++ modem_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
++ PS_MASTER_INTERFACE,
++ MODEM_ADDED, __added_modem,
++ NULL, NULL);
++
++ modem_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
++ PS_MASTER_INTERFACE,
++ MODEM_REMOVED, __removed_modem,
++ NULL, NULL);
++
++ service_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
++ PS_SERVICE_INTERFACE,
++ PROPERTY_CHANGED,
++ __changed_service,
++ NULL, NULL);
++
++ service_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
++ PS_MODEM_INTERFACE,
++ SERVICE_ADDED, __added_service,
++ NULL, NULL);
++
++ service_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
++ PS_MODEM_INTERFACE,
++ SERVICE_REMOVED,
++ __removed_service,
++ NULL, NULL);
++
++ context_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
++ PS_CONTEXT_INTERFACE,
++ PROPERTY_CHANGED,
++ __changed_context,
++ NULL, NULL);
++
++ context_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
++ PS_SERVICE_INTERFACE,
++ CONTEXT_ADDED, __added_context,
++ NULL, NULL);
++
++ context_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
++ PS_SERVICE_INTERFACE,
++ CONTEXT_REMOVED,
++ __removed_context,
++ NULL, NULL);
++
++ if (watch == 0 || modem_watch == 0 || modem_added_watch == 0
++ || modem_removed_watch == 0 || service_watch == 0
++ || service_added_watch == 0 || context_watch == 0
++ || service_removed_watch == 0
++ || context_added_watch == 0
++ || context_removed_watch == 0) {
++ err = -EIO;
++ goto remove;
++ }
++
++ err = connman_network_driver_register(&network_driver);
++ if (err < 0)
++ goto remove;
++
++ err = connman_device_driver_register(&modem_driver);
++ if (err < 0) {
++ connman_network_driver_unregister(&network_driver);
++ 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, modem_watch);
++ g_dbus_remove_watch(connection, modem_added_watch);
++ g_dbus_remove_watch(connection, modem_removed_watch);
++ g_dbus_remove_watch(connection, service_watch);
++ g_dbus_remove_watch(connection, service_added_watch);
++ g_dbus_remove_watch(connection, service_removed_watch);
++ g_dbus_remove_watch(connection, context_watch);
++ g_dbus_remove_watch(connection, context_added_watch);
++ g_dbus_remove_watch(connection, context_removed_watch);
++
++ dbus_connection_unref(connection);
++ return err;
++}
++
++static void telephony_exit(void)
++{
++ g_dbus_remove_watch(connection, 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, service_watch);
++ g_dbus_remove_watch(connection, service_added_watch);
++ g_dbus_remove_watch(connection, service_removed_watch);
++ g_dbus_remove_watch(connection, context_watch);
++ g_dbus_remove_watch(connection, context_added_watch);
++ g_dbus_remove_watch(connection, context_removed_watch);
++
++ telephony_disconnect(connection, NULL);
++
++ connman_device_driver_unregister(&modem_driver);
++ connman_network_driver_unregister(&network_driver);
++
++ dbus_connection_unref(connection);
++}
++
++CONNMAN_PLUGIN_DEFINE(telephony, "Samsung Telephony Framework plug-in", VERSION,
++ CONNMAN_PLUGIN_PRIORITY_DEFAULT, telephony_init, telephony_exit)
+--
+1.8.1.4
+
--- /dev/null
+From ede27f8e832d3ce5dc6bf2a8be78f34abddcc885 Mon Sep 17 00:00:00 2001
+From: Arron Wang <arron.wang@intel.com>
+Date: Fri, 12 Oct 2012 10:10:28 +0800
+Subject: [PATCH 13/32] Tizen: Fix wifi enterprise to support SIM and AKA
+
+Revise Wi-Fi enterprise to enable PEAP, TLS, TTLS
+Fix wifi enterprise to support SIM and AKA
+
+Change-Id: Ib9c10615fd0668b2ebca57eac9285bf8a3564427
+---
+ gsupplicant/supplicant.c | 20 ++++++++++++++++++++
+ src/service.c | 13 ++++++++++++-
+ 2 files changed, 32 insertions(+), 1 deletion(-)
+
+diff --git a/gsupplicant/supplicant.c b/gsupplicant/supplicant.c
+index d2e4a64..58a8c9f 100644
+--- a/gsupplicant/supplicant.c
++++ b/gsupplicant/supplicant.c
+@@ -4392,14 +4392,27 @@ static void add_network_security_eap(DBusMessageIter *dict,
+ {
+ char *eap_value;
+
++#if defined TIZEN_EXT
++ if (!ssid->eap)
++#else
+ if (!ssid->eap || !ssid->identity)
++#endif
+ return;
+
+ if (g_strcmp0(ssid->eap, "tls") == 0) {
+ add_network_security_tls(dict, ssid);
+ } else if (g_strcmp0(ssid->eap, "peap") == 0 ||
+ g_strcmp0(ssid->eap, "ttls") == 0) {
++#if defined TIZEN_EXT
++ if (!ssid->identity)
++ return;
++#endif
+ add_network_security_peap(dict, ssid);
++
++#if defined TIZEN_EXT
++ } else if (g_strcmp0(ssid->eap, "sim") == 0 ||
++ g_strcmp0(ssid->eap, "aka") == 0) {
++#endif
+ } else
+ return;
+
+@@ -4408,9 +4421,16 @@ static void add_network_security_eap(DBusMessageIter *dict,
+ supplicant_dbus_dict_append_basic(dict, "eap",
+ DBUS_TYPE_STRING,
+ &eap_value);
++#if defined TIZEN_EXT
++ if (ssid->identity != NULL)
++ supplicant_dbus_dict_append_basic(dict, "identity",
++ DBUS_TYPE_STRING,
++ &ssid->identity);
++#else
+ supplicant_dbus_dict_append_basic(dict, "identity",
+ DBUS_TYPE_STRING,
+ &ssid->identity);
++#endif
+
+ g_free(eap_value);
+ }
+diff --git a/src/service.c b/src/service.c
+index 8d3c619..99bb35d 100644
+--- a/src/service.c
++++ b/src/service.c
+@@ -5912,13 +5912,24 @@ static int service_connect(struct connman_service *service)
+ if (!service->eap)
+ return -EINVAL;
+
++#if defined TIZEN_EXT
++ /*
++ * never request credentials if using EAP-TLS, EAP-SIM
++ * or EAP-AKA (EAP-TLS, EAP-SIM and EAP-AKA networks
++ * need to be fully provisioned)
++ */
++ if (g_str_equal(service->eap, "tls") ||
++ g_str_equal(service->eap, "sim") ||
++ g_str_equal(service->eap, "aka"))
++ break;
++#else
+ /*
+ * never request credentials if using EAP-TLS
+ * (EAP-TLS networks need to be fully provisioned)
+ */
+ if (g_str_equal(service->eap, "tls"))
+ break;
+-
++#endif
+ /*
+ * Return -ENOKEY if either identity or passphrase is
+ * missing. Agent provided credentials can be used as
+--
+1.8.1.4
+
--- /dev/null
+From 1eb2741818fb2d2ec09ab055c8e4d1df1f2fb481 Mon Sep 17 00:00:00 2001
+From: "guoqiang.liu" <guoqiang.liu@archermind.com>
+Date: Fri, 27 Dec 2013 14:22:52 +0800
+Subject: [PATCH 14/32] Tizen: Check some telephony flags before active context
+
+Telephony active maybe fail if data_allowed or ps_attached is false,
+so check it before actived.
+
+When data_allowed is false, if connman starts to auto connect 3G
+service, it will result in 3G service auto connected fail, which
+leads to it will not be auto connected next time.
+
+Change-Id: Ibdd9c34fee7a612c1788a364c69550c4f7e79123
+Signed-off-by: guoqiang.liu <guoqiang.liu@archermind.com>
+---
+ plugins/telephony.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/plugins/telephony.c b/plugins/telephony.c
+index 63e7f6e..ea0bf65 100644
+--- a/plugins/telephony.c
++++ b/plugins/telephony.c
+@@ -323,6 +323,7 @@ static int __network_connect(struct connman_network *network)
+ {
+ struct connman_device *device;
+ struct telephony_modem *modem;
++ struct telephony_service *service;
+
+ DBG("network %p", network);
+
+@@ -334,9 +335,16 @@ static int __network_connect(struct connman_network *network)
+ if (modem == NULL)
+ return -ENODEV;
+
++ service = modem->s_service;
++ if (service == NULL)
++ return -ENOLINK;
++
+ if (modem->powered == FALSE)
+ return -ENOLINK;
+
++ if (modem->data_allowed == FALSE || service->ps_attached == FALSE)
++ return -ENOLINK;
++
+ return __request_network_activate(network);
+ }
+
+--
+1.8.1.4
+
--- /dev/null
+From ee0652fae6fc8615408e0937f3f61ebd28f9c42c Mon Sep 17 00:00:00 2001
+From: Zhang zhengguang <zhengguang.zhang@intel.com>
+Date: Tue, 25 Mar 2014 14:16:52 +0800
+Subject: [PATCH 15/32] Tizen: Unify bluetooth tethering enable logic
+
+In bluez 4.x plugin, when bluetooth tethering is enabled,
+set_tethering() returns 0, while in bluez 5.x plugin,
+it returns -EINPROGRESS, which is not compatiable for
+ConnMan to handle both of them, this patch makes bluez
+5.x tethering enable logic consistent with bluez 4.x.
+
+Change-Id: I618efd32b5f123fe9bdb58d10adb29c67a87796f
+---
+ plugins/bluetooth.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c
+index 82217d0..28df406 100644
+--- a/plugins/bluetooth.c
++++ b/plugins/bluetooth.c
+@@ -880,7 +880,7 @@ static int bluetooth_tech_set_tethering(struct connman_technology *technology,
+ if (i == 0)
+ return -ENODEV;
+
+- return -EINPROGRESS;
++ return 0;
+ }
+
+ static struct connman_technology_driver tech_driver = {
+--
+1.8.1.4
+
--- /dev/null
+From 763bd791fc3a52dc6381b18da246b7c0656861fd Mon Sep 17 00:00:00 2001
+From: Chengyi Zhao <chengyi1.zhao@archermind.com>
+Date: Wed, 10 Jul 2013 15:37:50 +0800
+Subject: [PATCH 16/32] Tethering: Add handling for wpa_supplicant
+ authorized/deauthorized signals
+
+Change-Id: Iff022e257ee9d2c5227585bf0b84e726914cc62b
+---
+ gsupplicant/gsupplicant.h | 2 ++
+ gsupplicant/supplicant.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 55 insertions(+)
+
+diff --git a/gsupplicant/gsupplicant.h b/gsupplicant/gsupplicant.h
+index 27826dc..1fab1ba 100644
+--- a/gsupplicant/gsupplicant.h
++++ b/gsupplicant/gsupplicant.h
+@@ -359,6 +359,8 @@ struct _GSupplicantCallbacks {
+ void (*network_removed) (GSupplicantNetwork *network);
+ void (*network_changed) (GSupplicantNetwork *network,
+ const char *property);
++ void (*add_station) (const char *mac);
++ void (*remove_station) (const char *mac);
+ void (*peer_found) (GSupplicantPeer *peer);
+ void (*peer_lost) (GSupplicantPeer *peer);
+ void (*peer_changed) (GSupplicantPeer *peer,
+diff --git a/gsupplicant/supplicant.c b/gsupplicant/supplicant.c
+index 58a8c9f..5ff9b3d 100644
+--- a/gsupplicant/supplicant.c
++++ b/gsupplicant/supplicant.c
+@@ -2609,6 +2609,56 @@ static void signal_wps_event(const char *path, DBusMessageIter *iter)
+ supplicant_dbus_property_foreach(iter, wps_event_args, interface);
+ }
+
++static void signal_station_connected(const char *path, DBusMessageIter *iter)
++{
++ GSupplicantInterface *interface;
++ const char *sta_mac = NULL;
++
++ SUPPLICANT_DBG("path %s %s", path, SUPPLICANT_PATH);
++
++ if (callbacks_pointer->add_station == NULL)
++ return;
++
++ if (g_strcmp0(path, "/") == 0)
++ return;
++
++ interface = g_hash_table_lookup(interface_table, path);
++ if (interface == NULL)
++ return;
++
++ dbus_message_iter_get_basic(iter, &sta_mac);
++ if (sta_mac == NULL)
++ return;
++
++ SUPPLICANT_DBG("New station %s connected", sta_mac);
++ callbacks_pointer->add_station(sta_mac);
++}
++
++static void signal_station_disconnected(const char *path, DBusMessageIter *iter)
++{
++ GSupplicantInterface *interface;
++ const char *sta_mac = NULL;
++
++ SUPPLICANT_DBG("path %s %s", path, SUPPLICANT_PATH);
++
++ if (callbacks_pointer->remove_station == NULL)
++ return;
++
++ if (g_strcmp0(path, "/") == 0)
++ return;
++
++ interface = g_hash_table_lookup(interface_table, path);
++ if (interface == NULL)
++ return;
++
++ dbus_message_iter_get_basic(iter, &sta_mac);
++ if (sta_mac == NULL)
++ return;
++
++ SUPPLICANT_DBG("Station %s disconnected", sta_mac);
++ callbacks_pointer->remove_station(sta_mac);
++}
++
+ static void create_peer_identifier(GSupplicantPeer *peer)
+ {
+ const unsigned char test[ETH_ALEN] = {};
+@@ -3171,6 +3221,9 @@ static struct {
+ { SUPPLICANT_INTERFACE ".Interface.WPS", "Credentials", signal_wps_credentials },
+ { SUPPLICANT_INTERFACE ".Interface.WPS", "Event", signal_wps_event },
+
++ { SUPPLICANT_INTERFACE".Interface", "StaAuthorized", signal_station_connected },
++ { SUPPLICANT_INTERFACE".Interface", "StaDeauthorized", signal_station_disconnected },
++
+ { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "DeviceFound", signal_peer_found },
+ { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "DeviceLost", signal_peer_lost },
+
+--
+1.8.1.4
+
--- /dev/null
+From c7d7214b511b0fa8b43f21b3b87416051fa9ef29 Mon Sep 17 00:00:00 2001
+From: Chengyi Zhao <chengyi1.zhao@archermind.com>
+Date: Wed, 10 Jul 2013 17:54:32 +0800
+Subject: [PATCH 17/32] Tethering: Add station information management feature
+
+Change-Id: I2f699e42ec5ce7f148b8c1d685b52ee32e2e236b
+---
+ include/technology.h | 4 +++
+ plugins/wifi.c | 13 ++++++++
+ src/tethering.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 104 insertions(+)
+
+diff --git a/include/technology.h b/include/technology.h
+index d7fcdde..b13d4ec 100644
+--- a/include/technology.h
++++ b/include/technology.h
+@@ -36,6 +36,10 @@ extern "C" {
+
+ struct connman_technology;
+
++int connman_technology_tethering_add_station(enum connman_service_type type,
++ const char *mac);
++int connman_technology_tethering_remove_station(const char *mac);
++
+ void connman_technology_tethering_notify(struct connman_technology *technology,
+ bool enabled);
+ int connman_technology_set_regdom(const char *alpha2);
+diff --git a/plugins/wifi.c b/plugins/wifi.c
+index 69a0e23..b5bc3ba 100644
+--- a/plugins/wifi.c
++++ b/plugins/wifi.c
+@@ -2719,6 +2719,17 @@ static void apply_peer_services(GSupplicantPeer *peer,
+ }
+ }
+
++static void add_station(const char *mac)
++{
++ connman_technology_tethering_add_station(CONNMAN_SERVICE_TYPE_WIFI,
++ mac);
++}
++
++static void remove_station(const char *mac)
++{
++ connman_technology_tethering_remove_station(mac);
++}
++
+ static void peer_found(GSupplicantPeer *peer)
+ {
+ GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
+@@ -2887,6 +2898,8 @@ static const GSupplicantCallbacks callbacks = {
+ .network_added = network_added,
+ .network_removed = network_removed,
+ .network_changed = network_changed,
++ .add_station = add_station,
++ .remove_station = remove_station,
+ .peer_found = peer_found,
+ .peer_lost = peer_lost,
+ .peer_changed = peer_changed,
+diff --git a/src/tethering.c b/src/tethering.c
+index ceeec74..0cbf06c 100644
+--- a/src/tethering.c
++++ b/src/tethering.c
+@@ -52,6 +52,9 @@
+
+ #define DEFAULT_MTU 1500
+
++#define CONNMAN_STATION_STR_INFO_LEN 64
++#define CONNMAN_STATION_MAC_INFO_LEN 32
++
+ static char *private_network_primary_dns = NULL;
+ static char *private_network_secondary_dns = NULL;
+
+@@ -60,6 +63,7 @@ static GDHCPServer *tethering_dhcp_server = NULL;
+ static struct connman_ippool *dhcp_ippool = NULL;
+ static DBusConnection *connection;
+ static GHashTable *pn_hash;
++static GHashTable *sta_hash;
+
+ struct connman_private_network {
+ char *owner;
+@@ -76,6 +80,84 @@ struct connman_private_network {
+ char *secondary_dns;
+ };
+
++struct connman_station_info {
++ bool is_connected;
++ char *path;
++ char *type;
++ char ip[CONNMAN_STATION_STR_INFO_LEN];
++ char mac[CONNMAN_STATION_MAC_INFO_LEN];
++ char hostname[CONNMAN_STATION_STR_INFO_LEN];
++};
++
++static void destroy_station(gpointer key, gpointer value, gpointer user_data)
++{
++ struct connman_station_info *station_info;
++
++ __sync_synchronize();
++
++ station_info = value;
++
++ g_free(station_info->path);
++ g_free(station_info->type);
++ g_free(station_info);
++}
++
++int connman_technology_tethering_add_station(enum connman_service_type type,
++ const char *mac)
++{
++ const char *str_type;
++ char *lower_mac;
++ char *path;
++ struct connman_station_info *station_info;
++
++ __sync_synchronize();
++
++ DBG("type %d", type);
++
++ str_type = __connman_service_type2string(type);
++ if (str_type == NULL)
++ return 0;
++
++ path = g_strdup_printf("%s/technology/%s", CONNMAN_PATH, str_type);
++
++ station_info = g_try_new0(struct connman_station_info, 1);
++ if (station_info == NULL)
++ return -ENOMEM;
++
++ lower_mac = g_ascii_strdown(mac, -1);
++
++ memcpy(station_info->mac, lower_mac, strlen(lower_mac) + 1);
++ station_info->path = path;
++ station_info->type = g_strdup(str_type);
++
++ g_hash_table_insert(sta_hash, station_info->mac, station_info);
++
++ g_free(lower_mac);
++ return 0;
++}
++
++int connman_technology_tethering_remove_station(const char *mac)
++{
++ char *lower_mac;
++ struct connman_station_info *info_found;
++
++ __sync_synchronize();
++
++ lower_mac = g_ascii_strdown(mac, -1);
++
++ info_found = g_hash_table_lookup(sta_hash, lower_mac);
++ if (info_found == NULL)
++ return -EACCES;
++
++ g_free(lower_mac);
++ g_hash_table_remove(sta_hash, info_found->mac);
++ g_free(info_found->path);
++ g_free(info_found->type);
++ g_free(info_found);
++
++ return 0;
++}
++
+ const char *__connman_tethering_get_bridge(void)
+ {
+ int sk, err;
+@@ -534,6 +616,9 @@ int __connman_tethering_init(void)
+ pn_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, remove_private_network);
+
++ sta_hash = g_hash_table_new_full(g_str_hash,
++ g_str_equal, NULL, NULL);
++
+ return 0;
+ }
+
+@@ -554,5 +639,7 @@ void __connman_tethering_cleanup(void)
+ return;
+
+ g_hash_table_destroy(pn_hash);
++ g_hash_table_foreach(sta_hash, destroy_station, NULL);
++ g_hash_table_destroy(sta_hash);
+ dbus_connection_unref(connection);
+ }
+--
+1.8.1.4
+
--- /dev/null
+From 5bd77bc62bc47d5752a9060cb887883a9d1b9844 Mon Sep 17 00:00:00 2001
+From: Chengyi Zhao <chengyi1.zhao@archermind.com>
+Date: Wed, 10 Jul 2013 19:17:02 +0800
+Subject: [PATCH 18/32] Tethering: Add interface that save lease in DHCP
+ information
+
+Change-Id: Ia09c875954d8a20a3e6c39f87076780d8a6582e4
+---
+ gdhcp/client.c | 65 ----------------------------------------------------------
+ gdhcp/common.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ gdhcp/common.h | 1 +
+ gdhcp/gdhcp.h | 5 +++++
+ gdhcp/server.c | 29 +++++++++++++++++++++++++-
+ 5 files changed, 99 insertions(+), 66 deletions(-)
+
+diff --git a/gdhcp/client.c b/gdhcp/client.c
+index 66c3a90..a72efb4 100644
+--- a/gdhcp/client.c
++++ b/gdhcp/client.c
+@@ -1808,71 +1808,6 @@ static char *get_ip(uint32_t ip)
+ return g_strdup(inet_ntoa(addr));
+ }
+
+-/* get a rough idea of how long an option will be */
+-static const uint8_t len_of_option_as_string[] = {
+- [OPTION_IP] = sizeof("255.255.255.255 "),
+- [OPTION_STRING] = 1,
+- [OPTION_U8] = sizeof("255 "),
+- [OPTION_U16] = sizeof("65535 "),
+- [OPTION_U32] = sizeof("4294967295 "),
+-};
+-
+-static int sprint_nip(char *dest, const char *pre, const uint8_t *ip)
+-{
+- return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]);
+-}
+-
+-/* Create "opt_value1 option_value2 ..." string */
+-static char *malloc_option_value_string(uint8_t *option, GDHCPOptionType type)
+-{
+- unsigned upper_length;
+- int len, optlen;
+- char *dest, *ret;
+-
+- len = option[OPT_LEN - OPT_DATA];
+- type &= OPTION_TYPE_MASK;
+- optlen = dhcp_option_lengths[type];
+- if (optlen == 0)
+- return NULL;
+- upper_length = len_of_option_as_string[type] *
+- ((unsigned)len / (unsigned)optlen);
+- dest = ret = g_malloc(upper_length + 1);
+- if (!ret)
+- return NULL;
+-
+- while (len >= optlen) {
+- switch (type) {
+- case OPTION_IP:
+- dest += sprint_nip(dest, "", option);
+- break;
+- case OPTION_U16: {
+- uint16_t val_u16 = get_be16(option);
+- dest += sprintf(dest, "%u", val_u16);
+- break;
+- }
+- case OPTION_U32: {
+- uint32_t val_u32 = get_be32(option);
+- dest += sprintf(dest, "%u", val_u32);
+- break;
+- }
+- case OPTION_STRING:
+- memcpy(dest, option, len);
+- dest[len] = '\0';
+- return ret;
+- default:
+- break;
+- }
+- option += optlen;
+- len -= optlen;
+- if (len <= 0)
+- break;
+- *dest++ = ' ';
+- *dest = '\0';
+- }
+-
+- return ret;
+-}
+-
+ static GList *get_option_value_list(char *value, GDHCPOptionType type)
+ {
+ char *pos = value;
+diff --git a/gdhcp/common.c b/gdhcp/common.c
+index 45278a8..ac6b125 100644
+--- a/gdhcp/common.c
++++ b/gdhcp/common.c
+@@ -144,6 +144,71 @@ int dhcp_end_option(uint8_t *optionptr)
+ return i;
+ }
+
++/* get a rough idea of how long an option will be */
++static const uint8_t len_of_option_as_string[] = {
++ [OPTION_IP] = sizeof("255.255.255.255 "),
++ [OPTION_STRING] = 1,
++ [OPTION_U8] = sizeof("255 "),
++ [OPTION_U16] = sizeof("65535 "),
++ [OPTION_U32] = sizeof("4294967295 "),
++};
++
++static int sprint_nip(char *dest, const char *pre, const uint8_t *ip)
++{
++ return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]);
++}
++
++/* Create "opt_value1 option_value2 ..." string */
++char *malloc_option_value_string(uint8_t *option, GDHCPOptionType type)
++{
++ unsigned upper_length;
++ int len, optlen;
++ char *dest, *ret;
++
++ len = option[OPT_LEN - OPT_DATA];
++ type &= OPTION_TYPE_MASK;
++ optlen = dhcp_option_lengths[type];
++ if (optlen == 0)
++ return NULL;
++ upper_length = len_of_option_as_string[type] *
++ ((unsigned)len / (unsigned)optlen);
++ dest = ret = g_malloc(upper_length + 1);
++ if (ret == NULL)
++ return NULL;
++
++ while (len >= optlen) {
++ switch (type) {
++ case OPTION_IP:
++ dest += sprint_nip(dest, "", option);
++ break;
++ case OPTION_U16: {
++ uint16_t val_u16 = get_be16(option);
++ dest += sprintf(dest, "%u", val_u16);
++ break;
++ }
++ case OPTION_U32: {
++ uint32_t val_u32 = get_be32(option);
++ dest += sprintf(dest, "%u", val_u32);
++ break;
++ }
++ case OPTION_STRING:
++ memcpy(dest, option, len);
++ dest[len] = '\0';
++ return ret;
++ default:
++ break;
++ }
++ option += optlen;
++ len -= optlen;
++ if (len <= 0)
++ break;
++ *dest++ = ' ';
++ *dest = '\0';
++ }
++
++ return ret;
++}
++
+ uint8_t *dhcpv6_get_option(struct dhcpv6_packet *packet, uint16_t pkt_len,
+ int code, uint16_t *option_len, int *option_count)
+ {
+diff --git a/gdhcp/common.h b/gdhcp/common.h
+index c692799..1ab9a7c 100644
+--- a/gdhcp/common.h
++++ b/gdhcp/common.h
+@@ -170,6 +170,7 @@ static const uint8_t dhcp_option_lengths[] = {
+ [OPTION_U32] = 4,
+ };
+
++char *malloc_option_value_string(uint8_t *option, GDHCPOptionType type);
+ uint8_t *dhcp_get_option(struct dhcp_packet *packet, int code);
+ uint8_t *dhcpv6_get_option(struct dhcpv6_packet *packet, uint16_t pkt_len,
+ int code, uint16_t *option_len, int *option_count);
+diff --git a/gdhcp/gdhcp.h b/gdhcp/gdhcp.h
+index f3e47bf..f4ef292 100644
+--- a/gdhcp/gdhcp.h
++++ b/gdhcp/gdhcp.h
+@@ -205,6 +205,9 @@ struct _GDHCPServer;
+
+ typedef struct _GDHCPServer GDHCPServer;
+
++typedef void (*GDHCPSaveACKLeaseFunc) (char *hostname,
++ unsigned char *mac, unsigned int nip);
++
+ GDHCPServer *g_dhcp_server_new(GDHCPType type,
+ int ifindex, GDHCPServerError *error);
+ int g_dhcp_server_start(GDHCPServer *server);
+@@ -223,6 +226,8 @@ void g_dhcp_server_set_lease_time(GDHCPServer *dhcp_server,
+ unsigned int lease_time);
+ void g_dhcp_server_set_save_lease(GDHCPServer *dhcp_server,
+ GDHCPSaveLeaseFunc func, gpointer user_data);
++void g_dhcp_server_set_save_ack_lease(GDHCPServer *dhcp_server,
++ GDHCPSaveACKLeaseFunc func, gpointer user_data);
+ #ifdef __cplusplus
+ }
+ #endif
+diff --git a/gdhcp/server.c b/gdhcp/server.c
+index aa40488..0171b5f 100644
+--- a/gdhcp/server.c
++++ b/gdhcp/server.c
+@@ -65,6 +65,7 @@ struct _GDHCPServer {
+ GHashTable *nip_lease_hash;
+ GHashTable *option_hash; /* Options send to client */
+ GDHCPSaveLeaseFunc save_lease_func;
++ GDHCPSaveACKLeaseFunc save_ack_lease_func;
+ GDHCPDebugFunc debug_func;
+ gpointer debug_data;
+ };
+@@ -398,6 +399,7 @@ GDHCPServer *g_dhcp_server_new(GDHCPType type,
+ dhcp_server->listener_watch = -1;
+ dhcp_server->listener_channel = NULL;
+ dhcp_server->save_lease_func = NULL;
++ dhcp_server->save_ack_lease_func = NULL;
+ dhcp_server->debug_func = NULL;
+ dhcp_server->debug_data = NULL;
+
+@@ -646,9 +648,12 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
+ struct dhcp_packet packet;
+ struct dhcp_lease *lease;
+ uint32_t requested_nip = 0;
+- uint8_t type, *server_id_option, *request_ip_option;
++ uint8_t type, *server_id_option, *request_ip_option, *host_name;
+ int re;
+
++ GDHCPOptionType option_type;
++ char *option_value;
++
+ if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+ dhcp_server->listener_watch = 0;
+ return FALSE;
+@@ -693,8 +698,21 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
+
+ if (lease && requested_nip == lease->lease_nip) {
+ debug(dhcp_server, "Sending ACK");
++
++ host_name = dhcp_get_option(&packet, DHCP_HOST_NAME);
++ option_type = dhcp_get_code_type(DHCP_HOST_NAME);
++ option_value = malloc_option_value_string(host_name,
++ option_type);
+ send_ACK(dhcp_server, &packet,
+ lease->lease_nip);
++
++ if (dhcp_server->save_ack_lease_func)
++ dhcp_server->save_ack_lease_func(
++ option_value,
++ lease->lease_mac,
++ lease->lease_nip);
++ g_free(option_value);
++
+ break;
+ }
+
+@@ -814,6 +832,15 @@ void g_dhcp_server_set_save_lease(GDHCPServer *dhcp_server,
+ dhcp_server->save_lease_func = func;
+ }
+
++void g_dhcp_server_set_save_ack_lease(GDHCPServer *dhcp_server,
++ GDHCPSaveACKLeaseFunc func, gpointer user_data)
++{
++ if (dhcp_server == NULL)
++ return;
++
++ dhcp_server->save_ack_lease_func = func;
++}
++
+ GDHCPServer *g_dhcp_server_ref(GDHCPServer *dhcp_server)
+ {
+ if (!dhcp_server)
+--
+1.8.1.4
+
--- /dev/null
+From b846a12300fa054beb16e97add2d13cd8e2496ae Mon Sep 17 00:00:00 2001
+From: Chengyi Zhao <chengyi1.zhao@archermind.com>
+Date: Wed, 10 Jul 2013 20:00:36 +0800
+Subject: [PATCH 19/32] Tethering: Notify listeners when station connection
+ changes
+
+Change-Id: I048c1a8a348b6f862ca104ad2fbe971f580fe180
+---
+ src/technology.c | 10 +++++++
+ src/tethering.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 94 insertions(+), 1 deletion(-)
+
+diff --git a/src/technology.c b/src/technology.c
+index d80d9e6..a06efd3 100644
+--- a/src/technology.c
++++ b/src/technology.c
+@@ -1070,6 +1070,16 @@ static const GDBusMethodTable technology_methods[] = {
+ static const GDBusSignalTable technology_signals[] = {
+ { GDBUS_SIGNAL("PropertyChanged",
+ GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
++ { GDBUS_SIGNAL("DhcpConnected",
++ GDBUS_ARGS({ "aptype", "s" },
++ { "ipaddr", "s" },
++ { "macaddr", "s" },
++ { "hostname", "s" })) },
++ { GDBUS_SIGNAL("DhcpLeaseDeleted",
++ GDBUS_ARGS({ "aptype", "s" },
++ { "ipaddr", "s" },
++ { "macaddr", "s" },
++ { "hostname", "s" })) },
+ { },
+ };
+
+diff --git a/src/tethering.c b/src/tethering.c
+index 0cbf06c..c0c9743 100644
+--- a/src/tethering.c
++++ b/src/tethering.c
+@@ -89,6 +89,32 @@ struct connman_station_info {
+ char hostname[CONNMAN_STATION_STR_INFO_LEN];
+ };
+
++static void emit_station_signal(char *action_str,
++ const struct connman_station_info *station_info)
++{
++ char *ip, *mac, *hostname;
++
++ if (station_info->path == NULL || station_info->type == NULL
++ || station_info->ip == NULL || station_info->mac == NULL
++ || station_info->hostname == NULL)
++ return;
++
++ ip = g_strdup(station_info->ip);
++ mac = g_strdup(station_info->mac);
++ hostname = g_strdup(station_info->hostname);
++
++ g_dbus_emit_signal(connection, station_info->path,
++ CONNMAN_TECHNOLOGY_INTERFACE, action_str,
++ DBUS_TYPE_STRING, &station_info->type,
++ DBUS_TYPE_STRING, &ip,
++ DBUS_TYPE_STRING, &mac,
++ DBUS_TYPE_STRING, &hostname,
++ DBUS_TYPE_INVALID);
++
++ g_free(ip);
++ g_free(mac);
++ g_free(hostname);
++}
+ static void destroy_station(gpointer key, gpointer value, gpointer user_data)
+ {
+ struct connman_station_info *station_info;
+@@ -97,11 +123,59 @@ static void destroy_station(gpointer key, gpointer value, gpointer user_data)
+
+ station_info = value;
+
++ if (station_info->is_connected) {
++ station_info->is_connected = FALSE;
++ emit_station_signal("DhcpLeaseDeleted", station_info);
++ }
++
+ g_free(station_info->path);
+ g_free(station_info->type);
+ g_free(station_info);
+ }
+
++static void save_dhcp_ack_lease_info(char *hostname,
++ unsigned char *mac, unsigned int nip)
++{
++ char *lower_mac;
++ const char *ip;
++ char sta_mac[CONNMAN_STATION_MAC_INFO_LEN];
++ struct connman_station_info *info_found;
++ struct in_addr addr;
++ int str_len;
++
++ __sync_synchronize();
++
++ snprintf(sta_mac, CONNMAN_STATION_MAC_INFO_LEN,
++ "%02x:%02x:%02x:%02x:%02x:%02x",
++ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
++ lower_mac = g_ascii_strdown(sta_mac, -1);
++
++ info_found = g_hash_table_lookup(sta_hash, lower_mac);
++ if (info_found == NULL) {
++ g_free(lower_mac);
++ return;
++ }
++
++ /* get the ip */
++ addr.s_addr = nip;
++ ip = inet_ntoa(addr);
++ str_len = strlen(ip) + 1;
++ if (str_len > CONNMAN_STATION_STR_INFO_LEN)
++ str_len = CONNMAN_STATION_STR_INFO_LEN - 1;
++ memcpy(info_found->ip, ip, str_len);
++
++ /* get hostname */
++ str_len = strlen(hostname) + 1;
++ if (str_len > CONNMAN_STATION_STR_INFO_LEN)
++ str_len = CONNMAN_STATION_STR_INFO_LEN - 1;
++ memcpy(info_found->hostname, hostname, str_len);
++
++ /* emit a signal */
++ info_found->is_connected = TRUE;
++ emit_station_signal("DhcpConnected", info_found);
++ g_free(lower_mac);
++}
++
+ int connman_technology_tethering_add_station(enum connman_service_type type,
+ const char *mac)
+ {
+@@ -146,9 +220,15 @@ int connman_technology_tethering_remove_station(const char *mac)
+ lower_mac = g_ascii_strdown(mac, -1);
+
+ info_found = g_hash_table_lookup(sta_hash, lower_mac);
+- if (info_found == NULL)
++ if (info_found == NULL) {
++ g_free(lower_mac);
+ return -EACCES;
++ }
+
++ if (info_found->is_connected) {
++ info_found->is_connected = FALSE;
++ emit_station_signal("DhcpLeaseDeleted", info_found);
++ }
+ g_free(lower_mac);
+ g_hash_table_remove(sta_hash, info_found->mac);
+ g_free(info_found->path);
+@@ -243,6 +323,9 @@ static GDHCPServer *dhcp_server_start(const char *bridge,
+ g_dhcp_server_set_option(dhcp_server, G_DHCP_DNS_SERVER, dns);
+ g_dhcp_server_set_ip_range(dhcp_server, start_ip, end_ip);
+
++ g_dhcp_server_set_save_ack_lease(dhcp_server,
++ save_dhcp_ack_lease_info, NULL);
++
+ g_dhcp_server_start(dhcp_server);
+
+ return dhcp_server;
+--
+1.8.1.4
+
--- /dev/null
+From d0fcec2219e62723f4ed4e67e1724b8dc2c1cd96 Mon Sep 17 00:00:00 2001
+From: Chengyi Zhao <chengyi1.zhao@archermind.com>
+Date: Thu, 11 Jul 2013 09:12:01 +0800
+Subject: [PATCH 20/32] Tethering: Add open access point support in technology
+
+Change-Id: I86f4a22567f5df2fbd5d0c0c03c6cc5b6fc24a2d
+---
+ src/technology.c | 36 +++++++++++++++++++++++-------------
+ 1 file changed, 23 insertions(+), 13 deletions(-)
+
+diff --git a/src/technology.c b/src/technology.c
+index a06efd3..be66c3a 100644
+--- a/src/technology.c
++++ b/src/technology.c
+@@ -245,8 +245,7 @@ static int set_tethering(struct connman_technology *technology,
+ if (!bridge)
+ return -EOPNOTSUPP;
+
+- if (technology->type == CONNMAN_SERVICE_TYPE_WIFI &&
+- (!ident || !passphrase))
++ if (technology->type == CONNMAN_SERVICE_TYPE_WIFI && (!ident))
+ return -EINVAL;
+
+ for (tech_drivers = technology->driver_list; tech_drivers;
+@@ -912,19 +911,30 @@ static DBusMessage *set_property(DBusConnection *conn,
+ if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
+ return __connman_error_not_supported(msg);
+
+- if (strlen(str) < 8 || strlen(str) > 63)
+- return __connman_error_passphrase_required(msg);
++ if (strlen(str) < 8 || strlen(str) > 63) {
++ if (g_str_equal(str, "")) {
++ technology->tethering_passphrase = NULL;
+
+- if (g_strcmp0(technology->tethering_passphrase, str) != 0) {
+- g_free(technology->tethering_passphrase);
+- technology->tethering_passphrase = g_strdup(str);
+- technology_save(technology);
++ connman_dbus_property_changed_basic(technology->path,
++ CONNMAN_TECHNOLOGY_INTERFACE,
++ "TetheringPassphrase",
++ DBUS_TYPE_STRING,
++ &str);
++ }
++ else
++ return __connman_error_passphrase_required(msg);
++ } else {
++ if (g_strcmp0(technology->tethering_passphrase, str) != 0) {
++ g_free(technology->tethering_passphrase);
++ technology->tethering_passphrase = g_strdup(str);
++ technology_save(technology);
+
+- connman_dbus_property_changed_basic(technology->path,
+- CONNMAN_TECHNOLOGY_INTERFACE,
+- "TetheringPassphrase",
+- DBUS_TYPE_STRING,
+- &technology->tethering_passphrase);
++ connman_dbus_property_changed_basic(technology->path,
++ CONNMAN_TECHNOLOGY_INTERFACE,
++ "TetheringPassphrase",
++ DBUS_TYPE_STRING,
++ &technology->tethering_passphrase);
++ }
+ }
+ } else if (g_str_equal(name, "Powered")) {
+ dbus_bool_t enable;
+--
+1.8.1.4
+
--- /dev/null
+From cdc3af7c29f82b71c2ce76fb6aa28dd6b3d9e5cd Mon Sep 17 00:00:00 2001
+From: Chengyi Zhao <chengyi1.zhao@archermind.com>
+Date: Thu, 11 Jul 2013 10:00:31 +0800
+Subject: [PATCH 21/32] Tethering: Add hidden access point support in
+ technology
+
+Change-Id: I73fccf5f322ee2597f8f58d5e3d7f60ddeb0a641
+---
+ doc/technology-api.txt | 5 +++++
+ gsupplicant/gsupplicant.h | 7 +++++++
+ gsupplicant/supplicant.c | 4 ++++
+ include/technology.h | 2 +-
+ plugins/bluetooth.c | 2 +-
+ plugins/bluetooth_legacy.c | 2 +-
+ plugins/ethernet.c | 2 +-
+ plugins/gadget.c | 2 +-
+ plugins/wifi.c | 13 ++++++++++---
+ src/technology.c | 33 ++++++++++++++++++++++++++++++++-
+ 10 files changed, 63 insertions(+), 9 deletions(-)
+
+diff --git a/doc/technology-api.txt b/doc/technology-api.txt
+index f97eac0..2fbc876 100644
+--- a/doc/technology-api.txt
++++ b/doc/technology-api.txt
+@@ -97,3 +97,8 @@ Properties boolean Powered [readwrite]
+ This property is only valid for the WiFi technology,
+ and is then mapped to the WPA pre-shared key clients
+ will have to use in order to establish a connection.
++
++ boolean Hidden [readwrite]
++
++ This option allows to enable or disable the support
++ for the hidden Wi-Fi tethering.
+diff --git a/gsupplicant/gsupplicant.h b/gsupplicant/gsupplicant.h
+index 1fab1ba..c5dad72 100644
+--- a/gsupplicant/gsupplicant.h
++++ b/gsupplicant/gsupplicant.h
+@@ -129,6 +129,12 @@ typedef enum {
+ G_SUPPLICANT_PEER_GROUP_FAILED,
+ } GSupplicantPeerState;
+
++enum GSupplicantAPHiddenSSID {
++ G_SUPPLICANT_AP_NO_SSID_HIDING,
++ G_SUPPLICANT_AP_HIDDEN_SSID_ZERO_LEN,
++ G_SUPPLICANT_AP_HIDDEN_SSID_ZERO_CONTENTS,
++};
++
+ struct _GSupplicantSSID {
+ const void *ssid;
+ unsigned int ssid_len;
+@@ -150,6 +156,7 @@ struct _GSupplicantSSID {
+ dbus_bool_t use_wps;
+ const char *pin_wps;
+ const char *bgscan;
++ int ignore_broadcast_ssid;
+ };
+
+ typedef struct _GSupplicantSSID GSupplicantSSID;
+diff --git a/gsupplicant/supplicant.c b/gsupplicant/supplicant.c
+index 5ff9b3d..59bf279 100644
+--- a/gsupplicant/supplicant.c
++++ b/gsupplicant/supplicant.c
+@@ -4659,6 +4659,10 @@ static void interface_add_network_params(DBusMessageIter *iter, void *user_data)
+ DBUS_TYPE_BYTE, &ssid->ssid,
+ ssid->ssid_len);
+
++ supplicant_dbus_dict_append_basic(&dict, "ignore_broadcast_ssid",
++ DBUS_TYPE_INT32,
++ &ssid->ignore_broadcast_ssid);
++
+ supplicant_dbus_dict_close(iter, &dict);
+ }
+
+diff --git a/include/technology.h b/include/technology.h
+index b13d4ec..8efe9e7 100644
+--- a/include/technology.h
++++ b/include/technology.h
+@@ -63,7 +63,7 @@ struct connman_technology_driver {
+ int index);
+ int (*set_tethering) (struct connman_technology *technology,
+ const char *identifier, const char *passphrase,
+- const char *bridge, bool enabled);
++ const char *bridge, bool enabled, bool hidden);
+ int (*set_regdom) (struct connman_technology *technology,
+ const char *alpha2);
+ };
+diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c
+index 28df406..f8abeac 100644
+--- a/plugins/bluetooth.c
++++ b/plugins/bluetooth.c
+@@ -854,7 +854,7 @@ static void bluetooth_tech_remove(struct connman_technology *technology)
+
+ static int bluetooth_tech_set_tethering(struct connman_technology *technology,
+ const char *identifier, const char *passphrase,
+- const char *bridge, bool enabled)
++ const char *bridge, bool enabled, bool hidden)
+ {
+ GHashTableIter hash_iter;
+ gpointer key, value;
+diff --git a/plugins/bluetooth_legacy.c b/plugins/bluetooth_legacy.c
+index 2d7a9e0..a9ff574 100644
+--- a/plugins/bluetooth_legacy.c
++++ b/plugins/bluetooth_legacy.c
+@@ -1234,7 +1234,7 @@ static void disable_nap(gpointer key, gpointer value, gpointer user_data)
+
+ static int tech_set_tethering(struct connman_technology *technology,
+ const char *identifier, const char *passphrase,
+- const char *bridge, bool enabled)
++ const char *bridge, bool enabled, bool hidden)
+ {
+ struct tethering_info info = {
+ .technology = technology,
+diff --git a/plugins/ethernet.c b/plugins/ethernet.c
+index b8e52ce..4e71346 100644
+--- a/plugins/ethernet.c
++++ b/plugins/ethernet.c
+@@ -309,7 +309,7 @@ static void eth_tech_disable_tethering(struct connman_technology *technology,
+
+ static int eth_tech_set_tethering(struct connman_technology *technology,
+ const char *identifier, const char *passphrase,
+- const char *bridge, bool enabled)
++ const char *bridge, bool enabled, bool hidden)
+ {
+ if (!connman_technology_is_tethering_allowed(
+ CONNMAN_SERVICE_TYPE_ETHERNET))
+diff --git a/plugins/gadget.c b/plugins/gadget.c
+index 94f6648..97807d8 100644
+--- a/plugins/gadget.c
++++ b/plugins/gadget.c
+@@ -291,7 +291,7 @@ static void gadget_tech_disable_tethering(struct connman_technology *technology,
+
+ static int gadget_tech_set_tethering(struct connman_technology *technology,
+ const char *identifier, const char *passphrase,
+- const char *bridge, bool enabled)
++ const char *bridge, bool enabled, bool hidden)
+ {
+ DBG("bridge %s enabled %d", bridge, enabled);
+
+diff --git a/plugins/wifi.c b/plugins/wifi.c
+index b5bc3ba..21f9912 100644
+--- a/plugins/wifi.c
++++ b/plugins/wifi.c
+@@ -2927,7 +2927,8 @@ struct wifi_tethering_info {
+ GSupplicantSSID *ssid;
+ };
+
+-static GSupplicantSSID *ssid_ap_init(const char *ssid, const char *passphrase)
++static GSupplicantSSID *ssid_ap_init(const char *ssid,
++ const char *passphrase, bool hidden)
+ {
+ GSupplicantSSID *ap;
+
+@@ -2952,6 +2953,12 @@ static GSupplicantSSID *ssid_ap_init(const char *ssid, const char *passphrase)
+ ap->passphrase = passphrase;
+ }
+
++ if (hidden)
++ ap->ignore_broadcast_ssid =
++ G_SUPPLICANT_AP_HIDDEN_SSID_ZERO_CONTENTS;
++ else
++ ap->ignore_broadcast_ssid = G_SUPPLICANT_AP_NO_SSID_HIDING;
++
+ return ap;
+ }
+
+@@ -3032,7 +3039,7 @@ static void sta_remove_callback(int result,
+
+ static int tech_set_tethering(struct connman_technology *technology,
+ const char *identifier, const char *passphrase,
+- const char *bridge, bool enabled)
++ const char *bridge, bool enabled, bool hidden)
+ {
+ GList *list;
+ GSupplicantInterface *interface;
+@@ -3085,7 +3092,7 @@ static int tech_set_tethering(struct connman_technology *technology,
+ info->wifi = wifi;
+ info->technology = technology;
+ info->wifi->bridge = bridge;
+- info->ssid = ssid_ap_init(identifier, passphrase);
++ info->ssid = ssid_ap_init(identifier, passphrase, hidden);
+ if (!info->ssid) {
+ g_free(info);
+ continue;
+diff --git a/src/technology.c b/src/technology.c
+index be66c3a..679c779 100644
+--- a/src/technology.c
++++ b/src/technology.c
+@@ -66,6 +66,7 @@ struct connman_technology {
+ */
+ char *tethering_ident;
+ char *tethering_passphrase;
++ bool tethering_hidden;
+
+ bool enable_persistent; /* Save the tech state */
+
+@@ -177,6 +178,9 @@ static void technology_save(struct connman_technology *technology)
+ g_key_file_set_boolean(keyfile, identifier, "Tethering",
+ technology->tethering_persistent);
+
++ g_key_file_set_boolean(keyfile, identifier, "Hidden",
++ technology->tethering_hidden);
++
+ if (technology->tethering_ident)
+ g_key_file_set_string(keyfile, identifier,
+ "Tethering.Identifier",
+@@ -233,9 +237,11 @@ static int set_tethering(struct connman_technology *technology,
+ int err;
+ const char *ident, *passphrase, *bridge;
+ GSList *tech_drivers;
++ bool hidden;
+
+ ident = technology->tethering_ident;
+ passphrase = technology->tethering_passphrase;
++ hidden = technology->tethering_hidden;
+
+ __sync_synchronize();
+ if (!technology->enabled)
+@@ -256,7 +262,7 @@ static int set_tethering(struct connman_technology *technology,
+ continue;
+
+ err = driver->set_tethering(technology, ident, passphrase,
+- bridge, enabled);
++ bridge, enabled, hidden);
+
+ if (result == -EINPROGRESS)
+ continue;
+@@ -523,6 +529,11 @@ static void append_properties(DBusMessageIter *iter,
+ DBUS_TYPE_STRING,
+ &technology->tethering_passphrase);
+
++ val = technology->tethering_hidden;
++ connman_dbus_dict_append_basic(&dict, "Hidden",
++ DBUS_TYPE_BOOLEAN,
++ &val);
++
+ connman_dbus_dict_close(iter, &dict);
+ }
+
+@@ -936,6 +947,25 @@ static DBusMessage *set_property(DBusConnection *conn,
+ &technology->tethering_passphrase);
+ }
+ }
++ } else if (g_str_equal(name, "Hidden")) {
++ dbus_bool_t hidden;
++
++ if (type != DBUS_TYPE_BOOLEAN)
++ return __connman_error_invalid_arguments(msg);
++
++ dbus_message_iter_get_basic(&value, &hidden);
++
++ if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
++ return __connman_error_not_supported(msg);
++
++ technology->tethering_hidden = hidden;
++ technology_save(technology);
++
++ connman_dbus_property_changed_basic(technology->path,
++ CONNMAN_TECHNOLOGY_INTERFACE,
++ "Hidden",
++ DBUS_TYPE_BOOLEAN,
++ &hidden);
+ } else if (g_str_equal(name, "Powered")) {
+ dbus_bool_t enable;
+
+@@ -1204,6 +1234,7 @@ static struct connman_technology *technology_get(enum connman_service_type type)
+
+ technology->refcount = 1;
+ technology->type = type;
++ technology->tethering_hidden = FALSE;
+ technology->path = g_strdup_printf("%s/technology/%s",
+ CONNMAN_PATH, str);
+ if (type == CONNMAN_SERVICE_TYPE_P2P) {
+--
+1.8.1.4
+
--- /dev/null
+From 395d388931d37b6760d7b9f59a5710dfe42662c7 Mon Sep 17 00:00:00 2001
+From: Chengyi Zhao <chengyi1.zhao@archermind.com>
+Date: Thu, 11 Jul 2013 10:29:38 +0800
+Subject: [PATCH 22/32] Tethering: Add test script of open and hidden AP
+
+Change-Id: I8dbeaeba5848c8a8739422a93786b2ca6ed31b21
+---
+ test/enable-tethering | 34 +++++++++++++++++++++++++++-------
+ 1 file changed, 27 insertions(+), 7 deletions(-)
+ mode change 100755 => 100644 test/enable-tethering
+
+diff --git a/test/enable-tethering b/test/enable-tethering
+old mode 100755
+new mode 100644
+index cbcd4e7..674b3c9
+--- a/test/enable-tethering
++++ b/test/enable-tethering
+@@ -3,8 +3,17 @@
+ import sys
+ import dbus
+
+-if (len(sys.argv) >= 3 and len(sys.argv) != 4 and sys.argv[1] == "wifi"):
+- print "Usage: %s wifi [SSID] [passphrase]" % (sys.argv[0])
++if (len(sys.argv) >= 2 and len(sys.argv) < 4 and sys.argv[1] == "wifi"):
++ print "Usage: %s wifi [SSID] [passphrase] [hidden]" % (sys.argv[0])
++ print "Example:"
++ print "Create the open system access point:"
++ print "%s wifi abcd \"\"" % (sys.argv[0])
++ print "Create the security access point:"
++ print "%s wifi abcd 123456789" % (sys.argv[0])
++ print "Create the hidden access point:"
++ print "%s wifi abcd 123456789 hidden" % (sys.argv[0])
++ print "Create the open and hidden access point:"
++ print "%s wifi abcd \"\" hidden" % (sys.argv[0])
+ sys.exit(1)
+ elif (len(sys.argv) < 2):
+ print "Usage: %s type" % (sys.argv[0])
+@@ -15,7 +24,7 @@ bus = dbus.SystemBus()
+ manager = dbus.Interface(bus.get_object('net.connman', "/"),
+ 'net.connman.Manager')
+
+-def technology_enable_tethering(path, tech_type, ssid, psk):
++def technology_enable_tethering(path, tech_type, ssid, psk, hidden):
+ tech = dbus.Interface(bus.get_object("net.connman", path),
+ "net.connman.Technology")
+
+@@ -27,9 +36,17 @@ def technology_enable_tethering(path, tech_type, ssid, psk):
+ if len(ssid) > 0:
+ tech.SetProperty("TetheringIdentifier",
+ ssid)
+- if len(psk) > 0:
+ tech.SetProperty("TetheringPassphrase",
+ psk)
++ if tech_type == "wifi":
++ if len(hidden) > 0:
++ if hidden == "hidden":
++ tech.SetProperty("Hidden",dbus.Boolean(1))
++ else:
++ tech.SetProperty("Hidden",dbus.Boolean(0))
++ else:
++ tech.SetProperty("Hidden",dbus.Boolean(0))
++
+ print "Enabling %s tethering" % tech_type
+ tech.SetProperty("Tethering", dbus.Boolean(1))
+
+@@ -41,11 +58,14 @@ technologies = manager.GetTechnologies()
+ tech = None
+
+ for path,_ in technologies:
+- if (len(sys.argv) == 4):
++ if (len(sys.argv) == 5):
++ tech = technology_enable_tethering(path,
++ sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4])
++ elif (len(sys.argv) == 4):
+ tech = technology_enable_tethering(path,
+- sys.argv[1], sys.argv[2], sys.argv[3])
++ sys.argv[1], sys.argv[2], sys.argv[3], "")
+ else:
+- tech = technology_enable_tethering(path, sys.argv[1], "", "")
++ tech = technology_enable_tethering(path, sys.argv[1], "", "", "")
+
+ if tech != None:
+ break;
+--
+1.8.1.4
+
--- /dev/null
+From 5eb028f4bdf85b35d8003f36ee95b15e48aa3fbc Mon Sep 17 00:00:00 2001
+From: Chengyi Zhao <chengyi1.zhao@archermind.com>
+Date: Fri, 26 Jul 2013 14:58:32 +0800
+Subject: [PATCH 23/32] Tethering: Add tethering interfaces description to
+ technology-api.txt
+
+Change-Id: I59768258d5f2515311ed3dad5db91618b1c459ec
+---
+ doc/technology-api.txt | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/doc/technology-api.txt b/doc/technology-api.txt
+index 2fbc876..14245eb 100644
+--- a/doc/technology-api.txt
++++ b/doc/technology-api.txt
+@@ -45,6 +45,18 @@ Signals PropertyChanged(string name, variant value)
+ This signal indicates a changed value of the given
+ property.
+
++ DhcpConnected(string aptype, string ipaddr,
++ string macaddr, string hostname)
++
++ This signal indicates a station information that
++ has connected to the AP(Access Point).
++
++ DhcpLeaseDeleted(string aptype, string ipaddr,
++ string macaddr, string hostname)
++
++ This signal indicates a station information that
++ has disconnected to the AP(Access Point).
++
+ Properties boolean Powered [readwrite]
+
+ Boolean representing the power state of the
+--
+1.8.1.4
+
--- /dev/null
+From 4f74881432eee7f368ae6827aa2453115749734e Mon Sep 17 00:00:00 2001
+From: Chengyi Zhao <chengyix.zhao@gmail.com>
+Date: Sun, 22 Sep 2013 14:14:06 +0800
+Subject: [PATCH 24/32] Tethering: Watch the connection and disconnection
+ signal of Bluetooth
+
+Signed-off-by: Chengyi Zhao <chengyix.zhao@intel.com>
+
+Change-Id: I38bb9b799c3e4c4c25acd9d264a4225bf59401dc
+---
+ plugins/bluetooth_legacy.c | 75 ++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 72 insertions(+), 3 deletions(-)
+
+diff --git a/plugins/bluetooth_legacy.c b/plugins/bluetooth_legacy.c
+index a9ff574..5a9a395 100644
+--- a/plugins/bluetooth_legacy.c
++++ b/plugins/bluetooth_legacy.c
+@@ -51,6 +51,9 @@
+ #define ADAPTER_REMOVED "AdapterRemoved"
+ #define DEVICE_REMOVED "DeviceRemoved"
+
++#define PEER_CONNECTED "PeerConnected"
++#define PEER_DISCONNECTED "PeerDisconnected"
++
+ #define PROPERTY_CHANGED "PropertyChanged"
+ #define GET_PROPERTIES "GetProperties"
+ #define SET_PROPERTY "SetProperty"
+@@ -334,6 +337,53 @@ static gboolean network_changed(DBusConnection *conn,
+ return TRUE;
+ }
+
++static void parse_peer_device(DBusMessage *message, char **dev,
++ char **address)
++{
++ const char *path = dbus_message_get_path(message);
++ DBusMessageIter iter;
++
++ DBG("path %s", path);
++
++ if (dbus_message_iter_init(message, &iter) == FALSE)
++ return;
++
++ dbus_message_iter_get_basic(&iter, dev);
++ dbus_message_iter_next(&iter);
++ dbus_message_iter_get_basic(&iter, address);
++}
++
++static gboolean peer_connected(DBusConnection *connection,
++ DBusMessage *message, void *user_data)
++{
++ char *dev, *address;
++
++ parse_peer_device(message, &dev, &address);
++
++ DBG("connection device is %s", dev);
++ DBG("connection address is %s", address);
++
++ connman_technology_tethering_add_station(
++ CONNMAN_SERVICE_TYPE_BLUETOOTH, address);
++
++ return TRUE;
++}
++
++static gboolean peer_disconnected(DBusConnection *connection,
++ DBusMessage *message, void *user_data)
++{
++ char *dev, *address;
++
++ parse_peer_device(message, &dev, &address);
++
++ DBG("disconnection device is %s", dev);
++ DBG("disconnection address is %s", address);
++
++ connman_technology_tethering_remove_station(address);
++
++ return TRUE;
++}
++
+ static void extract_properties(DBusMessage *reply, const char **parent,
+ const char **address,
+ const char **name,
+@@ -1270,6 +1320,8 @@ static guint adapter_watch;
+ static guint device_watch;
+ static guint device_removed_watch;
+ static guint network_watch;
++static guint peerconnected_watch;
++static guint peerdisconnected_watch;
+
+ static int bluetooth_init(void)
+ {
+@@ -1313,10 +1365,23 @@ static int bluetooth_init(void)
+ PROPERTY_CHANGED, network_changed,
+ NULL, NULL);
+
++ peerconnected_watch = g_dbus_add_signal_watch(connection,
++ BLUEZ_SERVICE,
++ NULL, BLUEZ_NETWORK_SERVER,
++ PEER_CONNECTED, peer_connected,
++ NULL, NULL);
++
++ peerdisconnected_watch = g_dbus_add_signal_watch(connection,
++ BLUEZ_SERVICE,
++ NULL, BLUEZ_NETWORK_SERVER,
++ PEER_DISCONNECTED,
++ peer_disconnected,
++ NULL, NULL);
++
+ if (watch == 0 || added_watch == 0 || removed_watch == 0
+- || adapter_watch == 0 || network_watch == 0
+- || device_watch == 0
+- || device_removed_watch == 0) {
++ || adapter_watch == 0 || network_watch == 0 || device_watch == 0
++ || peerconnected_watch == 0 || peerdisconnected_watch == 0
++ || device_removed_watch == 0) {
+ err = -EIO;
+ goto remove;
+ }
+@@ -1348,6 +1413,8 @@ remove:
+ g_dbus_remove_watch(connection, device_removed_watch);
+ g_dbus_remove_watch(connection, device_watch);
+ g_dbus_remove_watch(connection, network_watch);
++ g_dbus_remove_watch(connection, peerconnected_watch);
++ g_dbus_remove_watch(connection, peerdisconnected_watch);
+
+ dbus_connection_unref(connection);
+
+@@ -1363,6 +1430,8 @@ static void bluetooth_exit(void)
+ g_dbus_remove_watch(connection, device_removed_watch);
+ g_dbus_remove_watch(connection, device_watch);
+ g_dbus_remove_watch(connection, network_watch);
++ g_dbus_remove_watch(connection, peerconnected_watch);
++ g_dbus_remove_watch(connection, peerdisconnected_watch);
+
+ /*
+ * We unset the disabling of the Bluetooth device when shutting down
+--
+1.8.1.4
+
--- /dev/null
+From 58bd810c3a61593a3c7494f843fc5dfc1d411769 Mon Sep 17 00:00:00 2001
+From: "guoqiang.liu" <guoqiang.liu@archermind.com>
+Date: Wed, 25 Sep 2013 16:36:21 +0800
+Subject: [PATCH 25/32] Tethering: Get the client mac info of Gadget tether
+
+Change-Id: Icfa6cd683c659e6728060d6201b90109c63fe56d
+---
+ plugins/gadget.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 87 insertions(+)
+
+diff --git a/plugins/gadget.c b/plugins/gadget.c
+index 97807d8..6bc37a7 100644
+--- a/plugins/gadget.c
++++ b/plugins/gadget.c
+@@ -25,6 +25,8 @@
+
+ #include <errno.h>
+ #include <net/if.h>
++#include <stdio.h>
++#include <string.h>
+
+ #ifndef IFF_LOWER_UP
+ #define IFF_LOWER_UP 0x10000
+@@ -226,6 +228,71 @@ static struct connman_device_driver gadget_dev_driver = {
+ };
+
+ static GList *cdc_interface_list = NULL;
++static GHashTable *cdc_mac_hash = NULL;
++
++static void add_station(int index)
++{
++ char *path, line[128] = {'\0'};
++ char *ifname = connman_inet_ifname(index);
++ char *mac;
++ FILE *f;
++
++ if (ifname == NULL)
++ return;
++
++ path = g_strdup_printf("/sys/class/usb_mode/%s/f_rndis/ethaddr",
++ ifname);
++
++ f = fopen(path, "re");
++
++ g_free(ifname);
++ g_free(path);
++
++ if (f == NULL)
++ return;
++
++ if (fgets(line, sizeof(line), f) == NULL) {
++ fclose(f);
++ return;
++ }
++
++ fclose(f);
++
++ mac = g_ascii_strdown(line, strlen(line) - 1);
++ DBG("Add station %s in Technology %d", mac,
++ CONNMAN_SERVICE_TYPE_GADGET);
++
++ g_hash_table_insert(cdc_mac_hash, GINT_TO_POINTER(index),
++ mac);
++
++ connman_technology_tethering_add_station(CONNMAN_SERVICE_TYPE_GADGET,
++ mac);
++}
++
++static void remove_station(int index)
++{
++ char *mac;
++ mac = g_hash_table_lookup(cdc_mac_hash, GINT_TO_POINTER(index));
++ if (mac == NULL)
++ return;
++
++ connman_technology_tethering_remove_station(mac);
++
++ g_hash_table_remove(cdc_mac_hash, GINT_TO_POINTER(index));
++}
++
++static gboolean remove_all_station(gpointer key, gpointer value, gpointer user_data)
++{
++ char *mac;
++ mac = value;
++ if (mac == NULL)
++ return TRUE;
++
++ connman_technology_tethering_remove_station(mac);
++
++ return TRUE;
++}
++
+
+ static void gadget_tech_add_interface(struct connman_technology *technology,
+ int index, const char *name, const char *ident)
+@@ -246,6 +313,8 @@ static void gadget_tech_remove_interface(struct connman_technology *technology,
+
+ cdc_interface_list = g_list_remove(cdc_interface_list,
+ GINT_TO_POINTER((int) index));
++
++ remove_station(index);
+ }
+
+ static void gadget_tech_enable_tethering(struct connman_technology *technology,
+@@ -270,6 +339,8 @@ static void gadget_tech_enable_tethering(struct connman_technology *technology,
+ connman_inet_ifup(index);
+
+ connman_inet_add_to_bridge(index, bridge);
++
++ add_station(index);
+ }
+ }
+
+@@ -283,6 +354,8 @@ static void gadget_tech_disable_tethering(struct connman_technology *technology,
+
+ connman_inet_remove_from_bridge(index, bridge);
+
++ remove_station(index);
++
+ connman_inet_ifdown(index);
+
+ connman_technology_tethering_notify(technology, false);
+@@ -305,14 +378,28 @@ static int gadget_tech_set_tethering(struct connman_technology *technology,
+
+ static int gadget_tech_probe(struct connman_technology *technology)
+ {
++ DBG("tech probe %p", technology);
++
++ cdc_mac_hash = g_hash_table_new_full(g_direct_hash,
++ g_direct_equal, NULL, g_free);
++
+ return 0;
+ }
+
+ static void gadget_tech_remove(struct connman_technology *technology)
+ {
++ DBG("tech remove %p", technology);
++
+ g_list_free(cdc_interface_list);
+
+ cdc_interface_list = NULL;
++
++ if (cdc_mac_hash) {
++ g_hash_table_foreach_remove(cdc_mac_hash, remove_all_station,
++ NULL);
++ g_hash_table_destroy(cdc_mac_hash);
++ cdc_mac_hash = NULL;
++ }
+ }
+
+ static struct connman_technology_driver gadget_tech_driver = {
+--
+1.8.1.4
+
--- /dev/null
+From 113ccd0ca92ab8fe8a6e6c2db190cbcbeebe912d Mon Sep 17 00:00:00 2001
+From: Zhang zhengguang <zhengguang.zhang@intel.com>
+Date: Sat, 11 Oct 2014 15:06:14 +0800
+Subject: [PATCH 26/32] multi-user: Add function to get dbus user id
+ synchronously
+
+Change-Id: Ic41643e5f8b6e1a28ce00e0456d961fe2de7a7fb
+---
+ include/dbus.h | 4 ++++
+ src/dbus.c | 25 +++++++++++++++++++++++++
+ 2 files changed, 29 insertions(+)
+
+diff --git a/include/dbus.h b/include/dbus.h
+index 26f94d6..3087fe4 100644
+--- a/include/dbus.h
++++ b/include/dbus.h
+@@ -180,6 +180,10 @@ int connman_dbus_get_connection_unix_user(DBusConnection *connection,
+ connman_dbus_get_connection_unix_user_cb_t func,
+ void *user_data);
+
++int connman_dbus_get_connection_unix_user_sync(DBusConnection *connection,
++ const char *bus_name,
++ unsigned int *user_id);
++
+ typedef void (* connman_dbus_get_context_cb_t) (const unsigned char *context,
+ void *user_data, int err);
+
+diff --git a/src/dbus.c b/src/dbus.c
+index d80a46c..260cec6 100644
+--- a/src/dbus.c
++++ b/src/dbus.c
+@@ -524,6 +524,31 @@ err:
+ return err;
+ }
+
++int connman_dbus_get_connection_unix_user_sync(DBusConnection *connection,
++ const char *bus_name,
++ unsigned int *user_id)
++{
++ unsigned long uid;
++ DBusError err;
++
++ dbus_error_init(&err);
++
++ uid = dbus_bus_get_unix_user(connection, bus_name, &err);
++
++ if (uid == (unsigned long)-1) {
++ DBG("Can not get unix user ID!");
++ if (dbus_error_is_set(&err)) {
++ DBG("%s", err.message);
++ dbus_error_free(&err);
++ }
++ return -1;
++ }
++
++ *user_id = (unsigned int)uid;
++
++ return 0;
++}
++
+ static unsigned char *parse_context(DBusMessage *msg)
+ {
+ DBusMessageIter iter, array;
+--
+1.8.1.4
+
--- /dev/null
+From 44a0a44c579df0192ec33c291b2efdfabfe5c7eb Mon Sep 17 00:00:00 2001
+From: Zhang zhengguang <zhengguang.zhang@intel.com>
+Date: Sat, 11 Oct 2014 15:08:18 +0800
+Subject: [PATCH 27/32] multi-user: Add multi-user support in service
+
+Use cases:
+
+Given 2 users: UserA and UserB
+
+1. If UserA is connected to a wifi service, then UserB is not allowed
+to connect wifi service, and not allowed to disconnect the service
+UserA connected.
+
+2. If UserA is connected to a wifi service, then UserB is allowed to
+use the same connection, but he is not allowed to modify the connection.
+
+3. If UserA is connected to a wifi service with security wep/wpa/psk,
+then UserA disconnects it, when UserB tries to connect the same wifi
+service, it must input passphrase to connect it.
+
+Change-Id: Id686ebd7d1f3490875a9d8f877219bd004907227
+---
+ src/connman.h | 3 ++
+ src/service.c | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 159 insertions(+), 1 deletion(-)
+
+diff --git a/src/connman.h b/src/connman.h
+index 4d78eab..386e8c8 100644
+--- a/src/connman.h
++++ b/src/connman.h
+@@ -791,6 +791,9 @@ void __connman_service_notify(struct connman_service *service,
+ unsigned int rx_error, unsigned int tx_error,
+ unsigned int rx_dropped, unsigned int tx_dropped);
+
++bool __connman_service_is_user_allowed(enum connman_service_type type,
++ uid_t uid);
++
+ int __connman_service_counter_register(const char *counter);
+ void __connman_service_counter_unregister(const char *counter);
+
+diff --git a/src/service.c b/src/service.c
+index 99bb35d..a1124ae 100644
+--- a/src/service.c
++++ b/src/service.c
+@@ -39,6 +39,9 @@
+
+ #define CONNECT_TIMEOUT 120
+
++#define USER_ROOT 0
++#define USER_NONE (uid_t)-1
++
+ #if defined TIZEN_EXT
+ #define WIFI_BSSID_STR_LEN 18
+ #endif
+@@ -67,6 +70,11 @@ struct connman_stats_counter {
+ struct connman_stats stats_roaming;
+ };
+
++struct connman_service_user {
++ uid_t favorite_user;
++ uid_t current_user;
++};
++
+ struct connman_service {
+ int refcount;
+ char *identifier;
+@@ -89,6 +97,8 @@ struct connman_service {
+ char *name;
+ char *passphrase;
+ bool roaming;
++ bool request_passphrase_input;
++ struct connman_service_user user;
+ struct connman_ipconfig *ipconfig_ipv4;
+ struct connman_ipconfig *ipconfig_ipv6;
+ struct connman_network *network;
+@@ -351,6 +361,24 @@ static enum connman_service_proxy_method string2proxymethod(const char *method)
+ return CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
+ }
+
++static bool
++connman_service_is_user_allowed(struct connman_service *service, uid_t uid)
++{
++ uid_t favorite_user = service->user.favorite_user;
++ uid_t current_user = uid;
++
++ DBG("Service favorite UID: %d, current UID: %d", favorite_user, current_user);
++ if (favorite_user == USER_NONE || current_user == USER_ROOT)
++ return true;
++
++ if (favorite_user != current_user || current_user == USER_NONE) {
++ DBG("Current user is not a favorite user to this service!");
++ return false;
++ }
++
++ return true;
++}
++
+ int __connman_service_load_modifiable(struct connman_service *service)
+ {
+ GKeyFile *keyfile;
+@@ -574,6 +602,8 @@ static int service_load(struct connman_service *service)
+ service->hidden_service = g_key_file_get_boolean(keyfile,
+ service->identifier, "Hidden", NULL);
+
++ service->user.favorite_user = g_key_file_get_integer(keyfile,
++ service->identifier, "UID", NULL);
+ done:
+ g_key_file_free(keyfile);
+
+@@ -619,6 +649,9 @@ static int service_save(struct connman_service *service)
+ const unsigned char *ssid;
+ unsigned int ssid_len = 0;
+
++ g_key_file_set_integer(keyfile, service->identifier,
++ "UID", service->user.favorite_user);
++
+ ssid = connman_network_get_blob(service->network,
+ "WiFi.SSID", &ssid_len);
+
+@@ -3236,6 +3269,21 @@ static DBusMessage *set_property(DBusConnection *conn,
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return __connman_error_invalid_arguments(msg);
+
++ if (service->type == CONNMAN_SERVICE_TYPE_WIFI && is_connected(service)) {
++ uid_t uid;
++ if (connman_dbus_get_connection_unix_user_sync(conn,
++ dbus_message_get_sender(msg),
++ &uid) < 0) {
++ DBG("Can not get unix user id!");
++ return __connman_error_permission_denied(msg);
++ }
++
++ if (!connman_service_is_user_allowed(service, uid)) {
++ DBG("Not allow this user to operate this wifi service now!");
++ return __connman_error_permission_denied(msg);
++ }
++ }
++
+ dbus_message_iter_get_basic(&iter, &name);
+ dbus_message_iter_next(&iter);
+
+@@ -3997,6 +4045,26 @@ static DBusMessage *connect_service(DBusConnection *conn,
+ if (service->pending)
+ return __connman_error_in_progress(msg);
+
++ if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
++ uid_t uid;
++ if (connman_dbus_get_connection_unix_user_sync(conn,
++ dbus_message_get_sender(msg),
++ &uid) < 0) {
++ DBG("Can not get unix user id!");
++ return __connman_error_permission_denied(msg);
++ }
++
++ if (!__connman_service_is_user_allowed(CONNMAN_SERVICE_TYPE_WIFI, uid)) {
++ DBG("Not allow this user to connect this wifi service now!");
++ return __connman_error_permission_denied(msg);
++ }
++
++ if (uid != USER_ROOT && uid != service->user.favorite_user)
++ service->request_passphrase_input = true;
++
++ service->user.current_user = uid;
++ }
++
+ index = __connman_service_get_index(service);
+
+ for (list = service_list; list; list = list->next) {
+@@ -4048,6 +4116,21 @@ static DBusMessage *disconnect_service(DBusConnection *conn,
+
+ DBG("service %p", service);
+
++ if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
++ uid_t uid;
++ if (connman_dbus_get_connection_unix_user_sync(conn,
++ dbus_message_get_sender(msg),
++ &uid) < 0) {
++ DBG("Can not get unix user id!");
++ return __connman_error_permission_denied(msg);
++ }
++
++ if (!connman_service_is_user_allowed(service, uid)) {
++ DBG("Not allow this user to disconnect this wifi service now!");
++ return __connman_error_permission_denied(msg);
++ }
++ }
++
+ service->ignore = true;
+
+ err = __connman_service_disconnect(service);
+@@ -4103,6 +4186,21 @@ static DBusMessage *remove_service(DBusConnection *conn,
+
+ DBG("service %p", service);
+
++ if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
++ uid_t uid;
++ if (connman_dbus_get_connection_unix_user_sync(conn,
++ dbus_message_get_sender(msg),
++ &uid) < 0) {
++ DBG("Can not get unix user id!");
++ return __connman_error_permission_denied(msg);
++ }
++
++ if (!connman_service_is_user_allowed(service, uid)) {
++ DBG("Not allow this user to remove this wifi service now!");
++ return __connman_error_permission_denied(msg);
++ }
++ }
++
+ if (!__connman_service_remove(service))
+ return __connman_error_not_supported(msg);
+
+@@ -4583,6 +4681,11 @@ static void service_initialize(struct connman_service *service)
+
+ service->ignore = false;
+
++ service->user.favorite_user = USER_NONE;
++ service->user.current_user = USER_NONE;
++
++ service->request_passphrase_input = false;
++
+ service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_NONE;
+
+ service->order = 0;
+@@ -4809,6 +4912,40 @@ char *connman_service_get_interface(struct connman_service *service)
+ }
+
+ /**
++ * __connman_service_is_user_allowed:
++ * @type: service type
++ * @uid: user id
++ *
++ * Check a user is allowed to operate a type of service
++ */
++bool __connman_service_is_user_allowed(enum connman_service_type type,
++ uid_t uid)
++{
++ GList *list;
++ uid_t owner_user = USER_NONE;
++
++ for (list = service_list; list; list = list->next) {
++ struct connman_service *service = list->data;
++
++ if (service->type != type)
++ continue;
++
++ if (is_connected(service)) {
++ owner_user = service->user.favorite_user;
++ break;
++ }
++ }
++
++ if (uid == USER_NONE ||
++ (uid != USER_ROOT &&
++ owner_user != USER_NONE &&
++ owner_user != uid))
++ return false;
++
++ return true;
++}
++
++/**
+ * connman_service_get_network:
+ * @service: service structure
+ *
+@@ -5487,6 +5624,20 @@ static int service_indicate_state(struct connman_service *service)
+ default_changed();
+ }
+
++ if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
++ service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER &&
++ (new_state == CONNMAN_SERVICE_STATE_READY ||
++ new_state == CONNMAN_SERVICE_STATE_ONLINE)) {
++ if (service->user.favorite_user != service->user.current_user) {
++ DBG("Now set service favorite user id from %d to %d",
++ service->user.favorite_user, service->user.current_user);
++
++ service->user.favorite_user = service->user.current_user;
++
++ service_save(service);
++ }
++ }
++
+ return 0;
+ }
+
+@@ -5898,7 +6049,11 @@ static int service_connect(struct connman_service *service)
+ case CONNMAN_SERVICE_SECURITY_PSK:
+ case CONNMAN_SERVICE_SECURITY_WPA:
+ case CONNMAN_SERVICE_SECURITY_RSN:
+- if (!service->passphrase) {
++ if (service->request_passphrase_input) {
++ DBG("Now try to connect other user's favorite service");
++ service->request_passphrase_input = false;
++ return -ENOKEY;
++ } else if (!service->passphrase) {
+ if (!service->network)
+ return -EOPNOTSUPP;
+
+--
+1.8.1.4
+
--- /dev/null
+From 37cbead2d2cbea4b9bd9f7180caf26a4b653662d Mon Sep 17 00:00:00 2001
+From: Zhang zhengguang <zhengguang.zhang@intel.com>
+Date: Sat, 11 Oct 2014 15:09:09 +0800
+Subject: [PATCH 28/32] multi-user: Add multi-user support in technology
+
+Use case:
+
+Given 2 users: UserA and UserB
+
+If UserA is connected to a wifi service, then UserB is not allowed
+to set wifi technology properties.
+
+Change-Id: Ia783b22bc28e9e487ddfa3a4c249c9d1ea76bde8
+---
+ src/technology.c | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+diff --git a/src/technology.c b/src/technology.c
+index 679c779..70732f6 100644
+--- a/src/technology.c
++++ b/src/technology.c
+@@ -862,6 +862,21 @@ static DBusMessage *set_property(DBusConnection *conn,
+
+ DBG("property %s", name);
+
++ if (technology->type == CONNMAN_SERVICE_TYPE_WIFI && technology->connected) {
++ uid_t uid;
++ if (connman_dbus_get_connection_unix_user_sync(conn,
++ dbus_message_get_sender(msg),
++ &uid) < 0) {
++ DBG("Can not get unix user id!");
++ return __connman_error_permission_denied(msg);
++ }
++
++ if (!__connman_service_is_user_allowed(CONNMAN_SERVICE_TYPE_WIFI, uid)) {
++ DBG("Not allow this user to operate wifi technology now!");
++ return __connman_error_permission_denied(msg);
++ }
++ }
++
+ if (g_str_equal(name, "Tethering")) {
+ dbus_bool_t tethering;
+ int err;
+--
+1.8.1.4
+
--- /dev/null
+From 9235632fd02062efa3a1af7eb1957fdd364f4a8c Mon Sep 17 00:00:00 2001
+From: Zhang zhengguang <zhengguang.zhang@intel.com>
+Date: Fri, 17 Oct 2014 11:21:37 +0800
+Subject: [PATCH 29/32] multi-user: Add multi-user support in manager
+
+Use case:
+
+Given 2 users: UserA and UserB
+
+If UserA is connected to a wifi service, then UserB is not allowed
+to turn on offline mode.
+
+Change-Id: I54b108beb580a805c7fa2d3ae9dac192b836ba77
+---
+ src/manager.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/src/manager.c b/src/manager.c
+index d15ce20..bd52f39 100644
+--- a/src/manager.c
++++ b/src/manager.c
+@@ -102,6 +102,20 @@ static DBusMessage *set_property(DBusConnection *conn,
+
+ dbus_message_iter_get_basic(&value, &offlinemode);
+
++ if (offlinemode) {
++ uid_t uid;
++ if (connman_dbus_get_connection_unix_user_sync(conn,
++ dbus_message_get_sender(msg),
++ &uid) < 0) {
++ DBG("Can not get unix user id!");
++ return __connman_error_permission_denied(msg);
++ }
++
++ if (!__connman_service_is_user_allowed(CONNMAN_SERVICE_TYPE_WIFI, uid)) {
++ DBG("Not allow this user to turn on offlinemode now!");
++ return __connman_error_permission_denied(msg);
++ }
++ }
+ __connman_technology_set_offlinemode(offlinemode);
+ } else if (g_str_equal(name, "SessionMode")) {
+
+--
+1.8.1.4
+
--- /dev/null
+From 96469b8ff2cd0e7dc77b7974c431f1dd97981356 Mon Sep 17 00:00:00 2001
+From: Zhang zhengguang <zhengguang.zhang@intel.com>
+Date: Sat, 11 Oct 2014 16:46:50 +0800
+Subject: [PATCH 30/32] multi-user: Add multi-user support for auto connect
+ service
+
+Use case:
+
+For wifi auto connect mechamnism, only when the user who owns the
+wifi service login, the service is allowed to be auto connected.
+
+Change-Id: I99135117facafda41532e0280c89194b27baac16
+---
+ src/service.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 62 insertions(+)
+
+diff --git a/src/service.c b/src/service.c
+index a1124ae..55cf02c 100644
+--- a/src/service.c
++++ b/src/service.c
+@@ -30,6 +30,8 @@
+ #include <gdbus.h>
+ #include <ctype.h>
+ #include <stdint.h>
++#include <pwd.h>
++#include <utmpx.h>
+
+ #include <connman/storage.h>
+ #include <connman/setting.h>
+@@ -379,6 +381,61 @@ connman_service_is_user_allowed(struct connman_service *service, uid_t uid)
+ return true;
+ }
+
++static GList *connman_service_get_login_users()
++{
++ struct utmpx *utmp;
++ struct passwd *pwd;
++ GList *user_list = NULL;
++
++ setutxent();
++
++ while ((utmp = getutxent()) != NULL) {
++ if (utmp->ut_user != USER_ROOT && utmp->ut_type != USER_PROCESS)
++ continue;
++
++ pwd = getpwnam(utmp->ut_user);
++
++ if (!g_list_find(user_list, GUINT_TO_POINTER(pwd->pw_uid)))
++ user_list = g_list_append(user_list,
++ GUINT_TO_POINTER(pwd->pw_uid));
++
++ DBG("User Name: %s, UID: %d", utmp->ut_user, pwd->pw_uid);
++ }
++
++ endutxent();
++
++ return user_list;
++}
++
++static bool is_service_owner_user_login(struct connman_service *service)
++{
++ GList *list, *user_list;
++ bool ret = false;
++
++ /* Here we only care about wifi service */
++ if (service->type != CONNMAN_SERVICE_TYPE_WIFI)
++ return true;
++
++ user_list = connman_service_get_login_users();
++
++ DBG("service favorite user id is: %d", service->user.favorite_user);
++
++ for (list = user_list; list; list = list->next) {
++ uid_t uid = GPOINTER_TO_UINT(list->data);
++
++ DBG("login user id is %d", uid);
++
++ if (service->user.favorite_user == uid) {
++ ret = true;
++ break;
++ }
++ }
++
++ g_list_free(user_list);
++
++ return ret;
++}
++
+ int __connman_service_load_modifiable(struct connman_service *service)
+ {
+ GKeyFile *keyfile;
+@@ -3800,6 +3857,11 @@ static bool auto_connect_service(GList *services,
+ continue;
+ }
+
++ if (!is_service_owner_user_login(service)) {
++ DBG("favorite user not login, wifi auto connect denied");
++ continue;
++ }
++
+ DBG("service %p %s %s", service, service->name,
+ (preferred) ? "preferred" : reason2string(reason));
+
+--
+1.8.1.4
+
--- /dev/null
+From 9d476728838e2442d349adb679147581a963f8e9 Mon Sep 17 00:00:00 2001
+From: Zhang zhengguang <zhengguang.zhang@intel.com>
+Date: Wed, 19 Nov 2014 09:50:45 +0800
+Subject: [PATCH 31/32] multi-user: Expose function to check service user
+ favorite
+
+Expose the function to check whether the service is favorite
+to the current user.
+
+Change-Id: Ib232f16c652ec94ef2e10b199a638a98554a1066
+---
+ doc/service-api.txt | 7 +++++++
+ src/service.c | 27 +++++++++++++++++++++++++++
+ 2 files changed, 34 insertions(+)
+
+diff --git a/doc/service-api.txt b/doc/service-api.txt
+index 74c8345..0238d22 100644
+--- a/doc/service-api.txt
++++ b/doc/service-api.txt
+@@ -122,6 +122,13 @@ Methods dict GetProperties() [deprecated]
+
+ Possible Errors: None
+
++ boolean GetUserFavorite() [experimental]
++
++ This function is used to check whether this service
++ is favorite to the current user.
++
++ Possible Errors: None
++
+ Signals PropertyChanged(string name, variant value)
+
+ This signal indicates a changed value of the given
+diff --git a/src/service.c b/src/service.c
+index 55cf02c..5eca970 100644
+--- a/src/service.c
++++ b/src/service.c
+@@ -4472,6 +4472,30 @@ static DBusMessage *reset_counters(DBusConnection *conn,
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+ }
+
++static DBusMessage *get_user_favorite(DBusConnection *conn,
++ DBusMessage *msg, void *user_data)
++{
++ DBusMessage *reply;
++ uid_t uid = USER_NONE;
++ dbus_bool_t user_favorite = false;
++ struct connman_service *service = user_data;
++
++ connman_dbus_get_connection_unix_user_sync(conn,
++ dbus_message_get_sender(msg),
++ &uid);
++ if (uid == USER_ROOT)
++ user_favorite = service->favorite;
++ else if (uid != USER_NONE && uid == service->user.favorite_user) {
++ DBG("The service is favorite to this user!");
++ user_favorite = true;
++ }
++
++ reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
++ dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN,
++ &user_favorite, DBUS_TYPE_INVALID);
++ return reply;
++}
++
+ static struct _services_notify {
+ int id;
+ GHashTable *add;
+@@ -4613,6 +4637,9 @@ static const GDBusMethodTable service_methods[] = {
+ GDBUS_ARGS({ "service", "o" }), NULL,
+ move_after) },
+ { GDBUS_METHOD("ResetCounters", NULL, NULL, reset_counters) },
++ { GDBUS_METHOD("GetUserFavorite",
++ NULL, GDBUS_ARGS({ "value", "v" }),
++ get_user_favorite) },
+ { },
+ };
+
+--
+1.8.1.4
+
--- /dev/null
+From 7d48e7bfd2d9d371766ddb36bb3da99111dd3935 Mon Sep 17 00:00:00 2001
+From: Zhang zhengguang <zhengguang.zhang@intel.com>
+Date: Fri, 21 Nov 2014 16:34:11 +0800
+Subject: [PATCH 32/32] multi-user: Fix service load/save issues
+
+Refine service load/save to be multi-user complicant.
+
+Change-Id: Icc8a0507826f4cae72319191e4fdbebe548434fc
+---
+ src/service.c | 47 +++++++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 39 insertions(+), 8 deletions(-)
+
+diff --git a/src/service.c b/src/service.c
+index 5eca970..86dffaf 100644
+--- a/src/service.c
++++ b/src/service.c
+@@ -484,6 +484,23 @@ int __connman_service_load_modifiable(struct connman_service *service)
+ return 0;
+ }
+
++static int service_load_passphrase(struct connman_service *service)
++{
++ GKeyFile *keyfile;
++ gchar *str;
++
++ keyfile = connman_storage_load_service(service->identifier);
++ if (!keyfile)
++ return -EIO;
++
++ str = g_key_file_get_string(keyfile,
++ service->identifier, "Passphrase", NULL);
++ if (str)
++ service->passphrase = str;
++
++ return 0;
++}
++
+ static int service_load(struct connman_service *service)
+ {
+ GKeyFile *keyfile;
+@@ -659,7 +676,8 @@ static int service_load(struct connman_service *service)
+ service->hidden_service = g_key_file_get_boolean(keyfile,
+ service->identifier, "Hidden", NULL);
+
+- service->user.favorite_user = g_key_file_get_integer(keyfile,
++ if (g_key_file_has_key(keyfile, service->identifier, "UID", NULL))
++ service->user.favorite_user = g_key_file_get_integer(keyfile,
+ service->identifier, "UID", NULL);
+ done:
+ g_key_file_free(keyfile);
+@@ -706,8 +724,12 @@ static int service_save(struct connman_service *service)
+ const unsigned char *ssid;
+ unsigned int ssid_len = 0;
+
+- g_key_file_set_integer(keyfile, service->identifier,
+- "UID", service->user.favorite_user);
++ if (service->user.favorite_user == USER_NONE)
++ g_key_file_remove_key(keyfile, service->identifier,
++ "UID", NULL);
++ else
++ g_key_file_set_integer(keyfile, service->identifier,
++ "UID", service->user.favorite_user);
+
+ ssid = connman_network_get_blob(service->network,
+ "WiFi.SSID", &ssid_len);
+@@ -764,12 +786,14 @@ static int service_save(struct connman_service *service)
+ g_free(str);
+ }
+
+- if (service->passphrase && strlen(service->passphrase) > 0)
+- g_key_file_set_string(keyfile, service->identifier,
++ if (service->user.current_user == service->user.favorite_user) {
++ if (service->passphrase && 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);
++ else
++ g_key_file_remove_key(keyfile, service->identifier,
++ "Passphrase", NULL);
++ }
+
+ if (service->ipconfig_ipv4)
+ __connman_ipconfig_save(service->ipconfig_ipv4, keyfile,
+@@ -4125,6 +4149,11 @@ static DBusMessage *connect_service(DBusConnection *conn,
+ service->request_passphrase_input = true;
+
+ service->user.current_user = uid;
++
++ if (!service->passphrase && uid == service->user.favorite_user) {
++ DBG("Now load this favorite user's passphrase.");
++ service_load_passphrase(service);
++ }
+ }
+
+ index = __connman_service_get_index(service);
+@@ -4232,6 +4261,8 @@ bool __connman_service_remove(struct connman_service *service)
+
+ service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
+
++ service->user.favorite_user = USER_NONE;
++
+ __connman_service_set_favorite(service, false);
+
+ __connman_ipconfig_ipv6_reset_privacy(service->ipconfig_ipv6);
+--
+1.8.1.4
+
--- /dev/null
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += "file://0001-Add-bootstrap-files.patch"
+SRC_URI += "file://0002-Add-package-build-spec-file.patch"
+SRC_URI += "file://0003-Add-systemd-service-to-manager-ConnMan-NTP.patch"
+SRC_URI += "file://0004-Set-manifest-request-domain-to-floor.patch"
+SRC_URI += "file://0005-Set-ConnMan-default-settings-in-config-files.patch"
+SRC_URI += "file://0006-Enable-ConnMan-NTP-configurable-in-spec-file.patch"
+SRC_URI += "file://0007-Enable-ConnMan-VPND-OpenVPN-OpenConnect-configurable.patch"
+SRC_URI += "file://0008-Add-connmanctl-to-the-built-rpm.patch"
+SRC_URI += "file://0009-Tizen-Export-more-wifi-info-in-ConnMan-network-API.patch"
+SRC_URI += "file://0010-Tizen-Append-extra-wifi-service-property.patch"
+SRC_URI += "file://0011-Tizen-Export-network-proxy-API-for-telephony-plugin.patch"
+SRC_URI += "file://0012-Tizen-Integrate-telephony-plugin.patch"
+SRC_URI += "file://0013-Tizen-Fix-wifi-enterprise-to-support-SIM-and-AKA.patch"
+SRC_URI += "file://0014-Tizen-Check-some-telephony-flags-before-active-conte.patch"
+SRC_URI += "file://0015-Tizen-Unify-bluetooth-tethering-enable-logic.patch"
+SRC_URI += "file://0016-Tethering-Add-handling-for-wpa_supplicant-authorized.patch"
+SRC_URI += "file://0017-Tethering-Add-station-information-management-feature.patch"
+SRC_URI += "file://0018-Tethering-Add-interface-that-save-lease-in-DHCP-info.patch"
+SRC_URI += "file://0019-Tethering-Notify-listeners-when-station-connection-c.patch"
+SRC_URI += "file://0020-Tethering-Add-open-access-point-support-in-technolog.patch"
+SRC_URI += "file://0021-Tethering-Add-hidden-access-point-support-in-technol.patch"
+SRC_URI += "file://0022-Tethering-Add-test-script-of-open-and-hidden-AP.patch"
+SRC_URI += "file://0023-Tethering-Add-tethering-interfaces-description-to-te.patch"
+SRC_URI += "file://0024-Tethering-Watch-the-connection-and-disconnection-sig.patch"
+SRC_URI += "file://0025-Tethering-Get-the-client-mac-info-of-Gadget-tether.patch"
+SRC_URI += "file://0026-multi-user-Add-function-to-get-dbus-user-id-synchron.patch"
+SRC_URI += "file://0027-multi-user-Add-multi-user-support-in-service.patch"
+SRC_URI += "file://0028-multi-user-Add-multi-user-support-in-technology.patch"
+SRC_URI += "file://0029-multi-user-Add-multi-user-support-in-manager.patch"
+SRC_URI += "file://0030-multi-user-Add-multi-user-support-for-auto-connect-s.patch"
+SRC_URI += "file://0031-multi-user-Expose-function-to-check-service-user-fav.patch"
+SRC_URI += "file://0032-multi-user-Fix-service-load-save-issues.patch"