Initialize VPN CAPI for Tizen 3.0 16/54516/6
authorSeonah Moon <seonah1.moon@samsung.com>
Wed, 16 Dec 2015 01:01:17 +0000 (10:01 +0900)
committertaesub.kim <taesub.kim@samsung.com>
Mon, 21 Dec 2015 02:39:49 +0000 (11:39 +0900)
Change-Id: Ic3138ffd60b4440cb01ef45d9b7ab8e0728b90cc
Signed-off-by: Seonah Moon <seonah1.moon@samsung.com>
26 files changed:
CMakeLists.txt [new file with mode: 0755]
LICENSE-Apache.v2.0 [new file with mode: 0755]
daemon/CMakeLists.txt [new file with mode: 0755]
daemon/include/vpn_service_daemon.h [new file with mode: 0755]
daemon/include/vpndbus.h [new file with mode: 0755]
daemon/include/vpnsvc.h [new file with mode: 0755]
daemon/interfaces/org.tizen.vpnsvc.xml [new file with mode: 0755]
daemon/src/vpn_service_daemon.c [new file with mode: 0755]
daemon/src/vpn_service_daemon_main.c [new file with mode: 0755]
daemon/src/vpndbus.c [new file with mode: 0755]
daemon/src/vpnsvc.c [new file with mode: 0755]
daemon/vpnsvc-daemon.manifest [new file with mode: 0755]
doc/vpn_doc.h [new file with mode: 0755]
framework/CMakeLists.txt [new file with mode: 0755]
framework/capi-vpnsvc.manifest [new file with mode: 0755]
framework/capi-vpnsvc.pc.in [new file with mode: 0755]
framework/include/capi_vpn_service_private.h [new file with mode: 0755]
framework/src/capi_vpn_service.c [new file with mode: 0755]
include/tizen_vpn_error.h [new file with mode: 0755]
include/vpn_service.h [new file with mode: 0755]
packaging/capi-vpn-service.spec [new file with mode: 0755]
packaging/org.tizen.vpnsvc.service [new file with mode: 0755]
packaging/vpnsvc-daemon.service [new file with mode: 0755]
test/CMakeLists.txt [new file with mode: 0755]
test/vpn_service_test.c [new file with mode: 0755]
test/vpnsvc-test.manifest [new file with mode: 0755]

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..a8e110a
--- /dev/null
@@ -0,0 +1,40 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT("capi-vpn-service-pkg")
+
+############################# cmake packages ##################################
+
+INCLUDE(FindPkgConfig)
+
+############################# compiler flags ##################################
+
+SET(CMAKE_INSTALL_PREFIX /usr)
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+SET(EXEC_PREFIX ${PREFIX}/bin)
+SET(LIBDIR ${PREFIX}/lib)
+SET(INCLUDEDIR ${PREFIX}/include)
+
+# If supported for the target machine, emit position-independent code,suitable
+# for dynamic linking and avoiding any limit on the size of the global offset
+# table. This option makes a difference on the m68k, PowerPC and SPARC.
+# (BJ: our ARM too?)
+ADD_DEFINITIONS("-fPIC")
+
+# Set compiler warning flags
+
+#ADD_DEFINITIONS("-Werror")                      # Make all warnings into errors.
+ADD_DEFINITIONS("-Wall")                        # Generate all warnings
+ADD_DEFINITIONS("-Wextra")                      # Generate even more extra warnings
+
+STRING(REGEX MATCH "([^.]*)" API_VERSION "${VERSION}")
+ADD_DEFINITIONS("-DAPI_VERSION=\"$(API_VERSION)\"")
+ADD_DEFINITIONS("-DSMACK_ENABLED")
+
+IF (CMAKE_BUILD_TYPE MATCHES "DEBUG")
+    ADD_DEFINITIONS("-DTIZEN_DEBUG_ENABLE")
+    ADD_DEFINITIONS("-DBUILD_TYPE_DEBUG")
+ENDIF (CMAKE_BUILD_TYPE MATCHES "DEBUG")
+
+ADD_SUBDIRECTORY(framework)
+ADD_SUBDIRECTORY(daemon)
+ADD_SUBDIRECTORY(test)
+
diff --git a/LICENSE-Apache.v2.0 b/LICENSE-Apache.v2.0
new file mode 100755 (executable)
index 0000000..d645695
--- /dev/null
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..09ffa1d
--- /dev/null
@@ -0,0 +1,58 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(PACKAGE_NAME vpnsvc-daemon)
+SET(LIB_NAME ${PACKAGE_NAME})
+PROJECT(${LIB_NAME})
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+SET(EXEC_PREFIX "\${prefix}")
+SET(LIBDIR "\${prefix}/lib")
+SET(INCLUDEDIR "\${prefix}/include")
+SET(DAEMON_DIR "${CMAKE_SOURCE_DIR}/daemon")
+SET(VERSION 0.1)
+
+SET(requires "dlog dbus-1 glib-2.0 gio-2.0 gio-unix-2.0 capi-base-common capi-appfw-package-manager")
+SET(pc_requires "capi-base-common")
+
+SET(SRCS
+       src/vpnsvc.c
+       src/vpndbus.c
+       src/vpn_service_daemon.c
+       src/vpn_service_daemon_main.c
+)
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
+                                       ${CMAKE_SOURCE_DIR}/framework/include
+                                       ${CMAKE_SOURCE_DIR}/daemon/include)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(${PACKAGE_NAME} REQUIRED ${requires})
+FOREACH(flag ${${PACKAGE_NAME}_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+# Compiler flags
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fPIC -Wall -fvisibility=hidden")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -I${DAEMON_DIR}")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+
+ADD_DEFINITIONS("-DPREFIX=\"${PREFIX}\"")
+ADD_DEFINITIONS("-DFACTORYFS=\"$ENV{FACTORYFS}\"")
+ADD_DEFINITIONS("-DDATAFS=\"$ENV{DATADIR}\"")
+ADD_DEFINITIONS("-DSLP_DEBUG")
+
+SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=/usr/lib -pie")
+
+ADD_CUSTOM_COMMAND(
+       WORKING_DIRECTORY
+       OUTPUT ${DAEMON_DIR}/generated-code.c
+       COMMAND gdbus-codegen --interface-prefix org.tizen.
+                       --generate-c-code generated-code
+                       --c-generate-object-manager
+                       --generate-docbook generated-code-docs
+                       ${DAEMON_DIR}/interfaces/org.tizen.vpnsvc.xml
+                       COMMENT "Generating GDBus .c/.h")
+
+ADD_EXECUTABLE(${PACKAGE_NAME} ${SRCS} ${DAEMON_DIR}/generated-code.c)
+TARGET_LINK_LIBRARIES(${PACKAGE_NAME} ${${PACKAGE_NAME}_LDFLAGS} -lrt -ldl)
+
+INSTALL(TARGETS ${PACKAGE_NAME} DESTINATION bin)
+
diff --git a/daemon/include/vpn_service_daemon.h b/daemon/include/vpn_service_daemon.h
new file mode 100755 (executable)
index 0000000..9237184
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * VPN Service Module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#ifndef __TIZEN_CAPI_VPN_SERVICE_DAEMON_H__
+#define __TIZEN_CAPI_VPN_SERVICE_DAEMON_H__
+
+#include "capi_vpn_service_private.h"
+
+int vpn_daemon_init(const char* tun_name, size_t tun_name_len, int fd, vpnsvc_tun_s *handle_s);
+int vpn_daemon_deinit(const char* dev_name);
+int vpn_daemon_protect(int socket, const char* dev_name);
+int vpn_daemon_up(int tun_index, const char* local_ip, const char* remote_ip,
+                                       const struct vpnsvc_route* routes, size_t nr_routes,
+                                       char** dns_servers, size_t nr_dns, size_t total_dns_string_cnt,
+                                       const char* dns_suffix, const unsigned int mtu);
+int vpn_daemon_down(int tun_index);
+int vpn_daemon_block_networks(const struct vpnsvc_route* nets_vpn, size_t nr_nets_vpn,
+               const struct vpnsvc_route* nets_orig, size_t nr_nets_orig);
+int vpn_daemon_unblock_networks(void);
+
+#endif /* __TIZEN_CAPI_VPN_SERVICE_DAEMON_H__ */
diff --git a/daemon/include/vpndbus.h b/daemon/include/vpndbus.h
new file mode 100755 (executable)
index 0000000..85b39f6
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * VPN Service Module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __VPNSERVICE_VPNDBUS_H__
+#define __VPNSERVICE_VPNDBUS_H__
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <glib-object.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define VPNSERVICE_SERVICE             "org.tizen.vpnsvc"
+#define VPNSERVICE_INTERFACE           "org.tizen.vpnsvc"
+#define VPNSERVICE_PATH                        "/org/tizen/vpnsvc"
+
+typedef void (*vpnsvc_got_name_cb)(void);
+
+GDBusObjectManagerServer *vpnsvc_get_vpn_manager(void);
+GDBusConnection *vpnsvc_gdbus_get_connection(void);
+GCancellable *vpnsvc_gdbus_get_gdbus_cancellable(void);
+void vpnsvc_gdbus_pending_call_ref(void);
+void vpnsvc_gdbus_pending_call_unref(void);
+int vpnsvc_create_gdbus_call(GDBusConnection *conn);
+
+gboolean vpnsvc_invoke_dbus_method_nonblock(const char *dest, const char *path,
+               const char *interface_name, const char *method, GVariant *params,
+               GAsyncReadyCallback notify_func);
+GVariant *vpnsvc_invoke_dbus_method(const char *dest, const char *path,
+               const char *interface_name, const char *method,
+               GVariant *params);
+
+int vpnsvc_setup_gdbus(vpnsvc_got_name_cb cb);
+void vpnsvc_cleanup_gdbus(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __VPNSERVICE_VPNDBUS_H__ */
diff --git a/daemon/include/vpnsvc.h b/daemon/include/vpnsvc.h
new file mode 100755 (executable)
index 0000000..b6467a8
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * VPN Service Module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __VPNSERVICE_VPNSVC_H__
+#define __VPNSERVICE_VPNSVC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <glib-object.h>
+
+#include "generated-code.h"
+
+void vpnsvc_create_and_init(void);
+Vpnsvc *get_vpnsvc_object(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __VPNSERVICE_VPNSVC_H__ */
diff --git a/daemon/interfaces/org.tizen.vpnsvc.xml b/daemon/interfaces/org.tizen.vpnsvc.xml
new file mode 100755 (executable)
index 0000000..8c4d08d
--- /dev/null
@@ -0,0 +1,46 @@
+<node name='/org/tizen/vpnsvc'>
+       <interface name='org.tizen.vpnsvc'>
+               <method name='vpn_init'>
+                       <arg type='s' name='tun_name' direction='in'/>
+                       <arg type='u' name='tun_name_len' direction='in'/>
+                       <arg type='i' name='result' direction='out'/>
+                       <arg type='i' name='h_index' direction='out'/>
+                       <arg type='s' name='h_name' direction='out'/>
+               </method>
+               <method name='vpn_deinit'>
+                       <arg type='s' name='dev_name' direction='in'/>
+                       <arg type='i' name='result' direction='out'/>
+               </method>
+               <method name='vpn_protect'>
+                       <arg type='s' name='dev_name' direction='in'/>
+                       <arg type='i' name='result' direction='out'/>
+               </method>
+               <method name='vpn_up'>
+                       <arg type='i' name='tun_index' direction='in'/>
+                       <arg type='s' name='local_ip' direction='in'/>
+                       <arg type='s' name='remote_ip' direction='in'/>
+                       <arg type='v' name='routes' direction='in'/>
+                       <arg type='u' name='nr_routes' direction='in'/>
+                       <arg type='v' name='dns_servers' direction='in'/>
+                       <arg type='u' name='nr_dns' direction='in'/>
+                       <arg type='s' name='dns_suffix' direction='in'/>
+                       <arg type='u' name='mtu' direction='in'/>
+                       <arg type='i' name='result' direction='out'/>
+               </method>
+               <method name='vpn_down'>
+                       <arg type='i' name='tun_index' direction='in'/>
+                       <arg type='i' name='result' direction='out'/>
+               </method>
+               <method name='vpn_block_networks'>
+                       <arg type='v' name='nets_vpn' direction='in'/>
+                       <arg type='u' name='nr_nets_vpn' direction='in'/>
+                       <arg type='v' name='nets_orig' direction='in'/>
+                       <arg type='u' name='nr_nets_orig' direction='in'/>
+                       <arg type='i' name='result' direction='out'/>
+               </method>
+               <method name='vpn_unblock_networks'>
+                       <arg type='i' name='result' direction='out'/>
+               </method>
+       </interface>
+</node>
+
diff --git a/daemon/src/vpn_service_daemon.c b/daemon/src/vpn_service_daemon.c
new file mode 100755 (executable)
index 0000000..977426e
--- /dev/null
@@ -0,0 +1,931 @@
+/*
+ * VPN Service Module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#include <errno.h>
+#include <net/route.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/un.h>
+
+#include "vpn_service_daemon.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "VPNSVC_DAEMON"
+
+#define CONNMAN_SERVICE "net.connman"
+#define CONNMAN_INTERFACE_MANAGER "net.connman.Manager"
+#define CONNMAN_INTERFACE_SERVICE "net.connman.Service"
+
+
+/* for iptables */
+static char iptables_cmd[] = "/usr/sbin/iptables";
+static char iptables_filter_prefix[] = "CAPI_VPN_SERVICE_";
+static char iptables_filter_out[] = "OUTPUT";
+static char iptables_filter_in[] = "INPUT";
+static char iptables_filter_interface_wlan[] = "wlan0";
+/* static char iptables_register_fmt[] = "%s -N %s%s -w;" "%s -F %s%s -w;" "%s -A %s%s -j RETURN -w;" "%s -I %s -j %s%s -w;"; */
+static char iptables_register_fmt[] = "%s -N %s%s -w;" "%s -F %s%s -w;" "%s -A %s%s -j DROP -w;" "%s -A %s%s -j RETURN -w;" "%s -I %s -j %s%s -w;";
+static char iptables_unregister_fmt[] = "%s -D %s -j %s%s -w;" "%s -F %s%s -w;" "%s -X %s%s -w;";
+static char iptables_rule_fmt[] = "%s -%c %s%s -%c %s/%d -j ACCEPT -w;";
+static char iptables_rule_with_interface_fmt[] = "%s -%c %s%s -%c %s -%c %s/%d -j ACCEPT -w;";
+/*static char iptables_usage_fmt[] = "%s -L %s%s -n -v -w;";*/
+
+typedef unsigned long int ipv4;        /* Declare variable type for ipv4 net address. */
+
+static GDBusConnection *global_connection = NULL;
+
+static ipv4 make_mask(int prefix)
+{
+       ipv4 mask = 0;
+       int i = 0;
+
+       for (i = prefix; i > 0; i--)
+               mask += (ipv4) (1 << (32 - i));
+       return mask;
+}
+
+static in_addr_t host2net(ipv4 host)
+{
+       in_addr_t net;
+
+       net = 0;
+
+       net |= (host & 0x000000FF) << 24;
+       net |= (host & 0x0000FF00) <<  8;
+       net |= (host & 0x00FF0000) >>  8;
+       net |= (host & 0xFF000000) >> 24;
+
+       return net;
+}
+
+static int add_routes(char* if_name, const struct vpnsvc_route* routes, size_t nr_routes)
+{
+       struct rtentry rt;
+       struct sockaddr_in addr;
+       int sk;
+       unsigned int i = 0;
+
+       LOGD("Enter add_routes");
+
+       sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+       if (sk < 0) {
+               LOGE("socket failed : %s", strerror(errno));
+               return VPNSVC_ERROR_IO_ERROR;
+       }
+
+       for (i = 0; i < nr_routes; i++) {
+               memset(&rt, 0, sizeof(rt));
+               rt.rt_flags = RTF_UP;
+
+               memset(&addr, 0, sizeof(addr));
+               addr.sin_family = AF_INET;
+               addr.sin_addr.s_addr = inet_addr(routes[i].dest);
+               memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
+
+               memset(&addr, 0, sizeof(addr));
+               addr.sin_family = AF_INET;
+               addr.sin_addr.s_addr = INADDR_ANY;
+               memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway));
+
+               /* set mask using by prefix length */
+               memset(&addr, 0, sizeof(addr));
+               addr.sin_family = AF_INET;
+               addr.sin_addr.s_addr = INADDR_ANY;
+               addr.sin_addr.s_addr = host2net(make_mask(routes[i].prefix));
+               memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask));
+
+               rt.rt_dev = if_name;
+
+               if (ioctl(sk, SIOCADDRT, &rt) < 0) {
+                       LOGE("ioctl SIOCADDRT failed : %s", strerror(errno));
+                       close(sk);
+                       return VPNSVC_ERROR_IO_ERROR;
+               }
+       }
+
+       close(sk);
+
+       return VPNSVC_ERROR_NONE;
+}
+
+static void connman_connection_open(void)
+{
+       if (global_connection == NULL) {
+               GError *error = NULL;
+#if !GLIB_CHECK_VERSION(2, 36, 0)
+               g_type_init();
+#endif
+
+               global_connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+               if (global_connection == NULL) {
+                       if (error != NULL) {
+                               LOGE("Error connman connection open: %s", error->message);
+                               g_error_free(error);
+                       }
+               }
+       }
+}
+
+static void connman_connection_close(GDBusConnection *connection)
+{
+       if (connection)
+               g_object_unref(connection);
+}
+
+static GVariant *connman_method_call(
+       GDBusConnection *connection, char *service, char *path,
+       char *interface, char *method, GVariant *params)
+{
+       GError *error = NULL;
+       GVariant *message = NULL;
+
+       message = g_dbus_connection_call_sync(
+               connection, service, path, interface, method, params,
+               NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
+
+       if (message == NULL) {
+               if (error != NULL) {
+                       LOGE("error: g_dbus_connection_call_sync [%d: %s]", error->code, error->message);
+                       g_error_free(error);
+               } else {
+                       LOGE("error: g_dbus_connection_call_sync\n");
+               }
+       }
+
+       return message;
+}
+
+static char *connman_default_profile(GDBusConnection *connection)
+{
+       gchar *key = NULL;
+       GVariantIter *value = NULL;
+       GVariant *message = NULL;
+       GVariantIter *iter = NULL;
+       char *profile = NULL;
+
+       message = connman_method_call(connection, CONNMAN_SERVICE, "/",
+                                                                 CONNMAN_INTERFACE_MANAGER, "GetServices", NULL);
+
+       if (message) {
+               g_variant_get(message, "(a(oa{sv}))", &iter);
+               while (g_variant_iter_loop(iter, "(oa{sv})", &key, &value)) {
+                       profile = strdup(key);
+                       break;
+               }
+
+               if (value)
+                       g_variant_iter_free(value);
+               if (key)
+                       g_free(key);
+
+               g_variant_iter_free(iter);
+               g_variant_unref(message);
+       }
+
+       return profile;
+}
+
+static char *connman_get_items(GDBusConnection *connection, char *profile, const char *keystr)
+{
+       GVariant *message = NULL;
+       GVariantIter *iter = NULL;
+       GVariantIter *next = NULL;
+       gchar *obj = NULL;
+       char *items = NULL;
+
+       message = connman_method_call(connection, CONNMAN_SERVICE, "/",
+                                                                 CONNMAN_INTERFACE_MANAGER, "GetServices", NULL);
+
+       if (message) {
+               g_variant_get(message, "(a(oa{sv}))", &iter);
+               while (g_variant_iter_loop(iter, "(oa{sv})", &obj, &next)) {
+                       if (strcmp(obj, profile) == 0) {
+                               GVariant *var;
+                               gchar *key;
+
+                               while (g_variant_iter_loop(next, "{sv}", &key, &var)) {
+                                       if (g_strcmp0(key, keystr) == 0) {
+                                               GVariantIter *iter_item;
+                                               const gchar *value = NULL;
+
+                                               g_variant_get(var, "as", &iter_item);
+                                               while (g_variant_iter_loop(iter_item, "s", &value)) {
+                                                       if (items) {
+                                                               char *tmp_items;
+
+                                                               tmp_items = (char *) malloc(strlen(items) + 1 + strlen(value) + 1);
+                                                               if (items) {
+                                                                       sprintf(tmp_items, "%s,%s", items, value);
+                                                                       free(items);
+                                                                       items = tmp_items;
+                                                               }
+                                                       } else {
+                                                               items = strdup(value);
+                                                       }
+                                               }
+                                               g_variant_iter_free(iter_item);
+                                               break;
+                                       }
+                               }
+                               break;
+                       }
+               }
+               g_variant_iter_free(iter);
+               g_variant_unref(message);
+       }
+
+       return items;
+}
+
+static void connman_set_items(GDBusConnection *connection, char *profile,
+                                                         const char *keystr, char *items)
+{
+       GVariant *message = NULL;
+       GVariantBuilder *builder = NULL;
+       GVariant *params = NULL;
+       char *strings = strdup(items);
+       char *addr = NULL;
+
+       builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
+       if ((addr = strtok(strings, ", ")) != NULL) {
+               do {
+                       g_variant_builder_add(builder, "s", addr);
+               } while ((addr = strtok(NULL, ", ")) != NULL);
+       }
+       free(strings);
+       params = g_variant_new("(sv)", keystr,
+                                                  g_variant_builder_end(builder));
+       g_variant_builder_unref(builder);
+
+       message = connman_method_call(connection, CONNMAN_SERVICE, profile,
+                                                                 CONNMAN_INTERFACE_SERVICE, "SetProperty", params);
+       if (message)
+               g_variant_unref(message);
+
+}
+
+static char *connman_get_nameservers(GDBusConnection *connection, char *profile)
+{
+       return connman_get_items(connection, profile, "Nameservers");
+}
+
+static char *connman_get_nameservers_conf(GDBusConnection *connection, char *profile)
+{
+       return connman_get_items(connection, profile, "Nameservers.Configuration");
+}
+
+static void connman_set_nameservers(GDBusConnection *connection, char *profile,
+                                                                       char *nameservers)
+{
+       return connman_set_items(connection, profile,
+                                                        "Nameservers.Configuration", nameservers);
+}
+
+static char *connman_get_domains(GDBusConnection *connection, char *profile)
+{
+       return connman_get_items(connection, profile, "Domains");
+}
+
+static char *connman_get_domains_conf(GDBusConnection *connection, char *profile)
+{
+       return connman_get_items(connection, profile, "Domains.Configuration");
+}
+
+static void connman_set_domains(GDBusConnection *connection, char *profile,
+                                                                       char *domains)
+{
+       return connman_set_items(connection, profile,
+                                                        "Domains.Configuration", domains);
+}
+
+static int add_dns_servers(char** dns_servers, size_t nr_dns, size_t total_dns_string_cnt)
+{
+       char *profile = NULL;
+       char *items = NULL;
+       char *org_items = NULL;
+       char *new_items = NULL;
+       unsigned int i;
+
+       connman_connection_open();
+
+       profile = connman_default_profile(global_connection);
+       if (profile == NULL) {
+               LOGE("connman_default_profile failed");
+               connman_connection_close(global_connection);
+               return VPNSVC_ERROR_IPC_FAILED;
+       }
+
+       LOGD("profile : %s\n", profile);
+
+       /* add name servers */
+       org_items = connman_get_nameservers(global_connection, profile);
+
+       if (org_items) {
+               LOGD("original DNS : %s\n", org_items);
+               /* nr_dns = comma(,) count */
+               items = (char *) calloc((total_dns_string_cnt + nr_dns + strlen(org_items) + 1), sizeof(char));
+               if (items == NULL) {
+                       LOGE("OOM while malloc\n");
+                       return VPNSVC_ERROR_OUT_OF_MEMORY;
+               }
+               strncpy(items, org_items, strlen(org_items));
+               for (i = 0 ; i < nr_dns ; i++) {
+                       strcat(items, ",");
+                       strcat(items, dns_servers[i]);
+               }
+               free(org_items);
+               org_items = NULL;
+       } else {
+               /* nr_dns = comma(,) count + end null char */
+               items = (char *) calloc(total_dns_string_cnt + nr_dns, sizeof(char));
+               if (items == NULL) {
+                       LOGE("OOM while malloc\n");
+                       return VPNSVC_ERROR_OUT_OF_MEMORY;
+               }
+               for (i = 0 ; i < nr_dns ; i++) {
+                       strcat(items, dns_servers[i]);
+                       if (i != nr_dns - 1)
+                               strcat(items, ",");
+               }
+       }
+
+       if (items) {
+               LOGD("adding DNS : %s\n", items);
+               connman_set_nameservers(global_connection, profile, items);
+               free(items);
+               items = NULL;
+       }
+
+       /* print new DNSs */
+       new_items = connman_get_nameservers_conf(global_connection, profile);
+       LOGD("new_dns : %s\n", new_items);
+
+       if (new_items)
+               free(new_items);
+       free(profile);
+       return VPNSVC_ERROR_NONE;
+}
+
+static int del_dns_servers()
+{
+       char *profile = NULL;
+
+       connman_connection_open();
+
+       profile = connman_default_profile(global_connection);
+       if (profile == NULL) {
+               LOGE("connman_default_profile failed");
+               connman_connection_close(global_connection);
+               return VPNSVC_ERROR_IPC_FAILED;
+       }
+
+       LOGD("profile : %s", profile);
+
+       /* del name servers */
+       connman_set_nameservers(global_connection, profile, "");
+
+       if (profile)
+               free(profile);
+
+       return VPNSVC_ERROR_NONE;
+}
+
+static int add_dns_suffix(const char* dns_suffix, size_t dns_suffix_len)
+{
+       char *profile = NULL;
+       char *items = NULL;
+       char *org_items = NULL;
+       char *new_items = NULL;
+
+       connman_connection_open();
+
+       profile = connman_default_profile(global_connection);
+       if (profile == NULL) {
+               LOGE("connman_default_profile failed");
+               connman_connection_close(global_connection);
+               return VPNSVC_ERROR_IPC_FAILED;
+       }
+
+       LOGD("profile : %s", profile);
+
+       /* add name servers */
+       org_items = connman_get_domains(global_connection, profile);
+
+       if (org_items) {
+               LOGD("original DNS suffix : %s", org_items);
+               /* comma(,) and end null character included */
+               items = (char *) calloc((dns_suffix_len + strlen(org_items) + 2), sizeof(char));
+               if (items == NULL) {
+                       LOGE("OOM while malloc");
+                       return VPNSVC_ERROR_OUT_OF_MEMORY;
+               }
+               strncpy(items, org_items, strlen(org_items));
+               strcat(items, ",");
+               strcat(items, dns_suffix);
+               free(org_items);
+               org_items = NULL;
+       } else {
+               /* nr_dns = comma(,) count + end null char */
+               items = (char *) calloc((dns_suffix_len + 1), sizeof(char));
+               if (items == NULL) {
+                       LOGE("OOM while malloc");
+                       return VPNSVC_ERROR_OUT_OF_MEMORY;
+               }
+               strcat(items, dns_suffix);
+       }
+
+       if (items) {
+               LOGD("adding DNS suffix : %s\n", items);
+               connman_set_domains(global_connection, profile, items);
+               free(items);
+               items = NULL;
+       }
+
+       /* print new domains */
+       new_items = connman_get_domains_conf(global_connection, profile);
+       LOGD("new DNS suffix : %s\n", new_items);
+
+       if (new_items)
+               free(new_items);
+
+       if (profile)
+               free(profile);
+
+       return VPNSVC_ERROR_NONE;
+}
+
+static int del_dns_suffix()
+{
+       char *profile = NULL;
+
+       connman_connection_open();
+
+       profile = connman_default_profile(global_connection);
+       if (profile == NULL) {
+               LOGE("connman_default_profile failed");
+               connman_connection_close(global_connection);
+               return VPNSVC_ERROR_IPC_FAILED;
+       }
+
+       LOGD("profile : %s", profile);
+
+       /* del DNS suffix */
+       connman_set_domains(global_connection, profile, "");
+
+       if (profile)
+               free(profile);
+
+       return VPNSVC_ERROR_NONE;
+}
+
+
+static void iptables_exec(char *cmdline)
+{
+       FILE *fp = NULL;
+
+       fp = popen(cmdline, "r");
+
+       if (fp != NULL)
+               pclose(fp);
+}
+
+static void iptables_register(void)
+{
+       int size = 0;
+       char buf[8192], *filter;
+
+       filter = iptables_filter_out;
+       snprintf(buf + size, sizeof(buf) - size, iptables_register_fmt,
+                        iptables_cmd, iptables_filter_prefix, filter,
+                        iptables_cmd, iptables_filter_prefix, filter,
+                        iptables_cmd, iptables_filter_prefix, filter,
+                        iptables_cmd, iptables_filter_prefix, filter,
+                        iptables_cmd, filter, iptables_filter_prefix, filter);
+       size = strlen(buf);
+       filter = iptables_filter_in;
+       snprintf(buf + size, sizeof(buf) - size, iptables_register_fmt,
+                        iptables_cmd, iptables_filter_prefix, filter,
+                        iptables_cmd, iptables_filter_prefix, filter,
+                        iptables_cmd, iptables_filter_prefix, filter,
+                        iptables_cmd, iptables_filter_prefix, filter,
+                        iptables_cmd, filter, iptables_filter_prefix, filter);
+       LOGD("iptable reg cmd : %s", buf);
+       iptables_exec(buf);
+}
+
+static void iptables_unregister(void)
+{
+       int size = 0;
+       char buf[8192], *filter;
+
+       filter = iptables_filter_out;
+       snprintf(buf + size, sizeof(buf) - size, iptables_unregister_fmt,
+                        iptables_cmd, filter, iptables_filter_prefix, filter,
+                        iptables_cmd, iptables_filter_prefix, filter,
+                        iptables_cmd, iptables_filter_prefix, filter);
+       size = strlen(buf);
+       filter = iptables_filter_in;
+       snprintf(buf + size, sizeof(buf) - size, iptables_unregister_fmt,
+                        iptables_cmd, filter, iptables_filter_prefix, filter,
+                        iptables_cmd, iptables_filter_prefix, filter,
+                        iptables_cmd, iptables_filter_prefix, filter);
+       LOGD("iptable unreg cmd : %s", buf);
+       iptables_exec(buf);
+}
+
+static void iptables_rule(const char c, const char *addr, const int mask)
+{
+       int size = 0;
+       char buf[4096];
+
+       snprintf(buf + size, sizeof(buf) - size, iptables_rule_fmt, iptables_cmd, c,
+                        iptables_filter_prefix, iptables_filter_out, 'd', addr, mask);
+       size = strlen(buf);
+       snprintf(buf + size, sizeof(buf) - size, iptables_rule_fmt, iptables_cmd, c,
+                        iptables_filter_prefix, iptables_filter_in, 's', addr, mask);
+       LOGD("iptable cmd : %s", buf);
+       iptables_exec(buf);
+}
+
+static void iptables_rule_interface(const char c, const char *addr, const int mask, const char *interface)
+{
+       int size = 0;
+       char buf[4096];
+
+       snprintf(buf + size, sizeof(buf) - size,
+                       iptables_rule_with_interface_fmt, iptables_cmd,
+                       c, iptables_filter_prefix, iptables_filter_out,
+                       'o', interface, 'd', addr, mask);
+       size = strlen(buf);
+       snprintf(buf + size, sizeof(buf) - size,
+                       iptables_rule_with_interface_fmt, iptables_cmd,
+                       c, iptables_filter_prefix, iptables_filter_in,
+                       'i', interface, 's', addr, mask);
+       LOGD("iptable cmd : %s", buf);
+       iptables_exec(buf);
+}
+
+void iptables_add_orig(const char *addr, const int mask)
+{
+       iptables_rule_interface('I', addr, mask, iptables_filter_interface_wlan);
+}
+
+void iptables_delete_orig(const char *addr, const int mask)
+{
+       iptables_rule_interface('D', addr, mask, iptables_filter_interface_wlan);
+}
+
+void iptables_add(const char *addr, const int mask)
+{
+       iptables_rule('I', addr, mask);
+}
+
+void iptables_delete(const char *addr, const int mask)
+{
+       iptables_rule('D', addr, mask);
+}
+
+static int get_interface_index(const char *tun_name)
+{
+       struct ifreq ifr;
+       int sk = 0;
+
+       LOGD("enter get_interface_index, tun_name : %s", tun_name);
+
+       sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+       if (sk < 0) {
+               LOGE("socket failed : %s", strerror(errno));
+               return VPNSVC_ERROR_IO_ERROR;
+       }
+
+       memset(&ifr, 0, sizeof(ifr));
+
+       if (*tun_name)
+       strncpy(ifr.ifr_name, tun_name, strlen(tun_name));
+
+       /* get an interface name by ifindex */
+       if (ioctl(sk, SIOCGIFINDEX, &ifr) < 0) {
+               LOGE("ioctl SIOCGIFINDEX failed : %s", strerror(errno));
+               close(sk);
+               return VPNSVC_ERROR_IO_ERROR;
+       }
+
+       close(sk);
+
+       return ifr.ifr_ifindex;
+}
+
+
+int vpn_daemon_init(const char* tun_name, size_t tun_name_len, int fd, vpnsvc_tun_s *handle_s)
+{
+       struct ifreq ifr;
+       size_t len = 0;
+
+       LOGD("enter vpn_daemon_init, tun_name : %s, tun_name_len : %d, fd : %d\n", tun_name, tun_name_len, fd);
+
+       memset(&ifr, 0, sizeof(ifr));
+
+       /* Flags: IFF_TUN   - TUN device (no Ethernet headers)
+       *               IFF_TAP   - TAP device
+       *
+       *               IFF_NO_PI - Do not provide packet information
+       */
+
+       ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
+
+       if (*tun_name)
+               strncpy(ifr.ifr_name, tun_name, tun_name_len);
+
+       LOGD("before init, ifindex : %d", ifr.ifr_ifindex);
+
+       if (ioctl(fd, TUNSETIFF, (void *) &ifr) < 0) {
+               LOGE("TUNSETIFF Failed : %s", strerror(errno));
+               close(fd);
+               return VPNSVC_ERROR_IO_ERROR;
+       }
+
+       if (ioctl(fd, TUNSETOWNER, 5000) < 0) {
+               LOGE("TUNSETOWNER Failed : %s", strerror(errno));
+               close(fd);
+               return VPNSVC_ERROR_IO_ERROR;
+       }
+
+       if (ioctl(fd, TUNSETPERSIST, 1) < 0) {
+               LOGE("TUNSETPERSIST Failed : %s", strerror(errno));
+               close(fd);
+               return VPNSVC_ERROR_IO_ERROR;
+       }
+
+       handle_s->fd = 0;   /* server fd does not meaning */
+       handle_s->index = get_interface_index(tun_name);
+       len = strlen(ifr.ifr_name);
+       strncpy(handle_s->name, ifr.ifr_name, len);
+       handle_s->name[len] = '\0';
+
+       return VPNSVC_ERROR_NONE;
+}
+
+int vpn_daemon_deinit(const char* dev_name)
+{
+       char buf[100];
+       FILE *fp = NULL;
+
+       snprintf(buf, sizeof(buf), "/usr/sbin/ip link del %s", dev_name);
+       LOGD("link delete cmd : %s", buf);
+
+       fp = popen(buf, "r");
+       if (fp != NULL) {
+               pclose(fp);
+               return VPNSVC_ERROR_NONE;
+       } else {
+               return VPNSVC_ERROR_IO_ERROR;
+       }
+}
+
+int vpn_daemon_protect(int socket_fd, const char* dev_name)
+{
+       int ret = VPNSVC_ERROR_NONE;
+       LOGD("enter vpn_daemon_protect, socket : %d, dev_name : %s\n", socket_fd, dev_name);
+
+       ret = setsockopt(socket_fd, SOL_SOCKET, SO_BINDTODEVICE,
+                                       dev_name, strlen(dev_name));
+
+       if (ret < 0) {
+               LOGD("setsockopt failed : %d, %s", ret, strerror(errno));
+               ret = VPNSVC_ERROR_IO_ERROR;
+       } else {
+               ret = VPNSVC_ERROR_NONE;
+       }
+
+       return ret;
+}
+
+int vpn_daemon_up(int tun_index, const char* local_ip, const char* remote_ip,
+                                               const struct vpnsvc_route* routes, size_t nr_routes,
+                                               char** dns_servers, size_t nr_dns, size_t total_dns_string_cnt,
+                                               const char* dns_suffix, const unsigned int mtu) {
+
+       struct sockaddr_in local_addr;
+       struct sockaddr_in remote_addr;
+       struct ifreq ifr_tun;
+       int sk;
+       int ret = VPNSVC_ERROR_NONE;
+
+       LOGD("enter vpn_daemon_up");
+
+       LOGD("tun_index : %d", tun_index);
+       LOGD("local ip : %s", local_ip);
+       LOGD("remote ip : %s", remote_ip);
+       LOGD("route pointer : %p, nr_routes : %d, dns_server pointer : %p, nr_dns : %d, dns_suffix : %s, mtu : %d", routes, nr_routes, dns_servers, nr_dns, dns_suffix, mtu);
+
+
+       sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+       if (sk < 0) {
+               LOGE("socket failed : %s", strerror(errno));
+               return VPNSVC_ERROR_IO_ERROR;
+       }
+
+       memset(&ifr_tun, 0, sizeof(ifr_tun));
+       ifr_tun.ifr_ifindex = tun_index;
+
+       /* get an interface name by ifindex */
+       if (ioctl(sk, SIOCGIFNAME, &ifr_tun) < 0) {
+               LOGE("ioctl SIOCGIFNAME failed : %s", strerror(errno));
+               close(sk);
+               return VPNSVC_ERROR_IO_ERROR;
+       }
+
+       /* local ip setting */
+       memset(&local_addr, 0, sizeof(local_addr));
+       local_addr.sin_addr.s_addr = inet_addr(local_ip); /* network byte order */
+       local_addr.sin_family = AF_INET;
+       memcpy(&ifr_tun.ifr_addr, &local_addr, sizeof(ifr_tun.ifr_addr));
+       if (ioctl(sk, SIOCSIFADDR, &ifr_tun) < 0) {
+               LOGE("ioctl SIOCSIFADDR failed : %s", strerror(errno));
+               close(sk);
+               return VPNSVC_ERROR_IO_ERROR;
+       }
+
+       /* remote ip setting */
+       memset(&remote_addr, 0, sizeof(remote_addr));
+       remote_addr.sin_addr.s_addr = inet_addr(remote_ip); /*network byte order*/
+       remote_addr.sin_family = AF_INET;
+       memcpy(&ifr_tun.ifr_dstaddr, &remote_addr, sizeof(ifr_tun.ifr_dstaddr));
+       if (ioctl(sk, SIOCSIFDSTADDR, &ifr_tun) < 0) {
+               LOGE("ioctl SIOCSIFDSTADDR failed : %s", strerror(errno));
+               close(sk);
+               return VPNSVC_ERROR_IO_ERROR;
+       }
+
+       /* set the flags for vpn up */
+       if (ioctl(sk, SIOCGIFFLAGS, &ifr_tun) < 0) {
+               LOGE("ioctl SIOCGIFFLAGS failed : %s", strerror(errno));
+               close(sk);
+               return VPNSVC_ERROR_IO_ERROR;
+       }
+
+       ifr_tun.ifr_flags |= IFF_UP;
+       ifr_tun.ifr_flags |= IFF_RUNNING;
+
+       if (ioctl(sk, SIOCSIFFLAGS, &ifr_tun) < 0)  {
+               LOGE("ioctl SIOCSIFFLAGS failed : %s", strerror(errno));
+               close(sk);
+               return VPNSVC_ERROR_IO_ERROR;
+       }
+
+       /* mtu setting */
+       if (ioctl(sk, SIOCGIFMTU, &ifr_tun) < 0) {
+               LOGE("ioctl SIOCGIFMTU failed : %s", strerror(errno));
+               close(sk);
+               return VPNSVC_ERROR_IO_ERROR;
+       }
+
+       if (mtu > 0 && ifr_tun.ifr_mtu != (int)mtu) {
+               ifr_tun.ifr_mtu = mtu;
+               if (ioctl(sk, SIOCSIFMTU, &ifr_tun) < 0) {
+                       LOGE("ioctl SIOCSIFMTU failed : %s", strerror(errno));
+                       close(sk);
+                       return VPNSVC_ERROR_IO_ERROR;
+               }
+       }
+
+       close(sk);
+
+       /* add routes */
+       if (nr_routes > 0) {
+               ret = add_routes(ifr_tun.ifr_name, routes, nr_routes);
+               if (ret != VPNSVC_ERROR_NONE) {
+                       LOGE("add_routes failed");
+                       return ret;
+               }
+       }
+
+       /* add DNS servers */
+       if (nr_dns > 0) {
+               ret = add_dns_servers(dns_servers, nr_dns, total_dns_string_cnt);
+               if (ret != VPNSVC_ERROR_NONE) {
+                       LOGE("add_dns failed");
+                       return ret;
+               }
+       }
+
+       /* add_dns_suffix */
+       if (dns_suffix) {
+               ret = add_dns_suffix(dns_suffix, strlen(dns_suffix));
+               if (ret != VPNSVC_ERROR_NONE) {
+                       LOGE("add_dns_suffix failed");
+                       return ret;
+               }
+       }
+
+       return ret;
+}
+
+int vpn_daemon_down(int tun_index)
+{
+       struct ifreq ifr, addr_ifr;
+       struct sockaddr_in *addr = NULL;
+       int sk;
+
+       sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+       if (sk < 0) {
+               LOGE("socket failed : %s", strerror(errno));
+               return VPNSVC_ERROR_IO_ERROR;
+       }
+
+       memset(&ifr, 0, sizeof(ifr));
+       ifr.ifr_ifindex = tun_index;
+
+       if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
+               LOGE("ioctl SIOCGIFNAME failed : %s", strerror(errno));
+               close(sk);
+               return VPNSVC_ERROR_IO_ERROR;
+       }
+
+       if (ioctl(sk, SIOCGIFFLAGS, &ifr) < 0) {
+               LOGE("ioctl SIOCGIFFLAGS failed : %s", strerror(errno));
+               close(sk);
+               return VPNSVC_ERROR_IO_ERROR;
+       }
+
+       memset(&addr_ifr, 0, sizeof(addr_ifr));
+       memcpy(&addr_ifr.ifr_name, &ifr.ifr_name, sizeof(ifr.ifr_name) - 1);
+       addr = (struct sockaddr_in *)&addr_ifr.ifr_addr;
+       addr->sin_family = AF_INET;
+       if (ioctl(sk, SIOCSIFADDR, &addr_ifr) < 0)
+               LOGD("ioctl SIOCSIFADDR (could not clear IP address) failed : %s", strerror(errno));
+
+       if (!(ifr.ifr_flags & IFF_UP)) {
+               LOGD("Interface already down");
+               close(sk);
+               return VPNSVC_ERROR_NONE;
+       }
+
+       ifr.ifr_flags = (ifr.ifr_flags & ~IFF_UP) | IFF_DYNAMIC;
+       if (ioctl(sk, SIOCSIFFLAGS, &ifr) < 0) {
+               LOGE("ioctl SIOCSIFFLAGS (interface down) failed : %s", strerror(errno));
+               close(sk);
+               return VPNSVC_ERROR_IO_ERROR;
+       }
+
+       close(sk);
+
+       /* routes are will be removed  automatically while down interfaces */
+       /* remove dns servers */
+       del_dns_servers();
+
+       /* remove dns suffix */
+       del_dns_suffix();
+
+       return VPNSVC_ERROR_NONE;
+}
+
+int vpn_daemon_block_networks(const struct vpnsvc_route* nets_vpn, size_t nr_nets_vpn,
+               const struct vpnsvc_route* nets_orig, size_t nr_nets_orig) {
+       unsigned int i;
+
+       /* iptable chain regist */
+       iptables_register();
+
+       for (i = 0; i < nr_nets_vpn; i++) {
+               LOGD("block[%d] ip/mask : %s/%d", i, nets_vpn[i].dest, nets_vpn[i].prefix);
+               iptables_add(nets_vpn[i].dest, nets_vpn[i].prefix);
+       }
+
+       for (i = 0; i < nr_nets_orig; i++) {
+               LOGD("allow[%d] ip/mask : %s/%d", i, nets_orig[i].dest, nets_orig[i].prefix);
+               iptables_add_orig(nets_orig[i].dest, nets_orig[i].prefix);
+       }
+
+       return VPNSVC_ERROR_NONE;
+}
+
+int vpn_daemon_unblock_networks(void)
+{
+       iptables_unregister();
+
+       return VPNSVC_ERROR_NONE;
+}
diff --git a/daemon/src/vpn_service_daemon_main.c b/daemon/src/vpn_service_daemon_main.c
new file mode 100755 (executable)
index 0000000..1f14aaf
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+#include <stdlib.h> /* exit, EXIT_FAILURE */
+#include <dlog/dlog.h>
+
+#include "vpnsvc.h"
+#include "vpndbus.h"
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "VPNSVC_DAEMON"
+
+static GMainLoop *main_loop = NULL;
+
+static void __vpnsvc_got_name_cb(void)
+{
+       vpnsvc_create_and_init();
+}
+
+int main(void)
+{
+       int ret;
+
+       LOGD("VPN Service");
+       if (daemon(0, 0) != 0)
+               LOGD("Cannot start daemon");
+
+#if !GLIB_CHECK_VERSION(2, 36, 0)
+       g_type_init();
+#endif
+
+       main_loop = g_main_loop_new(NULL, FALSE);
+       if (main_loop == NULL) {
+               LOGE("Couldn't create GMainLoop\n");
+               return 0;
+       }
+
+       ret = vpnsvc_setup_gdbus(__vpnsvc_got_name_cb);
+       if (ret > 0) {
+               LOGE("_vpnsvc_setup_gdbus is failed\n");
+               return 0;
+       }
+
+       g_main_loop_run(main_loop);
+
+       vpnsvc_cleanup_gdbus();
+
+       return 0;
+}
diff --git a/daemon/src/vpndbus.c b/daemon/src/vpndbus.c
new file mode 100755 (executable)
index 0000000..9c12f82
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * VPN Service Module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <dlog/dlog.h>
+
+#include "vpndbus.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "VPNSVC_DAEMON"
+
+#define DBUS_REPLY_TIMEOUT (120 * 1000)
+
+static GDBusObjectManagerServer *manager_server_vpn = NULL;
+static guint owner_id = 0;
+static vpnsvc_got_name_cb g_callback = NULL;
+
+struct gdbus_conn_data {
+       GDBusConnection *connection;
+       int conn_ref_count;
+       GCancellable *cancellable;
+};
+
+static struct gdbus_conn_data gconn_data = {NULL, 0, NULL};
+
+GDBusObjectManagerServer *vpnsvc_get_vpn_manager(void)
+{
+       return manager_server_vpn;
+}
+
+GDBusConnection *vpnsvc_gdbus_get_connection(void)
+{
+       return gconn_data.connection;
+}
+
+GCancellable *vpnsvc_gdbus_get_gdbus_cancellable(void)
+{
+       return gconn_data.cancellable;
+}
+
+void vpnsvc_gdbus_pending_call_ref(void)
+{
+       g_object_ref(gconn_data.connection);
+
+       __sync_fetch_and_add(&gconn_data.conn_ref_count, 1);
+}
+
+void vpnsvc_gdbus_pending_call_unref(void)
+{
+       if (gconn_data.conn_ref_count < 1)
+               return;
+
+       g_object_unref(gconn_data.connection);
+
+       if (__sync_sub_and_fetch(&gconn_data.conn_ref_count, 1) < 1) {
+               /* TODO: Check this
+                * gconn_data.connection = NULL;
+                */
+       }
+}
+
+int vpnsvc_create_gdbus_call(GDBusConnection *conn)
+{
+       if (gconn_data.connection != NULL) {
+               LOGE("Connection already set");
+               return -1;
+       }
+
+       gconn_data.connection = conn;
+       if (gconn_data.connection == NULL) {
+               LOGE("Failed to connect to the D-BUS daemon");
+               return -1;
+       }
+
+       gconn_data.cancellable = g_cancellable_new();
+
+       return 0;
+}
+
+
+gboolean vpnsvc_invoke_dbus_method_nonblock(const char *dest, const char *path,
+               const char *interface_name, const char *method, GVariant *params,
+               GAsyncReadyCallback notify_func)
+{
+       GDBusConnection *connection = NULL;
+
+       LOGD("[GDBUS Async] %s %s %s", interface_name, method, path);
+
+       connection = vpnsvc_gdbus_get_connection();
+       if (connection == NULL) {
+               LOGE("Failed to get gdbus connection");
+               return FALSE;
+       }
+
+       g_dbus_connection_call(connection,
+                       dest,
+                       path,
+                       interface_name,
+                       method,
+                       params,
+                       NULL,
+                       G_DBUS_CALL_FLAGS_NONE,
+                       DBUS_REPLY_TIMEOUT,
+                       vpnsvc_gdbus_get_gdbus_cancellable(),
+                       (GAsyncReadyCallback) notify_func,
+                       NULL);
+
+       if (notify_func != NULL)
+               vpnsvc_gdbus_pending_call_ref();
+
+       return TRUE;
+}
+
+GVariant *vpnsvc_invoke_dbus_method(const char *dest, const char *path,
+               const char *interface_name, const char *method, GVariant *params)
+{
+
+       GError *error = NULL;
+       GVariant *reply = NULL;
+       GDBusConnection *connection;
+
+       connection = vpnsvc_gdbus_get_connection();
+       if (connection == NULL) {
+               LOGE("Failed to get GDBusconnection");
+               return reply;
+       }
+
+       reply = g_dbus_connection_call_sync(
+                       connection,
+                       dest,
+                       path,
+                       interface_name,
+                       method,
+                       params,
+                       NULL,
+                       G_DBUS_CALL_FLAGS_NONE,
+                       DBUS_REPLY_TIMEOUT,
+                       vpnsvc_gdbus_get_gdbus_cancellable(),
+                       &error);
+
+       if (reply == NULL) {
+               if (error != NULL) {
+                       LOGE("g_dbus_connection_call_sync() failed"
+                                               "error [%d: %s]", error->code, error->message);
+                       g_error_free(error);
+               } else {
+                       LOGE("g_dbus_connection_call_sync() failed");
+               }
+
+               return NULL;
+       }
+
+       return reply;
+}
+
+static void __vpnsvc_got_bus_cb(GDBusConnection *conn, const gchar *name,
+               gpointer user_data)
+{
+       LOGD("connection: [%p] name: [%s] user_data: [%p]", conn, name, user_data);
+
+       vpnsvc_create_gdbus_call(conn);
+}
+
+static void __vpnsvc_got_name_cb(GDBusConnection *conn, const gchar *name,
+               gpointer user_data)
+{
+       LOGD("connection: [%p] name: [%s] user_data: [%p]", conn, name, user_data);
+
+       if (g_callback != NULL)
+               g_callback();
+}
+
+static void __vpnsvc_lost_name_cb(GDBusConnection *conn, const gchar *name,
+               gpointer user_data)
+{
+       LOGD("connection: [%p] name: [%s] user_data: [%p]", conn, name, user_data);
+       /* May service name is already in use */
+       LOGE("Service name is already in use");
+
+       /* The result of DBus name request is only permitted,
+        *  such as DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER.
+        */
+       exit(2);
+}
+
+int vpnsvc_setup_gdbus(vpnsvc_got_name_cb cb)
+{
+       LOGD("VPN Service Setup!");
+
+       g_callback = cb;
+
+       manager_server_vpn = g_dbus_object_manager_server_new(
+                               VPNSERVICE_PATH);
+       if (manager_server_vpn == NULL) {
+               LOGE("Manager server for VPNSERVICE_PATH not created.");
+               exit(1);
+       }
+
+       owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM, VPNSERVICE_SERVICE,
+                       G_BUS_NAME_OWNER_FLAGS_NONE, __vpnsvc_got_bus_cb,
+                       __vpnsvc_got_name_cb, __vpnsvc_lost_name_cb,
+                       NULL, NULL);
+       if (!owner_id) {
+               LOGE("Could not get system bus!");
+               return -EIO;
+       }
+
+       LOGI("Got system bus!");
+       return 0;
+}
+
+void vpnsvc_cleanup_gdbus(void)
+{
+       LOGD("VPN Service Cleanup!");
+
+       g_bus_unown_name(owner_id);
+
+       return;
+}
diff --git a/daemon/src/vpnsvc.c b/daemon/src/vpnsvc.c
new file mode 100755 (executable)
index 0000000..d2a55fa
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * VPN Service Module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <dlog/dlog.h>
+#include <gio/gunixfdlist.h>
+
+#include "vpnsvc.h"
+#include "vpndbus.h"
+#include "vpn_service_daemon.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "VPNSVC_DAEMON"
+
+static Vpnsvc *vpnsvc = NULL;
+
+/*********************
+ * Handler Functions *
+ ********************/
+gboolean handle_vpn_init(Vpnsvc *object,
+                                                               GDBusMethodInvocation *invocation,
+                                                               const gchar *arg_tun_name,
+                                                               guint arg_tun_name_len)
+{
+       LOGD("handle_vpn_init");
+
+       vpnsvc_tun_s handle_s;
+       int result = VPNSVC_ERROR_NONE;
+       GDBusMessage *msg;
+       GUnixFDList *fd_list;
+       int fd_list_length;
+       const int *fds;
+
+       LOGD("vpn_init, %s, %u\n", arg_tun_name, arg_tun_name_len);
+
+       msg = g_dbus_method_invocation_get_message(invocation);
+       fd_list = g_dbus_message_get_unix_fd_list(msg);
+       fds = g_unix_fd_list_peek_fds(fd_list, &fd_list_length);
+
+       if (fd_list_length <= 0)
+               LOGD("D-Bus Message doesn't contain any fd!");
+
+       LOGD("fd:%d\n", *fds);
+
+       result = vpn_daemon_init(arg_tun_name, arg_tun_name_len, *fds, &handle_s);
+
+       LOGD("handle_s.fd : %d, handle_s.index : %d, handle_s.name : %s",
+                       handle_s.fd, handle_s.index, handle_s.name);
+
+       vpnsvc_complete_vpn_init(object, invocation, result, handle_s.index, handle_s.name);
+
+       return TRUE;
+}
+
+gboolean handle_vpn_deinit(Vpnsvc *object,
+                                                                       GDBusMethodInvocation *invocation,
+                                                                       const gchar *arg_dev_name)
+{
+       int result = VPNSVC_ERROR_NONE;
+
+       LOGD("handle_vpn_deinit");
+       LOGD("vpn_deinit, %s\n", arg_dev_name);
+
+       result = vpn_daemon_deinit(arg_dev_name);
+
+       vpnsvc_complete_vpn_deinit(object, invocation, result);
+
+       return TRUE;
+}
+
+gboolean handle_vpn_protect(Vpnsvc *object,
+                                                                       GDBusMethodInvocation *invocation,
+                                                                       const gchar *arg_dev_name)
+{
+       int result = VPNSVC_ERROR_NONE;
+       int socket;
+       GDBusMessage *msg;
+       GUnixFDList *fd_list;
+       int fd_list_length;
+       const int *fds;
+
+       LOGD("handle_vpn_protect");
+
+       msg = g_dbus_method_invocation_get_message(invocation);
+       fd_list = g_dbus_message_get_unix_fd_list(msg);
+       fds = g_unix_fd_list_peek_fds(fd_list, &fd_list_length);
+       if (fd_list_length <= 0)
+               LOGD("D-Bus Message doesn't contain any fd!");
+
+       socket = *fds;
+       LOGD("vpn_protect, %d, %s\n", socket, arg_dev_name);
+
+       result = vpn_daemon_protect(socket, arg_dev_name);
+
+       vpnsvc_complete_vpn_protect(object, invocation, result);
+
+       return TRUE;
+}
+
+gboolean handle_vpn_up(Vpnsvc *object,
+                                                               GDBusMethodInvocation *invocation,
+                                                               gint arg_tun_index,
+                                                               const gchar *arg_local_ip,
+                                                               const gchar *arg_remote_ip,
+                                                               GVariant *arg_routes,
+                                                               guint arg_nr_routes,
+                                                               GVariant *arg_dns_servers,
+                                                               guint arg_nr_dns,
+                                                               const gchar *arg_dns_suffix,
+                                                               guint arg_mtu)
+{
+       int result = VPNSVC_ERROR_NONE;
+
+       LOGD("handle_vpn_up");
+
+       struct vpnsvc_route* routes = NULL;
+       char **dns_servers = NULL;
+
+       unsigned int i = 0;
+       size_t total_dns_string_cnt = 0;
+       gchar* temp_dns_server;
+       GVariantIter iter;
+
+       gchar* route_dest;
+       gint route_prefix;
+
+       LOGD("tun_index : %d", arg_tun_index);
+       LOGD("local ip : %s", arg_local_ip);
+       LOGD("remote ip : %s", arg_remote_ip);
+       LOGD("dns_suffix : %s", arg_dns_suffix);
+       LOGD("mtu : %u", arg_mtu);
+       LOGD("arg_routes: %p", arg_routes);
+       LOGD("nr_routes : %u", arg_nr_routes);
+       LOGD("arg_dns_servers: %p", arg_dns_servers);
+       LOGD("nr_dns : %u", arg_nr_dns);
+
+       /* arg_routes check */
+       if (arg_nr_routes > 0) {
+               if (arg_routes != NULL) {
+                       GVariant *dict = g_variant_get_variant(arg_routes);
+                       routes = (struct vpnsvc_route*)malloc(sizeof(struct vpnsvc_route)*arg_nr_routes);
+                       if (routes == NULL) {
+                               LOGE("malloc failed.");
+                               result = VPNSVC_ERROR_OUT_OF_MEMORY;
+                               goto done;
+                       }
+                       g_variant_iter_init(&iter, dict);
+                       i = 0;
+                       while (g_variant_iter_loop(&iter, "{si}", &route_dest, &route_prefix)) {
+                               int temp_dest_str_len = strlen(route_dest);
+                               strncpy(routes[i].dest, route_dest, temp_dest_str_len);
+                               routes[i].dest[temp_dest_str_len] = '\0';
+                               routes[i].prefix = route_prefix;
+                               LOGD("routes[%d] : %s/%d", i, (routes[i].dest == NULL) ? "" : routes[i].dest, routes[i].prefix);
+                               i++;
+                       }
+               }
+       }
+
+
+       /* arg_nr_dns check */
+       if (arg_nr_dns > 0) {
+               if (arg_dns_servers != NULL) {
+                       GVariant *array = g_variant_get_variant(arg_dns_servers);
+                       dns_servers = (char **)malloc(arg_nr_dns*sizeof(char *));
+                       if (dns_servers == NULL) {
+                               LOGE("malloc failed.");
+                               result = VPNSVC_ERROR_OUT_OF_MEMORY;
+                               goto done;
+                       }
+                       g_variant_iter_init(&iter, array);
+                       i = 0;
+                       while (g_variant_iter_loop(&iter, "s", &temp_dns_server)) {
+                               int temp_dns_str_len = strlen(temp_dns_server);
+                               dns_servers[i] = (char *)malloc((temp_dns_str_len+1)*sizeof(char));
+                               strncpy(dns_servers[i], temp_dns_server, strlen(temp_dns_server));
+                               dns_servers[i][temp_dns_str_len] = '\0';
+                               total_dns_string_cnt += temp_dns_str_len;
+                               LOGD("dns_servers[%d] : %s", i, (dns_servers[i] == NULL) ? "" : dns_servers[i]);
+                               i++;
+                       }
+               }
+       }
+
+       result = vpn_daemon_up(arg_tun_index, arg_local_ip, arg_remote_ip,
+                       routes, arg_nr_routes, dns_servers, arg_nr_dns,
+                       total_dns_string_cnt, arg_dns_suffix, arg_mtu);
+done:
+       /* free pointers */
+       if (routes)
+               free(routes);
+
+       if (dns_servers) {
+               for (i = 0; i < arg_nr_dns; i++) {
+                       if (dns_servers[i])
+                               free(dns_servers[i]);
+               }
+               free(dns_servers);
+       }
+
+       vpnsvc_complete_vpn_up(object, invocation, result);
+
+       return TRUE;
+}
+
+gboolean handle_vpn_down(Vpnsvc *object,
+                                                                       GDBusMethodInvocation *invocation,
+                                                                       gint arg_tun_index)
+{
+       LOGD("handle_vpn_down");
+       int result = VPNSVC_ERROR_NONE;
+
+       LOGD("vpn_down, %d\n", arg_tun_index);
+
+       result = vpn_daemon_down(arg_tun_index);
+
+       vpnsvc_complete_vpn_down(object, invocation, result);
+
+       return TRUE;
+}
+
+gboolean handle_vpn_block_networks(Vpnsvc *object,
+                                                                                       GDBusMethodInvocation *invocation,
+                                                                                       GVariant *arg_nets_vpn,
+                                                                                       guint arg_nr_nets_vpn,
+                                                                                       GVariant *arg_nets_orig,
+                                                                                       guint arg_nr_nets_orig)
+{
+       LOGD("handle_vpn_block_networks");
+       int result = VPNSVC_ERROR_NONE;
+
+       struct vpnsvc_route* nets_vpn = NULL;
+       struct vpnsvc_route* nets_orig = NULL;
+
+       int i = 0;
+       GVariantIter iter;
+       gchar* route_dest;
+       gint route_prefix;
+
+       LOGD("vpn_block_networks");
+
+       /* arg_nets_vpn check */
+       if (arg_nr_nets_vpn > 0) {
+               if (arg_nets_vpn != NULL) {
+                       GVariant *dict_nets_vpn = g_variant_get_variant(arg_nets_vpn);
+                       nets_vpn = (struct vpnsvc_route*)malloc(sizeof(struct vpnsvc_route)*arg_nr_nets_vpn);
+                       if (nets_vpn == NULL) {
+                               LOGE("malloc failed.");
+                               result = VPNSVC_ERROR_OUT_OF_MEMORY;
+                               goto done;
+                       }
+                       g_variant_iter_init(&iter, dict_nets_vpn);
+                       i = 0;
+                       while (g_variant_iter_loop(&iter, "{si}", &route_dest, &route_prefix)) {
+                               int tmp_route_len = strlen(route_dest);
+                               strncpy(nets_vpn[i].dest, route_dest, tmp_route_len);
+                               nets_vpn[i].dest[tmp_route_len] = '\0';
+                               nets_vpn[i].prefix = route_prefix;
+                               LOGD("nets_vpn[%d] : %s/%d", i, (nets_vpn[i].dest == NULL) ? "" : nets_vpn[i].dest, nets_vpn[i].prefix);
+                               i++;
+                       }
+               }
+       }
+
+       /* arg_nets_orig check */
+       if (arg_nr_nets_orig > 0) {
+               if (arg_nets_orig != NULL) {
+                       GVariant *dict_nets_orig = g_variant_get_variant(arg_nets_orig);
+                       nets_orig = (struct vpnsvc_route*)malloc(sizeof(struct vpnsvc_route)*arg_nr_nets_orig);
+                       if (nets_orig == NULL) {
+                               LOGE("malloc failed.");
+                               result = VPNSVC_ERROR_OUT_OF_MEMORY;
+                               goto done;
+                       }
+                       g_variant_iter_init(&iter, dict_nets_orig);
+                       i = 0;
+                       while (g_variant_iter_loop(&iter, "{si}", &route_dest, &route_prefix)) {
+                               int tmp_route_len = strlen(route_dest);
+                               strncpy(nets_orig[i].dest, route_dest, tmp_route_len);
+                               nets_orig[i].dest[tmp_route_len] = '\0';
+                               nets_orig[i].prefix = route_prefix;
+                               LOGD("nets_orig[%d] : %s/%d", i, (nets_orig[i].dest == NULL) ? "" : nets_orig[i].dest, nets_orig[i].prefix);
+                               i++;
+                       }
+               }
+       }
+
+       /* call function */
+       result = vpn_daemon_block_networks(nets_vpn, arg_nr_nets_vpn, nets_orig, arg_nr_nets_orig);
+
+done:
+       if (nets_vpn)
+               free(nets_vpn);
+
+       if (nets_orig)
+               free(nets_orig);
+
+       vpnsvc_complete_vpn_block_networks(object, invocation, result);
+
+       return TRUE;
+}
+
+gboolean handle_vpn_unblock_networks(Vpnsvc *object,
+                                                                                       GDBusMethodInvocation *invocation)
+{
+       int result = VPNSVC_ERROR_NONE;
+
+       LOGD("handle_vpn_unblock_networks");
+       LOGD("vpn_unblock_networks");
+
+       result = vpn_daemon_unblock_networks();
+
+       vpnsvc_complete_vpn_unblock_networks(object, invocation, result);
+
+       return TRUE;
+}
+
+/*****************************
+ * Initializations Functions *
+ ****************************/
+Vpnsvc *get_vpnsvc_object(void)
+{
+       return vpnsvc;
+}
+
+void vpnsvc_create_and_init(void)
+{
+       LOGD("Create vpn object.");
+       GDBusInterfaceSkeleton *interface = NULL;
+       GDBusConnection *connection;
+       GDBusObjectManagerServer *server = vpnsvc_get_vpn_manager();
+       if (server == NULL)
+               return;
+
+       connection = vpnsvc_gdbus_get_connection();
+       g_dbus_object_manager_server_set_connection(server, connection);
+
+       /* Interface */
+       vpnsvc = vpnsvc_skeleton_new();
+       interface = G_DBUS_INTERFACE_SKELETON(vpnsvc);
+
+       /* VPN Service */
+       g_signal_connect(vpnsvc, "handle-vpn-init",
+                       G_CALLBACK(handle_vpn_init), NULL);
+       g_signal_connect(vpnsvc, "handle-vpn-deinit",
+                       G_CALLBACK(handle_vpn_deinit), NULL);
+       g_signal_connect(vpnsvc, "handle-vpn-protect",
+                       G_CALLBACK(handle_vpn_protect), NULL);
+       g_signal_connect(vpnsvc, "handle-vpn-up",
+                       G_CALLBACK(handle_vpn_up), NULL);
+       g_signal_connect(vpnsvc, "handle-vpn-down",
+                       G_CALLBACK(handle_vpn_down), NULL);
+       g_signal_connect(vpnsvc, "handle-vpn-block-networks",
+                       G_CALLBACK(handle_vpn_block_networks), NULL);
+       g_signal_connect(vpnsvc, "handle-vpn-unblock-networks",
+                       G_CALLBACK(handle_vpn_unblock_networks), NULL);
+
+       if (!g_dbus_interface_skeleton_export(interface, connection,
+                       VPNSERVICE_PATH, NULL)) {
+               LOGE("Export VPNSERVICE_PATH for vpn failed");
+       }
+
+       return;
+}
+
diff --git a/daemon/vpnsvc-daemon.manifest b/daemon/vpnsvc-daemon.manifest
new file mode 100755 (executable)
index 0000000..6b97c3a
--- /dev/null
@@ -0,0 +1,66 @@
+<manifest>
+       <define>
+               <domain name="vpnsvc"/>
+               <provide>
+                       <label name="vpnsvc::tun"/>
+                       <label name="vpnsvc::protect"/>
+                       <label name="vpnsvc::interface"/>
+                       <label name="vpnsvc::block_networks"/>
+               </provide>
+               <request>
+                       <smack request="connman" type="rw"/>
+                       <smack request="vpnsvc::tun" type="rw"/>
+                       <smack request="vpnsvc::protect" type="rw"/>
+                       <smack request="vpnsvc::interface" type="rw"/>
+                       <smack request="vpnsvc::block_networks" type="rw"/>
+                       <smack request="device::app_logging" type="rw"/>
+                       <smack request="device::sys_logging" type="rw"/>
+                       <smack request="pkgmgr::db" type="rlx"/>
+                       <smack request="pkgmgr::info" type="r"/>
+                       <smack request="tizen::vconf::platform::r" type="rw"/>
+                       <smack request="sdbd" type="rwx"/>
+                       <smack request="crash-worker" type="rwx"/>
+                       <smack request="vpnsvc_test" type="rwx"/>
+                       <smack request="core-vpn-tests" type="rwx"/>
+                       <smack request="sys-assert::core" type="rwx"/>
+               </request>
+               <permit>
+                       <smack permit="dbus" type="rwx"/>
+               </permit>
+       </define>
+       <assign>
+               <filesystem path="/usr/lib/systemd/system/vpn-service-daemon.service" label="_"/>
+               <filesystem path="/usr/share/dbus-1/services/org.tizen.vpnsvc.service" label="_"/>
+               <dbus name="org.tizen.vpnsvc" own="vpnsvc" bus="system">
+                       <node name="/org/tizen/vpnsvc">
+                               <interface name="org.tizen.vpnsvc">
+                                       <annotation name="org.tizen.smack" value="vpnsvc"/>
+                                       <method name="vpn_init">
+                                               <annotation name="org.tizen.smack" value="vpnsvc::tun"/>
+                                       </method>
+                                       <method name="vpn_deinit">
+                                               <annotation name="org.tizen.smack" value="vpnsvc::tun"/>
+                                       </method>
+                                       <method name="vpn_protect">
+                                               <annotation name="org.tizen.smack" value="vpnsvc::protect"/>
+                                       </method>
+                                       <method name="vpn_up">
+                                               <annotation name="org.tizen.smack" value="vpnsvc::interface"/>
+                                       </method>
+                                       <method name="vpn_down">
+                                               <annotation name="org.tizen.smack" value="vpnsvc::interface"/>
+                                       </method>
+                                       <method name="vpn_block_networks">
+                                               <annotation name="org.tizen.smack" value="vpnsvc::block_networks"/>
+                                       </method>
+                                       <method name="vpn_unblock_networks">
+                                               <annotation name="org.tizen.smack" value="vpnsvc::block_networks"/>
+                                       </method>
+                               </interface>
+                       </node>
+               </dbus>
+       </assign>
+       <request>
+               <domain name="vpnsvc"/>
+       </request>
+</manifest>
diff --git a/doc/vpn_doc.h b/doc/vpn_doc.h
new file mode 100755 (executable)
index 0000000..caa82e5
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * VPN Service Module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+
+#ifndef __TIZEN_NETWORK_VPN_DOC_H__
+#define __TIZEN_NETWORK_VPN_DOC_H__
+
+/**
+ * @defgroup CAPI_NETWORK_VPN_MODULE VPN
+ * @brief The VPN API provides functions for managing VPN.
+ * @ingroup CAPI_NETWORK_FRAMEWORK
+ *
+ * @section CAPI_NETWORK_VPN_MODULE_HEADER Required Header
+ *   \#include <vpn_service_product.h>
+ *
+ * @section CAPI_NETWORK_VPN_MODULE_OVERVIEW Overview
+ * VPN allows your application to manage VPN features.
+ * The VPN Service enables your application to init and deinit a VPN device(tun interface),
+ * Routing management, DNS management and Firewall management.
+ */
+
+/**
+ * @defgroup CAPI_NETWORK_VPN_SERVICE_MODULE  VPN Service
+ * @brief The VPN API provides functions for managing VPN.
+ * @ingroup CAPI_NETWORK_VPN_MODULE
+ *
+ * @section CAPI_NETWORK_VPN_SERVICE_MODULE_HEADER Required Header
+ *   \#include <vpn_service_product.h>
+ *
+ * @section CAPI_NETWORK_VPN_SERVICE_MODULE_OVERVEW Overview
+ * The VPN Service functions for managing VPN.
+ * Using the VPN Service, you can implement features that allow the users of your application to:
+ *     - Initialize / Deinitialize the VPN device
+ *     - Routing management
+ *     - DNS management
+ *     - Firewall management
+ * @section CAPI_NETWORK_VPN_SERVICE_MODULE_FEATURE Related Features
+ * This API is related with the following features:\n
+ * - http://developer.samsung.com/tizen/feature/network.vpn\n
+ *
+ * It is recommended to design feature related codes in your application for reliability.\n
+ * You can check if a device supports the related features for this API by using @ref CAPI_SYSTEM_SYSTEM_INFO_MODULE, thereby controlling the procedure of your application.\n
+ * To ensure your application is only running on the device with specific features, please define the features in your manifest file using the manifest editor in the SDK.\n
+ * More details on featuring your application can be found from <a href="../org.tizen.mobile.native.appprogramming/html/ide_sdk_tools/feature_element.htm"><b>Feature Element</b>.</a>
+ *
+ */
+
+#endif /* __TIZEN_NETWORK_VPN_DOC_H__ */
diff --git a/framework/CMakeLists.txt b/framework/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..2622891
--- /dev/null
@@ -0,0 +1,65 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(PACKAGE_NAME capi-vpnsvc)
+SET(LIB_NAME ${PACKAGE_NAME})
+PROJECT(${LIB_NAME})
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+SET(EXEC_PREFIX "\${prefix}")
+SET(LIBDIR "\${prefix}/lib")
+SET(INCLUDEDIR "\${prefix}/include")
+SET(VERSION 0.1)
+
+SET(requires "dlog dbus-1 glib-2.0 gio-2.0 gio-unix-2.0 capi-base-common capi-appfw-application capi-appfw-app-manager capi-system-info")
+SET(pc_requires "capi-base-common")
+
+SET(SRCS
+       src/capi_vpn_service.c
+)
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
+                                       ${CMAKE_SOURCE_DIR}/framework/include)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(${PACKAGE_NAME} REQUIRED ${requires})
+FOREACH(flag ${${PACKAGE_NAME}_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+# Compiler flags
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fPIC -Wall -fvisibility=hidden")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+
+ADD_DEFINITIONS("-DPREFIX=\"${PREFIX}\"")
+ADD_DEFINITIONS("-DFACTORYFS=\"$ENV{FACTORYFS}\"")
+ADD_DEFINITIONS("-DDATAFS=\"$ENV{DATADIR}\"")
+ADD_DEFINITIONS("-DSLP_DEBUG")
+
+SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=/usr/lib")
+
+ADD_LIBRARY(${PACKAGE_NAME} SHARED ${SRCS})
+TARGET_LINK_LIBRARIES(${PACKAGE_NAME} ${${PACKAGE_NAME}_LDFLAGS} -lrt -ldl)
+
+INSTALL(TARGETS ${PACKAGE_NAME} DESTINATION lib)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/include/vpn_service.h DESTINATION include)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/include/tizen_vpn_error.h DESTINATION include)
+
+SET_TARGET_PROPERTIES(${PACKAGE_NAME}
+      PROPERTIES
+      VERSION ${FULLVER}
+      SOVERSION ${MAJORVER}
+      CLEAN_DIRECT_OUTPUT 1
+)
+
+
+SET(PC_NAME ${PACKAGE_NAME})
+SET(PC_REQUIRED ${pc_requires})
+SET(PC_CFLAGS -I\${includedir})
+SET(PC_LDFLAGS -l${PACKAGE_NAME})
+
+CONFIGURE_FILE(
+    ${PACKAGE_NAME}.pc.in
+    ${CMAKE_CURRENT_SOURCE_DIR}/${PACKAGE_NAME}.pc
+    @ONLY
+)
+
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${PACKAGE_NAME}.pc DESTINATION lib/pkgconfig)
diff --git a/framework/capi-vpnsvc.manifest b/framework/capi-vpnsvc.manifest
new file mode 100755 (executable)
index 0000000..97e8c31
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+       <request>
+               <domain name="_"/>
+       </request>
+</manifest>
diff --git a/framework/capi-vpnsvc.pc.in b/framework/capi-vpnsvc.pc.in
new file mode 100755 (executable)
index 0000000..fbe305b
--- /dev/null
@@ -0,0 +1,14 @@
+
+# Package Information for pkg-config
+
+prefix=@PREFIX@
+exec_prefix=/usr
+libdir=/usr/lib
+includedir=/usr/include
+
+Name: @PC_NAME@
+Description: @PACKAGE_DESCRIPTION@
+Version: @VERSION@
+Requires: @PC_REQUIRED@
+Libs: -L${libdir} @PC_LDFLAGS@
+Cflags: -I${includedir}
diff --git a/framework/include/capi_vpn_service_private.h b/framework/include/capi_vpn_service_private.h
new file mode 100755 (executable)
index 0000000..0f56377
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * VPN Service Module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __VPN_SERVICE_H__
+#define __VPN_SERVICE_H__
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <fcntl.h>
+#include <dlog/dlog.h>
+#include <glib.h>
+#include <gio/gio.h>
+
+#include "vpn_service.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define DBUS_DAEMON_SERVICE_NAME  "org.freedesktop.DBus"
+#define DBUS_DAEMON_OBJECT_NAME  "/org/freedesktop/DBus"
+#define DBUS_DAEMON_INTERFACE_NAME  "org.freedesktop.DBus"
+#define DBUS_DAEMON_START_SERVICE_METHOD_NAME  "StartServiceByName"
+
+#define VPNSVC_DBUS_SERVICE_NAME  "org.tizen.vpnsvc"
+#define VPNSVC_DBUS_INTERFACE_NAME  "org.tizen.vpnsvc"
+#define VPNSVC_DBUS_INTERFACE_OBJ_NAME  "/org/tizen/vpnsvc"
+
+#define _MAX_FILE_PATH_LEN 512
+#define _USER_SETTING_DEFAULT_MTU 1500
+#define _USER_SETTING_DEFAULT_SESSION "VPN_Session"
+
+#define VPN_SERVICE_FEATURE    "http://tizen.org/feature/network.vpn"
+
+#define CHECK_FEATURE_SUPPORTED(feature_name) \
+       do { \
+               int feature_rv = _vpnsvc_check_feature_supported(feature_name); \
+               if (feature_rv != VPNSVC_ERROR_NONE) \
+                       return feature_rv; \
+       } while(0)
+
+/**
+  * @brief This data structure has a fido data and its length.
+  */
+typedef struct _vpnsvc_tun_s {
+       GDBusConnection *connection;            /**< D-Bus Connection */
+       int fd;                                 /**< tun socket fd */
+       int index;                              /**< tun index (if.if_index) */
+       char name[VPNSVC_TUN_IF_NAME_LEN];      /**< tun name (if.if_name) */
+       char session[VPNSVC_SESSION_STRING_LEN];/**< session name (user setting) */
+       unsigned int mtu;                       /**< mtu (user setting) */
+} vpnsvc_tun_s;
+
+int _vpnsvc_check_feature_supported(const char *feature_name);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
diff --git a/framework/src/capi_vpn_service.c b/framework/src/capi_vpn_service.c
new file mode 100755 (executable)
index 0000000..9f59ade
--- /dev/null
@@ -0,0 +1,911 @@
+/*
+ * VPN Service Module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#include "capi_vpn_service_private.h"
+#include <app.h>
+#include <app_info.h>
+#include <system_info.h>
+#include <gio/gunixfdlist.h>
+
+#define DBUS_REPLY_TIMEOUT (120 * 1000)
+
+GVariant *op = NULL;
+
+static __thread bool is_feature_checked = false;
+static __thread bool feature_supported = false;
+
+int _vpnsvc_check_feature_supported(const char *feature_name)
+{
+       if (is_feature_checked) {
+               if (!feature_supported) {
+                       LOGE("%s feature is disabled", feature_name);
+                       return VPNSVC_ERROR_NOT_SUPPORTED;
+               }
+       } else {
+               if (!system_info_get_platform_bool(feature_name, &feature_supported)) {
+                       is_feature_checked = true;
+                       if (!feature_supported) {
+                               LOGE("%s feature is disabled", feature_name);
+                               return VPNSVC_ERROR_NOT_SUPPORTED;
+                       }
+               } else {
+                       LOGE("Error - Feature getting from System Info");
+                       return VPNSVC_ERROR_IO_ERROR;
+               }
+       }
+
+       return VPNSVC_ERROR_NONE;
+}
+
+static void _vpnsvc_init_vpnsvc_tun_s(vpnsvc_tun_s **s)
+{
+       LOGD(" tun_s: %p", s);
+
+       if (s == NULL) return;
+       if (*s != NULL) {
+               LOGE("Can't Initialize vpnsvc_tun_s: %p", *s);
+               return;
+       }
+       *s = (vpnsvc_tun_s*)g_malloc0(sizeof(vpnsvc_tun_s));
+
+       if ((*s)->connection == NULL) {
+               GDBusConnection *connection = NULL;
+               GError* error = NULL;
+
+#if !GLIB_CHECK_VERSION(2, 36, 0)
+               g_type_init();
+#endif
+
+               connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+               if (error != NULL) {
+                       LOGE("Error creating Connection: %s", error->message);
+                       g_error_free(error);
+               } else {
+                       LOGD("Created Connection: %p", connection);
+                       (*s)->connection = connection;
+               }
+       }
+
+       /* Setting Default User Settings */
+       (*s)->mtu = _USER_SETTING_DEFAULT_MTU;
+       strncpy((*s)->session, _USER_SETTING_DEFAULT_SESSION, VPNSVC_SESSION_STRING_LEN);
+       (*s)->session[VPNSVC_SESSION_STRING_LEN-1] = '\0';
+}
+
+static void _vpnsvc_deinit_vpnsvc_tun_s(vpnsvc_tun_s *s)
+{
+       if (s == NULL) return;
+
+       if (s->connection)
+               s->connection = NULL;
+
+       s->fd = 0;
+       s->index = 0;
+       memset(s->name, 0, VPNSVC_TUN_IF_NAME_LEN);
+       memset(s->session, 0, VPNSVC_SESSION_STRING_LEN);
+
+       if (s)
+               g_free(s);
+}
+
+/*****************************************************************************
+* Global Functions Definition
+*****************************************************************************/
+GVariant *_vpnsvc_invoke_dbus_method(GDBusConnection *connection,
+               const char *dest, const char *path,
+               const char *interface_name, const char *method,
+               GVariant *params, int *dbus_error)
+{
+       GError *error = NULL;
+       GVariant *reply = NULL;
+       *dbus_error = VPNSVC_ERROR_NONE;
+
+       LOGD("Method Call() dest=%s path=%s iface=%s method=%s", dest, path, interface_name, method);
+
+       if (connection == NULL) {
+               LOGD("GDBusconnection is NULL");
+               *dbus_error = VPNSVC_ERROR_IO_ERROR;
+               return reply;
+       }
+
+       reply = g_dbus_connection_call_sync(connection,
+                                                                               dest,
+                                                                               path,
+                                                                               interface_name,
+                                                                               method,
+                                                                               params,
+                                                                               NULL,
+                                                                               G_DBUS_CALL_FLAGS_NONE,
+                                                                               DBUS_REPLY_TIMEOUT,
+                                                                               NULL,
+                                                                               &error);
+
+       if (reply == NULL) {
+               if (error != NULL) {
+                       LOGE("g_dbus_connection_call_sync() failed"
+                                       "error [%d: %s]", error->code, error->message);
+                       *dbus_error = VPNSVC_ERROR_IO_ERROR;
+                       g_error_free(error);
+               } else {
+                       LOGE("g_dbus_connection_call_sync() failed");
+                       *dbus_error = VPNSVC_ERROR_IPC_FAILED;
+               }
+
+               return NULL;
+       }
+
+       return reply;
+}
+GVariant *_vpnsvc_invoke_dbus_method_with_fd(GDBusConnection *connection,
+       const char *dest, const char *path,
+       const char *interface_name, const char *method,
+       GVariant *params, int fd, int *dbus_error)
+{
+       GError *error = NULL;
+       GVariant *reply = NULL;
+       GUnixFDList *fd_list = NULL;
+       *dbus_error = VPNSVC_ERROR_NONE;
+
+       LOGD("Method Call() dest=%s path=%s iface=%s method=%s fd=%d", dest, path, interface_name, method, fd);
+
+       if (connection == NULL) {
+               LOGD("GDBusconnection is NULL");
+               *dbus_error = VPNSVC_ERROR_IO_ERROR;
+               return reply;
+       }
+
+       /* Setting the fd_list */
+       fd_list = g_unix_fd_list_new();
+       if (fd_list == NULL) {
+               LOGE("g_unix_fd_list_new() failed!");
+               return NULL;
+       }
+       g_unix_fd_list_append(fd_list, fd, &error);
+       if (error != NULL) {
+               LOGE("g_unix_fd_list_append() failed"
+                               "error [%d: %s]", error->code, error->message);
+               *dbus_error = VPNSVC_ERROR_IO_ERROR;
+               g_error_free(error);
+               return NULL;
+       }
+
+       reply = g_dbus_connection_call_with_unix_fd_list_sync(connection,
+                                                                                                               dest,
+                                                                                                               path,
+                                                                                                               interface_name,
+                                                                                                               method,
+                                                                                                               params,
+                                                                                                               NULL,
+                                                                                                               G_DBUS_CALL_FLAGS_NONE,
+                                                                                                               DBUS_REPLY_TIMEOUT,
+                                                                                                               fd_list,
+                                                                                                               NULL,
+                                                                                                               NULL,
+                                                                                                               &error);
+
+       if (reply == NULL) {
+               if (error != NULL) {
+                       LOGE("g_dbus_connection_call_sync() failed"
+                                       "error [%d: %s]", error->code, error->message);
+                       *dbus_error = VPNSVC_ERROR_IO_ERROR;
+                       g_error_free(error);
+               } else {
+                       LOGE("g_dbus_connection_call_sync() failed");
+                       *dbus_error = VPNSVC_ERROR_IPC_FAILED;
+               }
+
+               return NULL;
+       }
+
+       return reply;
+}
+
+int vpnsvc_init(const char* tun_name, vpnsvc_tun_h *handle)
+{
+       CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+       int result = VPNSVC_ERROR_NONE;
+       int dbus_result;
+       int tun_fd = 0;
+
+       LOGD("enter vpnsvc_init, tun_name : %s", tun_name);
+       LOGD("handle : %p\n", handle);
+
+       /* parameter check */
+       if (tun_name == NULL || strlen(tun_name) <= 0) {
+               LOGE("tun_name is a NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       } else if (handle == NULL) {
+               LOGE("handle is a NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       } else if (*handle != NULL) {
+               LOGE("handle already created");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+
+       vpnsvc_tun_s *tmp_s = NULL;
+       _vpnsvc_init_vpnsvc_tun_s(&tmp_s);
+
+       op = _vpnsvc_invoke_dbus_method(tmp_s->connection,
+                                                                       DBUS_DAEMON_SERVICE_NAME,
+                                                                       DBUS_DAEMON_OBJECT_NAME,
+                                                                       DBUS_DAEMON_INTERFACE_NAME,
+                                                                       DBUS_DAEMON_START_SERVICE_METHOD_NAME,
+                                                                       g_variant_new("(su)", VPNSVC_DBUS_SERVICE_NAME, 0),
+                                                                       &dbus_result);
+
+       if (op == NULL) {
+               _vpnsvc_deinit_vpnsvc_tun_s(tmp_s);
+               LOGD("Service [%s] Start Failed!", VPNSVC_DBUS_SERVICE_NAME);
+               return VPNSVC_ERROR_IPC_FAILED;
+       } else {
+               unsigned int status = 0;
+               g_variant_get(op, "(u)", &status);
+               if (1 == status) {      /* DBUS_START_REPLY_SUCCESS */
+                       LOGD("Service [%s] Started Successfully!", VPNSVC_DBUS_SERVICE_NAME);
+               } else if (2 == status) {       /* DBUS_START_REPLY_ALREADY_RUNNING */
+                       LOGD("Service [%s] Already Running!", VPNSVC_DBUS_SERVICE_NAME);
+               } else {
+                       LOGD("Service [%s] Not Started! Status[%d]", VPNSVC_DBUS_SERVICE_NAME, status);
+                       g_variant_unref(op);
+                       op = NULL;
+                       _vpnsvc_deinit_vpnsvc_tun_s(tmp_s);
+                       return VPNSVC_ERROR_IO_ERROR;
+               }
+               g_variant_unref(op);
+               op = NULL;
+       }
+
+       if ((tun_fd = open("/dev/net/tun", O_RDWR)) < 0) {
+               LOGE("tun device open fail\n");
+               _vpnsvc_deinit_vpnsvc_tun_s(tmp_s);
+               return VPNSVC_ERROR_IO_ERROR;
+       }
+
+       LOGD("client tun_fd : %d", tun_fd);
+
+       op = _vpnsvc_invoke_dbus_method_with_fd(tmp_s->connection,
+                                                       VPNSVC_DBUS_SERVICE_NAME,
+                                                       VPNSVC_DBUS_INTERFACE_OBJ_NAME,
+                                                       VPNSVC_DBUS_INTERFACE_NAME,
+                                                       "vpn_init",
+                                                       g_variant_new("(su)", tun_name, strlen(tun_name)),
+                                                       tun_fd,
+                                                       &dbus_result);
+
+       if (op == NULL) {
+               close(tun_fd);
+               _vpnsvc_deinit_vpnsvc_tun_s(tmp_s);
+               return VPNSVC_ERROR_IPC_FAILED;
+       } else {
+               int tmp_index;
+               char* tmp_name;
+
+               g_variant_get(op, "(iis)", &result, &tmp_index, &tmp_name);
+               if (result != VPNSVC_ERROR_NONE) {
+                       LOGE("vpnsvc_init() failed");
+                       _vpnsvc_deinit_vpnsvc_tun_s(tmp_s);
+                       result = VPNSVC_ERROR_IPC_FAILED;
+               } else {
+                       LOGD("vpnsvc_init() succeed");
+                       tmp_s->fd = tun_fd;     /* client fd must be set */
+                       tmp_s->index = tmp_index;
+                       strncpy(tmp_s->name, tmp_name, VPNSVC_TUN_IF_NAME_LEN);
+                       tmp_s->name[VPNSVC_TUN_IF_NAME_LEN-1] = '\0';
+                       *handle = tmp_s;
+                       LOGD("handle : %p, handle->fd : %d, handle->index : %d, handle->name : %s",
+                               (*handle), ((vpnsvc_tun_s*)*handle)->fd, ((vpnsvc_tun_s*)*handle)->index, ((vpnsvc_tun_s*)*handle)->name);
+               }
+               if (op) {
+                       g_variant_unref(op);
+                       op = NULL;
+               }
+       }
+
+       return result;
+}
+
+int vpnsvc_deinit(vpnsvc_tun_h handle)
+{
+       CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+       int result = VPNSVC_ERROR_NONE;
+       int dbus_result;
+       vpnsvc_tun_s *tun_s = NULL;
+
+       /* parameter check */
+       if (handle == NULL) {
+               LOGE("handle is a NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+       tun_s = (vpnsvc_tun_s*)handle;
+
+       LOGD("enter vpnsvc_deinit, tun_fd : %d", tun_s->fd);
+
+       if (tun_s->fd > 0) {
+               op = _vpnsvc_invoke_dbus_method(tun_s->connection,
+                                                                       VPNSVC_DBUS_SERVICE_NAME,
+                                                                       VPNSVC_DBUS_INTERFACE_OBJ_NAME,
+                                                                       VPNSVC_DBUS_INTERFACE_NAME,
+                                                                       "vpn_deinit",
+                                                                       g_variant_new("(s)", tun_s->name),
+                                                                       &dbus_result);
+
+               if (op == NULL) {
+                       return VPNSVC_ERROR_IPC_FAILED;
+               } else {
+                       g_variant_get(op, "(i)", &result);
+                       if (result != VPNSVC_ERROR_NONE)
+                               LOGE("vpn_deinit() failed");
+                       else
+                               LOGD("vpn_deinit() succeed");
+               }
+
+               if (close(tun_s->fd) != 0) {
+                       LOGE("tun fd close : %s", strerror(errno));
+                       return VPNSVC_ERROR_IO_ERROR;
+               } else
+                       LOGD("tun fd close success");
+
+               /* free allocared handle memory */
+               _vpnsvc_deinit_vpnsvc_tun_s(tun_s);
+       }
+
+       return result;
+}
+
+int vpnsvc_protect(vpnsvc_tun_h handle, int socket_fd, const char* dev_name)
+{
+       CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+       int result = VPNSVC_ERROR_NONE;
+       int dbus_result;
+       vpnsvc_tun_s *tun_s = NULL;
+
+       /* parameter check */
+       if (handle == NULL) {
+               LOGE("handle is a NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+       tun_s = (vpnsvc_tun_s*)handle;
+
+       LOGD("enter vpnsvc_protect, socket : %d, dev_name : %s", socket_fd, dev_name);
+
+       if (tun_s->connection == NULL) {
+               LOGE("Connection Object is NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+
+       /* call vpnsvc_protect */
+       op = _vpnsvc_invoke_dbus_method_with_fd(tun_s->connection,
+                                               VPNSVC_DBUS_SERVICE_NAME,
+                                               VPNSVC_DBUS_INTERFACE_OBJ_NAME,
+                                               VPNSVC_DBUS_INTERFACE_NAME,
+                                               "vpn_protect",
+                                               g_variant_new("(s)", dev_name),
+                                               socket_fd,
+                                               &dbus_result);
+
+       if (op == NULL) {
+               return VPNSVC_ERROR_IPC_FAILED;
+       } else {
+               g_variant_get(op, "(i)", &result);
+
+               if (result != VPNSVC_ERROR_NONE)
+                       LOGE("vpn_protect() failed");
+               else
+                       LOGD("vpn_protect() succeed");
+       }
+
+       return result;
+}
+
+int vpnsvc_up(vpnsvc_tun_h handle, const char* local_ip, const char* remote_ip,
+                                       const struct vpnsvc_route* routes, size_t nr_routes,
+                                       const char** dns_servers, size_t nr_dns_servers,
+                                       const char* dns_suffix)
+{
+       CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+       int result = VPNSVC_ERROR_NONE;
+       int dbus_result;
+       GVariantBuilder route_builder, dns_builder;
+       size_t i = 0;
+       GVariant *route_param = NULL;
+       GVariant *dns_param = NULL;
+       vpnsvc_tun_s *tun_s = NULL;
+
+       /* parameter check */
+       if (handle == NULL) {
+               LOGE("handle is a NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+       tun_s = (vpnsvc_tun_s*)handle;
+
+       LOGD("enter vpnsvc_up");
+
+       if (tun_s->index <= 0) {
+               LOGE("invalid handle");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       } else if (tun_s->connection == NULL) {
+               LOGE("Connection Object is NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+
+       if (local_ip == NULL || remote_ip == NULL) {
+               LOGE("local and remote ip are invalid");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGD("tun_index %d", tun_s->index);
+       LOGD("local_ip : %s, remote_ip : %s", local_ip, remote_ip);
+
+       /* make a route parameter */
+       g_variant_builder_init(&route_builder, G_VARIANT_TYPE("a{si}"));
+       for (i = 0 ; i < nr_routes ; i++) {
+               if (strlen(routes[i].dest) <= 0) {
+                       LOGE("invalid routes[%d].dest", i);
+                       return VPNSVC_ERROR_INVALID_PARAMETER;
+               }
+               g_variant_builder_add(&route_builder, "{si}", routes[i].dest, routes[i].prefix);
+               LOGD("routes[%d].dest : %s", i, routes[i].dest);
+               LOGD("routes[%d].prefix : %d", i,  routes[i].prefix);
+       }
+       route_param = g_variant_builder_end(&route_builder);
+
+       /* make a dns parameter */
+       g_variant_builder_init(&dns_builder, G_VARIANT_TYPE("as"));
+       for (i = 0 ; i < nr_dns_servers ; i++) {
+               if (strlen(dns_servers[i]) <= 0) {
+                       LOGE("invalid dns_servers[%d]", i);
+                       return VPNSVC_ERROR_INVALID_PARAMETER;
+               }
+               LOGD("dns_servers[%d] : %s", i, dns_servers[i]);
+               g_variant_builder_add(&dns_builder, "s", dns_servers[i]);
+       }
+       dns_param = g_variant_builder_end(&dns_builder);
+
+       LOGD("dns_suffix : %s", dns_suffix);
+
+       op = _vpnsvc_invoke_dbus_method(tun_s->connection,
+                                                               VPNSVC_DBUS_SERVICE_NAME,
+                                                               VPNSVC_DBUS_INTERFACE_OBJ_NAME,
+                                                               VPNSVC_DBUS_INTERFACE_NAME,
+                                                               "vpn_up",
+                                                               g_variant_new("(issvuvusu)", tun_s->index, local_ip, \
+                                                               remote_ip, route_param, nr_routes, dns_param, nr_dns_servers, \
+                                                               dns_suffix, tun_s->mtu),
+                                                               &dbus_result);
+
+       if (op == NULL) {
+               return VPNSVC_ERROR_IPC_FAILED;
+       } else {
+               g_variant_get(op, "(i)", &result);
+               if (result != VPNSVC_ERROR_NONE)
+                       LOGE("vpn_up() failed");
+               else
+                       LOGD("vpn_up() succeed");
+       }
+
+       return result;
+}
+
+int vpnsvc_down(vpnsvc_tun_h handle)
+{
+       CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+       int result = VPNSVC_ERROR_NONE;
+       int dbus_result;
+       vpnsvc_tun_s *tun_s = NULL;
+
+       /* parameter check */
+       if (handle == NULL) {
+               LOGE("handle is a NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+       tun_s = (vpnsvc_tun_s*)handle;
+
+       LOGD("enter vpnsvc_down");
+
+       if (tun_s == NULL) {
+               LOGE("handle is a NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       } else if (tun_s->index <= 0) {
+               LOGE("invalid handle");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       } else if (tun_s->connection == NULL) {
+               LOGE("Connection Object is NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+
+       op = _vpnsvc_invoke_dbus_method(tun_s->connection,
+                                                               VPNSVC_DBUS_SERVICE_NAME,
+                                                               VPNSVC_DBUS_INTERFACE_OBJ_NAME,
+                                                               VPNSVC_DBUS_INTERFACE_NAME,
+                                                               "vpn_down",
+                                                               g_variant_new("(i)", tun_s->index),
+                                                               &dbus_result);
+
+       if (op == NULL) {
+               return VPNSVC_ERROR_IPC_FAILED;
+       } else {
+               g_variant_get(op, "(i)", &result);
+               if (result != VPNSVC_ERROR_NONE)
+                       LOGE("vpn_down() failed");
+               else
+                       LOGD("vpn_down() succeed");
+       }
+
+       return result;
+
+}
+
+/* this API must not be use IPC */
+int vpnsvc_read(vpnsvc_tun_h handle, int timeout_ms)
+{
+       CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+       fd_set read_set;
+       struct timeval tv;
+       int ret, retVal;
+       vpnsvc_tun_s *tun_s = NULL;
+
+       /* parameter check */
+       if (handle == NULL) {
+               LOGE("handle is a NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+       tun_s = (vpnsvc_tun_s*)handle;
+
+       if (tun_s->fd <= 0) {
+               LOGE("invalid handle");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+
+       /* listen for events */
+       FD_ZERO(&read_set);
+       FD_SET(tun_s->fd, &read_set);
+       tv.tv_usec = timeout_ms*1000;
+       retVal = select(tun_s->fd +1, &read_set, NULL, NULL, &tv);
+
+       if (retVal) {
+               LOGD("Data is available now.\n");
+               ret = VPNSVC_ERROR_NONE;
+       } else if (retVal == 0) {
+               LOGD("No data within %d ms\n", timeout_ms);
+               ret = VPNSVC_ERROR_TIMEOUT;
+       } else {
+               LOGE("select failed\n");
+               ret = VPNSVC_ERROR_IO_ERROR;
+       }
+
+       return ret;
+}
+
+/* this API must not be use IPC */
+int vpnsvc_write(vpnsvc_tun_h handle, const char* data, size_t size)
+{
+       CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+       vpnsvc_tun_s *tun_s = NULL;
+
+       /* parameter check */
+       if (handle == NULL) {
+               LOGE("handle is a NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+       tun_s = (vpnsvc_tun_s*)handle;
+
+       if (tun_s->fd <= 0) {
+               LOGE("invalid handle");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+
+       return write(tun_s->fd, data, size);
+}
+
+API int vpnsvc_block_networks(vpnsvc_tun_h handle,
+                                                                       const struct vpnsvc_route* allow_routes_vpn,
+                                                                       size_t nr_allow_routes_vpn,
+                                                                       const struct vpnsvc_route* allow_routes_orig,
+                                                                       size_t nr_allow_routes_orig)
+{
+       CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+       int result = VPNSVC_ERROR_NONE;
+       int dbus_result;
+       GVariantBuilder nets_builder;
+       size_t i = 0;
+       GVariant *nets_param_vpn;
+       GVariant *nets_param_orig;
+       vpnsvc_tun_s *tun_s = NULL;
+
+       /* parameter check */
+       if (handle == NULL) {
+               LOGE("handle is a NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+       tun_s = (vpnsvc_tun_s*)handle;
+
+       LOGD("enter vpnsvc_block_networks");
+
+       if (tun_s->connection == NULL) {
+               LOGE("Connection Object is NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+       /* make a route parameter for allowed VPN interface routes */
+       g_variant_builder_init(&nets_builder, G_VARIANT_TYPE("a{si}"));
+       for (i = 0 ; i < nr_allow_routes_vpn ; i++) {
+               g_variant_builder_add(&nets_builder, "{si}", allow_routes_vpn[i].dest, allow_routes_vpn[i].prefix);
+               LOGD("routes[%d].dest : %s", i, allow_routes_vpn[i].dest);
+               LOGD("routes[%d].prefix : %d", i,  allow_routes_vpn[i].prefix);
+       }
+       nets_param_vpn = g_variant_builder_end(&nets_builder);
+
+       /* make a route parameter for allowed Original interface Routes */
+       g_variant_builder_init(&nets_builder, G_VARIANT_TYPE("a{si}"));
+       for (i = 0 ; i < nr_allow_routes_orig ; i++) {
+               g_variant_builder_add(&nets_builder, "{si}", allow_routes_orig[i].dest, allow_routes_orig[i].prefix);
+               LOGD("routes[%d].dest : %s", i, allow_routes_orig[i].dest);
+               LOGD("routes[%d].prefix : %d", i,  allow_routes_orig[i].prefix);
+       }
+       nets_param_orig = g_variant_builder_end(&nets_builder);
+
+       op = _vpnsvc_invoke_dbus_method(tun_s->connection,
+                                                               VPNSVC_DBUS_SERVICE_NAME,
+                                                               VPNSVC_DBUS_INTERFACE_OBJ_NAME,
+                                                               VPNSVC_DBUS_INTERFACE_NAME,
+                                                               "vpn_block_networks",
+                                                               g_variant_new("(vuvu)", nets_param_vpn, nr_allow_routes_vpn,
+                                                               nets_param_orig, nr_allow_routes_orig),
+                                                               &dbus_result);
+
+       if (op == NULL) {
+               return VPNSVC_ERROR_IPC_FAILED;
+       } else {
+               g_variant_get(op, "(i)", &result);
+               if (result != VPNSVC_ERROR_NONE)
+                       LOGE("vpn_block_networks() failed");
+               else
+                       LOGD("vpn_block_networks() succeed");
+       }
+
+       return result;
+}
+
+int vpnsvc_unblock_networks(vpnsvc_tun_h handle)
+{
+       CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+       int result = VPNSVC_ERROR_NONE;
+       int dbus_result;
+       vpnsvc_tun_s *tun_s = NULL;
+
+       /* parameter check */
+       if (handle == NULL) {
+               LOGE("handle is a NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+       tun_s = (vpnsvc_tun_s*)handle;
+
+       LOGD("enter vpnsvc_unblock_networks");
+
+       if (tun_s == NULL) {
+               LOGE("handle is a NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       } else if (tun_s->connection == NULL) {
+               LOGE("Connection Object is NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+
+       op = _vpnsvc_invoke_dbus_method(tun_s->connection,
+                                                                       VPNSVC_DBUS_SERVICE_NAME,
+                                                                       VPNSVC_DBUS_INTERFACE_OBJ_NAME,
+                                                                       VPNSVC_DBUS_INTERFACE_NAME,
+                                                                       "vpn_unblock_networks",
+                                                                       g_variant_new("()"),
+                                                                       &dbus_result);
+
+       if (op == NULL) {
+               return VPNSVC_ERROR_IPC_FAILED;
+       } else {
+               g_variant_get(op, "(i)", &result);
+               if (result != VPNSVC_ERROR_NONE)
+                       LOGE("vpn_unblock_networks() failed");
+               else
+                       LOGD("vpn_unblock_networks() succeed");
+       }
+
+       return result;
+}
+
+int vpnsvc_get_tun_fd(vpnsvc_tun_h handle)
+{
+       CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+       vpnsvc_tun_s *tun_s = NULL;
+
+       /* parameter check */
+       if (handle == NULL) {
+               LOGE("handle is a NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+       tun_s = (vpnsvc_tun_s*)handle;
+
+       if (tun_s->fd <= 0) {
+               LOGE("invalid handle");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+
+       return tun_s->fd;
+}
+
+int vpnsvc_get_tun_index(vpnsvc_tun_h handle)
+{
+       CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+       vpnsvc_tun_s *tun_s = NULL;
+
+       /* parameter check */
+       if (handle == NULL) {
+               LOGE("handle is a NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+       tun_s = (vpnsvc_tun_s*)handle;
+
+       if (tun_s->index <= 0) {
+               LOGE("invalid handle");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+
+       return tun_s->index;
+}
+
+int vpnsvc_get_tun_name(vpnsvc_tun_h handle, char* tun_name)
+{
+       CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+       vpnsvc_tun_s *tun_s = NULL;
+
+       /* parameter check */
+       if (handle == NULL) {
+               LOGE("handle is a NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+       tun_s = (vpnsvc_tun_s*)handle;
+
+       if (strlen(tun_s->name) <= 0) {
+               LOGE("invalid handle");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+
+       strncpy(tun_name, tun_s->name, VPNSVC_TUN_IF_NAME_LEN);
+       tun_name[VPNSVC_TUN_IF_NAME_LEN-1] = '\0';
+
+       return VPNSVC_ERROR_NONE;
+}
+
+int vpnsvc_set_mtu(vpnsvc_tun_h handle, int mtu)
+{
+       CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+       vpnsvc_tun_s *tun_s = NULL;
+
+       /* parameter check */
+       if (handle == NULL) {
+               LOGE("handle is a NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+       tun_s = (vpnsvc_tun_s*)handle;
+
+       if (mtu <= 0) {
+               LOGE("Incorrect MTU Size = %d", mtu);
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+
+       tun_s->mtu = mtu;
+       return VPNSVC_ERROR_NONE;
+}
+
+int vpnsvc_set_blocking(vpnsvc_tun_h handle, bool blocking)
+{
+       CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+       vpnsvc_tun_s *tun_s = NULL;
+
+       /* parameter check */
+       if (handle == NULL) {
+               LOGE("handle is a NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+       tun_s = (vpnsvc_tun_s*)handle;
+
+       int flags;
+
+       if (tun_s->fd <= 0) {
+               LOGE("The Tunnel File Descriptor fd = %d", tun_s->fd);
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+
+       flags = fcntl(tun_s->fd, F_GETFL);
+       if (flags < 0) {
+               LOGD("File Descriptor Flags GET Failed fd = %d", tun_s->fd);
+               flags = 0;
+       }
+
+       if (blocking == false)
+               flags = flags | O_NONBLOCK;
+       else
+               flags = flags & (~O_NONBLOCK);
+
+       if (fcntl(tun_s->fd, F_SETFL, flags) < 0) {
+               LOGE("Failed fd = %d F_SETFL(flags) = %d", tun_s->fd, flags);
+               return VPNSVC_ERROR_IO_ERROR;
+       }
+       return VPNSVC_ERROR_NONE;
+}
+
+int vpnsvc_set_session(vpnsvc_tun_h handle, const char* session)
+{
+       CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+       vpnsvc_tun_s *tun_s = NULL;
+
+       /* parameter check */
+       if (handle == NULL) {
+               LOGE("handle is a NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+       tun_s = (vpnsvc_tun_s*)handle;
+
+       if (session == NULL) {
+               LOGE("Session Name string is NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+
+       strncpy(tun_s->session, session, VPNSVC_SESSION_STRING_LEN);
+       tun_s->session[VPNSVC_SESSION_STRING_LEN-1] = '\0';
+
+       return VPNSVC_ERROR_NONE;
+}
+
+int vpnsvc_get_session(vpnsvc_tun_h handle, char* session)
+{
+       CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+       vpnsvc_tun_s *tun_s = NULL;
+
+       /* parameter check */
+       if (handle == NULL) {
+               LOGE("handle is a NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+       tun_s = (vpnsvc_tun_s*)handle;
+
+       if (session == NULL) {
+               LOGE("Session Name string is NULL");
+               return VPNSVC_ERROR_INVALID_PARAMETER;
+       }
+
+       strncpy(session, tun_s->session, VPNSVC_SESSION_STRING_LEN);
+       session[VPNSVC_SESSION_STRING_LEN-1] = '\0';
+
+       return VPNSVC_ERROR_NONE;
+}
diff --git a/include/tizen_vpn_error.h b/include/tizen_vpn_error.h
new file mode 100755 (executable)
index 0000000..bbd32e4
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef __TIZEN_COMMON_VPN_ERROR_H__
+#define __TIZEN_COMMON_VPN_ERROR_H__
+
+#include <errno.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup CAPI_COMMON_VPN_ERROR Common VPN Error
+ * @brief This file provides error codes that are common for the whole TIZEN VPN API.
+ * @section CAPI_COMMON_VPN_ERROR_HEADER Required Header
+ *   \#include <tizen_vpn_error.h>
+ * @ingroup CAPI_COMMON_ERROR
+ * @{
+ */
+
+#define TIZEN_ERROR_MIN_VPN_ERROR (-268435456) /* = -268435455(0x0FFFFFFF) -1 */
+
+/* Check if slp error or not */
+#define TIZEN_ERROR_IS_VPN_ERROR(x) (TIZEN_ERROR_MIN_VPN_ERROR >= (x) && (x) < 0)
+
+/* Tizen VPN Service Error */
+#define TIZEN_ERROR_VPNSVC             -0x10000000
+
+/**
+ * @}
+ */
+#ifdef __cplusplus
+}
+#endif
+
+#endif         /**<__TIZEN_COMMON_VPN_ERROR_H__ */
diff --git a/include/vpn_service.h b/include/vpn_service.h
new file mode 100755 (executable)
index 0000000..3d6f6c5
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef __TIZEN_VPN_SERVICE_H__
+#define __TIZEN_VPN_SERVICE_H__
+
+/**
+ * @file vpn_service.h
+ */
+
+/**
+  *@defgroup VPNSVC_FRAMEWORK VPN_SERVICE
+  *@brief The VPN service APIs to manage VPN features such as VPN device (TUN interface) initialization, routing management, DNS management and firewall management.
+  *@section VPNSVC_FRAMEWORK_OVERVIEW Overview
+  * <table>
+  * <tr><th>API</th><th>Description></th></tr>
+  * <tr><td> @ref VPNSVC_FRAMEWORK</td>
+  *       <td> Provides functions to vpnsvc_init/vpnsvc_deinit/vpnsvc_protect/vpnsvc_up/vpnsvc_down/vpnsvc_read/vpnsvc_write/vpnsvc_block_networks/vpnsvc_unblock_networks.</td>
+  * </tr></table>
+  **/
+
+#include <tizen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tizen_error.h>
+#include <tizen_vpn_error.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "CAPI_VPNSVC"
+
+#ifndef API
+#define API __attribute__ ((visibility("default")))
+#endif
+
+/**
+  * @brief IPv4 address string length (includes end null character)
+  */
+#define VPNSVC_IP4_STRING_LEN 16
+
+/**
+  * @brief TUN interface name length (IFNAMSIZ)
+  */
+#define VPNSVC_TUN_IF_NAME_LEN 16
+
+/**
+  * @brief Session name string length (includes end null character)
+  */
+#define VPNSVC_SESSION_STRING_LEN 32
+
+
+/**
+  * @brief   Enumeration for VPN service error types
+  * @details Indicate formats of error type field
+  * @ingroup VPNSVC_FRAMEWORK
+  */
+typedef enum
+{
+    VPNSVC_ERROR_NONE = TIZEN_ERROR_NONE,                            /**< Successful */
+    VPNSVC_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER,  /**< Invalid parameter */
+    VPNSVC_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY,          /**< Out of memory */
+    VPNSVC_ERROR_PERMISSION_DENIED = TIZEN_ERROR_PERMISSION_DENIED,  /**< Permission denied */
+    VPNSVC_ERROR_NO_SUCH_FILE = TIZEN_ERROR_NO_SUCH_FILE,            /**< No such file or directory */
+    VPNSVC_ERROR_IO_ERROR = TIZEN_ERROR_IO_ERROR,                    /**< IO error */
+    VPNSVC_ERROR_TIMEOUT = TIZEN_ERROR_TIMED_OUT,                    /**< Time out error or no answer */
+    VPNSVC_ERROR_IPC_FAILED = TIZEN_ERROR_VPNSVC | 0x02,             /**< Failed to communicate with server */
+    VPNSVC_ERROR_LICENSE_FAILED = TIZEN_ERROR_VPNSVC | 0x03,         /**< Failed to verify license */
+    VPNSVC_ERROR_NOT_SUPPORTED = TIZEN_ERROR_NOT_SUPPORTED           /**< Not Supported */
+} vpnsvc_error_e;
+
+
+/**
+  * @brief   The structure containing the route information
+  * @details This structure can be used for both vpnsvc_up() and vpnsvc_block_networks() functions.
+  *
+  * @since_tizen 3.0
+  * @see vpnsvc_up()
+  * @see vpnsvc_block_networks()
+  */
+struct vpnsvc_route {
+    char dest[VPNSVC_IP4_STRING_LEN];   /**< Destination address of the route */
+    int prefix;                         /**< The prefix of route */
+};
+
+/**
+  * @brief   The VPN tun interface handle
+  * @details This handle can be obtained by calling vpnsvc_init() and destroyed(NULL) by calling vpnsvc_deinit().
+  * @since_tizen 3.0
+  * @see vpnsvc_init()
+  * @see vpnsvc_deinit()
+  */
+typedef void* vpnsvc_tun_h;
+
+
+/**
+ * @brief  Initializes TUN interface (/dev/net/tun)
+ * @detail You should call vpnsvc_get_tun_name() for checking the actual initialized TUN interface name. (In case of duplicated interface name)
+ *
+ * @since_tizen 3.0
+ * @privlevel public
+ * @privilege %http://tizen.org/privilege/vpnservicea
+ * @remarks  The license needed if you want to use this VPN API
+ *
+ * @param[in] tun_name The interface name
+ * @param[out] handle  The VPN tun interface handle
+ *
+ * @return 0 on success. otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE                  Success
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER     Invalid parameter
+ * @retval #VPNSVC_ERROR_IO_ERROR              I/O Error (e.g. socket I/O error)
+ * @retval #VPNSVC_ERROR_IPC_FAILED            Cannot connect to service daemon
+ * @retval #VPNSVC_ERROR_PERMISSION_DENIED     Permission Denied
+ * @retval #VPNSVC_ERROR_LICENSE_FAILED        Failed to verify license
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED         Not Supported
+ * @post Please call vpnsvc_deinit() if you want to de-initialize VPN tun interface.
+ * @post Please call vpnsvc_get_tun_fd() if you want to know the fd of tun interface.
+ * @post Please call vpnsvc_get_tun_index() if you want to know the fd of tun interface index(ifr.ifr_ifindex).
+ * @post Please call vpnsvc_get_tun_name() if you want to know the name of tun interface(ifr.ifr_name).
+ * @see vpnsvc_deinit()
+ * @see vpnsvc_get_tun_fd()
+ * @see vpnsvc_get_tun_index()
+ * @see vpnsvc_get_tun_name()
+ */
+API int vpnsvc_init(const char* tun_name, vpnsvc_tun_h *handle);
+
+/**
+ * @brief De-Initializes TUN interface
+ *
+ * @since_tizen 3.0
+ * @remarks The license needed if you want to use this VPN API
+ *
+ * @param[in] handle The VPN tun interface handle
+ *
+ * @return 0 on success. otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE                  Success
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER     Invalid parameter
+ * @retval #VPNSVC_ERROR_IPC_FAILED            Cannot connect to service daemon
+ * @retval #VPNSVC_ERROR_LICENSE_FAILED        Failed to verify license
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED         Not Supported
+ *
+ * @pre Before calling this function, VPN tun interface should be initialized already.
+ * @see vpnsvc_init()
+ */
+API int vpnsvc_deinit(vpnsvc_tun_h handle);
+
+/**
+ * @brief    Prevents the underlying VPN traffic to be routed to the VPN itself
+ * @details  The specific socket will be bound to the network interface using by this function.
+ *
+ * @since_tizen 3.0
+ * @remarks The license needed if you want to use this VPN API
+ *
+ * @param[in] handle    The VPN tun interface handle
+ * @param[in] socket_fd The opened socket file descriptor
+ * @param[in] dev_name  The network interface name (i.e. eth0 or ppp0, not to confuse with tunXXX) through which the VPN is working
+ *
+ * @return 0 on success. otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE                  Success
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER     Invalid parameter
+ * @retval #VPNSVC_ERROR_IO_ERROR              I/O Error (e.g. socket I/O error)
+ * @retval #VPNSVC_ERROR_IPC_FAILED            Cannot connect to service daemon
+ * @retval #VPNSVC_ERROR_LICENSE_FAILED        Failed to verify license
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED         Not Supported
+ */
+API int vpnsvc_protect(vpnsvc_tun_h handle, int socket_fd, const char* dev_name);
+
+/**
+ * @brief Sets-up TUN interface and brings it up. Installs specified routes/DNS servers/DNS suffix
+ *
+ * @since_tizen 3.0
+ * @remarks The license needed if you want to use this VPN API
+ *
+ * @param[in] handle         The VPN tun interface handle
+ * @param[in] local_ip       The local IP address
+ * @param[in] remote_ip      The remote IP address
+ * @param[in] routes         The list of routes for applying to routing table (see vpnsvc_route struct) - Optional
+ * @param[in] nr_routes      The number of routes - Optional
+ * @param[in] dns_servers    The list of DNS server names - Optional
+ * @param[in] nr_dns_servers The number of DNS server names - Optional
+ * @param[in] dns_suffix     The DNS suffix - Optional
+ *
+ * @return 0 on success. otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE                  Success
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER     Invalid parameter
+ * @retval #VPNSVC_ERROR_IPC_FAILED            Cannot connect to service daemon
+ * @retval #VPNSVC_ERROR_LICENSE_FAILED        Failed to verify license
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED         Not Supported
+ *
+ * @pre The VPN tun interface should be initialized already.
+ * @post If you want to set interface down, please call vpnsvc_down().
+ * @see #vpnsvc_route
+ * @see vpnsvc_init()
+ * @see vpnsvc_down()
+ */
+API int vpnsvc_up(vpnsvc_tun_h handle, const char* local_ip, const char* remote_ip,
+                               const struct vpnsvc_route* routes, size_t nr_routes,
+                               const char** dns_servers, size_t nr_dns_servers,
+                               const char* dns_suffix);
+
+/**
+ * @brief Brings the TUN interface down and restores original DNS servers/domains
+ *
+ * @since_tizen 3.0
+ * @remarks The license needed if you want to use this VPN API.
+ *
+ * @param[in] handle The VPN tun interface handle
+ *
+ * @return 0 on success. otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE                  Success
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER     Invalid parameter
+ * @retval #VPNSVC_ERROR_IPC_FAILED            Cannot connect to service daemon
+ * @retval #VPNSVC_ERROR_LICENSE_FAILED        Failed to verify license
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED         Not Supported
+ *
+ * @pre The VPN tun interface should be initialized already.
+ * @post Please call vpnsvc_deinit() if you want to de-initialize VPN tun interface.
+ * @see vpnsvc_up()
+ * @see vpnsvc_deinit()
+ */
+API int vpnsvc_down(vpnsvc_tun_h handle);
+
+/**
+ * @brief Waits for the read event on TUN descriptor, but no more than the indicated timeout in milliseconds
+ *
+ * @since_tizen 3.0
+ *
+ * @param[in] handle      The VPN tun interface handle
+ * @param[in] timeout_ms  The value of timeout (milliseconds)
+ *
+ * @return 0 on success. otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE                  Success
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER     Invalid parameter
+ * @retval #VPNSVC_ERROR_IO_ERROR              I/O Error (e.g. socket I/O error)
+ * @retval #VPNSVC_ERROR_TIMEOUT               Timeout (no answer in timeout_ms)
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED         Not Supported
+ *
+ * @pre The VPN interface should be initialized already.
+ * @see vpnsvc_init()
+ * @see vpnsvc_up()
+ */
+API int vpnsvc_read(vpnsvc_tun_h handle, int timeout_ms);
+
+/**
+ * @brief Writes the data supplied into the TUN interface
+ *
+ * @since_tizen 3.0
+ *
+ * @param[in] handle The VPN tun interface handle
+ * @param[in] data   Data writing to tun interface
+ * @param[in] size   The size of data
+ *
+ * @return On success, the number of bytes written is returned (zero indicates nothing was written). Otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER     Invalid parameter
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED         Not Supported
+ * @retval In case of negative error, please refer to standard posix write API's error code.
+ *
+ * @pre The VPN interface should be initialized already.
+ * @see vpnsvc_init()
+ * @see vpnsvc_up()
+ */
+API int vpnsvc_write(vpnsvc_tun_h handle, const char* data, size_t size);
+
+/**
+ * @brief Blocks all traffics except specified allowing networks
+ *
+ * @since_tizen 3.0
+ * @remarks The license needed if you want to use this VPN API
+ *
+ * @param[in] handle                  The VPN tun interface handle
+ * @param[in] allow_routes_vpn        The list of allowing networks over VPN interface (Please see vpnsvc_route structure).
+ * @param[in] nr_allow_routes_vpn     The number of allowing networks over VPN interface
+ * @param[in] allow_routes_orig       The list of allowing networks over the original interface (Please see vpnsvc_route structure).
+ * @param[in] nr_allow_routes_orig    The number of allowing networks over the original interface
+ *
+ * @return 0 on success. otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE                  Success
+ * @retval #VPNSVC_ERROR_IPC_FAILED            Cannot connect to service daemon
+ * @retval #VPNSVC_ERROR_LICENSE_FAILED        Failed to verify license
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED         Not Supported
+ *
+ * @post Please call vpnsvc_unblock_networks() if you want to allow all traffics.
+ * @see vpnsvc_unblock_networks()
+ */
+API int vpnsvc_block_networks(vpnsvc_tun_h handle,
+               const struct vpnsvc_route* allow_routes_vpn,
+               size_t nr_allow_routes_vpn,
+               const struct vpnsvc_route* allow_routes_orig,
+               size_t nr_allow_routes_orig);
+
+/**
+ * @brief Removes any restrictions imposed by vpnsvc_block_networks()
+ *
+ * @since_tizen 3.0
+ * @remarks The license needed if you want to use this VPN API
+ *
+ * @param[in] handle The VPN tun interface handle
+ *
+ * @return 0 on success. otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE                  Success
+ * @retval #VPNSVC_ERROR_IPC_FAILED            Cannot connect to service daemon
+ * @retval #VPNSVC_ERROR_LICENSE_FAILED        Failed to verify license
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED         Not Supported
+ *
+ */
+API int vpnsvc_unblock_networks(vpnsvc_tun_h handle);
+
+/**
+ * @brief Gets the fd of the VPN tun interface
+ *
+ * @since_tizen 3.0
+ *
+ * @param[in] handle The VPN tun interface handle
+ *
+ * @return The fd value of VPN tun interface. Otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER     Invalid parameter
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED         Not Supported
+ */
+API int vpnsvc_get_tun_fd(vpnsvc_tun_h handle);
+
+/**
+ * @brief Gets the index of VPN tun interface (if.if_index)
+ *
+ * @since_tizen 3.0
+ *
+ * @param[in] handle The VPN tun interface handle
+ *
+ * @return The index of the VPN tun interface. otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER     Invalid parameter
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED         Not Supported
+ *
+ * @pre Before calling this function, VPN tun interface should be initialized already.
+ * @see vpnsvc_init()
+ */
+API int vpnsvc_get_tun_index(vpnsvc_tun_h handle);
+
+/**
+ * @brief Gets the name of VPN tun interface (if.if_name)
+ *
+ * @since_tizen 3.0
+ *
+ * @param[in] handle    The VPN tun interface handle
+ * @param[out] tun_name The name of VPN tun interface name
+ *
+ * @return 0 on success. Otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE                  Success
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER     Invalid parameter
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED         Not Supported
+ *
+ * @pre Before calling this function, VPN tun interface should be initialized already.
+ * @see vpnsvc_init()
+ */
+API int vpnsvc_get_tun_name(vpnsvc_tun_h handle, char* tun_name);
+
+/**
+ * @brief Sets the MTU of the VPN tun interface (if.if_name)
+ *
+ * @since_tizen 3.0
+ *
+ * @param[in] handle The VPN tun interface handle
+ * @param[in] mtu    The MTU (Maximum Transmission Unit) value to be set for VPN tun interface. Default MTU size is 1500.
+ *
+ * @return 0 on success. Otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE                  Success
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER     Invalid parameter
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED         Not Supported
+ *
+ * @pre Before calling this function, VPN tun interface should be initialized already.
+ * @see vpnsvc_init()
+ */
+API int vpnsvc_set_mtu(vpnsvc_tun_h handle, int mtu);
+
+/**
+ * @brief Sets blocking mode of the file descriptor of VPN tun interface
+ *
+ * @since_tizen 3.0
+ *
+ * @param[in] handle    The VPN tun interface handle
+ * @param[in] blocking  The blocking mode flag; True = BLOCKING, False = NON_BLOCKING
+ *
+ * @return 0 on success. Otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE                  Success
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER     Invalid parameter
+ * @retval #VPNSVC_ERROR_IO_ERROR              Failed to set the blocking flags
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED         Not Supported
+ *
+ * @pre Before calling this function, VPN tun interface should be initialized already.
+ * @see vpnsvc_init()
+ */
+API int vpnsvc_set_blocking(vpnsvc_tun_h handle, bool blocking);
+
+/**
+ * @brief Sets the session name for the VPN
+ *
+ * @since_tizen 3.0
+ *
+ * @param[in] handle       The VPN tun interface handle
+ * @param[in] session      The Session Name
+ *
+ * @return 0 on success. Otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE                  Success
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER     Invalid parameter
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED         Not Supported
+ *
+ * @pre Before calling this function, VPN tun interface should be initialized already.
+ * @see vpnsvc_init()
+ */
+API int vpnsvc_set_session(vpnsvc_tun_h handle, const char* session);
+
+/**
+ * @brief Gets the session name for the VPN
+ *
+ * @since_tizen 3.0
+ *
+ * @param[in] handle   The VPN tun interface handle
+ * @param[out] session The Session Name returned
+ *
+ * @return 0 on success. Otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE                  Success
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER     Invalid parameter
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED         Not Supported
+ *
+ * @pre Before calling this function, VPN tun interface should be initialized already.
+ * @see vpnsvc_init()
+ */
+API int vpnsvc_get_session(vpnsvc_tun_h handle, char* session);
+
+#endif /* __TIZEN_CAPI_VPN_SERVICE_H__ */
diff --git a/packaging/capi-vpn-service.spec b/packaging/capi-vpn-service.spec
new file mode 100755 (executable)
index 0000000..1075804
--- /dev/null
@@ -0,0 +1,133 @@
+Name:       vpnsvc-pkg
+Summary:    VPN service library in TIZEN C API
+Version:    1.0.5
+Release:    1
+Group:      System/Network
+License:    Apache License, Version 2.0
+URL:        N/A
+Source0:    %{name}-%{version}.tar.gz
+Source1:    vpnsvc-daemon.service
+Source2:    org.tizen.vpnsvc.service
+BuildRequires: cmake
+BuildRequires: pkgconfig(dlog)
+BuildRequires:  pkgconfig(dbus-glib-1)
+BuildRequires:  pkgconfig(dbus-1)
+BuildRequires:  pkgconfig(glib-2.0)
+BuildRequires: pkgconfig(capi-base-common)
+BuildRequires:  pkgconfig(capi-appfw-application)
+BuildRequires:  pkgconfig(capi-appfw-package-manager)
+BuildRequires:  pkgconfig(capi-appfw-app-manager)
+BuildRequires: pkgconfig(capi-system-info)
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%description
+capi-vpn-service framework, service
+
+%package -n capi-vpnsvc
+Summary:  VPN service library in TIZEN C API
+Group:    Development/Libraries
+#Requires: capi-vpnsvc
+
+%description -n capi-vpnsvc
+capi-vpnsvc CAPI package
+
+%package -n capi-vpnsvc-devel
+Summary:  VPN service library in TIZEN C API (Development)
+Group:    Development/Libraries
+
+%description -n capi-vpnsvc-devel
+capi-vpnsvc CAPI devel package
+
+%package -n vpnsvc-test
+Summary:  Vpnsvc test
+Group:    Development/Libraries
+
+%description -n vpnsvc-test
+vpnsvc test package
+
+%package -n vpnsvc-daemon
+Summary:  Vpnsvc daemon
+Group:    Development/Libraries
+Requires:         systemd
+Requires(preun):  systemd
+Requires(post):   systemd
+Requires(postun): systemd
+
+%description -n vpnsvc-daemon
+vpnsvc daemon package
+
+%prep
+%setup -q
+
+%build
+%if 0%{?sec_build_binary_debug_enable}
+export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE"
+export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE"
+export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE"
+%endif
+
+%if 0%{?tizen_build_binary_release_type_eng}
+export CFLAGS="$CFLAGS -DTIZEN_ENGINEER_MODE"
+export CXXFLAGS="$CXXFLAGS -DTIZEN_ENGINEER_MODE"
+export FFLAGS="$FFLAGS -DTIZEN_ENGINEER_MODE"
+%endif
+
+export LDFLAGS+="-Wl,--rpath=%{_libdir}"
+
+MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
+%cmake . -DVERSION=%{version} \
+               -DFULLVER=%{version} \
+               -DMAJORVER=${MAJORVER} \
+        -DCMAKE_BUILD_TYPE=%{?build_type:%build_type}%{!?build_type:RELEASE} \
+               -DTIZEN_ENGINEER_MODE=%{?tizen_build_binary_release_type_eng:1}%{!?tizen_build_binary_release_type_eng:0} \
+        -DCMAKE_VERBOSE_MAKEFILE=ON
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+
+mkdir -p %{buildroot}/%{_datadir}/license
+cp LICENSE-Apache.v2.0 %{buildroot}/%{_datadir}/license/capi-vpnsvc
+#cp LICENSE.APLv2 %{buildroot}/usr/share/license/fpasmtztransport
+
+%make_install
+mkdir -p %{buildroot}%{_libdir}/systemd/system
+install -m 0644 %{SOURCE1} %{buildroot}%{_libdir}/systemd/system/vpnsvc-daemon.service
+mkdir -p %{buildroot}%{_datadir}/dbus-1/system-services
+install -m 0644 %{SOURCE2} %{buildroot}%{_datadir}/dbus-1/system-services/org.tizen.vpnsvc.service
+
+%clean
+rm -rf %{buildroot}
+
+%post -n capi-vpnsvc
+ln -s %{_libdir}/libcapi-vpnsvc.so.0 %{_libdir}/libcapi-vpnsvc.so
+
+%postun
+if [ $1 == 0 ]; then
+    # unistall
+    systemctl daemon-reload
+fi
+
+%files -n vpnsvc-daemon
+%manifest daemon/vpnsvc-daemon.manifest
+%attr(0755,root,root) %{_bindir}/vpnsvc-daemon
+%defattr(-,root,root,-)
+%{_libdir}/systemd/system/vpnsvc-daemon.service
+%{_datadir}/dbus-1/system-services/org.tizen.vpnsvc.service
+
+%files -n capi-vpnsvc
+%manifest framework/capi-vpnsvc.manifest
+%{_libdir}/libcapi-vpnsvc.so.*
+%{_datadir}/license/capi-vpnsvc
+
+%files -n capi-vpnsvc-devel
+%{_includedir}/*.h
+%{_libdir}/pkgconfig/capi-vpnsvc.pc
+%{_libdir}/libcapi-vpnsvc.so
+
+%files -n vpnsvc-test
+%manifest test/vpnsvc-test.manifest
+/usr/sbin/vpnsvc-test
+
diff --git a/packaging/org.tizen.vpnsvc.service b/packaging/org.tizen.vpnsvc.service
new file mode 100755 (executable)
index 0000000..079da3c
--- /dev/null
@@ -0,0 +1,7 @@
+[D-BUS Service]
+Name=org.tizen.vpnsvc
+Exec=/bin/false
+User=root
+Group=root
+SystemdService=vpnsvc-daemon.service
+
diff --git a/packaging/vpnsvc-daemon.service b/packaging/vpnsvc-daemon.service
new file mode 100755 (executable)
index 0000000..eab09e2
--- /dev/null
@@ -0,0 +1,13 @@
+[Unit]
+Description=Start vpn-service-daemon for vpn-service
+
+[Service]
+User=root
+Group=root
+SmackProcessLabel=vpnsvc
+Type=dbus
+BusName=org.tizen.vpnsvc
+RemainAfterExit=yes
+ExecStart=/usr/bin/vpnsvc-daemon
+Restart=always
+RestartSec=0
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..87a4496
--- /dev/null
@@ -0,0 +1,41 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(PACKAGE_NAME vpnsvc-test)
+SET(LIB_NAME ${PACKAGE_NAME})
+PROJECT(${LIB_NAME})
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+SET(EXEC_PREFIX "\${prefix}")
+SET(LIBDIR "\${prefix}/lib")
+SET(INCLUDEDIR "\${prefix}/include")
+SET(VERSION 0.1)
+
+SET(TEST_ROOT "${CMAKE_SOURCE_DIR}/test")
+
+SET(requires "dlog dbus-glib-1 capi-base-common capi-appfw-application")
+SET(pc_requires "capi-base-common")
+
+SET(TEST_SRCS
+       vpn_service_test.c)
+
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
+                                       ${CMAKE_SOURCE_DIR}/framework/include)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(${PACKAGE_NAME} REQUIRED ${requires})
+FOREACH(flag ${${PACKAGE_NAME}_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+# Compiler flags
+SET(EXTRA_C_FLAGS "${EXTRA_CFLAGS} -fPIC -Wall -fvisibility=hidden")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_C_FLAGS}")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+
+ADD_DEFINITIONS("-DSLP_DEBUG")
+
+SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=/usr/lib")
+
+ADD_EXECUTABLE(${PACKAGE_NAME} ${TEST_SRCS})
+TARGET_LINK_LIBRARIES(${PACKAGE_NAME} ${${PACKAGE_NAME}_LDFLAGS} "-ldl" capi-vpnsvc)
+
+INSTALL(TARGETS ${PACKAGE_NAME} DESTINATION sbin)
diff --git a/test/vpn_service_test.c b/test/vpn_service_test.c
new file mode 100755 (executable)
index 0000000..bf768ac
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * VPN Service Module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+
+#include "capi_vpn_service_private.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "VPNSVC_TEST"
+
+#define TEST_VPN_IF_NAME "vpnsvc_test"
+
+#define TEST_CONSOLE_PRINT(FMT, ARG...) fprintf(stderr, FMT, ##ARG); \
+       fprintf(stderr, "\n")
+#define TEST_CONSOLE_INPUT(BUFFER, LENGTH) \
+       do {\
+       if (fgets(BUFFER, sizeof BUFFER, stdin) == NULL) \
+               perror("fgets() failed!!!");\
+       } while (0);
+
+vpnsvc_tun_h handle = NULL;
+
+int test_vpnsvc_init()
+{
+       char *name = TEST_VPN_IF_NAME;
+       int ret = VPNSVC_ERROR_NONE;
+
+       printf("test vpnsvc_init\n");
+
+       ret = vpnsvc_init(name, &handle);
+
+       if (ret != VPNSVC_ERROR_NONE) {
+               printf("vpnsvc_init failed : %d\n", ret);
+       } else {
+               char result_name[VPNSVC_TUN_IF_NAME_LEN] = {0, };
+               printf("vpnsvc_init Succeed : %d\n", ret);
+
+               printf("tun_fd : %d\n", vpnsvc_get_tun_fd(handle));
+               printf("tun_index : %d\n", vpnsvc_get_tun_index(handle));
+               ret = vpnsvc_get_tun_name(handle, result_name);
+               if (ret == VPNSVC_ERROR_NONE)
+                       printf("tun_name : %s\n", result_name);
+       }
+
+       return 0;
+}
+
+int test_vpnsvc_deinit()
+{
+       printf("test vpnsvc_deinit\n");
+
+       if (handle)
+               vpnsvc_deinit(handle);
+
+       handle = NULL;
+
+       return 0;
+
+}
+
+int test_vpnsvc_protect()
+{
+       int sock, ret;
+
+       printf("test vpnsvc_protect\n");
+
+       if (!handle) {
+               printf("invalid handle\n");
+               return -1;
+       }
+
+       if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
+               printf("socket failed\n");
+               return -2;
+       }
+
+       ret = vpnsvc_protect(handle, sock, "wlan0");
+       if (ret != VPNSVC_ERROR_NONE)
+               printf("vpnsvc_protect failed!\n");
+       else
+               printf("vpnsvc_protect Succeed!\n");
+
+       close(sock);
+
+       return 0;
+}
+
+int test_vpnsvc_up()
+{
+       int ret;
+       char local[VPNSVC_IP4_STRING_LEN] = {'\0',};
+       char remote[VPNSVC_IP4_STRING_LEN] = {'\0',};
+       struct vpnsvc_route routes[2];
+       int nr_routes = 2;
+       const char *dns_server[2];
+       int nr_dns = 2;
+       char dns_suffix[100] = "tizen.org";
+
+       if (!handle) {
+               printf("invalid handle\n");
+               return -1;
+       }
+
+       strncpy(local, "192.168.0.82", VPNSVC_IP4_STRING_LEN);
+       strncpy(remote, "192.168.0.1", VPNSVC_IP4_STRING_LEN);
+
+       memset(routes, 0, sizeof(routes));
+       strncpy(routes[0].dest, "192.168.0.10", VPNSVC_IP4_STRING_LEN);
+       routes[0].prefix = 32;
+       strncpy(routes[1].dest, "192.168.0.11", VPNSVC_IP4_STRING_LEN);
+       routes[1].prefix = 32;
+
+       char *dns1 = "1.1.1.1";
+       char *dns2 = "2.2.2.2";
+
+       dns_server[0] = dns1;
+       dns_server[1] = dns2;
+
+       ret = vpnsvc_up(handle, local, remote, routes, nr_routes, dns_server, nr_dns, dns_suffix);
+       if (ret != VPNSVC_ERROR_NONE)
+               printf("vpnsvc_up failed!\n");
+       else
+               printf("vpnsvc_up Succeed!\n");
+
+       return 0;
+}
+
+int test_vpnsvc_down()
+{
+       int ret;
+
+       if (!handle) {
+               printf("invalid handle\n");
+               return -1;
+       }
+
+       ret = vpnsvc_down(handle);
+
+       if (ret != VPNSVC_ERROR_NONE)
+               printf("vpnsvc_down failed!\n");
+       else
+               printf("vpnsvc_down Succeed!\n");
+
+       return 0;
+
+}
+
+int test_vpnsvc_read()
+{
+       return 0;
+}
+
+int test_vpnsvc_write()
+{
+       return 0;
+}
+
+int test_vpnsvc_block_networks()
+{
+       struct vpnsvc_route block_nets[2];
+       int block_nr_nets = 2;
+       struct vpnsvc_route allow_nets[2];
+       int allow_nr_nets = 2;
+       int ret;
+
+       if (!handle) {
+               printf("invalid handle\n");
+               return -1;
+       }
+
+       memset(block_nets, 0, sizeof(block_nets));
+       strncpy(block_nets[0].dest, "125.209.222.141", VPNSVC_IP4_STRING_LEN);
+       block_nets[0].prefix = 32;
+       strncpy(block_nets[1].dest, "180.70.134.19", VPNSVC_IP4_STRING_LEN);
+       block_nets[1].prefix = 32;
+
+       memset(allow_nets, 0, sizeof(allow_nets));
+       strncpy(allow_nets[0].dest, "216.58.221.142", VPNSVC_IP4_STRING_LEN); /* google.com */
+       allow_nets[0].prefix = 32;
+       strncpy(allow_nets[1].dest, "206.190.36.45", VPNSVC_IP4_STRING_LEN); /* yahoo.com */
+       allow_nets[1].prefix = 32;
+
+       ret = vpnsvc_block_networks(handle, block_nets, block_nr_nets, allow_nets, allow_nr_nets);
+
+       if (ret != VPNSVC_ERROR_NONE)
+               printf("vpnsvc_block_networks failed!\n");
+       else
+               printf("vpnsvc_block_networks Succeed!\n");
+
+       return 0;
+
+}
+
+int test_vpnsvc_unblock_networks()
+{
+       int ret;
+
+       if (!handle) {
+               printf("invalid handle\n");
+               return -1;
+       }
+
+       ret = vpnsvc_unblock_networks(handle);
+
+       if (ret != VPNSVC_ERROR_NONE)
+               printf("vpnsvc_unblock_networks failed!\n");
+       else
+               printf("vpnsvc_unblock_networks Succeed!\n");
+
+       return 0;
+}
+
+int test_vpnsvc_set_mtu()
+{
+       int ret;
+
+       ret = vpnsvc_set_mtu(handle, 9000);
+
+       if (ret != VPNSVC_ERROR_NONE)
+               printf("vpnsvc_set_mtu failed!\n");
+       else
+               printf("vpnsvc_set_mtu Succeed!\n");
+
+       return 0;
+}
+
+bool g_blocking = false;
+
+int test_vpnsvc_set_blocking()
+{
+       int ret;
+       g_blocking = !g_blocking;
+
+       printf("Blocking Parameter: %s\n", g_blocking ? "true" : "false");
+       ret = vpnsvc_set_blocking(handle, g_blocking);
+
+       if (ret != VPNSVC_ERROR_NONE)
+               printf("vpnsvc_set_blocking failed!\n");
+       else
+               printf("vpnsvc_set_blocking Succeed!\n");
+
+       return 0;
+}
+
+int test_vpnsvc_set_session()
+{
+       int ret;
+       char *set_session = "vpnsvc_test VPN Session";
+       char get_session[VPNSVC_SESSION_STRING_LEN];
+
+       ret = vpnsvc_set_session(handle, set_session);
+
+       if (ret != VPNSVC_ERROR_NONE) {
+               printf("vpnsvc_set_session failed!\n");
+       } else {
+               ret = vpnsvc_get_session(handle, get_session);
+               printf("Session Name = %s\n", get_session);
+               printf("vpnsvc_set_session Succeed!\n");
+       }
+
+       return 0;
+}
+
+int test_exit()
+{
+       exit(0);
+}
+
+
+int (*test_function_table[])(void) = {
+       test_vpnsvc_init,
+       test_vpnsvc_deinit,
+       test_vpnsvc_protect,
+       test_vpnsvc_up,
+       test_vpnsvc_down,
+       test_vpnsvc_read,
+       test_vpnsvc_write,
+       test_vpnsvc_block_networks,
+       test_vpnsvc_unblock_networks,
+       test_vpnsvc_set_mtu,
+       test_vpnsvc_set_blocking,
+       test_vpnsvc_set_session,
+       test_exit,
+};
+
+int main()
+{
+       char input[3] = {0,};
+
+       printf("capi_vpn_service test\n");
+       while (1) {
+               __fpurge(stdin);
+               printf("1  : vpnsvc_init\n");
+               printf("2  : vpnsvc_deinit\n");
+               printf("3  : vpnsvc_protect\n");
+               printf("4  : vpnsvc_up\n");
+               printf("5  : vpnsvc_down\n");
+               printf("6  : vpnsvc_read\n");
+               printf("7  : vpnsvc_write\n");
+               printf("8  : vpnsvc_block_networks\n");
+               printf("9  : vpnsvc_unblock_networks\n");
+               printf("10 : vpnsvc_set_mtu\n");
+               printf("11 : vpnsvc_set_blocking\n");
+               printf("12 : vpnsvc_set_session\n");
+               printf("q  : quit\n");
+
+               TEST_CONSOLE_INPUT(input, 3);
+               unsigned int comm = strtoul(input, NULL, 0);
+               if (comm <= 0 || comm > (sizeof(test_function_table) / sizeof(int))) {
+                       if (input[0] == 'q') {
+                               test_exit();
+                               return 0;
+                       }
+
+                       printf("Invalid index. Retry\n");
+                       continue;
+               }
+
+               test_function_table[comm-1]();
+       }
+       return 0;
+}
diff --git a/test/vpnsvc-test.manifest b/test/vpnsvc-test.manifest
new file mode 100755 (executable)
index 0000000..80de6fa
--- /dev/null
@@ -0,0 +1,24 @@
+<manifest>
+       <define>
+               <domain name="vpnsvc_test"/>
+               <permit>
+                       <smack permit="sdbd" type="rwxat"/>
+                       <smack permit="dbus" type="rw"/>
+               </permit>
+               <request>
+                       <smack request="vpnsvc::tun" type="rw"/>
+                       <smack request="vpnsvc::protect" type="rw"/>
+                       <smack request="vpnsvc::interface" type="rw"/>
+                       <smack request="vpnsvc::block_networks" type="rw"/>
+                       <smack request="device::app_logging" type="w"/>
+                       <smack request="device::sys_logging" type="w"/>
+                       <smack request="sdbd" type="rwxat"/>
+               </request>
+       </define>
+       <assign>
+               <filesystem path="/usr/sbin/vpnsvc-test" label="vpnsvc_test" exec_label="vpnsvc_test"/>
+       </assign>
+       <request>
+               <domain name="vpnsvc_test"/>
+       </request>
+</manifest>