diff options
-rwxr-xr-x[-rw-r--r--] | AUTHORS | 0 | ||||
-rw-r--r-- | Makefile.am | 124 | ||||
-rwxr-xr-x[-rw-r--r--] | Makefile.plugins | 37 | ||||
-rwxr-xr-x[-rw-r--r--] | README | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | TODO | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | acinclude.m4 | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | client/agent.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | client/agent.h | 0 | ||||
-rw-r--r-- | client/commands.c | 642 | ||||
-rwxr-xr-x[-rw-r--r--] | client/commands.h | 0 | ||||
-rw-r--r-- | client/dbus_helpers.c | 49 | ||||
-rw-r--r-- | client/dbus_helpers.h | 9 | ||||
-rwxr-xr-x[-rw-r--r--] | client/input.c | 2 | ||||
-rwxr-xr-x[-rw-r--r--] | client/input.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | client/main.c | 0 | ||||
-rw-r--r-- | client/mesh.c | 166 | ||||
-rw-r--r-- | client/mesh.h | 40 | ||||
-rwxr-xr-x[-rw-r--r--] | client/peers.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | client/peers.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | client/services.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | client/services.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | client/vpnconnections.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | client/vpnconnections.h | 0 | ||||
-rw-r--r-- | configure.ac | 97 | ||||
-rw-r--r-- | connman.manifest | 5 | ||||
-rwxr-xr-x[-rw-r--r--] | doc/advanced-configuration.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | doc/agent-api.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | doc/backtrace.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | doc/behavior-api.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | doc/clock-api.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | doc/config-format.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | doc/counter-api.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | doc/ipconfig-api.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | doc/manager-api.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | doc/overview-api.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | doc/peer-api.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | doc/plugin-api.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | doc/service-api.txt | 26 | ||||
-rwxr-xr-x[-rw-r--r--] | doc/session-api.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | doc/session-overview.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | doc/session-policy-format.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | doc/technology-api.txt | 0 | ||||
-rw-r--r-- | doc/vpn-config-format.txt | 29 | ||||
-rwxr-xr-x[-rw-r--r--] | doc/vpn-connection-api.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | doc/vpn-manager-api.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | doc/vpn-overview.txt | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | gdbus/client.c | 8 | ||||
-rwxr-xr-x[-rw-r--r--] | gdbus/gdbus.h | 6 | ||||
-rwxr-xr-x[-rw-r--r--] | gdbus/mainloop.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | gdbus/object.c | 2 | ||||
-rwxr-xr-x[-rw-r--r--] | gdbus/polkit.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | gdbus/watch.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | gdhcp/client.c | 126 | ||||
-rwxr-xr-x[-rw-r--r--] | gdhcp/common.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | gdhcp/common.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | gdhcp/gdhcp.h | 9 | ||||
-rwxr-xr-x[-rw-r--r--] | gdhcp/ipv4ll.c | 0 | ||||
-rwxr-xr-x | gdhcp/ipv4ll.h | 55 | ||||
-rwxr-xr-x[-rw-r--r--] | gdhcp/server.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | gsupplicant/dbus.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | gsupplicant/dbus.h | 0 | ||||
-rw-r--r-- | gsupplicant/gsupplicant.h | 142 | ||||
-rw-r--r-- | gsupplicant/supplicant.c | 1644 | ||||
-rwxr-xr-x[-rw-r--r--] | gweb/giognutls.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | gweb/giognutls.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | gweb/gionotls.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | gweb/gresolv.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | gweb/gresolv.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | gweb/gweb.c | 14 | ||||
-rwxr-xr-x[-rw-r--r--] | gweb/gweb.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | include/agent.h | 0 | ||||
-rw-r--r-- | include/backtrace.h | 2 | ||||
-rw-r--r-- | include/dbus.h | 3 | ||||
-rw-r--r-- | include/device.h | 12 | ||||
-rw-r--r-- | include/inet.h | 9 | ||||
-rwxr-xr-x[-rw-r--r--] | include/inotify.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | include/ipaddress.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | include/ipconfig.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | include/log.h | 4 | ||||
-rwxr-xr-x[-rw-r--r--] | include/machine.h | 0 | ||||
-rw-r--r-- | include/mesh-netlink.h | 58 | ||||
-rw-r--r-- | include/mesh.h | 155 | ||||
-rwxr-xr-x[-rw-r--r--] | include/network.h | 105 | ||||
-rwxr-xr-x[-rw-r--r--] | include/notifier.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | include/option.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | include/peer.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | include/plugin.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | include/provider.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | include/provision.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | include/proxy.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | include/resolver.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | include/rtnl.h | 0 | ||||
-rw-r--r-- | include/service.h | 53 | ||||
-rwxr-xr-x[-rw-r--r--] | include/session.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | include/setting.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | include/storage.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | include/task.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | include/technology.h | 19 | ||||
-rwxr-xr-x[-rw-r--r--] | include/timeserver.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | include/utsname.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | include/version.h.in | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | include/vpn-dbus.h | 0 | ||||
-rw-r--r-- | packaging/connman.spec | 345 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/bluetooth.c | 33 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/connman-nmcompat.conf | 4 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/dundee.c | 0 | ||||
-rw-r--r-- | plugins/ethernet.c | 65 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/gadget.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/hh2serial-gps.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/iospm.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/loopback.c | 34 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/mcc.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/neard.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/nmcompat.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/ofono.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/pacrunner.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/polkit.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/polkit.policy | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/session_policy_local.c | 0 | ||||
-rwxr-xr-x | plugins/telephony.c | 1936 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/tist.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | plugins/vpn.c | 0 | ||||
-rw-r--r-- | plugins/wifi.c | 2192 | ||||
-rw-r--r-- | resources/usr/share/dbus-1/system-services/net.connman.service | 6 | ||||
-rw-r--r-- | resources/var/lib/connman/settings | 15 | ||||
-rw-r--r-- | scripts/500.connman_upgrade.sh | 9 | ||||
-rwxr-xr-x[-rw-r--r--] | scripts/connman.in | 2 | ||||
-rwxr-xr-x | scripts/ipsec-script.c | 146 | ||||
-rwxr-xr-x[-rw-r--r--] | scripts/libppp-plugin.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | scripts/openconnect-script.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | scripts/openvpn-script.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/6to4.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/agent-connman.c | 6 | ||||
-rwxr-xr-x[-rw-r--r--] | src/agent.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/bridge.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/clock.c | 6 | ||||
-rw-r--r-- | src/config.c | 63 | ||||
-rwxr-xr-x[-rw-r--r--] | src/connection.c | 70 | ||||
-rwxr-xr-x[-rw-r--r--] | src/connman-dbus.conf | 13 | ||||
-rwxr-xr-x[-rw-r--r--] | src/connman-polkit.conf | 6 | ||||
-rw-r--r-- | src/connman.conf | 38 | ||||
-rw-r--r-- | src/connman.h | 137 | ||||
-rwxr-xr-x[-rw-r--r--] | src/connman.service.in | 12 | ||||
-rw-r--r-- | src/connman.socket | 13 | ||||
-rw-r--r-- | src/connman_tv.service.in | 19 | ||||
-rwxr-xr-x[-rw-r--r--] | src/counter.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/dbus.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/detect.c | 7 | ||||
-rw-r--r-- | src/device.c | 196 | ||||
-rw-r--r-- | src/dhcp.c | 105 | ||||
-rwxr-xr-x[-rw-r--r--] | src/dhcpv6.c | 81 | ||||
-rwxr-xr-x[-rw-r--r--] | src/dnsproxy.c | 349 | ||||
-rwxr-xr-x[-rw-r--r--] | src/eduroam.config | 0 | ||||
-rw-r--r-- | src/error.c | 14 | ||||
-rw-r--r-- | src/inet.c | 148 | ||||
-rwxr-xr-x[-rw-r--r--] | src/inotify.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/ipaddress.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/ipconfig.c | 76 | ||||
-rwxr-xr-x[-rw-r--r--] | src/ippool.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/iptables.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/ipv6pd.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/log.c | 137 | ||||
-rwxr-xr-x[-rw-r--r--] | src/machine.c | 0 | ||||
-rw-r--r-- | src/main.c | 80 | ||||
-rwxr-xr-x[-rw-r--r--] | src/main.conf | 11 | ||||
-rwxr-xr-x | src/main_disable_eth.conf | 114 | ||||
-rwxr-xr-x | src/main_ivi.conf | 114 | ||||
-rwxr-xr-x | src/main_tv.conf | 118 | ||||
-rw-r--r-- | src/manager.c | 144 | ||||
-rw-r--r-- | src/mesh-netlink.c | 187 | ||||
-rw-r--r-- | src/mesh.c | 1660 | ||||
-rwxr-xr-x[-rw-r--r--] | src/nat.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/net.connman.service.in | 5 | ||||
-rwxr-xr-x[-rw-r--r--] | src/network.c | 564 | ||||
-rw-r--r-- | src/notifier.c | 6 | ||||
-rwxr-xr-x[-rw-r--r--] | src/ntp.c | 63 | ||||
-rwxr-xr-x[-rw-r--r--] | src/peer.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/peer_service.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/plugin.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/provider.c | 10 | ||||
-rwxr-xr-x[-rw-r--r--] | src/proxy.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/resolver.c | 27 | ||||
-rwxr-xr-x[-rw-r--r--] | src/rfkill.c | 10 | ||||
-rw-r--r-- | src/rtnl.c | 148 | ||||
-rw-r--r-- | src/service.c | 1946 | ||||
-rw-r--r-- | src/session.c | 3 | ||||
-rwxr-xr-x[-rw-r--r--] | src/shared/arp.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/shared/netlink.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/shared/netlink.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/shared/util.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/shared/util.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/stats.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/storage.c | 14 | ||||
-rwxr-xr-x[-rw-r--r--] | src/task.c | 0 | ||||
-rw-r--r-- | src/technology.c | 923 | ||||
-rwxr-xr-x[-rw-r--r--] | src/tethering.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/timeserver.c | 14 | ||||
-rwxr-xr-x[-rw-r--r--] | src/timezone.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/util.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | src/utsname.c | 0 | ||||
-rw-r--r-- | src/wispr.c | 29 | ||||
-rwxr-xr-x[-rw-r--r--] | src/wpad.c | 2 | ||||
-rwxr-xr-x | test/set-timezone | 21 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/dbus-test.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/dhcp-server-test.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/dhcp-test.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/dnsproxy-test.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/iptables-test.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/iptables-unit.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/manager-api.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/netlink-test.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/polkit-test.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/private-network-test.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/resolv-test.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/session-api.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/session-test.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/session-test.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/session-utils.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/stats-tool.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/supplicant-dbus.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/supplicant-dbus.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/supplicant-test.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/supplicant.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/supplicant.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/tap-test.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/web-test.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/wispr.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | tools/wpad-test.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | unit/test-ippool.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/connman-task.te | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/connman-vpn.service.in | 10 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/main.c | 28 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/net.connman.vpn.service.in | 3 | ||||
-rw-r--r-- | vpn/plugins/ipsec.c | 925 | ||||
-rw-r--r-- | vpn/plugins/ipsec.h | 51 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/plugins/l2tp.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/plugins/openconnect.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/plugins/openvpn.c | 2 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/plugins/pptp.c | 0 | ||||
-rw-r--r-- | vpn/plugins/vici-client.c | 1290 | ||||
-rw-r--r-- | vpn/plugins/vici-client.h | 84 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/plugins/vpn.c | 56 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/plugins/vpn.h | 7 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/plugins/vpnc.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/vpn-agent.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/vpn-agent.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/vpn-config.c | 14 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/vpn-dbus.conf | 29 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/vpn-ipconfig.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/vpn-manager.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/vpn-polkit.conf | 4 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/vpn-polkit.policy | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/vpn-provider.c | 23 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/vpn-provider.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/vpn-rtnl.c | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/vpn-rtnl.h | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/vpn.h | 5 | ||||
-rwxr-xr-x[-rw-r--r--] | vpn/vpn.ver | 0 |
258 files changed, 18558 insertions, 121 deletions
diff --git a/Makefile.am b/Makefile.am index 745bef05..5511c3f3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -14,6 +14,10 @@ include_HEADERS = include/log.h include/plugin.h \ include/inotify.h include/peer.h include/machine.h \ include/acd.h include/tethering.h +if TIZEN_EXT_WIFI_MESH +include_HEADERS += include/mesh.h include/mesh-netlink.h +endif + nodist_include_HEADERS = include/version.h noinst_HEADERS = include/rtnl.h include/task.h \ @@ -38,7 +42,7 @@ backtrace_sources = src/backtrace.c endif gdhcp_sources = gdhcp/gdhcp.h gdhcp/common.h gdhcp/common.c gdhcp/client.c \ - gdhcp/server.c gdhcp/unaligned.h + gdhcp/server.c gdhcp/ipv4ll.h gdhcp/ipv4ll.c gdhcp/unaligned.h gweb_sources = gweb/gweb.h gweb/gweb.c gweb/gresolv.h gweb/gresolv.c @@ -72,29 +76,32 @@ if VPN dbusconf_DATA += vpn/connman-vpn-dbus.conf dbusservicedir = @DBUS_DATADIR@ dbusservice_DATA = vpn/net.connman.vpn.service -endif if SYSTEMD systemdunitdir = @SYSTEMD_UNITDIR@ -systemdunit_DATA = src/connman.service src/connman-wait-online.service - -tmpfilesdir = @SYSTEMD_TMPFILESDIR@ -nodist_tmpfiles_DATA = scripts/connman_resolvconf.conf +systemdunit_DATA = src/connman.service vpn/connman-vpn.service -if VPN -systemdunit_DATA += vpn/connman-vpn.service -endif -endif endif service_files_sources = src/connman.service.in src/net.connman.service.in \ vpn/connman-vpn.service.in \ - vpn/net.connman.vpn.service.in \ - src/connman-wait-online.service.in + vpn/net.connman.vpn.service.in service_files = src/connman.service src/net.connman.service \ vpn/connman-vpn.service \ - vpn/net.connman.vpn.service \ - src/connman-wait-online.service + vpn/net.connman.vpn.service + +else + +if SYSTEMD +systemdunitdir = @SYSTEMD_UNITDIR@ +systemdunit_DATA = src/connman.service + +endif + +service_files_sources = src/connman.service.in src/net.connman.service.in +service_files = src/connman.service src/net.connman.service +endif +endif plugin_LTLIBRARIES = @@ -106,13 +113,21 @@ builtin_libadd = builtin_cflags = noinst_PROGRAMS = +if TIZEN_EXT +bin_PROGRAMS = src/connmand +else bin_PROGRAMS = +endif unit_objects = MANUAL_PAGES = +if TIZEN_EXT +sbin_PROGRAMS = +else sbin_PROGRAMS = src/connmand src/connmand-wait-online +endif src_connmand_SOURCES = $(gdhcp_sources) $(gweb_sources) $(stats_sources) \ $(backtrace_sources) $(builtin_sources) $(shared_sources) \ @@ -139,12 +154,19 @@ endif if SYSTEMD_RESOLVED_DNS_BACKEND src_connmand_SOURCES += src/dns-systemd-resolved.c endif +if TIZEN_EXT_WIFI_MESH +src_connmand_SOURCES += src/mesh.c src/mesh-netlink.c +endif src_connmand_LDADD = gdbus/libgdbus-internal.la $(builtin_libadd) \ - @GLIB_LIBS@ @DBUS_LIBS@ @GNUTLS_LIBS@ \ + @GLIB_LIBS@ @DBUS_LIBS@ @GNUTLS_LIBS@ @LIBSYSTEMD_LIBS@ \ -lresolv -ldl -lrt -src_connmand_LDFLAGS = -Wl,--export-dynamic \ +if TIZEN_EXT_WIFI_MESH +src_connmand_LDADD += @LIBNL_LIBS@ @LIBNL_GENL_LIBS@ +endif + +src_connmand_LDFLAGS = -Wl,--export-dynamic -pie \ -Wl,--version-script=$(srcdir)/src/connman.ver src_connmand_wait_online_SOURCES = src/connmand-wait-online.c @@ -172,22 +194,49 @@ builtin_vpn_sources = builtin_vpn_libadd = builtin_vpn_cflags = +if TIZEN_EXT +bin_PROGRAMS += vpn/connman-vpnd +else sbin_PROGRAMS += vpn/connman-vpnd +endif -vpn_connman_vpnd_SOURCES = $(builtin_vpn_sources) $(backtrace_sources) \ +vpn_connman_vpnd_SOURCES = $(gdhcp_sources) $(builtin_vpn_sources) \ + $(shared_sources) \ $(gweb_sources) vpn/vpn.ver vpn/main.c vpn/vpn.h \ - src/log.c src/error.c src/plugin.c src/task.c \ vpn/vpn-manager.c vpn/vpn-provider.c \ vpn/vpn-provider.h vpn/vpn-rtnl.h \ vpn/vpn-ipconfig.c src/inet.c vpn/vpn-rtnl.c \ - src/dbus.c src/storage.c src/ipaddress.c src/agent.c \ - vpn/vpn-agent.c vpn/vpn-agent.h src/inotify.c \ - vpn/vpn-config.c + src/log.c src/error.c src/plugin.c src/task.c \ + src/device.c src/network.c src/connection.c \ + src/manager.c src/service.c \ + src/clock.c src/timezone.c src/agent-connman.c \ + src/agent.c src/notifier.c src/provider.c \ + src/resolver.c src/ipconfig.c src/detect.c \ + src/dhcp.c src/dhcpv6.c src/rtnl.c src/proxy.c \ + src/utsname.c src/timeserver.c src/rfkill.c \ + src/storage.c src/dbus.c src/config.c \ + src/technology.c src/counter.c src/ntp.c \ + src/session.c src/tethering.c src/wpad.c src/wispr.c \ + src/stats.c src/iptables.c src/dnsproxy.c src/6to4.c \ + src/ippool.c src/bridge.c src/nat.c src/ipaddress.c \ + src/inotify.c src/firewall-iptables.c src/ipv6pd.c src/peer.c \ + src/peer_service.c src/machine.c src/util.c \ + vpn/vpn-agent.c vpn/vpn-agent.h \ + vpn/vpn-config.c src/acd.c + +if TIZEN_EXT_WIFI_MESH +vpn_connman_vpnd_SOURCES += src/mesh.c src/mesh-netlink.c +endif vpn_connman_vpnd_LDADD = gdbus/libgdbus-internal.la $(builtin_vpn_libadd) \ @GLIB_LIBS@ @DBUS_LIBS@ @GNUTLS_LIBS@ \ + @LIBSYSTEMD_LIBS@ @XTABLES_LIBS@ \ -lresolv -ldl +if TIZEN_EXT_WIFI_MESH +vpn_connman_vpnd_LDADD += @LIBNL_LIBS@ @LIBNL_GENL_LIBS@ +endif + vpn_connman_vpnd_LDFLAGS = -Wl,--export-dynamic \ -Wl,--version-script=$(srcdir)/vpn/vpn.ver endif @@ -235,7 +284,7 @@ build_vpn_plugindir = $(vpn_plugindir) endif endif -AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ \ +AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ @LIBSYSTEMD_CFLAGS@\ @GNUTLS_CFLAGS@ $(builtin_cflags) \ -DCONNMAN_PLUGIN_BUILTIN \ -DSTATEDIR=\""$(statedir)"\" \ @@ -244,7 +293,8 @@ AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ \ -DSCRIPTDIR=\""$(build_scriptdir)"\" \ -DSTORAGEDIR=\""$(storagedir)\"" \ -DVPN_STORAGEDIR=\""$(vpn_storagedir)\"" \ - -DCONFIGDIR=\""$(configdir)\"" + -DCONFIGDIR=\""$(configdir)\"" \ + -fPIE if VPN AM_CPPFLAGS = -I$(builddir)/include -I$(srcdir)/gdbus @@ -268,7 +318,7 @@ EXTRA_DIST = src/genbuiltin src/connman-dbus.conf src/connman-polkit.conf \ $(service_files_sources) scripts/connman.in if VPN -vpn_connman_vpnd_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ \ +vpn_connman_vpnd_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ @XTABLES_CFLAGS@ \ $(builtin_vpn_cflags) \ -DCONNMAN_PLUGIN_BUILTIN \ -DVPN_STATEDIR=\""$(vpn_statedir)"\" \ @@ -291,6 +341,14 @@ AM_CFLAGS += @NFTABLES_CFLAGS@ src_connmand_CFLAGS += @NFTABLES_CFLAGS@ endif +if TIZEN_EXT_WIFI_MESH +AM_CFLAGS += @LIBNL_CFLAGS@ @LIBNL_GENL_CFLAGS@ +src_connmand_CFLAGS += @LIBNL_CFLAGS@ @LIBNL_GENL_CFLAGS@ +if VPN +vpn_connman_vpnd_CFLAGS += @LIBNL_CFLAGS@ @LIBNL_GENL_CFLAGS@ +endif +endif + EXTRA_DIST += vpn/vpn-dbus.conf vpn/vpn-polkit.conf script_DATA = @@ -312,8 +370,12 @@ client_connmanctl_SOURCES = client/dbus_helpers.h client/dbus_helpers.c \ client/vpnconnections.h client/vpnconnections.c \ client/main.c +if TIZEN_EXT_WIFI_MESH +client_connmanctl_SOURCES += client/mesh.c client/mesh.h +endif + client_connmanctl_LDADD = gdbus/libgdbus-internal.la @DBUS_LIBS@ @GLIB_LIBS@ \ - -lreadline -ldl + -lreadline -ldl -lncurses endif noinst_PROGRAMS += unit/test-ippool @@ -464,13 +526,12 @@ EXTRA_DIST += doc/overview-api.txt doc/behavior-api.txt \ doc/connman.8.in doc/connman-vpn.8.in EXTRA_DIST += src/main.conf \ - src/eduroam.config \ - scripts/connman_resolvconf.conf.in + src/eduroam.config -MANUAL_PAGES += doc/connmanctl.1 doc/connman.conf.5 \ - doc/connman-service.config.5 doc/connman-vpn.conf.5 \ - doc/connman-vpn-provider.config.5 \ - doc/connman.8 doc/connman-vpn.8 +#MANUAL_PAGES += doc/connmanctl.1 doc/connman.conf.5 \ +# doc/connman-service.config.5 doc/connman-vpn.conf.5 \ +# doc/connman-vpn-provider.config.5 \ +# doc/connman.8 doc/connman-vpn.8 nodist_man_MANS = $(MANUAL_PAGES) @@ -482,6 +543,7 @@ DISTCHECK_CONFIGURE_FLAGS = --disable-datafiles \ --enable-hh2serial-gps \ --enable-openconnect \ --enable-openvpn \ + --enable-ipsec \ --enable-vpnc \ --enable-session-policy-local \ --enable-nmcompat \ diff --git a/Makefile.plugins b/Makefile.plugins index dce8b283..1eb0c3f2 100644..100755 --- a/Makefile.plugins +++ b/Makefile.plugins @@ -58,6 +58,18 @@ builtin_modules += dundee builtin_sources += plugins/dundee.c endif +if TELEPHONY +if TELEPHONY_BUILTIN +builtin_modules += telephony +builtin_sources += plugins/telephony.c +else +plugin_LTLIBRARIES += plugins/telephony.la +plugin_objects += $(plugins_telephony_la_OBJECTS) +plugins_telephony_la_CFLAGS = $(plugin_cflags) +plugins_telephony_la_LDFLAGS = $(plugin_ldflags) +endif +endif + if VPN builtin_modules += vpn builtin_sources += plugins/vpn.c @@ -99,6 +111,25 @@ vpn_plugins_openvpn_la_LDFLAGS = $(plugin_ldflags) endif endif +if IPSEC +if IPSEC_BUILTIN +builtin_vpn_modules += ipsec +builtin_vpn_sources += vpn/plugins/ipsec.h vpn/plugins/ipsec.c +builtin_vpn_sources += vpn/plugins/vici-client.h vpn/plugins/vici-client.c +builtin_vpn_source = vpn/plugins/vpn.c vpn/plugins/vpn.h +builtin_vpn_cflags += -DIPSEC=\"@IPSEC@\" +else +vpn_plugin_LTLIBRARIES += vpn/plugins/ipsec.la +vpn_plugin_objects += $(plugins_ipsec_la_OBJECTS) +vpn_plugins_ipsec_la_SOURCES = vpn/plugins/vpn.h vpn/plugins/vpn.c \ + vpn/plugins/ipsec.c vpn/plugins/vici-client.c +vpn_plugins_ipsec_la_CFLAGS = $(plugin_cflags) -DIPSEC=\"@IPSEC@\" \ + -DVPN_STATEDIR=\""$(vpn_statedir)"\" \ + -DSCRIPTDIR=\""$(build_scriptdir)"\" @GIO_CFLAGS@ +vpn_plugins_ipsec_la_LDFLAGS = $(plugin_ldflags) @GIO_LIBS@ +endif +endif + if VPNC if VPNC_BUILTIN builtin_vpn_modules += vpnc @@ -216,6 +247,12 @@ script_PROGRAMS += scripts/openvpn-script scripts_openvpn_script_LDADD = @DBUS_LIBS@ endif +if IPSEC +script_PROGRAMS += scripts/ipsec-script + +scripts_ipsec_script_LDADD = @DBUS_LIBS@ +endif + if NMCOMPAT builtin_modules += nmcompat builtin_sources += plugins/nmcompat.c diff --git a/acinclude.m4 b/acinclude.m4 index 9e8e0dc5..9e8e0dc5 100644..100755 --- a/acinclude.m4 +++ b/acinclude.m4 diff --git a/client/agent.c b/client/agent.c index d0208892..d0208892 100644..100755 --- a/client/agent.c +++ b/client/agent.c diff --git a/client/agent.h b/client/agent.h index 669a5934..669a5934 100644..100755 --- a/client/agent.h +++ b/client/agent.h diff --git a/client/commands.c b/client/commands.c index 097d293a..6abe7db5 100644 --- a/client/commands.c +++ b/client/commands.c @@ -44,6 +44,9 @@ #include "commands.h" #include "agent.h" #include "vpnconnections.h" +#if defined TIZEN_EXT_WIFI_MESH +#include "mesh.h" +#endif static DBusConnection *connection; static GHashTable *service_hash; @@ -612,6 +615,578 @@ static int tether_set_ssid(char *ssid, char *passphrase, int set_tethering) return -EINPROGRESS; } +#if defined TIZEN_EXT_WIFI_MESH +struct mesh_if_prop { + char *ifname; + char *parent_ifname; + char *bridge_ifname; +}; + +struct mesh_create_network { + char *name; + unsigned int freq; + char *sec_type; +}; + +struct mesh_specific_scan_params { + char *name; + unsigned int freq; +}; + +struct mesh_gate_params { + bool gate_announce; + int hwmp_rootmode; + int stp; +}; + +static int mesh_return(DBusMessageIter *iter, const char *error, + void *user_data) +{ + char *method = user_data; + + if (error) + fprintf(stderr, "Error %s: %s\n", method, error); + else + fprintf(stderr, "Success %s\n", method); + + g_free(method); + + return 0; +} + +static void mesh_interface_add_append(DBusMessageIter *iter, void *user_data) +{ + struct mesh_if_prop *append = user_data; + + /* Append Virtual Interface Name */ + __connmanctl_dbus_append_dict_entry(iter, "Ifname", + DBUS_TYPE_STRING, &append->ifname); + + /* Append Parent WiFi Interface Name */ + __connmanctl_dbus_append_dict_entry(iter, "ParentIfname", + DBUS_TYPE_STRING, &append->parent_ifname); + + /* Append Bridge Interface Name */ + if (append->bridge_ifname) + __connmanctl_dbus_append_dict_entry(iter, "BridgeIfname", + DBUS_TYPE_STRING, &append->bridge_ifname); +} + +static void mesh_interface_remove_append(DBusMessageIter *iter, void *user_data) +{ + struct mesh_if_prop *append = user_data; + + /* Append Virtual Interface Name */ + __connmanctl_dbus_append_dict_entry(iter, "Ifname", + DBUS_TYPE_STRING, &append->ifname); +} + +static void mesh_create_network_append(DBusMessageIter *iter, void *user_data) +{ + struct mesh_create_network *append = user_data; + + /* Append Mesh Network Name */ + __connmanctl_dbus_append_dict_entry(iter, "Name", + DBUS_TYPE_STRING, &append->name); + + /* Append Mesh Network Frequency */ + __connmanctl_dbus_append_dict_entry(iter, "Frequency", + DBUS_TYPE_UINT16, &append->freq); + + /* Append Mesh Network Security Type */ + __connmanctl_dbus_append_dict_entry(iter, "Security", + DBUS_TYPE_STRING, &append->sec_type); +} + +static void mesh_specific_scan_append(DBusMessageIter *iter, void *user_data) +{ + struct mesh_specific_scan_params *append = user_data; + + /* Append Mesh Network Name */ + __connmanctl_dbus_append_dict_entry(iter, "Name", + DBUS_TYPE_STRING, &append->name); + + /* Append Mesh Network Frequency */ + __connmanctl_dbus_append_dict_entry(iter, "Frequency", + DBUS_TYPE_UINT16, &append->freq); +} + +static void mesh_set_gate_append(DBusMessageIter *iter, void *user_data) +{ + struct mesh_gate_params *append = user_data; + + /* Append Gate Announce Protocol */ + __connmanctl_dbus_append_dict_entry(iter, "GateAnnounce", + DBUS_TYPE_BOOLEAN, &append->gate_announce); + + /* Append HWMP Root Mode */ + __connmanctl_dbus_append_dict_entry(iter, "HWMPRootMode", + DBUS_TYPE_UINT16, &append->hwmp_rootmode); + + /* Append STP */ + __connmanctl_dbus_append_dict_entry(iter, "STP", DBUS_TYPE_UINT16, + &append->stp); +} + +static void mesh_peer_append(DBusMessageIter *iter, void *user_data) +{ + char *peer_addr = user_data; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &peer_addr); + + g_free(peer_addr); +} + +static int mesh_peers_list(DBusMessageIter *iter, + const char *error, void *user_data) +{ + if (!error) { + __connmanctl_mesh_peers_list(iter); + fprintf(stdout, "\n"); + } else + fprintf(stderr, "Error: %s\n", error); + + return 0; +} + +static int connected_mesh_peers_list(DBusMessageIter *iter, + const char *error, void *user_data) +{ + if (!error) { + __connmanctl_mesh_connected_peers_list(iter); + fprintf(stdout, "\n"); + } else + fprintf(stderr, "Error: %s\n", error); + + return 0; +} + +static int disconnected_mesh_peers_list(DBusMessageIter *iter, + const char *error, void *user_data) +{ + if (!error) { + __connmanctl_mesh_disconnected_peers_list(iter); + fprintf(stdout, "\n"); + } else + fprintf(stderr, "Error: %s\n", error); + + return 0; +} + +static int mesh_connect_return(DBusMessageIter *iter, const char *error, + void *user_data) +{ + char *path = user_data; + + if (!error) { + char *str = strrchr(path, '/'); + str++; + fprintf(stdout, "Connected %s\n", str); + } else + fprintf(stderr, "Error %s: %s\n", path, error); + + g_free(user_data); + + return 0; +} + +static int mesh_disconnect_return(DBusMessageIter *iter, const char *error, + void *user_data) +{ + char *path = user_data; + + if (!error) { + char *str = strrchr(path, '/'); + str++; + fprintf(stdout, "Disconnected %s\n", str); + } else + fprintf(stderr, "Error %s: %s\n", path, error); + + g_free(user_data); + + return 0; +} + +static int mesh_remove_return(DBusMessageIter *iter, const char *error, + void *user_data) +{ + char *path = user_data; + + if (!error) { + char *str = strrchr(path, '/'); + str++; + fprintf(stdout, "Removed %s\n", str); + } else + fprintf(stderr, "Error %s: %s\n", path, error); + + g_free(user_data); + + return 0; +} + +static int mesh_config_return(DBusMessageIter *iter, const char *error, + void *user_data) +{ + char *path = user_data; + char *str = strrchr(path, '/'); + str++; + + if (error) + fprintf(stderr, "Error %s: %s\n", path, error); + else + fprintf(stdout, "Success SetProperty %s\n", str); + + g_free(user_data); + + return 0; +} + +static int cmd_mesh(char *args[], int num, struct connman_option *options) +{ + int result = 0; + int c; + char *path = NULL; + char *method = NULL; + char *mesh_peer_name = NULL; + char *mesh_peer_path = NULL; + char *property = NULL; + char *value = NULL; + struct mesh_if_prop *append; + struct mesh_create_network *network; + struct mesh_specific_scan_params *scan_params; + struct mesh_gate_params *gate_params; + char *mesh_peer_addr = NULL; + + c = parse_args(args[1], options); + + switch (c) { + case 'a': + if (num < 4 || num > 5) { + result = -EINVAL; + break; + } + path = g_strdup_printf("/net/connman/technology/mesh"); + + append = dbus_malloc0(sizeof(struct mesh_if_prop)); + append->ifname = g_strdup(args[2]); + append->parent_ifname = g_strdup(args[3]); + if (num == 5) + append->bridge_ifname = g_strdup(args[4]); + method = g_strdup("MeshInterfaceAdd"); + result = __connmanctl_dbus_mesh_dict(connection, path, + "net.connman.Technology", mesh_return, method, + "MeshInterfaceAdd", DBUS_TYPE_STRING, + mesh_interface_add_append, append); + g_free(append->ifname); + g_free(append->parent_ifname); + g_free(append->bridge_ifname); + g_free(append); + break; + + case 'r': + if (num != 3) { + result = -EINVAL; + break; + } + path = g_strdup_printf("/net/connman/technology/mesh"); + + append = dbus_malloc0(sizeof(struct mesh_if_prop)); + append->ifname = g_strdup(args[2]); + method = g_strdup("MeshInterfaceRemove"); + result = __connmanctl_dbus_mesh_dict(connection, path, + "net.connman.Technology", mesh_return, method, + "MeshInterfaceRemove", DBUS_TYPE_STRING, + mesh_interface_remove_append, append); + g_free(append->ifname); + g_free(append); + break; + + case 'p': + if (num > 3) { + result = -E2BIG; + break; + } + + if (num == 3) + mesh_peer_name = args[2]; + + if (!mesh_peer_name) { + result = __connmanctl_dbus_method_call(connection, + CONNMAN_SERVICE, CONNMAN_PATH, + "net.connman.Manager", "GetMeshPeers", + mesh_peers_list, NULL, NULL, NULL); + break; + } + + if (check_dbus_name(mesh_peer_name) == false) { + result = -EINVAL; + break; + } + + mesh_peer_path = g_strdup_printf("/net/connman/mesh/%s", + mesh_peer_name); + result = __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE, + mesh_peer_path, "net.connman.Mesh", "GetProperties", + object_properties, mesh_peer_path, NULL, NULL); + break; + + case 'c': + if (num < 3) { + result = -EINVAL; + break; + } + + if (num > 3) { + result = -E2BIG; + break; + } + + mesh_peer_name = args[2]; + + if (check_dbus_name(mesh_peer_name) == false) { + result = -EINVAL; + break; + } + + mesh_peer_path = g_strdup_printf("/net/connman/mesh/%s", + mesh_peer_name); + result = __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE, + mesh_peer_path, "net.connman.Mesh", "Connect", + mesh_connect_return, mesh_peer_path, NULL, NULL); + break; + + case 'd': + if (num < 3) { + result = -EINVAL; + break; + } + + if (num > 3) { + result = -E2BIG; + break; + } + + mesh_peer_name = args[2]; + + if (check_dbus_name(mesh_peer_name) == false) { + result = -EINVAL; + break; + } + + mesh_peer_path = g_strdup_printf("/net/connman/mesh/%s", + mesh_peer_name); + result = __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE, + mesh_peer_path, "net.connman.Mesh", "Disconnect", + mesh_disconnect_return, mesh_peer_path, NULL, NULL); + break; + + case 'f': + if (num < 3) { + result = -EINVAL; + break; + } + + if (num > 3) { + result = -E2BIG; + break; + } + + mesh_peer_name = args[2]; + + if (check_dbus_name(mesh_peer_name) == false) { + result = -EINVAL; + break; + } + + mesh_peer_path = g_strdup_printf("/net/connman/mesh/%s", + mesh_peer_name); + result = __connmanctl_dbus_method_call(connection, CONNMAN_SERVICE, + mesh_peer_path, "net.connman.Mesh", "Remove", + mesh_remove_return, mesh_peer_path, NULL, NULL); + break; + + case 'C': + if (num > 2) { + result = -E2BIG; + break; + } + + result = __connmanctl_dbus_method_call(connection, + CONNMAN_SERVICE, CONNMAN_PATH, + "net.connman.Manager", "GetConnectedMeshPeers", + connected_mesh_peers_list, NULL, NULL, NULL); + break; + + case 'D': + if (num > 2) { + result = -E2BIG; + break; + } + + result = __connmanctl_dbus_method_call(connection, + CONNMAN_SERVICE, CONNMAN_PATH, + "net.connman.Manager", + "GetDisconnectedMeshPeers", + disconnected_mesh_peers_list, NULL, NULL, NULL); + break; + + case 'n': + if (num != 5) { + result = -EINVAL; + break; + } + path = g_strdup_printf("/net/connman/technology/mesh"); + + network = dbus_malloc0(sizeof(struct mesh_create_network)); + network->name = g_strdup(args[2]); + network->freq = atoi(args[3]); + network->sec_type = g_strdup(args[4]); + method = g_strdup("MeshCreateNetwork"); + result = __connmanctl_dbus_mesh_dict(connection, path, + "net.connman.Technology", mesh_return, method, + "MeshCreateNetwork", DBUS_TYPE_STRING, + mesh_create_network_append, network); + g_free(network->name); + g_free(network->sec_type); + g_free(network); + break; + + case 'A': + if (num != 2) { + result = -EINVAL; + break; + } + path = g_strdup_printf("/net/connman/technology/mesh"); + + method = g_strdup("AbortScan"); + result = __connmanctl_dbus_mesh_dict(connection, path, + "net.connman.Technology", mesh_return, method, + "AbortScan", DBUS_TYPE_STRING, + NULL, NULL); + break; + + case 'S': + if (num != 4) { + result = -EINVAL; + break; + } + path = g_strdup_printf("/net/connman/technology/mesh"); + + scan_params = dbus_malloc0(sizeof(struct mesh_specific_scan_params)); + scan_params->name = g_strdup(args[2]); + scan_params->freq = atoi(args[3]); + method = g_strdup("MeshSpecificScan"); + result = __connmanctl_dbus_mesh_dict(connection, path, + "net.connman.Technology", mesh_return, method, + "MeshSpecificScan", DBUS_TYPE_STRING, + mesh_specific_scan_append, scan_params); + g_free(scan_params->name); + g_free(scan_params); + break; + + case 'P': + if (num != 5) { + result = -EINVAL; + break; + } + + mesh_peer_name = args[2]; + property = args[3]; + value = args[4]; + + if (check_dbus_name(mesh_peer_name) == false) { + result = -EINVAL; + break; + } + + mesh_peer_path = g_strdup_printf("/net/connman/mesh/%s", + mesh_peer_name); + + if (g_strcmp0(property, "Passphrase") == 0) { + result = __connmanctl_dbus_set_property(connection, + mesh_peer_path, "net.connman.Mesh", + mesh_config_return, mesh_peer_path, property, + DBUS_TYPE_STRING, &value); + } else { + printf("Invalid property %s\n", property); + result = -EINVAL; + } + + break; + + case 'G': + if (num != 5) { + result = -EINVAL; + break; + } + + path = g_strdup_printf("/net/connman/technology/mesh"); + + gate_params = dbus_malloc0(sizeof(struct mesh_gate_params)); + gate_params->gate_announce = atoi(args[2]); + gate_params->hwmp_rootmode = atoi(args[3]); + gate_params->stp = atoi(args[4]); + + method = g_strdup("SetMeshGate"); + + result = __connmanctl_dbus_mesh_dict(connection, path, + "net.connman.Technology", mesh_return, method, + "SetMeshGate", DBUS_TYPE_STRING, + mesh_set_gate_append, gate_params); + + break; + + case 'z': + if (num != 3) { + result = -EINVAL; + break; + } + + mesh_peer_addr = g_strdup(args[2]); + method = g_strdup("MeshAddPeer"); + + result = __connmanctl_dbus_method_call(connection, + CONNMAN_SERVICE, CONNMAN_PATH, + "net.connman.Manager", "MeshAddPeer", + mesh_return, method, mesh_peer_append, + mesh_peer_addr); + + break; + + case 'y': + if (num != 3) { + result = -EINVAL; + break; + } + + mesh_peer_addr = g_strdup(args[2]); + method = g_strdup("MeshRemovePeer"); + + result = __connmanctl_dbus_method_call(connection, + CONNMAN_SERVICE, CONNMAN_PATH, + "net.connman.Manager", "MeshRemovePeer", + mesh_return, method, mesh_peer_append, + mesh_peer_addr); + + break; + + default: + result = -EINVAL; + break; + } + + g_free(path); + + if (result < 0) { + if (result != -EINPROGRESS) + printf("Error '%s': %s\n", args[1], strerror(-result)); + } + + + return result; +} +#endif + static int cmd_tether(char *args[], int num, struct connman_option *options) { char *ssid, *passphrase; @@ -2410,6 +2985,38 @@ static struct connman_option session_options[] = { { NULL, } }; +#if defined TIZEN_EXT_WIFI_MESH +static struct connman_option mesh_options[] = { + {"ifadd", 'a', "<ifname> <wifi_ifname>\n" + " [bridge_ifname] Add Virtual Mesh " + "interface"}, + {"ifrmv", 'r', "<ifname> Remove Virtual Mesh " + "interface"}, + {"peers", 'p', "[peer] Display Mesh peer " + "informations"}, + {"connect", 'c', "<peer> Connect Mesh Peer"}, + {"disconnect", 'd', "<peer> Disconnect Mesh Peer"}, + {"remove", 'f', "<peer> Forget Mesh Peer"}, + {"connected_peers", 'C', "[] Displays connected" + " Peer informations"}, + {"disconnected_peers", 'D', "[] Displays " + "Disconnected Peer informations"}, + {"create_network", 'n', "<name> <frequency> <sec_type> Create New Mesh " + "Network"}, + {"abort_scan", 'A', " Abort ongoing mesh " + "scan"}, + {"specific_scan", 'S', "<name> <frequency> Create New Mesh " + "Network"}, + {"config", 'P', "<peer> Set Mesh Network " + "Configurations\n Passphrase <passphrase>"}, + {"set_gate", 'G', "<gate_ann> <rootmode> <stp> Set Mesh Gate " + "Option"}, + {"add_peer", 'z', "<addr> Add Mesh Peer"}, + {"remove_peer", 'y', "<addr> Remove Mesh Peer"}, + { NULL, } +}; +#endif + static char *lookup_options(struct connman_option *options, const char *text, int state) { @@ -2462,6 +3069,13 @@ static char *lookup_session(const char *text, int state) return lookup_options(session_options, text, state); } +#if defined TIZEN_EXT_WIFI_MESH +static char *lookup_mesh(const char *text, int state) +{ + return lookup_options(mesh_options, text, state); +} +#endif + static int peer_service_cb(DBusMessageIter *iter, const char *error, void *user_data) { @@ -2554,12 +3168,30 @@ static struct _peer_service *fill_in_peer_service(unsigned char *bjr_query, service = dbus_malloc0(sizeof(*service)); +#if defined TIZEN_EXT + if (!service) + return NULL; +#endif + if (bjr_query_len && bjr_response_len) { service->bjr_query = dbus_malloc0(bjr_query_len); +#if defined TIZEN_EXT + if(!service->bjr_query) { + dbus_free(service); + return NULL; + } +#endif memcpy(service->bjr_query, bjr_query, bjr_query_len); service->bjr_query_len = bjr_query_len; service->bjr_response = dbus_malloc0(bjr_response_len); +#if defined TIZEN_EXT + if(!service->bjr_response) { + dbus_free(service->bjr_query); + dbus_free(service); + return NULL; + } +#endif memcpy(service->bjr_response, bjr_response, bjr_response_len); service->bjr_response_len = bjr_response_len; } else if (upnp_service && version) { @@ -2567,6 +3199,12 @@ static struct _peer_service *fill_in_peer_service(unsigned char *bjr_query, service->version = version; } else if (wfd_ies && wfd_ies_len) { service->wfd_ies = dbus_malloc0(wfd_ies_len); +#if defined TIZEN_EXT + if (!service->wfd_ies) { + dbus_free(service); + return NULL; + } +#endif memcpy(service->wfd_ies, wfd_ies, wfd_ies_len); service->wfd_ies_len = wfd_ies_len; } else { @@ -2749,6 +3387,10 @@ static const struct { { "disable", "<technology>|offline", NULL, cmd_disable, "Disables given technology or offline mode", lookup_technology_offline }, +#if defined TIZEN_EXT_WIFI_MESH + { "mesh", "", mesh_options, cmd_mesh, "Mesh specific commands", + lookup_mesh }, +#endif { "tether", "<technology> on|off\n" " wifi [on|off] <ssid> <passphrase> ", NULL, cmd_tether, diff --git a/client/commands.h b/client/commands.h index d5d1becf..d5d1becf 100644..100755 --- a/client/commands.h +++ b/client/commands.h diff --git a/client/dbus_helpers.c b/client/dbus_helpers.c index 6ca407d4..8c6bdbb3 100644 --- a/client/dbus_helpers.c +++ b/client/dbus_helpers.c @@ -224,6 +224,11 @@ static int append_variant(DBusMessageIter *iter, const char *property, case DBUS_TYPE_INT32: type_str = DBUS_TYPE_INT32_AS_STRING; break; +#if defined TIZEN_EXT_WIFI_MESH + case DBUS_TYPE_UINT16: + type_str = DBUS_TYPE_UINT16_AS_STRING; + break; +#endif default: return -EOPNOTSUPP; } @@ -354,6 +359,50 @@ int __connmanctl_dbus_set_property_dict(DBusConnection *connection, return send_method_call(connection, message, cb, user_data); } +#if defined TIZEN_EXT_WIFI_MESH +int __connmanctl_dbus_mesh_dict(DBusConnection *connection, + const char *path, const char *interface, + connmanctl_dbus_method_return_func_t cb, void *user_data, + const char *property, int type, + connmanctl_dbus_append_func_t append_fn, + void *append_user_data) +{ + DBusMessage *message; + DBusMessageIter iter, variant, dict; + + message = dbus_message_new_method_call(CONNMAN_SERVICE, path, + interface, "MeshCommands"); + + if (!message) + return -ENOMEM; + + dbus_message_iter_init_append(message, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &property); + dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, + DBUS_TYPE_ARRAY_AS_STRING + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &variant); + + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &dict); + + if (append_fn) + append_fn(&dict, append_user_data); + + dbus_message_iter_close_container(&variant, &dict); + dbus_message_iter_close_container(&iter, &variant); + + return send_method_call(connection, message, cb, user_data); +} +#endif + static void append_variant_array(DBusMessageIter *iter, const char *property, connmanctl_dbus_append_func_t append_fn, void *append_user_data) diff --git a/client/dbus_helpers.h b/client/dbus_helpers.h index 395808ac..69458395 100644 --- a/client/dbus_helpers.h +++ b/client/dbus_helpers.h @@ -67,6 +67,15 @@ int __connmanctl_dbus_set_property_dict(DBusConnection *connection, connmanctl_dbus_append_func_t append_fn, void *append_user_data); +#if defined TIZEN_EXT_WIFI_MESH +int __connmanctl_dbus_mesh_dict(DBusConnection *connection, + const char *path, const char *interface, + connmanctl_dbus_method_return_func_t cb, void *user_data, + const char *property, int type, + connmanctl_dbus_append_func_t append_fn, + void *append_user_data); +#endif + void __connmanctl_dbus_append_dict_string_array(DBusMessageIter *iter, const char *property, connmanctl_dbus_append_func_t append_fn, void *append_user_data); diff --git a/client/input.c b/client/input.c index 78319ff8..d9d2b7b1 100644..100755 --- a/client/input.c +++ b/client/input.c @@ -273,7 +273,9 @@ int __connmanctl_input_init(int argc, char *argv[]) __connmanctl_monitor_completions(NULL); rl_callback_handler_remove(); +#if !defined TIZEN_EXT rl_message(""); +#endif } dbus_connection_unref(connection); diff --git a/client/input.h b/client/input.h index c7256a41..c7256a41 100644..100755 --- a/client/input.h +++ b/client/input.h diff --git a/client/main.c b/client/main.c index 6d3c57f9..6d3c57f9 100644..100755 --- a/client/main.c +++ b/client/main.c diff --git a/client/mesh.c b/client/mesh.c new file mode 100644 index 00000000..6e577934 --- /dev/null +++ b/client/mesh.c @@ -0,0 +1,166 @@ +/* + * + * Connection Manager + * + * + * Copyright (C) 2017 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <string.h> + +#include "mesh.h" +#include "dbus_helpers.h" + +static void print_mesh_peer(char *path, DBusMessageIter *iter) +{ + char *name = ""; + char state = ' '; + char *str, *property; + DBusMessageIter entry, val; + int count = 0, favorite = 0; + + while (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) { + dbus_message_iter_recurse(iter, &entry); + dbus_message_iter_get_basic(&entry, &property); + + if (strcmp(property, "Name") == 0) { + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &val); + dbus_message_iter_get_basic(&val, &name); + } else if (strcmp(property, "State") == 0) { + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &val); + dbus_message_iter_get_basic(&val, &str); + + if (str) { + if (strcmp(str, "online") == 0) + state = 'O'; + else if (strcmp(str, "ready") == 0) + state = 'R'; + else if (!strcmp(str, "association")) + state = 'a'; + else if (!strcmp(str, "configuration")) + state = 'c'; + else if (!strcmp(str, "disconnect")) + state = 'd'; + } + } else if (strcmp(property, "Favorite") == 0) { + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &val); + dbus_message_iter_get_basic(&val, &favorite); + } + + dbus_message_iter_next(iter); + count++; + } + + str = strrchr(path, '/'); + if (str) + str++; + else + str = path; + + if (count > 0) + fprintf(stdout, "%c%c %-20s %s", favorite != 0 ? 'A' : ' ', + state, name, str); + else + fprintf(stdout, "%s %s", "unchanged", str); +} + +static void list_mesh_peer_array(DBusMessageIter *iter) +{ + DBusMessageIter array, dict; + char *path = NULL; + + while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRUCT) { + dbus_message_iter_recurse(iter, &array); + if (dbus_message_iter_get_arg_type(&array) + != DBUS_TYPE_OBJECT_PATH) + return; + + dbus_message_iter_get_basic(&array, &path); + + dbus_message_iter_next(&array); + if (dbus_message_iter_get_arg_type(&array) + == DBUS_TYPE_ARRAY) { + dbus_message_iter_recurse(&array, &dict); + print_mesh_peer(path, &dict); + } + + if (dbus_message_iter_has_next(iter)) + fprintf(stdout, "\n"); + + dbus_message_iter_next(iter); + } +} + +void __connmanctl_mesh_peers_list(DBusMessageIter *iter) +{ + DBusMessageIter array; + char *path; + + if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) + return; + + dbus_message_iter_recurse(iter, &array); + list_mesh_peer_array(&array); + + dbus_message_iter_next(iter); + if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) + return; + + fprintf(stdout, "\n}, {"); + + dbus_message_iter_recurse(iter, &array); + while (dbus_message_iter_get_arg_type(&array) + == DBUS_TYPE_OBJECT_PATH) { + dbus_message_iter_get_basic(&array, &path); + fprintf(stdout, "\n%s %s", "removed", path); + + dbus_message_iter_next(&array); + } + +} + +void __connmanctl_mesh_connected_peers_list(DBusMessageIter *iter) +{ + DBusMessageIter array; + + if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) + return; + + dbus_message_iter_recurse(iter, &array); + __connmanctl_dbus_print(&array, " ", " = ", "\n"); + fprintf(stdout, "\n"); +} + +void __connmanctl_mesh_disconnected_peers_list(DBusMessageIter *iter) +{ + DBusMessageIter array; + + if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) + return; + + dbus_message_iter_recurse(iter, &array); + __connmanctl_dbus_print(&array, " ", " = ", "\n"); + fprintf(stdout, "\n"); +} diff --git a/client/mesh.h b/client/mesh.h new file mode 100644 index 00000000..8dd413d0 --- /dev/null +++ b/client/mesh.h @@ -0,0 +1,40 @@ +/* + * + * Connection Manager + * + * + * Copyright (C) 2017 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef __CONNMANCTL_MESH_H +#define __CONNMANCTL_MESH_H + +#include <dbus/dbus.h> + +#ifdef __cplusplus +extern "C" { +#endif + +void __connmanctl_mesh_peers_list(DBusMessageIter *iter); +void __connmanctl_mesh_connected_peers_list(DBusMessageIter *iter); +void __connmanctl_mesh_disconnected_peers_list(DBusMessageIter *iter); + +#ifdef __cplusplus +} +#endif + +#endif /* __CONNMANCTL_MESH_H */ diff --git a/client/peers.c b/client/peers.c index bf1aa0ea..bf1aa0ea 100644..100755 --- a/client/peers.c +++ b/client/peers.c diff --git a/client/peers.h b/client/peers.h index fdf7ce76..fdf7ce76 100644..100755 --- a/client/peers.h +++ b/client/peers.h diff --git a/client/services.c b/client/services.c index 0c18669b..0c18669b 100644..100755 --- a/client/services.c +++ b/client/services.c diff --git a/client/services.h b/client/services.h index 9b555fe7..9b555fe7 100644..100755 --- a/client/services.h +++ b/client/services.h diff --git a/client/vpnconnections.c b/client/vpnconnections.c index d7bcbfee..d7bcbfee 100644..100755 --- a/client/vpnconnections.c +++ b/client/vpnconnections.c diff --git a/client/vpnconnections.h b/client/vpnconnections.h index a915c843..a915c843 100644..100755 --- a/client/vpnconnections.h +++ b/client/vpnconnections.h diff --git a/configure.ac b/configure.ac index ee49a22c..a1c34e1f 100644 --- a/configure.ac +++ b/configure.ac @@ -66,6 +66,32 @@ AC_ARG_ENABLE(hh2serial-gps, AM_CONDITIONAL(HH2SERIAL_GPS, test "${enable_hh2serial_gps}" != "no") AM_CONDITIONAL(HH2SERIAL_GPS_BUILTIN, test "${enable_hh2serial_gps}" = "builtin") +AC_ARG_ENABLE(telephony, + AC_HELP_STRING([--enable-telephony], [enable Telephony support]), + [enable_telephony=${enableval}], [enable_telephony="yes"]) +AM_CONDITIONAL(TELEPHONY, test "${enable_telephony}" != "no") +AM_CONDITIONAL(TELEPHONY_BUILTIN, test "${enable_telephony}" = "builtin") + +AC_ARG_ENABLE(tizen-ext, + AC_HELP_STRING([--enable-tizen-ext], [enable TIZEN extensions]), + [if (test "${enableval}" = "yes"); then + CFLAGS="$CFLAGS -DTIZEN_EXT" + LIBS="$LIBS -lsmack" + fi]) +AM_CONDITIONAL(TIZEN_EXT, test "${enable-tizen-ext}" != "no") + +AC_ARG_ENABLE(tizen-ext-wifi-mesh, + AC_HELP_STRING([--enable-tizen-ext-wifi-mesh], [enable TIZEN extensions for Wi-Fi Mesh]), + [CFLAGS="$CFLAGS -DTIZEN_EXT_WIFI_MESH"], [enable_tizen_ext_wifi_mesh="no"]) +AM_CONDITIONAL(TIZEN_EXT_WIFI_MESH, test "${enable_tizen_ext_wifi_mesh}" != "no") + +AC_ARG_ENABLE(tizen-maintain-online, + AC_HELP_STRING([--enable-tizen-maintain-online], [enable TIZEN extensions]), + [if (test "${enableval}" = "yes"); then + CFLAGS="$CFLAGS -DTIZEN_MAINTAIN_ONLINE" + LIBS="$LIBS -lsmack" + fi]) + AC_ARG_WITH(openconnect, AC_HELP_STRING([--with-openconnect=PROGRAM], [specify location of openconnect binary]), [path_openconnect=${withval}]) @@ -74,7 +100,7 @@ AC_ARG_ENABLE(openconnect, [enable_openconnect=${enableval}], [enable_openconnect="no"]) if (test "${enable_openconnect}" != "no"); then if (test -z "${path_openconnect}"); then - AC_PATH_PROG(OPENCONNECT, [openconnect], [], $PATH:/sbin:/usr/sbin) + AC_PATH_PROG(OPENCONNECT, [openconnect], [], $PATH:/bin:/usr/bin) if (test -z "${OPENCONNECT}"); then AC_MSG_ERROR(openconnect binary not found) fi @@ -94,7 +120,7 @@ AC_ARG_ENABLE(openvpn, [enable_openvpn=${enableval}], [enable_openvpn="no"]) if (test "${enable_openvpn}" != "no"); then if (test -z "${path_openvpn}"); then - AC_PATH_PROG(OPENVPN, [openvpn], [], $PATH:/sbin:/usr/sbin) + AC_PATH_PROG(OPENVPN, [openvpn], [/usr/bin/openvpn], $PATH:/bin:/usr/bin) if (test -z "${OPENVPN}"); then AC_MSG_ERROR(openvpn binary not found) fi @@ -106,6 +132,30 @@ fi AM_CONDITIONAL(OPENVPN, test "${enable_openvpn}" != "no") AM_CONDITIONAL(OPENVPN_BUILTIN, test "${enable_openvpn}" = "builtin") +AC_ARG_WITH(ipsec, AC_HELP_STRING([--with-ipsec=PROGRAM], + [specify location of ipsec binary]), [path_ipsec=${withval}]) + +AC_ARG_ENABLE(ipsec, + AC_HELP_STRING([--enable-ipsec], [enable ipsec support]), + [enable_ipsec=${enableval}], [enable_ipsec="no"]) +if (test "${enable_ipsec}" != "no"); then + PKG_CHECK_MODULES(GIO, gio-2.0 >= 2.28, dummy=yes, + AC_MSG_ERROR(GIO >= 2.28 is required)) + AC_SUBST(GIO_CFLAGS) + AC_SUBST(GIO_LIBS) + if (test -z "${path_ipsec}"); then + AC_PATH_PROG(IPSEC, [charon], [/usr/bin/charon], $PATH:/usr/bin) + if (test -z "${IPSEC}"); then + AC_MSG_ERROR(ipsec binary not found) + fi + else + IPSEC="${path_ipsec}" + AC_SUBST(IPSEC) + fi +fi +AM_CONDITIONAL(IPSEC, test "${enable_ipsec}" != "no") +AM_CONDITIONAL(IPSEC_BUILTIN, test "${enable_ipsec}" = "builtin") + AC_ARG_WITH(vpnc, AC_HELP_STRING([--with-vpnc=PROGRAM], [specify location of vpnc binary]), [path_vpnc=${withval}]) @@ -114,7 +164,7 @@ AC_ARG_ENABLE(vpnc, [enable_vpnc=${enableval}], [enable_vpnc="no"]) if (test "${enable_vpnc}" != "no"); then if (test -z "${path_vpnc}"); then - AC_PATH_PROG(VPNC, [vpnc], [], $PATH:/sbin:/usr/sbin) + AC_PATH_PROG(VPNC, [vpnc], [], $PATH:/bin:/usr/bin) if (test -z "${VPNC}"); then AC_MSG_ERROR(vpnc binary not found) fi @@ -134,7 +184,7 @@ AC_ARG_ENABLE(l2tp, [enable_l2tp=${enableval}], [enable_l2tp="no"]) if (test "${enable_l2tp}" != "no"); then if (test -z "${path_pppd}"); then - AC_PATH_PROG(PPPD, [pppd], [/usr/sbin/pppd], $PATH:/sbin:/usr/sbin) + AC_PATH_PROG(PPPD, [pppd], [/usr/bin/pppd], $PATH:/bin:/usr/bin) else PPPD="${path_pppd}" AC_SUBST(PPPD) @@ -142,7 +192,7 @@ if (test "${enable_l2tp}" != "no"); then AC_CHECK_HEADERS(pppd/pppd.h, dummy=yes, AC_MSG_ERROR(ppp header files are required)) if (test -z "${path_l2tp}"); then - AC_PATH_PROG(L2TP, [xl2tpd], [/usr/sbin/xl2tpd], $PATH:/sbin:/usr/sbin) + AC_PATH_PROG(L2TP, [xl2tpd], [/usr/bin/xl2tpd], $PATH:/bin:/usr/bin) else L2TP="${path_l2tp}" AC_SUBST(L2TP) @@ -159,7 +209,7 @@ AC_ARG_ENABLE(pptp, [enable_pptp=${enableval}], [enable_pptp="no"]) if (test "${enable_pptp}" != "no"); then if (test -z "${path_pppd}"); then - AC_PATH_PROG(PPPD, [pppd], [/usr/sbin/pppd], $PATH:/sbin:/usr/sbin) + AC_PATH_PROG(PPPD, [pppd], [/usr/bin/pppd], $PATH:/bin:/usr/bin) else PPPD="${path_pppd}" AC_SUBST(PPPD) @@ -167,7 +217,7 @@ if (test "${enable_pptp}" != "no"); then AC_CHECK_HEADERS(pppd/pppd.h, dummy=yes, AC_MSG_ERROR(ppp header files are required)) if (test -z "${path_pptp}"); then - AC_PATH_PROG(PPTP, [pptp], [/usr/sbin/pptp], $PATH:/sbin:/usr/sbin) + AC_PATH_PROG(PPTP, [pptp], [/usr/bin/pptp], $PATH:/bin:/usr/bin) else PPTP="${path_pptp}" AC_SUBST(PPTP) @@ -226,6 +276,21 @@ PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.40, dummy=yes, AC_SUBST(GLIB_CFLAGS) AC_SUBST(GLIB_LIBS) +PKG_CHECK_MODULES(LIBNL, libnl-3.0, dummy=yes, + AC_MSG_ERROR(libnl-3.0 is required)) +AC_SUBST(LIBNL_CFLAGS) +AC_SUBST(LIBNL_LIBS) + +PKG_CHECK_MODULES(LIBNL_GENL, libnl-genl-3.0, dummy=yes, + AC_MSG_ERROR(libnl-genl-3.0 is required)) +AC_SUBST(LIBNL_GENL_CFLAGS) +AC_SUBST(LIBNL_GENL_LIBS) + +PKG_CHECK_MODULES(LIBSYSTEMD, libsystemd-daemon, dummy=yes, + AC_MSG_ERROR(libsystemd-daemon library is required)) +AC_SUBST(LIBSYSTEMD_CFLAGS) +AC_SUBST(LIBSYSTEMD_LIBS) + PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.4, dummy=yes, AC_MSG_ERROR(D-Bus >= 1.4 is required)) AC_SUBST(DBUS_CFLAGS) @@ -233,9 +298,9 @@ AC_SUBST(DBUS_LIBS) AC_ARG_WITH(dbusconfdir, AC_HELP_STRING([--with-dbusconfdir=PATH], [path to D-Bus config directory]), [path_dbusconf=${withval}], - [path_dbusconf="`$PKG_CONFIG --variable=datadir dbus-1`"]) + [path_dbusconf="`$PKG_CONFIG --variable=sysconfdir dbus-1`"]) if (test -z "${path_dbusconf}"); then - DBUS_CONFDIR="${datadir}/dbus-1/system.d" + DBUS_CONFDIR="${sysconfdir}/dbus-1/system.d" else DBUS_CONFDIR="${path_dbusconf}/dbus-1/system.d" fi @@ -378,6 +443,11 @@ AC_ARG_ENABLE(wispr, AC_HELP_STRING([--disable-wispr], [enable_wispr=${enableval}]) AM_CONDITIONAL(WISPR, test "${enable_wispr}" != "no") +AC_ARG_ENABLE(backtrace, AC_HELP_STRING([--disable-backtrace], + [disable backtrace support]), + [enable_backtrace=${enableval}]) +AM_CONDITIONAL(BACKTRACE, test "${enable_backtrace}" != "no") + AC_ARG_ENABLE(tools, AC_HELP_STRING([--disable-tools], [disable testing tools]), [enable_tools=${enableval}]) @@ -390,9 +460,9 @@ AM_CONDITIONAL(STATS, test "${enable_stats}" != "no") if (test "${enable_tools}" != "no"); then AC_PATH_PROGS(IPTABLES_SAVE, [iptables-save], [], - $PATH:/sbin:/usr/sbin) + $PATH:/bin:/usr/bin) AC_PATH_PROGS(IP6TABLES_SAVE, [ip6tables-save], [], - $PATH:/sbin:/usr/sbin) + $PATH:/bin:/usr/bin) IPTABLES_SAVE=$ac_cv_path_IPTABLES_SAVE IP6TABLES_SAVE=$ac_cv_path_IP6TABLES_SAVE else @@ -427,7 +497,7 @@ fi if (test "${enable_wifi}" != "no"); then AC_PATH_PROG(WPASUPPLICANT, [wpa_supplicant], [], - $PATH:/sbin:/usr/sbin) + $PATH:/bin:/usr/bin) fi AC_ARG_ENABLE(datafiles, AC_HELP_STRING([--disable-datafiles], @@ -442,6 +512,7 @@ fi AM_CONDITIONAL(VPN, test "${enable_openconnect}" != "no" -o \ "${enable_openvpn}" != "no" -o \ + "${enable_ipsec}" != "no" -o \ "${enable_vpnc}" != "no" -o \ "${enable_l2tp}" != "no" -o \ "${enable_pptp}" != "no") @@ -460,4 +531,4 @@ AM_CONDITIONAL(INTERNAL_DNS_BACKEND, test "${dns_backend}" = "internal") AM_CONDITIONAL(SYSTEMD_RESOLVED_DNS_BACKEND, test "${dns_backend}" = "systemd-resolved") AC_MSG_RESULT(${dns_backend}) -AC_OUTPUT(Makefile include/version.h connman.pc) +AC_OUTPUT(Makefile include/version.h connman.pc src/connman.service src/connman_tv.service vpn/connman-vpn.service) diff --git a/connman.manifest b/connman.manifest new file mode 100644 index 00000000..97e8c313 --- /dev/null +++ b/connman.manifest @@ -0,0 +1,5 @@ +<manifest> + <request> + <domain name="_"/> + </request> +</manifest> diff --git a/doc/advanced-configuration.txt b/doc/advanced-configuration.txt index 12c2250e..12c2250e 100644..100755 --- a/doc/advanced-configuration.txt +++ b/doc/advanced-configuration.txt diff --git a/doc/agent-api.txt b/doc/agent-api.txt index e3c1dcde..e3c1dcde 100644..100755 --- a/doc/agent-api.txt +++ b/doc/agent-api.txt diff --git a/doc/backtrace.txt b/doc/backtrace.txt index ac8472cc..ac8472cc 100644..100755 --- a/doc/backtrace.txt +++ b/doc/backtrace.txt diff --git a/doc/behavior-api.txt b/doc/behavior-api.txt index 5feea768..5feea768 100644..100755 --- a/doc/behavior-api.txt +++ b/doc/behavior-api.txt diff --git a/doc/clock-api.txt b/doc/clock-api.txt index 6818f5a8..6818f5a8 100644..100755 --- a/doc/clock-api.txt +++ b/doc/clock-api.txt diff --git a/doc/config-format.txt b/doc/config-format.txt index 584220f0..584220f0 100644..100755 --- a/doc/config-format.txt +++ b/doc/config-format.txt diff --git a/doc/counter-api.txt b/doc/counter-api.txt index 32411d57..32411d57 100644..100755 --- a/doc/counter-api.txt +++ b/doc/counter-api.txt diff --git a/doc/ipconfig-api.txt b/doc/ipconfig-api.txt index 080fdac5..080fdac5 100644..100755 --- a/doc/ipconfig-api.txt +++ b/doc/ipconfig-api.txt diff --git a/doc/manager-api.txt b/doc/manager-api.txt index bfb07bd3..bfb07bd3 100644..100755 --- a/doc/manager-api.txt +++ b/doc/manager-api.txt diff --git a/doc/overview-api.txt b/doc/overview-api.txt index fd51d706..fd51d706 100644..100755 --- a/doc/overview-api.txt +++ b/doc/overview-api.txt diff --git a/doc/peer-api.txt b/doc/peer-api.txt index cc094ff2..cc094ff2 100644..100755 --- a/doc/peer-api.txt +++ b/doc/peer-api.txt diff --git a/doc/plugin-api.txt b/doc/plugin-api.txt index 36391e96..36391e96 100644..100755 --- a/doc/plugin-api.txt +++ b/doc/plugin-api.txt diff --git a/doc/service-api.txt b/doc/service-api.txt index c0d5adbb..f8dbb96d 100644..100755 --- a/doc/service-api.txt +++ b/doc/service-api.txt @@ -200,6 +200,32 @@ Properties string State [readonly] This property might be only present for WiFi services. + string BSSID [readonly] + + If the service type is WiFi, then this property + indicates the BSSID of the service. + + uint32 MaxRate [readonly] + + If the service type is WiFi, then this property + indicates the Maximum speed(bps) of the service. + + uint16 Frequency [readonly] + + If the service type is WiFi, then this property + indicates the frequency band(MHz) of the service. + + string EncryptionMode [readonly] + + If the service type is WiFi, then this property + indicates the key encryption mode. + + Possible values are "none", "wep", "tkip", "aes" + and "mixed". + + This property might be only present for WiFi + services. + uint8 Strength [readonly] Indicates the signal strength of the service. This diff --git a/doc/session-api.txt b/doc/session-api.txt index 46ac5f3d..46ac5f3d 100644..100755 --- a/doc/session-api.txt +++ b/doc/session-api.txt diff --git a/doc/session-overview.txt b/doc/session-overview.txt index 976c3518..976c3518 100644..100755 --- a/doc/session-overview.txt +++ b/doc/session-overview.txt diff --git a/doc/session-policy-format.txt b/doc/session-policy-format.txt index babc2c10..babc2c10 100644..100755 --- a/doc/session-policy-format.txt +++ b/doc/session-policy-format.txt diff --git a/doc/technology-api.txt b/doc/technology-api.txt index f22e9b29..f22e9b29 100644..100755 --- a/doc/technology-api.txt +++ b/doc/technology-api.txt diff --git a/doc/vpn-config-format.txt b/doc/vpn-config-format.txt index 0bc62c08..cb0f16a8 100644 --- a/doc/vpn-config-format.txt +++ b/doc/vpn-config-format.txt @@ -207,6 +207,35 @@ PPTP VPN supports following options (see pptp(8) and pppd(8) for details) PPPD.RequirMPPEStateful mppe-stateful Allow MPPE to use stateful mode (O) PPPD.NoVJ novj No Van Jacobson compression (O) +IPsec VPN supports following options (see swanctl.conf(5) for details): + Option name IPSec config value Description + IPsec.Version Version IKE major version to use for connection (M) + IPsec.LeftAddrs local_addrs Local address(es) to use for IKE communication (M) + IPsec.RightAddrs remote_addrs Remote address(es) to use for IKE communication (M) + + + IPsec.LocalAuth local.auth Authentication to perform locally (M) + IPsec.LocalCerts local.certs Certificate candidate to use for authentication (O) + IPsec.LocalID local.id IKE identity to use for authentication round (O) + IPsec.LocalXauthID local.xauth_id Client XAuth username used in the XAuth exchange (O) + IPsec.LocalXauthAuth local-xauth.auth Xauth round authentication to perform locally (O) + IPsec.LocalXauthXauthID local-xauth.xauth_id Xauth round client XAuth username used in the XAuth exchange (O) + + IPsec.RemoteAuth remote.auth Authentication to expect from remote (M) + IPsec.RemoteCerts remote.certs Certificate candidate to use for authentication (O) + IPsec.RemoteID remote.id IKE identity to use for authentication round (O) + IPsec.RemoteXauthAuth remote-xauth.auth Xauth round authentication to expect from remote (O) + IPsec.ChildrenLocalTs children.local_ts local selectors to include in CHILD_SA (O) + IPsec.ChildrenRemoteTs children.remote_ts Remote selectors to include in CHILD_SA (O) + + IPsec.IKEData secret.data IKE PSK raw shared key data + IPsec.IKEOwners secret.Owners list of shared key owner identities + IPsec.XauthData secret.data XAUTH raw shared key data + IPsec.XauthOwners secret.Owners list of shared key owner identities + + IPsec.CertType cert.type certificate type, X509|X509_AC|X509_CRL + IPsec.CertFlag cert.flag X.509 certificate flag, NONE|CA|AA|OCSP + IPsec.CertData cert.data PEM or DER encoded certificate data Example ======= diff --git a/doc/vpn-connection-api.txt b/doc/vpn-connection-api.txt index 1fd3be26..1fd3be26 100644..100755 --- a/doc/vpn-connection-api.txt +++ b/doc/vpn-connection-api.txt diff --git a/doc/vpn-manager-api.txt b/doc/vpn-manager-api.txt index 66c5beef..66c5beef 100644..100755 --- a/doc/vpn-manager-api.txt +++ b/doc/vpn-manager-api.txt diff --git a/doc/vpn-overview.txt b/doc/vpn-overview.txt index 42b6e94a..42b6e94a 100644..100755 --- a/doc/vpn-overview.txt +++ b/doc/vpn-overview.txt diff --git a/gdbus/client.c b/gdbus/client.c index a011e19c..9748ae25 100644..100755 --- a/gdbus/client.c +++ b/gdbus/client.c @@ -58,8 +58,10 @@ struct GDBusClient { void *signal_data; GDBusProxyFunction proxy_added; GDBusProxyFunction proxy_removed; +#if !defined TIZEN_EXT GDBusClientFunction ready; void *ready_data; +#endif GDBusPropertyFunction property_changed; void *user_data; GList *proxy_list; @@ -729,6 +731,7 @@ gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy, return TRUE; } +#if !defined TIZEN_EXT gboolean g_dbus_proxy_set_property_array(GDBusProxy *proxy, const char *name, int type, const void *value, size_t size, GDBusResultFunction function, @@ -815,6 +818,7 @@ gboolean g_dbus_proxy_set_property_array(GDBusProxy *proxy, return TRUE; } +#endif struct method_call_data { GDBusReturnFunction function; @@ -1095,8 +1099,10 @@ static void get_managed_objects_reply(DBusPendingCall *call, void *user_data) parse_managed_objects(client, reply); done: +#if !defined TIZEN_EXT if (client->ready) client->ready(client, client->ready_data); +#endif dbus_message_unref(reply); @@ -1367,6 +1373,7 @@ gboolean g_dbus_client_set_signal_watch(GDBusClient *client, return TRUE; } +#if !defined TIZEN_EXT gboolean g_dbus_client_set_ready_watch(GDBusClient *client, GDBusClientFunction ready, void *user_data) { @@ -1378,6 +1385,7 @@ gboolean g_dbus_client_set_ready_watch(GDBusClient *client, return TRUE; } +#endif gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client, GDBusProxyFunction proxy_added, diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h index 69fbc107..70190b71 100644..100755 --- a/gdbus/gdbus.h +++ b/gdbus/gdbus.h @@ -339,10 +339,12 @@ gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy, GDBusResultFunction function, void *user_data, GDBusDestroyFunction destroy); +#if !defined TIZEN_EXT gboolean g_dbus_proxy_set_property_array(GDBusProxy *proxy, const char *name, int type, const void *value, size_t size, GDBusResultFunction function, void *user_data, GDBusDestroyFunction destroy); +#endif typedef void (* GDBusSetupFunction) (DBusMessageIter *iter, void *user_data); typedef void (* GDBusReturnFunction) (DBusMessage *message, void *user_data); @@ -352,7 +354,9 @@ gboolean g_dbus_proxy_method_call(GDBusProxy *proxy, const char *method, GDBusReturnFunction function, void *user_data, GDBusDestroyFunction destroy); +#if !defined TIZEN_EXT typedef void (* GDBusClientFunction) (GDBusClient *client, void *user_data); +#endif typedef void (* GDBusProxyFunction) (GDBusProxy *proxy, void *user_data); typedef void (* GDBusPropertyFunction) (GDBusProxy *proxy, const char *name, DBusMessageIter *iter, void *user_data); @@ -379,8 +383,10 @@ gboolean g_dbus_client_set_disconnect_watch(GDBusClient *client, GDBusWatchFunction function, void *user_data); gboolean g_dbus_client_set_signal_watch(GDBusClient *client, GDBusMessageFunction function, void *user_data); +#if !defined TIZEN_EXT gboolean g_dbus_client_set_ready_watch(GDBusClient *client, GDBusClientFunction ready, void *user_data); +#endif gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client, GDBusProxyFunction proxy_added, GDBusProxyFunction proxy_removed, diff --git a/gdbus/mainloop.c b/gdbus/mainloop.c index b90a8447..b90a8447 100644..100755 --- a/gdbus/mainloop.c +++ b/gdbus/mainloop.c diff --git a/gdbus/object.c b/gdbus/object.c index a2201016..c333d5b7 100644..100755 --- a/gdbus/object.c +++ b/gdbus/object.c @@ -1248,8 +1248,10 @@ static struct generic_data *object_path_ref(DBusConnection *connection, if (!dbus_connection_register_object_path(connection, path, &generic_table, data)) { +#if !defined TIZEN_EXT dbus_connection_unref(data->conn); g_free(data->path); +#endif g_free(data->introspect); g_free(data); return NULL; diff --git a/gdbus/polkit.c b/gdbus/polkit.c index 9e95fa38..9e95fa38 100644..100755 --- a/gdbus/polkit.c +++ b/gdbus/polkit.c diff --git a/gdbus/watch.c b/gdbus/watch.c index 447e4867..447e4867 100644..100755 --- a/gdbus/watch.c +++ b/gdbus/watch.c diff --git a/gdhcp/client.c b/gdhcp/client.c index aab74378..22bbc8e2 100644..100755 --- a/gdhcp/client.c +++ b/gdhcp/client.c @@ -50,9 +50,30 @@ #define DISCOVER_TIMEOUT 5 #define DISCOVER_RETRIES 6 +#if defined TIZEN_EXT +#define REQUEST_TIMEOUT 1 +#else #define REQUEST_TIMEOUT 5 +#endif #define REQUEST_RETRIES 3 +#if defined TIZEN_EXT +#define DISCOVER_TIMEOUT_WIFI 1 +#define DISCOVER_RETRIES_WIFI 10 +static int dhcp_discover_timeout = DISCOVER_TIMEOUT_WIFI; +static int dhcp_discover_max_retry = DISCOVER_RETRIES_WIFI; + +void set_dhcp_discover_timeout(int timeout_value) +{ + dhcp_discover_timeout = timeout_value; +} + +void set_dhcp_discover_retry_count(int retry_count) +{ + dhcp_discover_max_retry = retry_count; +} +#endif + typedef enum _listen_mode { L_NONE, L2, @@ -158,6 +179,10 @@ struct _GDHCPClient { bool retransmit; struct timeval start_time; bool request_bcast; +#if defined TIZEN_EXT + uint32_t dhcp_lease_seconds; + gboolean init_reboot; +#endif }; static inline void debug(GDHCPClient *client, const char *format, ...) @@ -512,6 +537,9 @@ static int send_request(GDHCPClient *dhcp_client) init_packet(dhcp_client, &packet, DHCPREQUEST); packet.xid = dhcp_client->xid; +#if defined TIZEN_EXT + if (dhcp_client->init_reboot != TRUE) +#endif packet.secs = dhcp_attempt_secs(dhcp_client); if (dhcp_client->state == REQUESTING || dhcp_client->state == REBOOTING) @@ -1519,6 +1547,21 @@ static gboolean request_timeout(gpointer user_data) { GDHCPClient *dhcp_client = user_data; +#if defined TIZEN_EXT + if (dhcp_client->init_reboot) { + debug(dhcp_client, "DHCPREQUEST of INIT-REBOOT has failed"); + + /* Start DHCPDISCOVERY when DHCPREQUEST of INIT-REBOOT has failed */ + g_dhcp_client_set_address_known(dhcp_client, FALSE); + + dhcp_client->retry_times = 0; + dhcp_client->requested_ip = 0; + + g_dhcp_client_start(dhcp_client, dhcp_client->last_address); + + return FALSE; + } +#endif debug(dhcp_client, "request timeout (retries %d)", dhcp_client->retry_times); @@ -2428,6 +2471,10 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, dhcp_client->lease_seconds = get_lease(&packet); +#if defined TIZEN_EXT + dhcp_client->dhcp_lease_seconds = dhcp_client->lease_seconds; +#endif + get_request(dhcp_client, &packet); switch_listening_mode(dhcp_client, L_NONE); @@ -2452,6 +2499,18 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, remove_timeouts(dhcp_client); +#if defined TIZEN_EXT + if (dhcp_client->init_reboot) { + g_dhcp_client_set_address_known(dhcp_client, FALSE); + dhcp_client->timeout = g_idle_add_full( + G_PRIORITY_HIGH, + restart_dhcp_timeout, + dhcp_client, + NULL); + + break; + } +#endif dhcp_client->timeout = g_timeout_add_seconds_full( G_PRIORITY_HIGH, 3, restart_dhcp_timeout, @@ -2689,6 +2748,11 @@ static gboolean ipv4ll_announce_timeout(gpointer dhcp_data) GDHCPClient *dhcp_client = dhcp_data; uint32_t ip; +#if defined TIZEN_EXT + if (!dhcp_client) + return FALSE; +#endif + debug(dhcp_client, "request timeout (retries %d)", dhcp_client->retry_times); @@ -2741,6 +2805,11 @@ int g_dhcp_client_start(GDHCPClient *dhcp_client, const char *last_address) uint64_t rand; ClientState oldstate = dhcp_client->state; +#if defined TIZEN_EXT + int discover_retry = 0; + int timeout = 0; +#endif + remove_timeouts(dhcp_client); if (dhcp_client->type == G_DHCP_IPV6) { @@ -2827,13 +2896,32 @@ int g_dhcp_client_start(GDHCPClient *dhcp_client, const char *last_address) return 0; } +#if defined TIZEN_EXT + if (g_ascii_strncasecmp(dhcp_client->interface, "wlan", 4) + == 0) { + discover_retry = DISCOVER_RETRIES_WIFI; + timeout = DISCOVER_TIMEOUT_WIFI; + } else { + discover_retry = DISCOVER_RETRIES; + timeout = DISCOVER_TIMEOUT; + } + + debug(dhcp_client, "[DHCPC] Discover retry/total : [%d]/[%d] timeout [%d]", + dhcp_client->retry_times, discover_retry, timeout); +#endif + + if (dhcp_client->type == G_DHCP_IPV4LL) { dhcp_client->state = INIT_SELECTING; ipv4ll_start(dhcp_client); return 0; } +#if defined TIZEN_EXT + if (dhcp_client->retry_times == discover_retry) { +#else if (dhcp_client->retry_times == DISCOVER_RETRIES) { +#endif if (dhcp_client->no_lease_cb) dhcp_client->no_lease_cb(dhcp_client, dhcp_client->no_lease_data); @@ -2877,7 +2965,11 @@ int g_dhcp_client_start(GDHCPClient *dhcp_client, const char *last_address) dhcp_client->timeout = g_timeout_add_seconds_full( G_PRIORITY_HIGH, +#if defined TIZEN_EXT + timeout, +#else REQUEST_TIMEOUT, +#endif reboot_timeout, dhcp_client, NULL); @@ -2886,7 +2978,11 @@ int g_dhcp_client_start(GDHCPClient *dhcp_client, const char *last_address) send_discover(dhcp_client, addr); dhcp_client->timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH, +#if defined TIZEN_EXT + timeout, +#else DISCOVER_TIMEOUT, +#endif discover_timeout, dhcp_client, NULL); @@ -3027,9 +3123,20 @@ char *g_dhcp_client_get_server_address(GDHCPClient *dhcp_client) if (!dhcp_client) return NULL; +#if defined TIZEN_EXT + return get_ip(htonl(dhcp_client->server_ip)); +#else return get_ip(dhcp_client->server_ip); +#endif } +#if defined TIZEN_EXT +int g_dhcp_client_get_dhcp_lease_duration(GDHCPClient *dhcp_client) +{ + return dhcp_client->dhcp_lease_seconds; +} +#endif + char *g_dhcp_client_get_address(GDHCPClient *dhcp_client) { return g_strdup(dhcp_client->assigned_ip); @@ -3257,6 +3364,9 @@ void g_dhcp_client_unref(GDHCPClient *dhcp_client) g_hash_table_destroy(dhcp_client->secs_bcast_hash); g_free(dhcp_client); +#if defined TIZEN_EXT + dhcp_client = NULL; +#endif } void g_dhcp_client_set_debug(GDHCPClient *dhcp_client, @@ -3292,3 +3402,19 @@ GSList *g_dhcpv6_copy_prefixes(GSList *prefixes) return copy; } + +#if defined TIZEN_EXT +void g_dhcp_client_set_address_known(GDHCPClient *dhcp_client, gboolean known) +{ + /* DHCPREQUEST during INIT-REBOOT state (rfc2131) + * 4.4.3 Initialization with known network address + * 4.3.2 DHCPREQUEST generated during INIT-REBOOT state + */ + debug(dhcp_client, "known network address (%d)", known); + + if (dhcp_client->init_reboot == known) + return; + + dhcp_client->init_reboot = known; +} +#endif diff --git a/gdhcp/common.c b/gdhcp/common.c index 8f7a65cc..8f7a65cc 100644..100755 --- a/gdhcp/common.c +++ b/gdhcp/common.c diff --git a/gdhcp/common.h b/gdhcp/common.h index 6899499e..6899499e 100644..100755 --- a/gdhcp/common.h +++ b/gdhcp/common.h diff --git a/gdhcp/gdhcp.h b/gdhcp/gdhcp.h index e3b01311..d9944882 100644..100755 --- a/gdhcp/gdhcp.h +++ b/gdhcp/gdhcp.h @@ -154,6 +154,11 @@ GDHCPClientError g_dhcp_client_set_send(GDHCPClient *client, const char *option_value); char *g_dhcp_client_get_server_address(GDHCPClient *client); + +#if defined TIZEN_EXT +int g_dhcp_client_get_dhcp_lease_duration(GDHCPClient *client); +#endif + char *g_dhcp_client_get_address(GDHCPClient *client); char *g_dhcp_client_get_netmask(GDHCPClient *client); GList *g_dhcp_client_get_option(GDHCPClient *client, @@ -233,6 +238,10 @@ void g_dhcp_server_set_save_lease(GDHCPServer *dhcp_server, void g_dhcp_server_set_lease_added_cb(GDHCPServer *dhcp_server, GDHCPLeaseAddedCb cb); +#if defined TIZEN_EXT +void g_dhcp_client_set_address_known(GDHCPClient *client, gboolean known); +#endif + #ifdef __cplusplus } #endif diff --git a/gdhcp/ipv4ll.c b/gdhcp/ipv4ll.c index de4e0764..de4e0764 100644..100755 --- a/gdhcp/ipv4ll.c +++ b/gdhcp/ipv4ll.c diff --git a/gdhcp/ipv4ll.h b/gdhcp/ipv4ll.h new file mode 100755 index 00000000..bee8138a --- /dev/null +++ b/gdhcp/ipv4ll.h @@ -0,0 +1,55 @@ +/* + * + * IPV4 Local Link library with GLib integration + * + * Copyright (C) 2009-2010 Aldebaran Robotics. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __G_IPV4LL_H +#define __G_IPV4LL_H + +#include <glib.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* 169.254.0.0 */ +#define LINKLOCAL_ADDR 0xa9fe0000 + +/* See RFC 3927 */ +#define PROBE_WAIT 1 +#define PROBE_NUM 3 +#define PROBE_MIN 1 +#define PROBE_MAX 2 +#define ANNOUNCE_WAIT 2 +#define ANNOUNCE_NUM 2 +#define ANNOUNCE_INTERVAL 2 +#define MAX_CONFLICTS 10 +#define RATE_LIMIT_INTERVAL 60 +#define DEFEND_INTERVAL 10 + +uint32_t ipv4ll_random_ip(void); +guint ipv4ll_random_delay_ms(guint secs); +int ipv4ll_send_arp_packet(uint8_t* source_eth, uint32_t source_ip, + uint32_t target_ip, int ifindex); +int ipv4ll_arp_socket(int ifindex); + +#ifdef __cplusplus +} +#endif +#endif /* !IPV4LL_H_ */ diff --git a/gdhcp/server.c b/gdhcp/server.c index 85405f19..85405f19 100644..100755 --- a/gdhcp/server.c +++ b/gdhcp/server.c diff --git a/gsupplicant/dbus.c b/gsupplicant/dbus.c index 2957979a..2957979a 100644..100755 --- a/gsupplicant/dbus.c +++ b/gsupplicant/dbus.c diff --git a/gsupplicant/dbus.h b/gsupplicant/dbus.h index 3a904069..3a904069 100644..100755 --- a/gsupplicant/dbus.h +++ b/gsupplicant/dbus.h diff --git a/gsupplicant/gsupplicant.h b/gsupplicant/gsupplicant.h index bfb52db7..f79e6e49 100644 --- a/gsupplicant/gsupplicant.h +++ b/gsupplicant/gsupplicant.h @@ -50,17 +50,29 @@ extern "C" { #define G_SUPPLICANT_CAPABILITY_MODE_IBSS (1 << 1) #define G_SUPPLICANT_CAPABILITY_MODE_AP (1 << 2) #define G_SUPPLICANT_CAPABILITY_MODE_P2P (1 << 3) +#if defined TIZEN_EXT_WIFI_MESH +#define G_SUPPLICANT_CAPABILITY_MODE_MESH (1 << 4) +#endif #define G_SUPPLICANT_KEYMGMT_NONE (1 << 0) #define G_SUPPLICANT_KEYMGMT_IEEE8021X (1 << 1) #define G_SUPPLICANT_KEYMGMT_WPA_NONE (1 << 2) #define G_SUPPLICANT_KEYMGMT_WPA_PSK (1 << 3) #define G_SUPPLICANT_KEYMGMT_WPA_PSK_256 (1 << 4) +#if defined TIZEN_EXT +#define G_SUPPLICANT_KEYMGMT_WPA_FT_EAP (1 << 5) +#define G_SUPPLICANT_KEYMGMT_WPA_FT_PSK (1 << 6) +#else #define G_SUPPLICANT_KEYMGMT_WPA_FT_PSK (1 << 5) #define G_SUPPLICANT_KEYMGMT_WPA_FT_EAP (1 << 6) +#endif #define G_SUPPLICANT_KEYMGMT_WPA_EAP (1 << 7) #define G_SUPPLICANT_KEYMGMT_WPA_EAP_256 (1 << 8) #define G_SUPPLICANT_KEYMGMT_WPS (1 << 9) +#if defined TIZEN_EXT +#define G_SUPPLICANT_KEYMGMT_SAE (1 << 10) +#define G_SUPPLICANT_KEYMGMT_OWE (1 << 22) +#endif #define G_SUPPLICANT_PROTO_WPA (1 << 0) #define G_SUPPLICANT_PROTO_RSN (1 << 1) @@ -89,16 +101,52 @@ typedef enum { G_SUPPLICANT_MODE_INFRA, G_SUPPLICANT_MODE_IBSS, G_SUPPLICANT_MODE_MASTER, +#if defined TIZEN_EXT_WIFI_MESH + G_SUPPLICANT_MODE_MESH, +#endif } GSupplicantMode; +#if defined TIZEN_EXT_WIFI_MESH +typedef enum { + G_SUPPLICANT_IEEE80211W_UNKNOWN, + G_SUPPLICANT_IEEE80211W_OPTIONAL, + G_SUPPLICANT_IEEE80211W_REQUIRED, +} GSupplicantPmf; +#endif + typedef enum { G_SUPPLICANT_SECURITY_UNKNOWN, G_SUPPLICANT_SECURITY_NONE, G_SUPPLICANT_SECURITY_WEP, G_SUPPLICANT_SECURITY_PSK, G_SUPPLICANT_SECURITY_IEEE8021X, +#if defined TIZEN_EXT + G_SUPPLICANT_SECURITY_FT_PSK, + G_SUPPLICANT_SECURITY_FT_IEEE8021X, + G_SUPPLICANT_SECURITY_SAE, + G_SUPPLICANT_SECURITY_OWE, +#endif } GSupplicantSecurity; +#if defined TIZEN_EXT +typedef enum { + G_SUPPLICANT_EAP_KEYMGMT_NONE, + G_SUPPLICANT_EAP_KEYMGMT_FT, + G_SUPPLICANT_EAP_KEYMGMT_CCKM, + G_SUPPLICANT_EAP_KEYMGMT_OKC, +} GSupplicantEapKeymgmt; + +typedef enum { + G_SUPPLICANT_MODE_IEEE80211_UNKNOWN, + G_SUPPLICANT_MODE_IEEE80211B, + G_SUPPLICANT_MODE_IEEE80211BG, + G_SUPPLICANT_MODE_IEEE80211BGN, + G_SUPPLICANT_MODE_IEEE80211A, + G_SUPPLICANT_MODE_IEEE80211AN, + G_SUPPLICANT_MODE_IEEE80211ANAC, +} GSupplicantPhy_mode; +#endif + typedef enum { G_SUPPLICANT_STATE_UNKNOWN, G_SUPPLICANT_STATE_DISABLED, @@ -130,7 +178,11 @@ typedef enum { } GSupplicantPeerState; struct _GSupplicantSSID { +#if defined TIZEN_EXT + void *ssid; +#else const void *ssid; +#endif unsigned int ssid_len; unsigned int scan_ssid; GSupplicantMode mode; @@ -155,10 +207,28 @@ struct _GSupplicantSSID { dbus_bool_t use_wps; const char *pin_wps; const char *bgscan; +#if defined TIZEN_EXT + unsigned char *bssid; + unsigned int bssid_for_connect_len; + unsigned char bssid_for_connect[6]; + GSupplicantEapKeymgmt eap_keymgmt; + const char *phase1; + const char *pac_file; + uint16_t ieee80211w; +#endif }; typedef struct _GSupplicantSSID GSupplicantSSID; +/* + * Max number of SSIDs that can be scanned. + * In wpa_s 0.7x the limit is 4. + * In wps_s 0.8 or later it is 16. + * The value is only used if wpa_supplicant does not return any max limit + * for number of scannable SSIDs. + */ +#define WPAS_MAX_SCAN_SSIDS 4 + struct scan_ssid { unsigned char ssid[32]; uint8_t ssid_len; @@ -211,11 +281,19 @@ struct _GSupplicantPeer; typedef struct _GSupplicantInterface GSupplicantInterface; typedef struct _GSupplicantPeer GSupplicantPeer; +#if defined TIZEN_EXT_WIFI_MESH +typedef struct _GSupplicantMeshPeer GSupplicantMeshPeer; +#endif typedef void (*GSupplicantInterfaceCallback) (int result, GSupplicantInterface *interface, void *user_data); +#if defined TIZEN_EXT +typedef void (*GSupplicantMaxSpeedCallback) (int result, int maxspeed, + uint8_t strength, void *user_data); +#endif + void g_supplicant_interface_cancel(GSupplicantInterface *interface); int g_supplicant_interface_create(const char *ifname, const char *driver, @@ -230,6 +308,12 @@ int g_supplicant_interface_scan(GSupplicantInterface *interface, GSupplicantInterfaceCallback callback, void *user_data); +#if defined TIZEN_EXT +int g_supplicant_interface_signalpoll(GSupplicantInterface *interface, + GSupplicantMaxSpeedCallback callback, + void *user_data); +#endif + int g_supplicant_interface_p2p_find(GSupplicantInterface *interface, GSupplicantInterfaceCallback callback, void *user_data); @@ -275,6 +359,9 @@ void g_supplicant_interface_set_data(GSupplicantInterface *interface, void *data); void *g_supplicant_interface_get_data(GSupplicantInterface *interface); const char *g_supplicant_interface_get_ifname(GSupplicantInterface *interface); +#if defined TIZEN_EXT +bool g_supplicant_interface_get_is_5_0_ghz_supported(GSupplicantInterface *interface); +#endif const char *g_supplicant_interface_get_driver(GSupplicantInterface *interface); GSupplicantState g_supplicant_interface_get_state(GSupplicantInterface *interface); const char *g_supplicant_interface_get_wps_key(GSupplicantInterface *interface); @@ -300,6 +387,26 @@ GSupplicantPeer *g_supplicant_interface_peer_lookup(GSupplicantInterface *interf const char *identifier); bool g_supplicant_interface_is_p2p_finding(GSupplicantInterface *interface); +#if defined TIZEN_EXT_WIFI_MESH +bool g_supplicant_interface_has_mesh(GSupplicantInterface *interface); +int g_supplicant_mesh_interface_create(const char *ifname, const char *driver, + const char *bridge, const char *parent_ifname, + GSupplicantInterfaceCallback callback, void *user_data); +const void *g_supplicant_interface_get_mesh_group_ssid( + GSupplicantInterface *interface, + unsigned int *ssid_len); +int g_supplicant_mesh_get_disconnect_reason(GSupplicantInterface *interface); +const char *g_supplicant_mesh_peer_get_address(GSupplicantMeshPeer *mesh_peer); +int g_supplicant_mesh_peer_get_disconnect_reason( + GSupplicantMeshPeer *mesh_peer); +int g_supplicant_interface_abort_scan(GSupplicantInterface *interface, + GSupplicantInterfaceCallback callback, void *user_data); +int g_supplicant_interface_mesh_peer_change_status( + GSupplicantInterface *interface, + GSupplicantInterfaceCallback callback, const char *peer_address, + const char *method, void *user_data); +#endif + /* Network and Peer API */ struct _GSupplicantNetwork; struct _GSupplicantGroup; @@ -337,6 +444,27 @@ GSupplicantInterface *g_supplicant_peer_get_group_interface(GSupplicantPeer *pee bool g_supplicant_peer_is_client(GSupplicantPeer *peer); bool g_supplicant_peer_has_requested_connection(GSupplicantPeer *peer); +#if defined TIZEN_EXT +/* +* Description: Network client requires additional wifi specific info +*/ +const unsigned char *g_supplicant_network_get_bssid( + GSupplicantNetwork *network); +unsigned int g_supplicant_network_get_maxrate(GSupplicantNetwork *network); +const char *g_supplicant_network_get_enc_mode(GSupplicantNetwork *network); +bool g_supplicant_network_get_rsn_mode(GSupplicantNetwork *network); +bool g_supplicant_network_is_hs20AP(GSupplicantNetwork *network); +const char *g_supplicant_network_get_eap(GSupplicantNetwork *network); +const char *g_supplicant_network_get_identity(GSupplicantNetwork *network); +const char *g_supplicant_network_get_phase2(GSupplicantNetwork *network); +unsigned int g_supplicant_network_get_keymgmt(GSupplicantNetwork *network); +void *g_supplicant_network_get_wifi_vsie(GSupplicantNetwork *network); +const unsigned char *g_supplicant_network_get_countrycode(GSupplicantNetwork + *network); +void *g_supplicant_network_get_bssid_list(GSupplicantNetwork *network); +GSupplicantPhy_mode g_supplicant_network_get_phy_mode(GSupplicantNetwork *network); +#endif + struct _GSupplicantCallbacks { void (*system_ready) (void); void (*system_killed) (void); @@ -349,9 +477,16 @@ struct _GSupplicantCallbacks { void (*ap_create_fail) (GSupplicantInterface *interface); void (*network_added) (GSupplicantNetwork *network); void (*network_removed) (GSupplicantNetwork *network); +#if defined TIZEN_EXT + void (*network_merged) (GSupplicantNetwork *network); +#endif void (*network_changed) (GSupplicantNetwork *network, const char *property); void (*network_associated) (GSupplicantNetwork *network); +#if defined TIZEN_EXT + void (*system_power_off) (void); + void (*assoc_failed) (void *user_data); +#endif void (*sta_authorized) (GSupplicantInterface *interface, const char *addr); void (*sta_deauthorized) (GSupplicantInterface *interface, @@ -366,6 +501,13 @@ struct _GSupplicantCallbacks { int reasoncode); void (*assoc_status_code)(GSupplicantInterface *interface, int reasoncode); +#if defined TIZEN_EXT_WIFI_MESH + void (*mesh_support) (GSupplicantInterface *interface); + void (*mesh_group_started) (GSupplicantInterface *interface); + void (*mesh_group_removed) (GSupplicantInterface *interface); + void (*mesh_peer_connected) (GSupplicantMeshPeer *mesh_peer); + void (*mesh_peer_disconnected) (GSupplicantMeshPeer *mesh_peer); +#endif }; typedef struct _GSupplicantCallbacks GSupplicantCallbacks; diff --git a/gsupplicant/supplicant.c b/gsupplicant/supplicant.c index 6052f7b6..9c12093e 100644 --- a/gsupplicant/supplicant.c +++ b/gsupplicant/supplicant.c @@ -44,6 +44,15 @@ #define IEEE80211_CAP_IBSS 0x0002 #define IEEE80211_CAP_PRIVACY 0x0010 +#if defined TIZEN_EXT +#define WLAN_EID_HT_CAP 45 +#define WLAN_EID_VHT_CAP 191 +#define WLAN_EID_SUPP_RATES 1 +#define WLAN_EID_EXT_SUPP_RATES 50 +#define COUNTRY_CODE_LENGTH 2 +#define WIFI_BSSID_LEN_MAX 6 +#endif + #define BSS_UNKNOWN_STRENGTH -90 static DBusConnection *connection; @@ -92,6 +101,10 @@ static struct strvalmap keymgmt_map[] = { { "wpa-eap", G_SUPPLICANT_KEYMGMT_WPA_EAP }, { "wpa-eap-sha256", G_SUPPLICANT_KEYMGMT_WPA_EAP_256 }, { "wps", G_SUPPLICANT_KEYMGMT_WPS }, +#if defined TIZEN_EXT + { "sae", G_SUPPLICANT_KEYMGMT_SAE }, + { "owe", G_SUPPLICANT_KEYMGMT_OWE }, +#endif { } }; @@ -135,6 +148,9 @@ static struct strvalmap mode_capa_map[] = { { "ad-hoc", G_SUPPLICANT_CAPABILITY_MODE_IBSS }, { "ap", G_SUPPLICANT_CAPABILITY_MODE_AP }, { "p2p", G_SUPPLICANT_CAPABILITY_MODE_P2P }, +#if defined TIZEN_EXT_WIFI_MESH + { "mesh", G_SUPPLICANT_CAPABILITY_MODE_MESH }, +#endif { } }; @@ -158,6 +174,14 @@ struct added_network_information { char * private_passphrase; }; +#if defined TIZEN_EXT_WIFI_MESH +struct _GSupplicantMeshGroupInfo { + unsigned char ssid[32]; + unsigned int ssid_len; + int disconnect_reason; +}; +#endif + struct _GSupplicantInterface { char *path; char *network_path; @@ -191,6 +215,14 @@ struct _GSupplicantInterface { const char *pending_peer_path; GSupplicantNetwork *current_network; struct added_network_information network_info; +#if defined TIZEN_EXT + dbus_bool_t is_5_0_Ghz_supported; + int disconnect_reason; +#endif +#if defined TIZEN_EXT_WIFI_MESH + bool mesh_support; + struct _GSupplicantMeshGroupInfo group_info; +#endif }; struct g_supplicant_bss { @@ -215,7 +247,19 @@ struct g_supplicant_bss { dbus_bool_t privacy; dbus_bool_t psk; dbus_bool_t ieee8021x; +#if defined TIZEN_EXT + dbus_bool_t ft_psk; + dbus_bool_t ft_ieee8021x; + GSList *vsie_list; + dbus_bool_t hs20; + unsigned char country_code[COUNTRY_CODE_LENGTH]; + GSupplicantPhy_mode phy_mode; +#endif unsigned int wps_capabilities; +#if defined TIZEN_EXT + dbus_bool_t sae; + dbus_bool_t owe; +#endif }; struct _GSupplicantNetwork { @@ -234,6 +278,16 @@ struct _GSupplicantNetwork { unsigned int wps_capabilities; GHashTable *bss_table; GHashTable *config_table; +#if defined TIZEN_EXT + bool isHS20AP; + char *eap; + char *identity; + char *phase2; + unsigned int keymgmt; + GSList *vsie_list; + unsigned char country_code[COUNTRY_CODE_LENGTH]; + GSupplicantPhy_mode phy_mode; +#endif }; struct _GSupplicantPeer { @@ -270,10 +324,23 @@ struct interface_data { GSupplicantSSID *ssid; }; +#if defined TIZEN_EXT +struct interface_signalpoll_data { + GSupplicantInterface *interface; + char *path; + GSupplicantMaxSpeedCallback callback; + void *user_data; +}; +#endif + struct interface_create_data { char *ifname; char *driver; char *bridge; +#if defined TIZEN_EXT_WIFI_MESH + char *parent_ifname; + bool is_mesh_interface; +#endif GSupplicantInterface *interface; GSupplicantInterfaceCallback callback; void *user_data; @@ -298,8 +365,24 @@ struct interface_scan_data { void *user_data; }; +#if defined TIZEN_EXT +struct g_connman_bssids { + unsigned char bssid[WIFI_BSSID_LEN_MAX]; + uint16_t strength; + uint16_t frequency; +}; +#endif + static int network_remove(struct interface_data *data); +#if defined TIZEN_EXT_WIFI_MESH +struct _GSupplicantMeshPeer { + GSupplicantInterface *interface; + char *peer_address; + int disconnect_reason; +}; +#endif + static inline void debug(const char *format, ...) { char str[256]; @@ -328,6 +411,10 @@ static GSupplicantMode string2mode(const char *mode) return G_SUPPLICANT_MODE_INFRA; else if (g_str_equal(mode, "ad-hoc")) return G_SUPPLICANT_MODE_IBSS; +#if defined TIZEN_EXT_WIFI_MESH + else if (g_str_equal(mode, "mesh")) + return G_SUPPLICANT_MODE_MESH; +#endif return G_SUPPLICANT_MODE_UNKNOWN; } @@ -343,6 +430,10 @@ static const char *mode2string(GSupplicantMode mode) return "adhoc"; case G_SUPPLICANT_MODE_MASTER: return "ap"; +#if defined TIZEN_EXT_WIFI_MESH + case G_SUPPLICANT_MODE_MESH: + return "mesh"; +#endif } return NULL; @@ -361,6 +452,16 @@ static const char *security2string(GSupplicantSecurity security) return "psk"; case G_SUPPLICANT_SECURITY_IEEE8021X: return "ieee8021x"; +#if defined TIZEN_EXT + case G_SUPPLICANT_SECURITY_FT_PSK: + return "ft_psk"; + case G_SUPPLICANT_SECURITY_FT_IEEE8021X: + return "ft_ieee8021x"; + case G_SUPPLICANT_SECURITY_SAE: + return "sae"; + case G_SUPPLICANT_SECURITY_OWE: + return "owe"; +#endif } return NULL; @@ -400,6 +501,11 @@ static GSupplicantState string2state(const char *state) static bool compare_network_parameters(GSupplicantInterface *interface, GSupplicantSSID *ssid) { +#if defined TIZEN_EXT + if (!interface->network_info.ssid) + return FALSE; +#endif + if (memcmp(interface->network_info.ssid, ssid->ssid, ssid->ssid_len)) return FALSE; @@ -525,6 +631,7 @@ static void callback_interface_removed(GSupplicantInterface *interface) callbacks_pointer->interface_removed(interface); } +#if !defined TIZEN_EXT static void callback_p2p_support(GSupplicantInterface *interface) { SUPPLICANT_DBG(""); @@ -535,6 +642,28 @@ static void callback_p2p_support(GSupplicantInterface *interface) if (callbacks_pointer && callbacks_pointer->p2p_support) callbacks_pointer->p2p_support(interface); } +#endif + +#if defined TIZEN_EXT_WIFI_MESH +static void callback_mesh_support(GSupplicantInterface *interface) +{ + SUPPLICANT_DBG(""); + + if (!interface->mesh_support) + return; + + if (callbacks_pointer && callbacks_pointer->mesh_support) + callbacks_pointer->mesh_support(interface); +} + +bool g_supplicant_interface_has_mesh(GSupplicantInterface *interface) +{ + if (!interface) + return false; + + return interface->mesh_support; +} +#endif static void callback_scan_started(GSupplicantInterface *interface) { @@ -591,6 +720,30 @@ static void callback_network_removed(GSupplicantNetwork *network) callbacks_pointer->network_removed(network); } +#if defined TIZEN_EXT +static void callback_network_merged(GSupplicantNetwork *network) +{ + if (!callbacks_pointer) + return; + + if (!callbacks_pointer->network_merged) + return; + + callbacks_pointer->network_merged(network); +} + +static void callback_assoc_failed(void *user_data) +{ + if (!callbacks_pointer) + return; + + if (!callbacks_pointer->assoc_failed) + return; + + callbacks_pointer->assoc_failed(user_data); +} +#endif + static void callback_network_changed(GSupplicantNetwork *network, const char *property) { @@ -752,6 +905,9 @@ static void remove_interface(gpointer data) g_free(interface->wps_cred.key); g_free(interface->path); g_free(interface->network_path); +#if defined TIZEN_EXT + interface->network_path = NULL; +#endif g_free(interface->ifname); g_free(interface->driver); g_free(interface->bridge); @@ -772,6 +928,15 @@ static void remove_network(gpointer data) g_free(network->path); g_free(network->group); g_free(network->name); +#if defined TIZEN_EXT + g_free(network->eap); + g_free(network->identity); + g_free(network->phase2); +#endif +#if defined TIZEN_EXT + g_slist_free_full(network->vsie_list, g_free); +#endif + g_free(network); } @@ -782,6 +947,9 @@ static void remove_bss(gpointer data) supplicant_dbus_property_call_cancel_all(bss); g_free(bss->path); +#if defined TIZEN_EXT + g_slist_free_full(bss->vsie_list, g_free); +#endif g_free(bss); } @@ -975,7 +1143,13 @@ static void interface_capability(const char *key, DBusMessageIter *iter, if (max_scan_ssid < 2) max_scan_ssid = 0; interface->max_scan_ssids = max_scan_ssid; +#if defined TIZEN_EXT + } else if (g_strcmp0(key, "Is5GhzSupported") == 0) { + dbus_bool_t is_5_0_Ghz_supported; + dbus_message_iter_get_basic(iter, &is_5_0_Ghz_supported); + interface->is_5_0_Ghz_supported = is_5_0_Ghz_supported; +#endif } else SUPPLICANT_DBG("key %s type %c", key, dbus_message_iter_get_arg_type(iter)); @@ -1064,6 +1238,16 @@ const char *g_supplicant_interface_get_ifname(GSupplicantInterface *interface) return interface->ifname; } +#if defined TIZEN_EXT +bool g_supplicant_interface_get_is_5_0_ghz_supported(GSupplicantInterface *interface) +{ + if (!interface) + return NULL; + + return interface->is_5_0_Ghz_supported; +} +#endif + const char *g_supplicant_interface_get_driver(GSupplicantInterface *interface) { if (!interface) @@ -1127,6 +1311,9 @@ unsigned int g_supplicant_interface_get_max_scan_ssids( if (!interface) return 0; + if (interface->max_scan_ssids == 0) + return WPAS_MAX_SCAN_SSIDS; + return interface->max_scan_ssids; } @@ -1279,6 +1466,16 @@ dbus_bool_t g_supplicant_network_is_wps_advertizing(GSupplicantNetwork *network) return FALSE; } +#ifdef TIZEN_EXT +GSupplicantPhy_mode g_supplicant_network_get_phy_mode(GSupplicantNetwork *network) +{ + if (!network) + return G_SUPPLICANT_MODE_IEEE80211_UNKNOWN; + + return network->phy_mode; +} +#endif + GSupplicantInterface *g_supplicant_peer_get_interface(GSupplicantPeer *peer) { if (!peer) @@ -1327,6 +1524,57 @@ const char *g_supplicant_peer_get_name(GSupplicantPeer *peer) return peer->name; } +#if defined TIZEN_EXT +bool g_supplicant_network_is_hs20AP(GSupplicantNetwork *network) +{ + if (!network) + return 0; + + return network->isHS20AP; +} + +const char *g_supplicant_network_get_eap(GSupplicantNetwork *network) +{ + if (!network || !network->eap) + return NULL; + + return network->eap; +} + +const char *g_supplicant_network_get_identity(GSupplicantNetwork *network) +{ + if (!network || !network->identity) + return NULL; + + return network->identity; +} + +const char *g_supplicant_network_get_phase2(GSupplicantNetwork *network) +{ + if (!network || !network->phase2) + return NULL; + + return network->phase2; +} + +unsigned int g_supplicant_network_get_keymgmt(GSupplicantNetwork *network) +{ + if (network == NULL) + return 0; + + return network->keymgmt; +} + +const unsigned char *g_supplicant_network_get_countrycode(GSupplicantNetwork + *network) +{ + if (!network) + return NULL; + + return network->country_code; +} +#endif + const unsigned char *g_supplicant_peer_get_widi_ies(GSupplicantPeer *peer, int *length) { @@ -1409,16 +1657,178 @@ bool g_supplicant_peer_has_requested_connection(GSupplicantPeer *peer) return peer->connection_requested; } +#if defined TIZEN_EXT +/* + * Description: Network client requires additional wifi specific info + */ +const unsigned char *g_supplicant_network_get_bssid(GSupplicantNetwork *network) +{ + if (network == NULL || network->best_bss == NULL) + return NULL; + + return (const unsigned char *)network->best_bss->bssid; +} + +unsigned int g_supplicant_network_get_maxrate(GSupplicantNetwork *network) +{ + if (network == NULL || network->best_bss == NULL) + return 0; + + return network->best_bss->maxrate; +} + +const char *g_supplicant_network_get_enc_mode(GSupplicantNetwork *network) +{ + if (network == NULL || network->best_bss == NULL) + return NULL; + + if (network->best_bss->security == G_SUPPLICANT_SECURITY_PSK || +#if defined TIZEN_EXT + network->best_bss->security == G_SUPPLICANT_SECURITY_SAE || + network->best_bss->security == G_SUPPLICANT_SECURITY_OWE || +#endif /* TIZEN_EXT */ + network->best_bss->security == G_SUPPLICANT_SECURITY_IEEE8021X) { + unsigned int pairwise; + + pairwise = network->best_bss->rsn_pairwise | + network->best_bss->wpa_pairwise; + + if ((pairwise & G_SUPPLICANT_PAIRWISE_CCMP) && + (pairwise & G_SUPPLICANT_PAIRWISE_TKIP)) + return "mixed"; + else if (pairwise & G_SUPPLICANT_PAIRWISE_CCMP) + return "aes"; + else if (pairwise & G_SUPPLICANT_PAIRWISE_TKIP) + return "tkip"; + + } else if (network->best_bss->security == G_SUPPLICANT_SECURITY_WEP) + return "wep"; + else if (network->best_bss->security == G_SUPPLICANT_SECURITY_NONE) + return "none"; + + return NULL; +} + +bool g_supplicant_network_get_rsn_mode(GSupplicantNetwork *network) +{ + if (network == NULL || network->best_bss == NULL) + return 0; + +#if defined TIZEN_EXT + if (network->best_bss->security == G_SUPPLICANT_SECURITY_SAE || + network->best_bss->security == G_SUPPLICANT_SECURITY_OWE) + return false; +#endif /* TIZEN_EXT */ + + if (network->best_bss->rsn_selected) { + const char *mode = g_supplicant_network_get_enc_mode(network); + if (g_strcmp0(mode, "aes") == 0 || + g_strcmp0(mode, "mixed") == 0) + return true; + else + return false; + } else + return false; +} + +void *g_supplicant_network_get_wifi_vsie(GSupplicantNetwork *network) +{ + GSList *vsie_list = NULL; + + if (!network) + return NULL; + + if (g_slist_length(network->vsie_list) > 0) { + GSList *list = NULL; + unsigned char *vsie = NULL; + for (list = network->vsie_list; list; list = list->next) { + unsigned char *ie = (unsigned char *)list->data; + if (ie == NULL) + continue; + vsie = (unsigned char *)g_try_malloc0(ie[1]+2); // tag number size(1), tag length size(1) + + if (vsie) { + memcpy(vsie, ie, ie[1]+2); + vsie_list = g_slist_append(vsie_list, vsie); + } else + SUPPLICANT_DBG("Failed to allocate memory"); + } + } + + return vsie_list; +} + +static void update_bssid_list(gpointer key, gpointer value, gpointer user_data) +{ + struct g_supplicant_bss *bss = value; + struct g_connman_bssids *bssids = NULL; + GSList **list = (GSList **)user_data; + + bssids = (struct g_connman_bssids *)g_try_malloc0(sizeof(struct g_connman_bssids)); + + if (bssids) { + memcpy(bssids->bssid, bss->bssid, WIFI_BSSID_LEN_MAX); + + bssids->strength = bss->signal; + bssids->strength += 120; + + if (bssids->strength > 100) + bssids->strength = 100; + + bssids->frequency = bss->frequency; + *list = g_slist_append(*list, bssids); + } else + SUPPLICANT_DBG("Failed to allocate memory"); +} + +static gint cmp_bss(gconstpointer a, gconstpointer b) +{ + struct g_connman_bssids *entry_a = (struct g_connman_bssids *)a; + struct g_connman_bssids *entry_b = (struct g_connman_bssids *)b; + + if (entry_a->strength > entry_b->strength) + return -1; + + if (entry_a->strength < entry_b->strength) + return 1; + + return 0; +} + +void *g_supplicant_network_get_bssid_list(GSupplicantNetwork *network) +{ + GSList *bssid_list = NULL; + + if (g_hash_table_size(network->bss_table) < 1) + return NULL; + + g_hash_table_foreach(network->bss_table, update_bssid_list, &bssid_list); + bssid_list = g_slist_sort(bssid_list, cmp_bss); + + return bssid_list; +} +#endif + static void merge_network(GSupplicantNetwork *network) { GString *str; const char *ssid, *mode, *key_mgmt; +#if defined TIZEN_EXT + const char *isHS20AP; + const char *eap, *identity, *phase2; +#endif unsigned int i, ssid_len; char *group; ssid = g_hash_table_lookup(network->config_table, "ssid"); mode = g_hash_table_lookup(network->config_table, "mode"); key_mgmt = g_hash_table_lookup(network->config_table, "key_mgmt"); +#if defined TIZEN_EXT + isHS20AP = g_hash_table_lookup(network->config_table, "isHS20AP"); + eap = g_hash_table_lookup(network->config_table, "eap"); + identity = g_hash_table_lookup(network->config_table, "identity"); + phase2 = g_hash_table_lookup(network->config_table, "phase2"); +#endif SUPPLICANT_DBG("ssid %s mode %s", ssid, mode); @@ -1432,20 +1842,59 @@ static void merge_network(GSupplicantNetwork *network) return; for (i = 0; i < ssid_len; i++) +#if defined TIZEN_EXT + { + if (ssid[i] != '"') +#endif g_string_append_printf(str, "%02x", ssid[i]); +#if defined TIZEN_EXT + } +#endif if (g_strcmp0(mode, "0") == 0) g_string_append_printf(str, "_managed"); else if (g_strcmp0(mode, "1") == 0) g_string_append_printf(str, "_adhoc"); +#if defined TIZEN_EXT_WIFI_MESH + else if (g_strcmp0(mode, "5") == 0) + g_string_append_printf(str, "_mesh"); +#endif if (g_strcmp0(key_mgmt, "WPA-PSK") == 0) g_string_append_printf(str, "_psk"); +#if defined TIZEN_EXT + else if (g_strcmp0(key_mgmt, "WPA-EAP") == 0) + g_string_append_printf(str, "_ieee8021x"); + else + g_string_append_printf(str, "_none"); +#endif group = g_string_free(str, FALSE); SUPPLICANT_DBG("%s", group); +#if defined TIZEN_EXT + if (g_strcmp0(isHS20AP, "1") == 0) { + network->isHS20AP = 1; + if (network->eap) + g_free(network->eap); + network->eap = g_strdup(eap); + + if (network->identity) + g_free(network->identity); + network->identity = g_strdup(identity); + + if (network->phase2) + g_free(network->phase2); + network->phase2 = g_strdup(phase2); + } else + network->isHS20AP = 0; + + network->group = g_strdup(group); + callback_network_merged(network); + g_free(network->group); +#endif + g_free(group); g_hash_table_destroy(network->config_table); @@ -1643,6 +2092,29 @@ static int add_or_replace_bss_to_network(struct g_supplicant_bss *bss) network->wps_capabilities = bss->wps_capabilities; } +#if defined TIZEN_EXT + network->keymgmt = bss->keymgmt; + + if (g_slist_length(bss->vsie_list) > 0) { + GSList *list = NULL; + unsigned char *vsie = NULL; + for (list = bss->vsie_list; list; list = list->next) { + unsigned char *ie = (unsigned char *)list->data; + vsie = (unsigned char *)g_try_malloc0(ie[1]+2); // tag number size(1), tag length size(1) + + if (vsie) { + memcpy(vsie, ie, ie[1]+2); + network->vsie_list = g_slist_append(network->vsie_list, vsie); + } else + SUPPLICANT_DBG("Failed to allocate memory."); + } + } + + network->isHS20AP = bss->hs20; + memcpy(network->country_code, bss->country_code, COUNTRY_CODE_LENGTH); + network->phy_mode = bss->phy_mode; +#endif + SUPPLICANT_DBG("New network %s created", network->name); network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal, @@ -1826,6 +2298,50 @@ static unsigned int get_tlv(unsigned char *ie, unsigned int ie_size, return 0; } +#if defined TIZEN_EXT +static void get_bss_phy_mode(unsigned int max_rate, + unsigned int max_ext_rate, bool ht, bool vht, void *data) +{ + struct g_supplicant_bss *bss = data; + unsigned int freq = bss->frequency; + + /* Following conditions are used to determine + * IEEE 802.11 Protocol Modes:- + * + * 1. If “Supported rates” is only till 11 Mbps, + * and frequency is in 2.4GHz band, then protocol is 11B. + * 2. If “Supported rates” is till 54Mbps or + * “Extended supported rates” are present, + * and frequency is in 2.4GHz band, then protocol is 11G. + * 3. If “Supported rates” is only till 54 Mbps, + * frequency is in 5GHz band , then protocol is 11A. + * 4. If “HT capabilities” is supported , then protocol is 11N. + * 5. If “HT capabilities” & “VHT” is supported and + * frequency is in 5 GHz band, then protocol is 11AC. + * */ + + if (freq >= 2412 && freq <= 2484) { /* 2.4 Ghz Band */ + if (max_rate <= 11 && max_ext_rate <= 0 && !ht) + bss->phy_mode = G_SUPPLICANT_MODE_IEEE80211B; + else if ((max_rate <= 54 || max_ext_rate > 0) && !ht) + bss->phy_mode = G_SUPPLICANT_MODE_IEEE80211BG; + else if ((max_rate >= 54 || max_ext_rate > 0) && ht) + bss->phy_mode = G_SUPPLICANT_MODE_IEEE80211BGN; + else + bss->phy_mode = G_SUPPLICANT_MODE_UNKNOWN; + } else if (freq >= 5180 && freq <= 5825) { /* 5 Ghz Band */ + if (max_rate <= 54 && !ht) + bss->phy_mode = G_SUPPLICANT_MODE_IEEE80211A; + else if ((max_rate >= 54 || max_ext_rate > 0) && ht && !vht) + bss->phy_mode = G_SUPPLICANT_MODE_IEEE80211AN; + else if ((max_rate >= 54 || max_ext_rate > 0) && ht && vht) + bss->phy_mode = G_SUPPLICANT_MODE_IEEE80211ANAC; + else + bss->phy_mode = G_SUPPLICANT_MODE_UNKNOWN; + } +} +#endif + static void bss_process_ies(DBusMessageIter *iter, void *user_data) { struct g_supplicant_bss *bss = user_data; @@ -1834,6 +2350,15 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data) DBusMessageIter array; unsigned int value; int ie_len; +#if defined TIZEN_EXT + int r_len, j; + unsigned char *rates = NULL; + unsigned char *ext_rates = NULL; + unsigned int max_rate = 0; + unsigned int max_ext_rate = 0; + bool ht = false; + bool vht = false; +#endif #define WMM_WPA1_WPS_INFO 221 #define WPS_INFO_MIN_LEN 6 @@ -1845,6 +2370,10 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data) #define WPS_PBC 0x04 #define WPS_PIN 0x00 #define WPS_CONFIGURED 0x02 +#if defined TIZEN_EXT +#define VENDOR_SPECIFIC_INFO 0xDD +#define WLAN_EID_COUNTRY 7 +#endif dbus_message_iter_recurse(iter, &array); dbus_message_iter_get_fixed_array(&array, &ie, &ie_len); @@ -1857,7 +2386,69 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data) for (ie_end = ie + ie_len; ie < ie_end && ie + ie[1] + 1 <= ie_end; ie += ie[1] + 2) { +#if defined TIZEN_EXT + unsigned char *vsie; + int vsie_len = 0; + if(ie[0] == VENDOR_SPECIFIC_INFO && memcmp(ie+2, WPS_OUI, sizeof(WPS_OUI)) != 0) { + SUPPLICANT_DBG("IE: match vendor specific data"); + + vsie_len = ie[1]+2; // tag number size(1), tag length size(1) + vsie = (unsigned char *)g_try_malloc0(vsie_len); + + if (vsie) { + memcpy(vsie, ie, vsie_len); + bss->vsie_list = g_slist_append(bss->vsie_list, vsie); + } else + SUPPLICANT_DBG("Failed to allocate memory"); + continue; + } + + if(ie[0] == WLAN_EID_COUNTRY && ie[1] >= 2) { + /* Add country code only if it is a valid alphabet */ + if (ie[2] >= 65 && ie[2] <= 90 && ie[3] >= 65 && ie[3] <= 90) { + memcpy(bss->country_code, ie+2, COUNTRY_CODE_LENGTH); + continue; + } + } + if (ie[0] == WLAN_EID_HT_CAP && ie[1]) { + ht = true; + continue; + } + + if (ie[0] == WLAN_EID_VHT_CAP && ie[1]) { + vht = true; + continue; + } + + if (ie[0] == WLAN_EID_SUPP_RATES && ie[1]) { + r_len = ie[1]; + rates = g_malloc0(r_len); + if (!rates) + continue; + + for (j = 0; ie && j < r_len; j++) { + rates[j] = ((ie[j + 2] & 0x7f) * 500000)/1000000; + if (max_rate < rates[j]) + max_rate = rates[j]; + } + continue; + } + + if (ie[0] == WLAN_EID_EXT_SUPP_RATES && ie[1] > 0) { + r_len = ie[1]; + ext_rates = g_malloc0(r_len); + if (!ext_rates) + continue; + + for (j = 0; ie && j < r_len; j++) { + ext_rates[j] = ((ie[j + 2] & 0x7f) * 500000)/1000000; + if (max_ext_rate < ext_rates[j]) + max_ext_rate = ext_rates[j]; + } + continue; + } +#endif if (ie[0] != WMM_WPA1_WPS_INFO || ie[1] < WPS_INFO_MIN_LEN || memcmp(ie+2, WPS_OUI, sizeof(WPS_OUI)) != 0) continue; @@ -1892,6 +2483,13 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data) SUPPLICANT_DBG("WPS Methods 0x%x", bss->wps_capabilities); } +#ifdef TIZEN_EXT + get_bss_phy_mode(max_rate, max_ext_rate, ht, vht, user_data); + if (rates) + g_free(rates); + if (ext_rates) + g_free(ext_rates); +#endif } static void bss_compute_security(struct g_supplicant_bss *bss) @@ -1903,23 +2501,62 @@ static void bss_compute_security(struct g_supplicant_bss *bss) bss->ieee8021x = FALSE; bss->psk = FALSE; +#if defined TIZEN_EXT + bss->ft_ieee8021x = FALSE; + bss->ft_psk = FALSE; +#endif +#if defined TIZEN_EXT + if (bss->keymgmt & + (G_SUPPLICANT_KEYMGMT_WPA_EAP | + G_SUPPLICANT_KEYMGMT_WPA_EAP_256)) + bss->ieee8021x = TRUE; + else if (bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPA_FT_EAP) + bss->ft_ieee8021x = TRUE; +#else if (bss->keymgmt & (G_SUPPLICANT_KEYMGMT_WPA_EAP | G_SUPPLICANT_KEYMGMT_WPA_FT_EAP | G_SUPPLICANT_KEYMGMT_WPA_EAP_256)) bss->ieee8021x = TRUE; +#endif +#if defined TIZEN_EXT + if (bss->keymgmt & + (G_SUPPLICANT_KEYMGMT_WPA_PSK | + G_SUPPLICANT_KEYMGMT_WPA_PSK_256)) + bss->psk = TRUE; + else if (bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPA_FT_PSK) + bss->ft_psk = TRUE; +#else if (bss->keymgmt & (G_SUPPLICANT_KEYMGMT_WPA_PSK | G_SUPPLICANT_KEYMGMT_WPA_FT_PSK | G_SUPPLICANT_KEYMGMT_WPA_PSK_256)) bss->psk = TRUE; +#endif + +#if defined TIZEN_EXT + if (bss->keymgmt & G_SUPPLICANT_KEYMGMT_SAE) + bss->sae = TRUE; + if (bss->keymgmt & G_SUPPLICANT_KEYMGMT_OWE) + bss->owe = TRUE; +#endif if (bss->ieee8021x) bss->security = G_SUPPLICANT_SECURITY_IEEE8021X; else if (bss->psk) bss->security = G_SUPPLICANT_SECURITY_PSK; +#if defined TIZEN_EXT + else if (bss->ft_psk) + bss->security = G_SUPPLICANT_SECURITY_FT_PSK; + else if (bss->ft_ieee8021x == TRUE) + bss->security = G_SUPPLICANT_SECURITY_IEEE8021X; + else if (bss->sae) + bss->security = G_SUPPLICANT_SECURITY_SAE; + else if (bss->owe) + bss->security = G_SUPPLICANT_SECURITY_OWE; +#endif else if (bss->privacy) bss->security = G_SUPPLICANT_SECURITY_WEP; else @@ -2021,6 +2658,12 @@ static void bss_property(const char *key, DBusMessageIter *iter, bss->rsn_selected = FALSE; supplicant_dbus_property_foreach(iter, bss_wpa, bss); +#if defined TIZEN_EXT + } else if (g_strcmp0(key, "HS20") == 0) { + dbus_bool_t hs20 = FALSE; + dbus_message_iter_get_basic(iter, &hs20); + bss->hs20 = hs20; +#endif } else if (g_strcmp0(key, "IEs") == 0) bss_process_ies(iter, bss); else @@ -2234,7 +2877,11 @@ static void interface_bss_removed(DBusMessageIter *iter, void *user_data) g_hash_table_remove(interface->network_table, network->group); } else { if (is_current_network_bss && network->best_bss) +#if defined TIZEN_EXT + callback_network_changed(network, "CheckMultiBssidConnect"); +#else callback_network_changed(network, ""); +#endif } } @@ -2312,8 +2959,14 @@ static void interface_property(const char *key, DBusMessageIter *iter, if (g_strcmp0(key, "Capabilities") == 0) { supplicant_dbus_property_foreach(iter, interface_capability, interface); +#if !defined TIZEN_EXT if (interface->mode_capa & G_SUPPLICANT_CAPABILITY_MODE_P2P) interface->p2p_support = true; +#endif +#if defined TIZEN_EXT_WIFI_MESH + if (interface->mode_capa & G_SUPPLICANT_CAPABILITY_MODE_MESH) + interface->mesh_support = true; +#endif } else if (g_strcmp0(key, "State") == 0) { const char *str = NULL; @@ -2390,6 +3043,9 @@ static void interface_property(const char *key, DBusMessageIter *iter, } else if (g_strcmp0(key, "CurrentBSS") == 0) { interface_current_bss(interface, iter); } else if (g_strcmp0(key, "CurrentNetwork") == 0) { +#if defined TIZEN_EXT + if (interface->state != G_SUPPLICANT_STATE_COMPLETED) +#endif interface_network_added(iter, interface); } else if (g_strcmp0(key, "BSSs") == 0) { supplicant_dbus_array_foreach(iter, @@ -2446,15 +3102,30 @@ static void scan_bss_data(const char *key, DBusMessageIter *iter, { GSupplicantInterface *interface = user_data; +/*Fixed : stucking in scanning state when scan failed*/ +#if defined TIZEN_EXT + GSupplicantInterfaceCallback scan_callback; +#endif + if (iter) supplicant_dbus_array_foreach(iter, scan_network_update, interface); +#if defined TIZEN_EXT + scan_callback = interface->scan_callback; +#endif + if (interface->scan_callback) interface->scan_callback(0, interface, interface->scan_data); +#if defined TIZEN_EXT + if (interface->scan_callback == scan_callback) { +#endif interface->scan_callback = NULL; interface->scan_data = NULL; +#if defined TIZEN_EXT + } +#endif } static GSupplicantInterface *interface_alloc(const char *path) @@ -2760,6 +3431,13 @@ static void signal_network_removed(const char *path, DBusMessageIter *iter) interface_network_removed(iter, interface); } +#if defined TIZEN_EXT +void *copy_vsie_list(gconstpointer src, gpointer data) +{ + return g_strdup(src); +} +#endif + static void signal_sta_authorized(const char *path, DBusMessageIter *iter) { @@ -2821,6 +3499,10 @@ static void signal_bss_changed(const char *path, DBusMessageIter *iter) supplicant_dbus_property_foreach(iter, bss_property, bss); +#if defined TIZEN_EXT + network->frequency = bss->frequency; + network->phy_mode = bss->phy_mode; +#endif old_security = network->security; bss_compute_security(bss); @@ -2846,6 +3528,9 @@ static void signal_bss_changed(const char *path, DBusMessageIter *iter) memcpy(new_bss, bss, sizeof(struct g_supplicant_bss)); new_bss->path = g_strdup(bss->path); +#if defined TIZEN_EXT + new_bss->vsie_list = g_slist_copy_deep(bss->vsie_list, copy_vsie_list, NULL); +#endif if (network->best_bss == bss) { network->best_bss = NULL; @@ -2884,12 +3569,27 @@ static void signal_bss_changed(const char *path, DBusMessageIter *iter) callback_network_changed(network, "WPSCapabilities"); } +#if defined TIZEN_EXT + if ((bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPS) != 0) { + network->wps = TRUE; + network->wps_capabilities |= bss->wps_capabilities; + } else + network->wps = FALSE; +#endif + /* Consider only property changes of the connected BSS */ if (network == interface->current_network && bss != network->best_bss) return; if (bss->signal == network->signal) +#ifndef TIZEN_EXT return; +#else + { + callback_network_changed(network, ""); + return; + } +#endif /* * If the new signal is lower than the SSID signal, we need @@ -2897,7 +3597,14 @@ static void signal_bss_changed(const char *path, DBusMessageIter *iter) */ if (bss->signal < network->signal) { if (bss != network->best_bss) +#ifndef TIZEN_EXT return; +#else + { + callback_network_changed(network, ""); + return; + } +#endif network->signal = bss->signal; update_network_signal(network); } else { @@ -3012,6 +3719,29 @@ static void signal_wps_event(const char *path, DBusMessageIter *iter) supplicant_dbus_property_foreach(iter, wps_event_args, interface); } +#if defined TIZEN_EXT +static void signal_power_off(const char *path, DBusMessageIter *iter) +{ + int poweroff_state = 0; + + dbus_message_iter_get_basic(iter, &poweroff_state); + + SUPPLICANT_DBG("poweroff_state(%d)", poweroff_state); + + /* POWER_OFF_DIRECT 2 && POWER_OFF_RESTART 3 */ + if (poweroff_state != 2 && poweroff_state != 3) + return; + + if (callbacks_pointer == NULL) + return; + + if (callbacks_pointer->system_power_off == NULL) + return; + + callbacks_pointer->system_power_off(); +} +#endif + static void create_peer_identifier(GSupplicantPeer *peer) { const unsigned char test[ETH_ALEN] = {}; @@ -3553,6 +4283,214 @@ static void signal_group_peer_disconnected(const char *path, DBusMessageIter *it peer->connection_requested = false; } +#if defined TIZEN_EXT_WIFI_MESH +const void *g_supplicant_interface_get_mesh_group_ssid( + GSupplicantInterface *interface, + unsigned int *ssid_len) +{ + if (!ssid_len) + return NULL; + + if (!interface || interface->group_info.ssid_len == 0) { + *ssid_len = 0; + return NULL; + } + + *ssid_len = interface->group_info.ssid_len; + return interface->group_info.ssid; +} + +int g_supplicant_mesh_get_disconnect_reason(GSupplicantInterface *interface) +{ + if (!interface) + return -EINVAL; + + return interface->group_info.disconnect_reason; +} + +const char *g_supplicant_mesh_peer_get_address(GSupplicantMeshPeer *mesh_peer) +{ + if (!mesh_peer || !mesh_peer->peer_address) + return NULL; + + return mesh_peer->peer_address; +} + +int g_supplicant_mesh_peer_get_disconnect_reason(GSupplicantMeshPeer *mesh_peer) +{ + if (!mesh_peer) + return -EINVAL; + + return mesh_peer->disconnect_reason; +} + +static void callback_mesh_group_started(GSupplicantInterface *interface) +{ + if (!callbacks_pointer) + return; + + if (!callbacks_pointer->mesh_group_started) + return; + + callbacks_pointer->mesh_group_started(interface); +} + +static void callback_mesh_group_removed(GSupplicantInterface *interface) +{ + if (!callbacks_pointer) + return; + + if (!callbacks_pointer->mesh_group_removed) + return; + + callbacks_pointer->mesh_group_removed(interface); +} + +static void mesh_group_info(const char *key, DBusMessageIter *iter, + void *user_data) +{ + GSupplicantInterface *interface = user_data; + if (!key) + return; + + if (g_strcmp0(key, "SSID") == 0) { + DBusMessageIter array; + unsigned char *ssid; + int ssid_len; + + dbus_message_iter_recurse(iter, &array); + dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len); + + if (ssid_len > 0 && ssid_len < 33) { + memcpy(interface->group_info.ssid, ssid, ssid_len); + interface->group_info.ssid_len = ssid_len; + } else { + memset(interface->group_info.ssid, 0, 32); + interface->group_info.ssid_len = 0; + } + } else if (g_strcmp0(key, "DisconnectReason") == 0) { + int disconnect_reason = 0; + dbus_message_iter_get_basic(iter, &disconnect_reason); + interface->group_info.disconnect_reason = disconnect_reason; + } +} + +static void signal_mesh_group_started(const char *path, DBusMessageIter *iter) +{ + GSupplicantInterface *interface; + + interface = g_hash_table_lookup(interface_table, path); + if (!interface) + return; + + supplicant_dbus_property_foreach(iter, mesh_group_info, interface); + + callback_mesh_group_started(interface); +} + +static void signal_mesh_group_removed(const char *path, DBusMessageIter *iter) +{ + GSupplicantInterface *interface; + + interface = g_hash_table_lookup(interface_table, path); + if (!interface) + return; + + supplicant_dbus_property_foreach(iter, mesh_group_info, interface); + + callback_mesh_group_removed(interface); +} + +static void callback_mesh_peer_connected(GSupplicantMeshPeer *mesh_peer) +{ + if (!callbacks_pointer) + return; + + if (!callbacks_pointer->mesh_peer_connected) + return; + + callbacks_pointer->mesh_peer_connected(mesh_peer); +} + +static void callback_mesh_peer_disconnected(GSupplicantMeshPeer *mesh_peer) +{ + if (!callbacks_pointer) + return; + + if (!callbacks_pointer->mesh_peer_disconnected) + return; + + callbacks_pointer->mesh_peer_disconnected(mesh_peer); +} + +static void mesh_peer_info(const char *key, DBusMessageIter *iter, + void *user_data) +{ + GSupplicantMeshPeer *mesh_peer = user_data; + if (!key) + return; + + if (g_strcmp0(key, "PeerAddress") == 0) { + DBusMessageIter array; + unsigned char *addr; + int addr_len; + + dbus_message_iter_recurse(iter, &array); + dbus_message_iter_get_fixed_array(&array, &addr, &addr_len); + + if (addr_len == 6) { + mesh_peer->peer_address = g_malloc0(19); + snprintf(mesh_peer->peer_address, 19, + "%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], + addr[2], addr[3], addr[4], addr[5]); + } + } else if (g_strcmp0(key, "DisconnectReason") == 0) { + int disconnect_reason = 0; + dbus_message_iter_get_basic(iter, &disconnect_reason); + mesh_peer->disconnect_reason = disconnect_reason; + } +} + +static void signal_mesh_peer_connected(const char *path, DBusMessageIter *iter) +{ + GSupplicantInterface *interface; + GSupplicantMeshPeer *mesh_peer; + + interface = g_hash_table_lookup(interface_table, path); + if (!interface) + return; + + mesh_peer = dbus_malloc0(sizeof(GSupplicantMeshPeer)); + mesh_peer->interface = interface; + + supplicant_dbus_property_foreach(iter, mesh_peer_info, mesh_peer); + + callback_mesh_peer_connected(mesh_peer); + g_free(mesh_peer->peer_address); + g_free(mesh_peer); +} + +static void signal_mesh_peer_disconnected(const char *path, + DBusMessageIter *iter) +{ + GSupplicantInterface *interface; + GSupplicantMeshPeer *mesh_peer; + + interface = g_hash_table_lookup(interface_table, path); + if (!interface) + return; + + mesh_peer = dbus_malloc0(sizeof(GSupplicantMeshPeer)); + mesh_peer->interface = interface; + + supplicant_dbus_property_foreach(iter, mesh_peer_info, mesh_peer); + + callback_mesh_peer_disconnected(mesh_peer); + g_free(mesh_peer->peer_address); + g_free(mesh_peer); +} +#endif + static struct { const char *interface; const char *member; @@ -3578,6 +4516,9 @@ static struct { { SUPPLICANT_INTERFACE ".Interface.WPS", "Credentials", signal_wps_credentials }, { SUPPLICANT_INTERFACE ".Interface.WPS", "Event", signal_wps_event }, +#if defined TIZEN_EXT + { "org.tizen.system.deviced.PowerOff", "ChangeState", signal_power_off }, +#endif { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "DeviceFound", signal_peer_found }, { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "DeviceLost", signal_peer_lost }, @@ -3592,6 +4533,16 @@ static struct { { SUPPLICANT_INTERFACE ".Group", "PeerJoined", signal_group_peer_joined }, { SUPPLICANT_INTERFACE ".Group", "PeerDisconnected", signal_group_peer_disconnected }, +#if defined TIZEN_EXT_WIFI_MESH + { SUPPLICANT_INTERFACE ".Interface.Mesh", "MeshGroupStarted", + signal_mesh_group_started }, + { SUPPLICANT_INTERFACE ".Interface.Mesh", "MeshGroupRemoved", + signal_mesh_group_removed }, + { SUPPLICANT_INTERFACE ".Interface.Mesh", "MeshPeerConnected", + signal_mesh_peer_connected }, + { SUPPLICANT_INTERFACE ".Interface.Mesh", "MeshPeerDisconnected", + signal_mesh_peer_disconnected }, +#endif { } }; @@ -3870,6 +4821,9 @@ static void interface_create_data_free(struct interface_create_data *data) g_free(data->ifname); g_free(data->driver); g_free(data->bridge); +#if defined TIZEN_EXT_WIFI_MESH + g_free(data->parent_ifname); +#endif dbus_free(data); } @@ -3894,7 +4848,12 @@ static void interface_create_property(const char *key, DBusMessageIter *iter, if (!key) { if (data->callback) { data->callback(0, data->interface, data->user_data); +#if !defined TIZEN_EXT callback_p2p_support(interface); +#endif +#if defined TIZEN_EXT_WIFI_MESH + callback_mesh_support(interface); +#endif } interface_create_data_free(data); @@ -3981,6 +4940,17 @@ static void interface_create_params(DBusMessageIter *iter, void *user_data) DBUS_TYPE_STRING, &config_file); } +#if defined TIZEN_EXT_WIFI_MESH + if (data->is_mesh_interface) { + if (data->parent_ifname) + supplicant_dbus_dict_append_basic(&dict, "ParentIfname", + DBUS_TYPE_STRING, &data->parent_ifname); + + supplicant_dbus_dict_append_basic(&dict, "IsMeshInterface", + DBUS_TYPE_BOOLEAN, &data->is_mesh_interface); + } +#endif + supplicant_dbus_dict_close(iter, &dict); } @@ -4013,7 +4983,12 @@ static void interface_get_result(const char *error, if (data->callback) { data->callback(0, interface, data->user_data); +#if !defined TIZEN_EXT callback_p2p_support(interface); +#endif +#if defined TIZEN_EXT_WIFI_MESH + callback_mesh_support(interface); +#endif } interface_create_data_free(data); @@ -4053,6 +5028,117 @@ static void interface_get_params(DBusMessageIter *iter, void *user_data) dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname); } +#if defined TIZEN_EXT_WIFI_MESH +int g_supplicant_mesh_interface_create(const char *ifname, const char *driver, + const char *bridge, const char *parent_ifname, + GSupplicantInterfaceCallback callback, void *user_data) +{ + struct interface_create_data *data; + int ret; + + SUPPLICANT_DBG("ifname %s", ifname); + + if (!ifname || !parent_ifname) + return -EINVAL; + + if (!system_available) + return -EFAULT; + + data = dbus_malloc0(sizeof(*data)); + if (!data) + return -ENOMEM; + + data->ifname = g_strdup(ifname); + data->driver = g_strdup(driver); + data->bridge = g_strdup(bridge); + data->is_mesh_interface = true; + data->parent_ifname = g_strdup(parent_ifname); + data->callback = callback; + data->user_data = user_data; + + ret = supplicant_dbus_method_call(SUPPLICANT_PATH, + SUPPLICANT_INTERFACE, + "CreateInterface", + interface_create_params, + interface_create_result, data, + NULL); + return ret; +} + +struct interface_mesh_peer_data { + char *peer_address; + char *method; + GSupplicantInterface *interface; + GSupplicantInterfaceCallback callback; + void *user_data; +}; + +static void interface_mesh_change_peer_params(DBusMessageIter *iter, + void *user_data) +{ + struct interface_mesh_peer_data *data = user_data; + + SUPPLICANT_DBG(""); + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->peer_address); +} + +static void interface_mesh_change_peer_result(const char *error, + DBusMessageIter *iter, void *user_data) +{ + struct interface_mesh_peer_data *data = user_data; + int err = 0; + + SUPPLICANT_DBG("%s", data->method); + + if (error) { + err = -EIO; + SUPPLICANT_DBG("error %s", error); + } + + if (data->callback) + data->callback(err, data->interface, data->user_data); + + g_free(data->peer_address); + g_free(data->method); + dbus_free(data); +} + +int g_supplicant_interface_mesh_peer_change_status( + GSupplicantInterface *interface, + GSupplicantInterfaceCallback callback, const char *peer_address, + const char *method, void *user_data) +{ + struct interface_mesh_peer_data *data; + int ret; + + if (!peer_address) + return -EINVAL; + + data = dbus_malloc0(sizeof(*data)); + if (!data) + return -ENOMEM; + + data->peer_address = g_strdup(peer_address); + data->method = g_strdup(method); + data->interface = interface; + data->callback = callback; + data->user_data = user_data; + + ret = supplicant_dbus_method_call(interface->path, + SUPPLICANT_INTERFACE ".Interface.Mesh", + method, interface_mesh_change_peer_params, + interface_mesh_change_peer_result, data, NULL); + if (ret < 0) { + g_free(data->peer_address); + g_free(data->method); + dbus_free(data); + } + + return ret; +} +#endif + int g_supplicant_interface_create(const char *ifname, const char *driver, const char *bridge, GSupplicantInterfaceCallback callback, @@ -4309,6 +5395,10 @@ static void interface_scan_params(DBusMessageIter *iter, void *user_data) supplicant_dbus_dict_append_basic(&dict, "Type", DBUS_TYPE_STRING, &type); +#if defined TIZEN_EXT + SUPPLICANT_DBG("[specific_scan] num_ssids %d", + data->scan_params->num_ssids); +#endif if (data->scan_params->ssids) { supplicant_dbus_dict_append_array(&dict, "SSIDs", @@ -4343,8 +5433,14 @@ static int interface_ready_to_scan(GSupplicantInterface *interface) case G_SUPPLICANT_STATE_4WAY_HANDSHAKE: case G_SUPPLICANT_STATE_GROUP_HANDSHAKE: return -EBUSY; +#if defined TIZEN_EXT + case G_SUPPLICANT_STATE_DISABLED: + return -ENOLINK; + case G_SUPPLICANT_STATE_UNKNOWN: +#else case G_SUPPLICANT_STATE_UNKNOWN: case G_SUPPLICANT_STATE_DISABLED: +#endif case G_SUPPLICANT_STATE_DISCONNECTED: case G_SUPPLICANT_STATE_INACTIVE: case G_SUPPLICANT_STATE_SCANNING: @@ -4355,6 +5451,57 @@ static int interface_ready_to_scan(GSupplicantInterface *interface) return 0; } +#if defined TIZEN_EXT_WIFI_MESH +static void interface_abort_scan_result(const char *error, + DBusMessageIter *iter, void *user_data) +{ + struct interface_scan_data *data = user_data; + int err = 0; + + if (error) { + SUPPLICANT_DBG("error %s", error); + err = -EIO; + } + + g_free(data->path); + + if (data->callback) + data->callback(err, data->interface, data->user_data); + + dbus_free(data); +} + +int g_supplicant_interface_abort_scan(GSupplicantInterface *interface, + GSupplicantInterfaceCallback callback, void *user_data) +{ + struct interface_scan_data *data; + int ret; + + if (!interface->scanning) + return -EEXIST; + + data = dbus_malloc0(sizeof(*data)); + if (!data) + return -ENOMEM; + + data->interface = interface; + data->path = g_strdup(interface->path); + data->callback = callback; + data->user_data = user_data; + + ret = supplicant_dbus_method_call(interface->path, + SUPPLICANT_INTERFACE ".Interface", "AbortScan", NULL, + interface_abort_scan_result, data, interface); + + if (ret < 0) { + g_free(data->path); + dbus_free(data); + } + + return ret; +} +#endif + int g_supplicant_interface_scan(GSupplicantInterface *interface, GSupplicantScanParams *scan_data, GSupplicantInterfaceCallback callback, @@ -4373,8 +5520,13 @@ int g_supplicant_interface_scan(GSupplicantInterface *interface, data->interface = interface; data->path = g_strdup(interface->path); +#if defined TIZEN_EXT + data->interface->scan_callback = data->callback = callback; + data->interface->scan_data = data->user_data = user_data; +#else data->callback = callback; data->user_data = user_data; +#endif data->scan_params = scan_data; interface->scan_callback = callback; @@ -4393,6 +5545,96 @@ int g_supplicant_interface_scan(GSupplicantInterface *interface, return ret; } +#if defined TIZEN_EXT +static void interface_signalpoll_result(const char *error, + DBusMessageIter *iter, void *user_data) +{ + struct interface_signalpoll_data *data = user_data; + int err = 0; + dbus_int32_t maxspeed = 0; + unsigned char strength = 0; + DBusMessageIter sub_iter, dict; + + if (error) { + err = -EIO; + SUPPLICANT_DBG("error: %s", error); + goto out; + } + + dbus_message_iter_get_arg_type(iter); + dbus_message_iter_recurse(iter, &sub_iter); + dbus_message_iter_recurse(&sub_iter, &dict); + + while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { + DBusMessageIter entry, value; + const char *key; + + dbus_message_iter_recurse(&dict, &entry); + dbus_message_iter_get_basic(&entry, &key); + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &value); + + switch (dbus_message_iter_get_arg_type(&value)) { + case DBUS_TYPE_INT32: + if (g_strcmp0(key, "linkspeed") == 0) { + dbus_message_iter_get_basic(&value, &maxspeed); + SUPPLICANT_DBG("linkspeed = %d", maxspeed); + break; + } + case DBUS_TYPE_BYTE: + if (g_strcmp0(key, "rssi") == 0) { + dbus_message_iter_get_basic(&value, &strength); + SUPPLICANT_DBG("Strength = %d", strength); + break; + } + } + dbus_message_iter_next(&dict); + } + +out: + if(data->callback) + data->callback(err, maxspeed, strength, data->user_data); + + g_free(data->path); + dbus_free(data); +} + +int g_supplicant_interface_signalpoll(GSupplicantInterface *interface, + GSupplicantMaxSpeedCallback callback, + void *user_data) +{ + struct interface_signalpoll_data *data; + int ret; + + if (!interface) + return -EINVAL; + + if (!system_available) + return -EFAULT; + + data = dbus_malloc0(sizeof(*data)); + if (!data) + return -ENOMEM; + + data->interface = interface; + data->path = g_strdup(interface->path); + data->callback = callback; + data->user_data = user_data; + + ret = supplicant_dbus_method_call(interface->path, + SUPPLICANT_INTERFACE ".Interface", "SignalPoll", + NULL, interface_signalpoll_result, data, + interface); + + if (ret < 0) { + g_free(data->path); + dbus_free(data); + } + + return ret; +} +#endif + static int parse_supplicant_error(DBusMessageIter *iter) { int err = -ECONNABORTED; @@ -4429,7 +5671,11 @@ static void interface_select_network_result(const char *error, err = 0; if (error) { +#if defined TIZEN_EXT + SUPPLICANT_DBG("SelectNetwork errorFreq %s", error); +#else SUPPLICANT_DBG("SelectNetwork error %s", error); +#endif err = parse_supplicant_error(iter); } @@ -4438,6 +5684,10 @@ static void interface_select_network_result(const char *error, if (data->callback) data->callback(err, data->interface, data->user_data); +#if defined TIZEN_EXT + g_free(data->ssid->ssid); + g_free((char *)data->ssid->passphrase); +#endif g_free(data->ssid); dbus_free(data); } @@ -4447,9 +5697,16 @@ static void interface_select_network_params(DBusMessageIter *iter, { struct interface_connect_data *data = user_data; GSupplicantInterface *interface = data->interface; +#if defined TIZEN_EXT + GSupplicantSSID *ssid = data->ssid; +#endif dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &interface->network_path); +#if defined TIZEN_EXT + if (!ssid->bssid_for_connect_len) + dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &ssid->freq); +#endif } static void interface_add_network_result(const char *error, @@ -4469,15 +5726,37 @@ static void interface_add_network_result(const char *error, SUPPLICANT_DBG("PATH: %s", path); +#if defined TIZEN_EXT + if (interface->network_path) + g_free(interface->network_path); +#endif interface->network_path = g_strdup(path); store_network_information(interface, data->ssid); +#if defined TIZEN_EXT + SUPPLICANT_DBG(".Interface.SelectNetworkFreq"); + GSupplicantSSID *ssid = data->ssid; + + if (!ssid->bssid_for_connect_len) + supplicant_dbus_method_call(data->interface->path, + SUPPLICANT_INTERFACE ".Interface", "SelectNetworkFreq", + interface_select_network_params, + interface_select_network_result, data, + interface); + else + supplicant_dbus_method_call(data->interface->path, + SUPPLICANT_INTERFACE ".Interface", "SelectNetwork", + interface_select_network_params, + interface_select_network_result, data, + interface); +#else supplicant_dbus_method_call(data->interface->path, SUPPLICANT_INTERFACE ".Interface", "SelectNetwork", interface_select_network_params, interface_select_network_result, data, interface); +#endif return; @@ -4494,6 +5773,10 @@ error: } g_free(data->path); +#if defined TIZEN_EXT + g_free(data->ssid->ssid); + g_free((char *)data->ssid->passphrase); +#endif g_free(data->ssid); g_free(data); } @@ -4643,8 +5926,10 @@ static void add_network_security_tls(DBusMessageIter *dict, if (!ssid->private_key_path) return; +#if !defined TIZEN_EXT if (!ssid->private_key_passphrase) return; +#endif if (ssid->ca_cert_path) supplicant_dbus_dict_append_basic(dict, "ca_cert", @@ -4653,9 +5938,11 @@ static void add_network_security_tls(DBusMessageIter *dict, supplicant_dbus_dict_append_basic(dict, "private_key", DBUS_TYPE_STRING, &ssid->private_key_path); +#if !defined TIZEN_EXT supplicant_dbus_dict_append_basic(dict, "private_key_passwd", DBUS_TYPE_STRING, &ssid->private_key_passphrase); +#endif supplicant_dbus_dict_append_basic(dict, "client_cert", DBUS_TYPE_STRING, &ssid->client_cert_path); @@ -4687,8 +5974,10 @@ static void add_network_security_peap(DBusMessageIter *dict, if (!ssid->private_key_path) return; +#if !defined TIZEN_EXT if (!ssid->private_key_passphrase) return; +#endif supplicant_dbus_dict_append_basic(dict, "client_cert", DBUS_TYPE_STRING, @@ -4698,9 +5987,11 @@ static void add_network_security_peap(DBusMessageIter *dict, DBUS_TYPE_STRING, &ssid->private_key_path); +#if !defined TIZEN_EXT supplicant_dbus_dict_append_basic(dict, "private_key_passwd", DBUS_TYPE_STRING, &ssid->private_key_passphrase); +#endif } @@ -4728,19 +6019,85 @@ static void add_network_security_peap(DBusMessageIter *dict, g_free(phase2_auth); } +#if defined TIZEN_EXT +static void add_network_security_aka_sim(DBusMessageIter *dict, + GSupplicantSSID *ssid) +{ + if (!ssid->passphrase) + return; + + supplicant_dbus_dict_append_basic(dict, "password", + DBUS_TYPE_STRING, + &ssid->passphrase); +} + +static void add_network_security_fast(DBusMessageIter *dict, + GSupplicantSSID *ssid) +{ + /* + * For FAST, we at least need: + * id / password + * phase1 (provisiong information) + * pac_file + */ + + /* Allow provisioing both authenticated and unauthenticated */ + const char *phase1 = "fast_provisioning=2"; + supplicant_dbus_dict_append_basic(dict, "phase1", + DBUS_TYPE_STRING, + &phase1); + + SUPPLICANT_DBG("pac_file [%s]", ssid->pac_file); + if(ssid->pac_file) + supplicant_dbus_dict_append_basic(dict, "pac_file", + DBUS_TYPE_STRING, + &ssid->pac_file); + + supplicant_dbus_dict_append_basic(dict, "password", + DBUS_TYPE_STRING, + &ssid->passphrase); +} +#endif + static void add_network_security_eap(DBusMessageIter *dict, GSupplicantSSID *ssid) { char *eap_value; +#if defined TIZEN_EXT + if (!ssid->eap) +#else if (!ssid->eap || !ssid->identity) +#endif return; if (g_strcmp0(ssid->eap, "tls") == 0) { add_network_security_tls(dict, ssid); } else if (g_strcmp0(ssid->eap, "peap") == 0 || g_strcmp0(ssid->eap, "ttls") == 0) { +#if defined TIZEN_EXT + if (!ssid->identity) + return; +#endif add_network_security_peap(dict, ssid); + +#if defined TIZEN_EXT + } else if (g_strcmp0(ssid->eap, "sim") == 0 || + g_strcmp0(ssid->eap, "aka") == 0 || + g_strcmp0(ssid->eap, "aka'") == 0) { + add_network_security_aka_sim(dict, ssid); + } else if (g_strcmp0(ssid->eap, "pwd") == 0) { + if(!ssid->passphrase) + return; + supplicant_dbus_dict_append_basic(dict, "password", + DBUS_TYPE_STRING, + &ssid->passphrase); + } else if (g_strcmp0(ssid->eap, "fast") == 0){ + if (!ssid->identity || !ssid->passphrase) + return; + + add_network_security_fast(dict, ssid); +#endif } else return; @@ -4749,9 +6106,16 @@ static void add_network_security_eap(DBusMessageIter *dict, supplicant_dbus_dict_append_basic(dict, "eap", DBUS_TYPE_STRING, &eap_value); +#if defined TIZEN_EXT + if (ssid->identity != NULL) + supplicant_dbus_dict_append_basic(dict, "identity", + DBUS_TYPE_STRING, + &ssid->identity); +#else supplicant_dbus_dict_append_basic(dict, "identity", DBUS_TYPE_STRING, &ssid->identity); +#endif if(ssid->anonymous_identity) supplicant_dbus_dict_append_basic(dict, "anonymous_identity", DBUS_TYPE_STRING, @@ -4872,6 +6236,18 @@ static void add_network_security_proto(DBusMessageIter *dict, g_free(proto); } +#if defined TIZEN_EXT +static void add_network_ieee80211w(DBusMessageIter *dict, GSupplicantSSID *ssid) +{ + if (ssid->security != G_SUPPLICANT_SECURITY_SAE + && ssid->security != G_SUPPLICANT_SECURITY_OWE) + return; + + supplicant_dbus_dict_append_basic(dict, "ieee80211w", DBUS_TYPE_UINT32, + &ssid->ieee80211w); +} +#endif + static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid) { char *key_mgmt; @@ -4900,6 +6276,29 @@ static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid) add_network_security_ciphers(dict, ssid); add_network_security_proto(dict, ssid); break; +#if defined TIZEN_EXT + case G_SUPPLICANT_SECURITY_FT_PSK: + key_mgmt = "FT-PSK"; + add_network_security_psk(dict, ssid); + add_network_security_ciphers(dict, ssid); + add_network_security_proto(dict, ssid); + break; + case G_SUPPLICANT_SECURITY_FT_IEEE8021X: + key_mgmt = "FT-EAP"; + add_network_security_eap(dict, ssid); + add_network_security_ciphers(dict, ssid); + add_network_security_proto(dict, ssid); + break; + case G_SUPPLICANT_SECURITY_SAE: + key_mgmt = "SAE"; + add_network_security_psk(dict, ssid); + break; + case G_SUPPLICANT_SECURITY_OWE: + key_mgmt = "OWE"; + add_network_security_ciphers(dict, ssid); + add_network_security_proto(dict, ssid); + break; +#endif } supplicant_dbus_dict_append_basic(dict, "key_mgmt", @@ -4921,6 +6320,11 @@ static void add_network_mode(DBusMessageIter *dict, GSupplicantSSID *ssid) case G_SUPPLICANT_MODE_MASTER: mode = 2; break; +#if defined TIZEN_EXT_WIFI_MESH + case G_SUPPLICANT_MODE_MESH: + mode = 5; + break; +#endif } supplicant_dbus_dict_append_basic(dict, "mode", @@ -4951,10 +6355,39 @@ static void interface_add_network_params(DBusMessageIter *iter, void *user_data) add_network_security(&dict, ssid); +#if defined TIZEN_EXT + add_network_ieee80211w(&dict, ssid); +#endif + supplicant_dbus_dict_append_fixed_array(&dict, "ssid", DBUS_TYPE_BYTE, &ssid->ssid, ssid->ssid_len); +#if defined TIZEN_EXT + if (ssid->bssid) { + char *bssid = NULL; + bssid = g_try_malloc0(18); + if (bssid == NULL) { + SUPPLICANT_DBG("memory allocation error"); + supplicant_dbus_dict_close(iter, &dict); + return; + } + + if (ssid->bssid_for_connect_len) + snprintf(bssid, 18, "%02x:%02x:%02x:%02x:%02x:%02x", + ssid->bssid_for_connect[0], ssid->bssid_for_connect[1], ssid->bssid_for_connect[2], + ssid->bssid_for_connect[3], ssid->bssid_for_connect[4], ssid->bssid_for_connect[5]); + else + snprintf(bssid, 18, "%02x:%02x:%02x:%02x:%02x:%02x", + ssid->bssid[0], ssid->bssid[1], ssid->bssid[2], + ssid->bssid[3], ssid->bssid[4], ssid->bssid[5]); + + supplicant_dbus_dict_append_basic(&dict, "bssid", + DBUS_TYPE_STRING, &bssid); + g_free(bssid); + } +#endif + supplicant_dbus_dict_close(iter, &dict); } @@ -5004,6 +6437,12 @@ static void interface_add_wps_params(DBusMessageIter *iter, void *user_data) supplicant_dbus_dict_append_basic(&dict, "Type", DBUS_TYPE_STRING, &type); +#if defined TIZEN_EXT + if (ssid->bssid) + supplicant_dbus_dict_append_fixed_array(&dict, "Bssid", + DBUS_TYPE_BYTE, &ssid->bssid, 6); +#endif + supplicant_dbus_dict_close(iter, &dict); } @@ -5021,6 +6460,17 @@ static void wps_start(const char *error, DBusMessageIter *iter, void *user_data) return; } +#if defined TIZEN_EXT + GSupplicantSSID *ssid = data->ssid; + if (ssid->pin_wps != NULL) { + if (!g_utf8_validate(ssid->pin_wps, 8, NULL)) { + SUPPLICANT_DBG("Invalid characters in WPS_PIN"); + g_free(data->ssid); + dbus_free(data); + return; + } + } +#endif supplicant_dbus_method_call(data->interface->path, SUPPLICANT_INTERFACE ".Interface.WPS", "Start", interface_add_wps_params, @@ -5037,6 +6487,134 @@ static void wps_process_credentials(DBusMessageIter *iter, void *user_data) } +#if defined TIZEN_EXT +#define NETCONFIG_SERVICE "net.netconfig" +#define NETCONFIG_WIFI_PATH "/net/netconfig/wifi" +#define NETCONFIG_WIFI_INTERFACE NETCONFIG_SERVICE ".wifi" + +struct dec_method_call_data { + struct interface_connect_data *data; + DBusPendingCall *pending_call; +}; + +static struct dec_method_call_data decrypt_request_data; + +static void crypt_method_call_cancel(void) +{ + if (decrypt_request_data.pending_call) { + dbus_pending_call_cancel(decrypt_request_data.pending_call); + dbus_pending_call_unref(decrypt_request_data.pending_call); + decrypt_request_data.pending_call = NULL; + } + + g_free(decrypt_request_data.data->path); + g_free(decrypt_request_data.data->ssid); + dbus_free(decrypt_request_data.data); + decrypt_request_data.data = NULL; +} + +static void decryption_request_reply(DBusPendingCall *call, + void *user_data) +{ + DBusMessage *reply; + DBusError error; + DBusMessageIter args; + char *out_data; + int ret; + struct interface_connect_data *data = user_data; + + SUPPLICANT_DBG(""); + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&error); + if (dbus_set_error_from_message(&error, reply)) { + SUPPLICANT_DBG("decryption_request_reply() %s %s", error.name, error.message); + dbus_error_free(&error); + ret = -EINVAL; + goto done; + } + + if (dbus_message_iter_init(reply, &args) == FALSE) { + SUPPLICANT_DBG("dbus_message_iter_init() failed"); + ret = -EINVAL; + goto done; + } + + dbus_message_iter_get_basic(&args, &out_data); + data->ssid->passphrase = g_strdup((const gchar *)out_data); + + ret = supplicant_dbus_method_call(data->interface->path, + SUPPLICANT_INTERFACE ".Interface", "AddNetwork", + interface_add_network_params, + interface_add_network_result, data, + data->interface); + +done: + if (ret < 0) { + SUPPLICANT_DBG("AddNetwork failed %d", ret); + callback_assoc_failed(decrypt_request_data.data->user_data); + g_free(data->path); + g_free(data->ssid->ssid); + g_free((char *)data->ssid->passphrase); + g_free(data->ssid); + dbus_free(data); + } + + dbus_message_unref(reply); + dbus_pending_call_unref(call); + + decrypt_request_data.pending_call = NULL; + decrypt_request_data.data = NULL; +} + +static int send_decryption_request(const char *passphrase, + struct interface_connect_data *data) +{ + DBusMessage *msg = NULL; + DBusPendingCall *call; + + SUPPLICANT_DBG("Decryption request"); + + if (!passphrase) { + SUPPLICANT_DBG("Invalid parameter"); + return -EINVAL; + } + + if (!connection) + return -EINVAL; + + msg = dbus_message_new_method_call(NETCONFIG_SERVICE, NETCONFIG_WIFI_PATH, + NETCONFIG_WIFI_INTERFACE, "DecryptPassphrase"); + if (!msg) + return -EINVAL; + + dbus_message_append_args(msg, DBUS_TYPE_STRING, &passphrase, + DBUS_TYPE_INVALID); + + if (!dbus_connection_send_with_reply(connection, msg, + &call, DBUS_TIMEOUT_USE_DEFAULT)) { + dbus_message_unref(msg); + return -EIO; + } + + if (!call) { + dbus_message_unref(msg); + return -EIO; + } + + decrypt_request_data.pending_call = call; + decrypt_request_data.data = data; + + dbus_pending_call_set_notify(call, decryption_request_reply, data, NULL); + dbus_message_unref(msg); + + SUPPLICANT_DBG("Decryption request succeeded"); + + return 0; +} +#endif + int g_supplicant_interface_connect(GSupplicantInterface *interface, GSupplicantSSID *ssid, GSupplicantInterfaceCallback callback, @@ -5120,6 +6698,18 @@ int g_supplicant_interface_connect(GSupplicantInterface *interface, intf_data->network_remove_in_progress = TRUE; network_remove(intf_data); } else { +#if defined TIZEN_EXT + if (ssid->passphrase && + g_strcmp0(ssid->passphrase, "") != 0 && +#if defined TIZEN_EXT_WIFI_MESH + ssid->mode != G_SUPPLICANT_MODE_MESH && +#endif + !ssid->eap) { + ret = send_decryption_request(ssid->passphrase, data); + if (ret < 0) + SUPPLICANT_DBG("Decryption request failed %d", ret); + } else +#endif ret = supplicant_dbus_method_call(interface->path, SUPPLICANT_INTERFACE ".Interface", "AddNetwork", interface_add_network_params, @@ -5172,6 +6762,19 @@ static void network_remove_result(const char *error, connect_data->ssid = data->ssid; connect_data->user_data = data->user_data; +#if defined TIZEN_EXT + int ret; + if (data->ssid->passphrase && g_strcmp0(data->ssid->passphrase, "") != 0 + && !data->ssid->eap) { + ret = send_decryption_request(data->ssid->passphrase, connect_data); + if (ret < 0) { + SUPPLICANT_DBG("Decryption request failed %d", ret); + g_free(connect_data->ssid); + g_free(connect_data->path); + dbus_free(connect_data); + } + } else +#endif supplicant_dbus_method_call(data->interface->path, SUPPLICANT_INTERFACE ".Interface", "AddNetwork", interface_add_network_params, @@ -5201,6 +6804,16 @@ static int network_remove(struct interface_data *data) SUPPLICANT_DBG(""); +#if defined TIZEN_EXT + GSupplicantInterface *intf = NULL; + /* + * Check if 'interface' is valid + */ + intf = g_hash_table_lookup(interface_table, interface->path); + if (intf == NULL) + return -EINVAL; +#endif + return supplicant_dbus_method_call(interface->path, SUPPLICANT_INTERFACE ".Interface", "RemoveNetwork", network_remove_params, network_remove_result, data, @@ -5267,7 +6880,17 @@ int g_supplicant_interface_disconnect(GSupplicantInterface *interface, if (!system_available) return -EFAULT; +#if defined TIZEN_EXT + if (decrypt_request_data.pending_call && + decrypt_request_data.data && + decrypt_request_data.data->user_data == user_data) { + + callback_assoc_failed(decrypt_request_data.data->user_data); + crypt_method_call_cancel(); + return 0; + } +#endif data = dbus_malloc0(sizeof(*data)); if (!data) return -ENOMEM; @@ -5759,12 +7382,18 @@ static const char *g_supplicant_rule4 = "type=signal," "interface=" SUPPLICANT_INTERFACE ".BSS"; static const char *g_supplicant_rule5 = "type=signal," "interface=" SUPPLICANT_INTERFACE ".Network"; +#if !defined TIZEN_EXT static const char *g_supplicant_rule6 = "type=signal," "interface=" SUPPLICANT_INTERFACE ".Interface.P2PDevice"; static const char *g_supplicant_rule7 = "type=signal," "interface=" SUPPLICANT_INTERFACE ".Peer"; static const char *g_supplicant_rule8 = "type=signal," "interface=" SUPPLICANT_INTERFACE ".Group"; +#endif +#if defined TIZEN_EXT_WIFI_MESH +static const char *g_supplicant_rule9 = "type=signal," + "interface=" SUPPLICANT_INTERFACE ".Interface.Mesh"; +#endif static void invoke_introspect_method(void) { @@ -5821,9 +7450,19 @@ int g_supplicant_register(const GSupplicantCallbacks *callbacks) dbus_bus_add_match(connection, g_supplicant_rule3, NULL); dbus_bus_add_match(connection, g_supplicant_rule4, NULL); dbus_bus_add_match(connection, g_supplicant_rule5, NULL); +#if defined TIZEN_EXT + dbus_bus_add_match(connection, + "type=signal,interface=org.tizen.system.deviced.PowerOff," + "member=ChangeState", NULL); +#endif +#if !defined TIZEN_EXT dbus_bus_add_match(connection, g_supplicant_rule6, NULL); dbus_bus_add_match(connection, g_supplicant_rule7, NULL); dbus_bus_add_match(connection, g_supplicant_rule8, NULL); +#endif +#if defined TIZEN_EXT_WIFI_MESH + dbus_bus_add_match(connection, g_supplicant_rule9, NULL); +#endif dbus_connection_flush(connection); if (dbus_bus_name_has_owner(connection, @@ -5865,9 +7504,14 @@ void g_supplicant_unregister(const GSupplicantCallbacks *callbacks) SUPPLICANT_DBG(""); if (connection) { +#if defined TIZEN_EXT_WIFI_MESH + dbus_bus_remove_match(connection, g_supplicant_rule9, NULL); +#endif +#if !defined TIZEN_EXT dbus_bus_remove_match(connection, g_supplicant_rule8, NULL); dbus_bus_remove_match(connection, g_supplicant_rule7, NULL); dbus_bus_remove_match(connection, g_supplicant_rule6, NULL); +#endif dbus_bus_remove_match(connection, g_supplicant_rule5, NULL); dbus_bus_remove_match(connection, g_supplicant_rule4, NULL); dbus_bus_remove_match(connection, g_supplicant_rule3, NULL); diff --git a/gweb/giognutls.c b/gweb/giognutls.c index b5c476cb..b5c476cb 100644..100755 --- a/gweb/giognutls.c +++ b/gweb/giognutls.c diff --git a/gweb/giognutls.h b/gweb/giognutls.h index ea0df8ff..ea0df8ff 100644..100755 --- a/gweb/giognutls.h +++ b/gweb/giognutls.h diff --git a/gweb/gionotls.c b/gweb/gionotls.c index 29988954..29988954 100644..100755 --- a/gweb/gionotls.c +++ b/gweb/gionotls.c diff --git a/gweb/gresolv.c b/gweb/gresolv.c index 38a554e0..38a554e0 100644..100755 --- a/gweb/gresolv.c +++ b/gweb/gresolv.c diff --git a/gweb/gresolv.h b/gweb/gresolv.h index 5e82c168..5e82c168 100644..100755 --- a/gweb/gresolv.h +++ b/gweb/gresolv.h diff --git a/gweb/gweb.c b/gweb/gweb.c index 393afe0a..7037cd94 100644..100755 --- a/gweb/gweb.c +++ b/gweb/gweb.c @@ -809,6 +809,10 @@ static void handle_multi_line(struct web_session *session) g_string_insert_c(session->current_header, 0, ' '); } +#if defined TIZEN_EXT + if (session->result.last_key == NULL) + return; +#endif value = g_hash_table_lookup(session->result.headers, session->result.last_key); if (value) { @@ -1257,6 +1261,16 @@ static void resolv_result(GResolvResultStatus status, return; } +#if defined TIZEN_EXT + // check the DNS address validation + // if dns is the class c private address + // wispr should be stopped - non internet connection + if(g_str_has_prefix(results[0],"192.168.")){ + call_result_func(session, 404); + return; + } +#endif + g_free(session->address); session->address = g_strdup(results[0]); diff --git a/gweb/gweb.h b/gweb/gweb.h index 6c28542a..6c28542a 100644..100755 --- a/gweb/gweb.h +++ b/gweb/gweb.h diff --git a/include/agent.h b/include/agent.h index 6961f7a1..6961f7a1 100644..100755 --- a/include/agent.h +++ b/include/agent.h diff --git a/include/backtrace.h b/include/backtrace.h index 12a202d7..65415fb6 100644 --- a/include/backtrace.h +++ b/include/backtrace.h @@ -22,7 +22,7 @@ #ifndef __CONNMAN_BACKTRACE_H #define __CONNMAN_BACKTRACE_H -#ifdef HAVE_EXECINFO_H +#if defined HAVE_EXECINFO_H && defined BACKTRACE void print_backtrace(const char* program_path, const char* program_exec, unsigned int offset); #else diff --git a/include/dbus.h b/include/dbus.h index bcab4189..d53037b4 100644 --- a/include/dbus.h +++ b/include/dbus.h @@ -45,6 +45,9 @@ extern "C" { #define CONNMAN_SESSION_INTERFACE CONNMAN_SERVICE ".Session" #define CONNMAN_NOTIFICATION_INTERFACE CONNMAN_SERVICE ".Notification" #define CONNMAN_PEER_INTERFACE CONNMAN_SERVICE ".Peer" +#if defined TIZEN_EXT_WIFI_MESH +#define CONNMAN_MESH_INTERFACE CONNMAN_SERVICE ".Mesh" +#endif #define CONNMAN_PRIVILEGE_MODIFY 1 #define CONNMAN_PRIVILEGE_SECRET 2 diff --git a/include/device.h b/include/device.h index 0fc06bd0..77c476a4 100644 --- a/include/device.h +++ b/include/device.h @@ -137,6 +137,18 @@ struct connman_device_driver { struct connman_device *device); int (*set_regdom) (struct connman_device *device, const char *alpha2); +#if defined TIZEN_EXT + int (*specific_scan) (enum connman_service_type type, + struct connman_device *device, int scan_type, + GSList *specific_scan_list, void *user_data); +#endif +#if defined TIZEN_EXT_WIFI_MESH + int (*abort_scan) (enum connman_service_type type, + struct connman_device *device); + int (*mesh_specific_scan) (enum connman_service_type type, + struct connman_device *device, const char *ssid, unsigned int freq, + void *user_data); +#endif }; int connman_device_driver_register(struct connman_device_driver *driver); diff --git a/include/inet.h b/include/inet.h index 9c1918f3..4844979b 100644 --- a/include/inet.h +++ b/include/inet.h @@ -40,6 +40,10 @@ int connman_inet_ifup(int index); int connman_inet_ifdown(int index); bool connman_inet_is_ifup(int index); +#if defined TIZEN_EXT +void connman_inet_update_device_ident(struct connman_device *device); +#endif + int connman_inet_set_address(int index, struct connman_ipaddress *ipaddress); int connman_inet_clear_address(int index, struct connman_ipaddress *ipaddress); int connman_inet_add_host_route(int index, const char *host, const char *gateway); @@ -78,6 +82,11 @@ int connman_inet_check_ipaddress(const char *host); bool connman_inet_check_hostname(const char *ptr, size_t len); bool connman_inet_is_ipv6_supported(); +#if defined TIZEN_EXT_WIFI_MESH +char *connman_inet_ifaddr(const char *name); +char *connman_inet_ifname2addr(const char *name); +#endif + #ifdef __cplusplus } #endif diff --git a/include/inotify.h b/include/inotify.h index 4bc63303..4bc63303 100644..100755 --- a/include/inotify.h +++ b/include/inotify.h diff --git a/include/ipaddress.h b/include/ipaddress.h index 3655ca86..3655ca86 100644..100755 --- a/include/ipaddress.h +++ b/include/ipaddress.h diff --git a/include/ipconfig.h b/include/ipconfig.h index 68ef40b6..68ef40b6 100644..100755 --- a/include/ipconfig.h +++ b/include/ipconfig.h diff --git a/include/log.h b/include/log.h index 8b00e9dc..7687ed0b 100644..100755 --- a/include/log.h +++ b/include/log.h @@ -52,7 +52,11 @@ void connman_debug(const char *format, ...) struct connman_debug_desc { const char *name; const char *file; +#if defined TIZEN_EXT +#define CONNMAN_DEBUG_FLAG_DEFAULT (1) +#else #define CONNMAN_DEBUG_FLAG_DEFAULT (0) +#endif #define CONNMAN_DEBUG_FLAG_PRINT (1 << 0) #define CONNMAN_DEBUG_FLAG_ALIAS (1 << 1) unsigned int flags; diff --git a/include/machine.h b/include/machine.h index c8d8735e..c8d8735e 100644..100755 --- a/include/machine.h +++ b/include/machine.h diff --git a/include/mesh-netlink.h b/include/mesh-netlink.h new file mode 100644 index 00000000..78b3e36e --- /dev/null +++ b/include/mesh-netlink.h @@ -0,0 +1,58 @@ +/* + * + * Connection Manager + * + * + * Copyright (C) 2017 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef __CONNMAN_MESH_NETLINK_H +#define __CONNMAN_MESH_NETLINK_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + int id; + struct nl_sock *nl_socket; + struct nl_cb *cb; +} mesh_nl80211_global; + +#define MESH_HWMP_ROOTMODE_NO_ROOT 0 +#define MESH_HWMP_ROOTMODE_PROACTIVE_PREQ_NO_PREP 2 +#define MESH_HWMP_ROOTMODE_PROACTIVE_PREQ_WITH_PREP 3 +#define MESH_HWMP_ROOTMODE_RANN 4 + +#define NL80211_ATTR_IFINDEX 3 +#define NL80211_CMD_SET_MESH_CONFIG 29 +#define NL80211_ATTR_MESH_CONFIG 35 + +#define NL80211_MESHCONF_HWMP_ROOTMODE 14 +#define NL80211_MESHCONF_GATE_ANNOUNCEMENTS 17 + +int __connman_mesh_netlink_set_gate_announce(mesh_nl80211_global *global, + int mesh_if_index, bool gate_announce, int hwmp_rootmode); + +mesh_nl80211_global *__connman_mesh_nl80211_global_init(void); +void __connman_mesh_nl80211_global_deinit(mesh_nl80211_global *global); + +#ifdef __cplusplus +} +#endif + +#endif /* __CONNMAN_MESH_NETLINK_H */ diff --git a/include/mesh.h b/include/mesh.h new file mode 100644 index 00000000..547c237e --- /dev/null +++ b/include/mesh.h @@ -0,0 +1,155 @@ +/* + * + * Connection Manager + * + * + * Copyright (C) 2017 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef __CONNMAN_MESH_H +#define __CONNMAN_MESH_H + +#include <gdbus.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct connman_mesh; + +enum connman_mesh_security { + CONNMAN_MESH_SECURITY_UNKNOWN = 0, + CONNMAN_MESH_SECURITY_NONE = 1, + CONNMAN_MESH_SECURITY_SAE = 2, +}; + +enum connman_mesh_state { + CONNMAN_MESH_STATE_UNKNOWN = 0, + CONNMAN_MESH_STATE_IDLE = 1, + CONNMAN_MESH_STATE_ASSOCIATION = 2, + CONNMAN_MESH_STATE_CONFIGURATION = 3, + CONNMAN_MESH_STATE_READY = 4, + CONNMAN_MESH_STATE_DISCONNECT = 5, + CONNMAN_MESH_STATE_FAILURE = 6, +}; + +enum connman_mesh_peer_type { + CONNMAN_MESH_PEER_TYPE_CREATED = 0, + CONNMAN_MESH_PEER_TYPE_DISCOVERED = 1, +}; + +enum connman_mesh_peer_disconnect_reason { + CONNMAN_MESH_REASON_UNKNOWN = 0, + CONNMAN_MESH_DEAUTH_LEAVING = 1, + CONNMAN_MESH_PEERING_CANCELLED = 2, + CONNMAN_MESH_MAX_PEERS = 3, + CONNMAN_MESH_CONFIG_POLICY_VIOLATION = 4, + CONNMAN_MESH_CLOSE_RCVD = 5, + CONNMAN_MESH_MAX_RETRIES = 6, + CONNMAN_MESH_CONFIRM_TIMEOUT = 7, + CONNMAN_MESH_INVALID_GTK = 8, + CONNMAN_MESH_INCONSISTENT_PARAMS = 9, + CONNMAN_MESH_INVALID_SECURITY_CAP = 10, +}; + +enum connman_mesh_peer_status { + CONNMAN_MESH_PEER_ADD = 0, + CONNMAN_MESH_PEER_REMOVE = 1, +}; + +struct connman_mesh *connman_mesh_create(const char *interface_addr, + const char *identifier); + +void connman_mesh_set_name(struct connman_mesh *mesh, const char *name); +const char *connman_mesh_get_name(struct connman_mesh *mesh); +void connman_mesh_set_passphrase(struct connman_mesh *mesh, + const char *passphrase); +const char *connman_mesh_get_passphrase(struct connman_mesh *mesh); +void connman_mesh_set_address(struct connman_mesh *mesh, const char *address); +void connman_mesh_set_security(struct connman_mesh *mesh, const char *security); +const char *connman_mesh_get_security(struct connman_mesh *mesh); +void connman_mesh_set_frequency(struct connman_mesh *mesh, uint16_t frequency); +uint16_t connman_mesh_get_frequency(struct connman_mesh *mesh); +void connman_mesh_set_ieee80211w(struct connman_mesh *mesh, uint16_t ieee80211w); +uint16_t connman_mesh_get_ieee80211w(struct connman_mesh *mesh); +int connman_mesh_peer_set_state(struct connman_mesh *mesh, + enum connman_mesh_state new_state); +void connman_mesh_set_peer_type(struct connman_mesh *mesh, + enum connman_mesh_peer_type type); +bool connman_mesh_peer_is_connected_state(struct connman_mesh *mesh); +struct connman_mesh *connman_get_connected_mesh_from_name(char *name); +struct connman_mesh *connman_get_connecting_mesh_from_name(char *name); +void connman_mesh_set_index(struct connman_mesh *mesh, int index); +void connman_mesh_set_strength(struct connman_mesh *mesh, uint8_t strength); +void connman_mesh_peer_set_disconnect_reason(struct connman_mesh *mesh, + int disconnect_reason); +void __connman_mesh_add_ethernet_to_bridge(void); +void __connman_mesh_remove_ethernet_from_bridge(void); +int __connman_mesh_change_peer_status(DBusMessage *msg, + const char *peer_address, + enum connman_mesh_peer_status status); + +int connman_mesh_register(struct connman_mesh *mesh); +void connman_mesh_unregister(struct connman_mesh *mesh); + +int __connman_mesh_add_virtual_interface(const char *ifname, + const char *parent_ifname, const char *bridge_ifname); + +int __connman_mesh_remove_virtual_interface(const char *ifname); +int __connman_mesh_set_stp_gate_announce(bool gate_announce, int hwmp_rootmode, + int stp); + +const char *connman_mesh_get_interface_name(void); +bool connman_mesh_is_interface_created(void); + +struct connman_mesh *connman_mesh_get(const char *interface_addr, + const char *identifier); + +int connman_mesh_notify_interface_create(bool success); +int connman_mesh_notify_interface_remove(bool success); + +int connman_mesh_add_connected_peer(const char *peer_address); +int connman_mesh_remove_connected_peer(const char *peer_address, int reason); + +typedef void (*mesh_change_peer_status_cb_t) (int result, void *user_data); + +struct connman_mesh_driver { + int (*add_interface) (const char *ifname, const char *parent_ifname); + int (*remove_interface) (const char *ifname); + int (*connect) (struct connman_mesh *mesh); + int (*disconnect) (struct connman_mesh *mesh); + int (*change_peer_status) (const char *peer_address, + enum connman_mesh_peer_status status, + mesh_change_peer_status_cb_t callback, void *user_data); +}; + +int connman_mesh_driver_register(struct connman_mesh_driver *driver); +void connman_mesh_driver_unregister(struct connman_mesh_driver *driver); + +struct connman_mesh_eth_driver { + int (*add_to_bridge) (const char *bridge); + int (*remove_from_bridge) (const char *bridge); +}; + +int connman_mesh_eth_driver_register(struct connman_mesh_eth_driver *driver); +void connman_mesh_eth_driver_unregister(struct connman_mesh_eth_driver *driver); + +#ifdef __cplusplus +} +#endif + +#endif /* __CONNMAN_MESH_H */ diff --git a/include/network.h b/include/network.h index 8f87d7c5..14b94429 100644..100755 --- a/include/network.h +++ b/include/network.h @@ -34,6 +34,12 @@ extern "C" { #endif +#if defined TIZEN_EXT +#define WIFI_ENCYPTION_MODE_LEN_MAX 6 +#define WIFI_BSSID_LEN_MAX 6 +#define MAC_ADDRESS_LENGTH 18 +#endif + /** * SECTION:network * @title: Network premitives @@ -57,9 +63,45 @@ enum connman_network_error { CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL = 2, CONNMAN_NETWORK_ERROR_INVALID_KEY = 3, CONNMAN_NETWORK_ERROR_CONNECT_FAIL = 4, +#if defined TIZEN_EXT + CONNMAN_NETWORK_ERROR_DHCP_FAIL = 5, + CONNMAN_NETWORK_ERROR_BLOCKED = 6, +#else CONNMAN_NETWORK_ERROR_BLOCKED = 5, +#endif }; +#if defined TIZEN_EXT +struct connman_bssids { + unsigned char bssid[WIFI_BSSID_LEN_MAX]; + uint16_t strength; + uint16_t frequency; +}; + +/* Backward compatible + * modes of available network */ +typedef enum { + IEEE80211_UNKNOWN, + IEEE80211_MODE_B, + IEEE80211_MODE_BG, + IEEE80211_MODE_BGN, + IEEE80211_MODE_A, + IEEE80211_MODE_AN, + IEEE80211_MODE_ANAC, +} ieee80211_modes_e; + +/* connection mode of connected network + * based on current linkspeed */ +typedef enum { + CONNECTION_MODE_IEEE80211_UNKNOWN, + CONNECTION_MODE_IEEE80211B, + CONNECTION_MODE_IEEE80211G, + CONNECTION_MODE_IEEE80211N, + CONNECTION_MODE_IEEE80211A, + CONNECTION_MODE_IEEE80211AC, +} connection_mode_e; +#endif + #define CONNMAN_NETWORK_PRIORITY_LOW -100 #define CONNMAN_NETWORK_PRIORITY_DEFAULT 0 #define CONNMAN_NETWORK_PRIORITY_HIGH 100 @@ -92,6 +134,9 @@ void connman_network_set_group(struct connman_network *network, const char *connman_network_get_group(struct connman_network *network); bool connman_network_get_connecting(struct connman_network *network); +#if defined TIZEN_EXT +void connman_network_set_connecting(struct connman_network *network); +#endif int connman_network_set_available(struct connman_network *network, bool available); bool connman_network_get_available(struct connman_network *network); @@ -121,6 +166,59 @@ int connman_network_set_nameservers(struct connman_network *network, const char *nameservers); int connman_network_set_domain(struct connman_network *network, const char *domain); +#if defined TIZEN_EXT +/* + * Description: Network client requires additional wifi specific info + */ +int connman_network_set_bssid(struct connman_network *network, + const unsigned char *bssid); +unsigned char *connman_network_get_bssid(struct connman_network *network); + +int connman_network_set_maxrate(struct connman_network *network, + unsigned int maxrate); + +int connman_network_set_maxspeed(struct connman_network *network, + int maxrate); + +unsigned int connman_network_get_maxrate(struct connman_network *network); + +int connman_network_get_maxspeed(struct connman_network *network); + +int connman_network_set_enc_mode(struct connman_network *network, + const char *encryption_mode); +const char *connman_network_get_enc_mode(struct connman_network *network); + +int connman_network_set_rsn_mode(struct connman_network *network, + bool rsn_mode); + +int connman_network_set_proxy(struct connman_network *network, + const char *proxies); + +void connman_network_clear_associating(struct connman_network *network); + +int connman_network_set_keymgmt(struct connman_network *network, + unsigned int keymgmt); +unsigned int connman_network_get_keymgmt(struct connman_network *network); +int connman_network_set_disconnect_reason(struct connman_network *network, + int reason_code); +int connman_network_get_disconnect_reason(struct connman_network *network); +int connman_network_get_assoc_status_code(struct connman_network *network); +int connman_network_set_assoc_status_code(struct connman_network *network, + int assoc_status_code); +int connman_network_set_countrycode(struct connman_network *network, const + unsigned char *country_code); +unsigned char *connman_network_get_countrycode(struct connman_network *network); +int connman_network_set_bssid_list(struct connman_network *network, + GSList *bssids); +void *connman_network_get_bssid_list(struct connman_network *network); +int connman_network_set_phy_mode(struct connman_network *network, + ieee80211_modes_e mode); +ieee80211_modes_e connman_network_get_phy_mode(struct connman_network *network); +int connman_network_set_connection_mode(struct connman_network *network, + connection_mode_e mode); +connection_mode_e connman_network_get_connection_mode(struct connman_network *network); +#endif + int connman_network_set_name(struct connman_network *network, const char *name); int connman_network_set_strength(struct connman_network *network, @@ -145,6 +243,10 @@ int connman_network_set_blob(struct connman_network *network, const char *key, const void *data, unsigned int size); const void *connman_network_get_blob(struct connman_network *network, const char *key, unsigned int *size); +#if defined TIZEN_EXT +void connman_network_set_vsie_list(struct connman_network *network, GSList *vsie_list); +void *connman_network_get_vsie_list(struct connman_network *network); +#endif struct connman_device *connman_network_get_device(struct connman_network *network); @@ -161,6 +263,9 @@ struct connman_network_driver { void (*remove) (struct connman_network *network); int (*connect) (struct connman_network *network); int (*disconnect) (struct connman_network *network); +#if defined TIZEN_EXT + int (*merge) (struct connman_network *network); +#endif }; int connman_network_driver_register(struct connman_network_driver *driver); diff --git a/include/notifier.h b/include/notifier.h index 9c0909c7..9c0909c7 100644..100755 --- a/include/notifier.h +++ b/include/notifier.h diff --git a/include/option.h b/include/option.h index 5e97ed4c..5e97ed4c 100644..100755 --- a/include/option.h +++ b/include/option.h diff --git a/include/peer.h b/include/peer.h index 80663932..80663932 100644..100755 --- a/include/peer.h +++ b/include/peer.h diff --git a/include/plugin.h b/include/plugin.h index 8d2bb08e..8d2bb08e 100644..100755 --- a/include/plugin.h +++ b/include/plugin.h diff --git a/include/provider.h b/include/provider.h index d28651ad..d28651ad 100644..100755 --- a/include/provider.h +++ b/include/provider.h diff --git a/include/provision.h b/include/provision.h index 3eb80a86..3eb80a86 100644..100755 --- a/include/provision.h +++ b/include/provision.h diff --git a/include/proxy.h b/include/proxy.h index 7842f65f..7842f65f 100644..100755 --- a/include/proxy.h +++ b/include/proxy.h diff --git a/include/resolver.h b/include/resolver.h index 70a02ade..70a02ade 100644..100755 --- a/include/resolver.h +++ b/include/resolver.h diff --git a/include/rtnl.h b/include/rtnl.h index aa70f4d8..aa70f4d8 100644..100755 --- a/include/rtnl.h +++ b/include/rtnl.h diff --git a/include/service.h b/include/service.h index 97fdf7d5..6ae94021 100644 --- a/include/service.h +++ b/include/service.h @@ -24,6 +24,10 @@ #include <stdbool.h> +#if defined TIZEN_EXT +#include <glib.h> +#endif + #ifdef __cplusplus extern "C" { #endif @@ -45,8 +49,15 @@ enum connman_service_type { CONNMAN_SERVICE_TYPE_VPN = 7, CONNMAN_SERVICE_TYPE_GADGET = 8, CONNMAN_SERVICE_TYPE_P2P = 9, +#if defined TIZEN_EXT_WIFI_MESH + CONNMAN_SERVICE_TYPE_MESH = 10, +#endif }; +#if defined TIZEN_EXT_WIFI_MESH +#define MAX_CONNMAN_SERVICE_TYPES 11 +#else #define MAX_CONNMAN_SERVICE_TYPES 10 +#endif enum connman_service_security { @@ -57,6 +68,10 @@ enum connman_service_security { CONNMAN_SERVICE_SECURITY_8021X = 4, CONNMAN_SERVICE_SECURITY_WPA = 8, CONNMAN_SERVICE_SECURITY_RSN = 9, +#if defined TIZEN_EXT + CONNMAN_SERVICE_SECURITY_SAE = 10, + CONNMAN_SERVICE_SECURITY_OWE = 11, +#endif }; enum connman_service_state { @@ -147,6 +162,44 @@ void connman_service_create_ip4config(struct connman_service *service, void connman_service_create_ip6config(struct connman_service *service, int index); +#if defined TIZEN_EXT +/* + * Description: TIZEN implements system global connection management. + * It's only for PDP (cellular) bearer. Wi-Fi is managed by ConnMan automatically. + * Reference count can help to manage open/close connection requests by each application. + */ + +/* + * Increase reference count of user-initiated packet data network connection + */ +void connman_service_user_pdn_connection_ref(struct connman_service *service); + +/* + * Decrease reference count of user initiated packet data network connection + * and return TRUE if counter is zero. + */ +gboolean connman_service_user_pdn_connection_unref_and_test( + struct connman_service *service); + +/* + * Test reference count of user initiated packet data network connection + * and return TRUE if counter is zero. No impact to reference count + */ +gboolean connman_service_is_no_ref_user_pdn_connection( + struct connman_service *service); + +struct connman_service *connman_service_get_default_connection(void); + +/* + * Description: telephony plug-in requires manual PROXY setting + */ +int connman_service_set_proxy(struct connman_service *service, + const char *proxy, gboolean active); + +void connman_service_set_disconnection_requested(struct connman_service *service, + bool disconnection_requested); +#endif + #ifdef __cplusplus } #endif diff --git a/include/session.h b/include/session.h index 39f33685..39f33685 100644..100755 --- a/include/session.h +++ b/include/session.h diff --git a/include/setting.h b/include/setting.h index a8820217..a8820217 100644..100755 --- a/include/setting.h +++ b/include/setting.h diff --git a/include/storage.h b/include/storage.h index 4c23a14e..4c23a14e 100644..100755 --- a/include/storage.h +++ b/include/storage.h diff --git a/include/task.h b/include/task.h index 9977d634..9977d634 100644..100755 --- a/include/task.h +++ b/include/task.h diff --git a/include/technology.h b/include/technology.h index 7508a9a1..3bd6414a 100644..100755 --- a/include/technology.h +++ b/include/technology.h @@ -34,6 +34,19 @@ extern "C" { * @short_description: Functions for handling technology details */ +#if defined TIZEN_EXT +typedef enum { + CONNMAN_MULTI_SCAN_SSID = 0x01, + CONNMAN_MULTI_SCAN_FREQ, + CONNMAN_MULTI_SCAN_SSID_FREQ, +} connman_multi_scan_type_e; + +typedef struct { + char str[128]; + gboolean flag; +} connman_multi_scan_ap_s; +#endif + struct connman_technology; int connman_technology_tethering_notify(struct connman_technology *technology, @@ -68,6 +81,12 @@ struct connman_technology_driver { int connman_technology_driver_register(struct connman_technology_driver *driver); void connman_technology_driver_unregister(struct connman_technology_driver *driver); +#if defined TIZEN_EXT +void connman_techonology_wifi_set_5ghz_supported(struct connman_technology *technology, + bool is_5_0_Ghz_supported); +void connman_techonology_set_max_scan_ssids(struct connman_technology *technology, + int max_scan_ssids); +#endif #ifdef __cplusplus } diff --git a/include/timeserver.h b/include/timeserver.h index 48ea1945..48ea1945 100644..100755 --- a/include/timeserver.h +++ b/include/timeserver.h diff --git a/include/utsname.h b/include/utsname.h index b8165f68..b8165f68 100644..100755 --- a/include/utsname.h +++ b/include/utsname.h diff --git a/include/version.h.in b/include/version.h.in index d3d6dd37..d3d6dd37 100644..100755 --- a/include/version.h.in +++ b/include/version.h.in diff --git a/include/vpn-dbus.h b/include/vpn-dbus.h index 07743bd0..07743bd0 100644..100755 --- a/include/vpn-dbus.h +++ b/include/vpn-dbus.h diff --git a/packaging/connman.spec b/packaging/connman.spec new file mode 100644 index 00000000..af8e27f0 --- /dev/null +++ b/packaging/connman.spec @@ -0,0 +1,345 @@ +%bcond_with connman_openconnect +%bcond_without connman_openvpn +%bcond_without connman_ipsec +%bcond_without connman_vpnd + +Name: connman +Version: 1.37 +Release: 33 +License: GPL-2.0+ +Summary: Connection Manager +Url: http://connman.net +Group: Network & Connectivity/Connection Management +Source0: %{name}-%{version}.tar.gz +BuildRequires: systemd-devel +BuildRequires: pkgconfig(dbus-1) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(gio-2.0) +BuildRequires: pkgconfig(libiptc) +BuildRequires: pkgconfig(xtables) +BuildRequires: pkgconfig(libsmack) +BuildRequires: pkgconfig(libnl-3.0) +BuildRequires: pkgconfig(libnl-genl-3.0) +BuildRequires: pkgconfig(libsystemd-daemon) +%if %{with connman_openconnect} +BuildRequires: openconnect +%endif +%if %{with connman_openvpn} +BuildRequires: openvpn +%endif +%if %{with connman_ipsec} +BuildRequires: strongswan +%endif +BuildRequires: readline-devel +#%systemd_requires +Requires: iptables +Requires: systemd +Requires(post): systemd +Requires(preun): systemd +Requires(postun): systemd +Requires: net-config +Requires: security-config +Provides: %{name}-profile_common = %{version}-%{release} +Provides: %{name}-profile_mobile = %{version}-%{release} +Provides: %{name}-profile_wearable = %{version}-%{release} + +%define upgrade_script_filename 500.connman_upgrade.sh +%define upgrade_script_path /usr/share/upgrade/scripts + +%description +Connection Manager provides a daemon for managing Internet connections +within embedded devices running the Linux operating system. + +%if %{with connman_openconnect} +%package plugin-openconnect +Summary: Openconnect Support for Connman +Requires: %{name} = %{version} +Requires: openconnect + +%description plugin-openconnect +Openconnect Support for Connman. +%endif + +%if %{with connman_openvpn} +%package plugin-openvpn +Summary: Openvpn Support for Connman +Requires: %{name} = %{version} +Requires: openvpn + +%description plugin-openvpn +OpenVPN support for Connman. +%endif + +%if %{with connman_ipsec} +%package plugin-ipsec +Summary: IPsec Support for Connman +Requires: %{name} = %{version} +Requires: strongswan + +%description plugin-ipsec +OpenVPN support for Connman. +%endif + +%if %{with connman_vpnd} +%package connman-vpnd +Summary: VPN Support for Connman +#BuildRequires: %{name} = %{version} +Requires: %{name} = %{version} + +%description connman-vpnd +Provides VPN support for Connman +%endif + +%package test +Summary: Test Scripts for Connection Manager +Group: Development/Tools +Requires: %{name} = %{version} +Requires: dbus-python +Requires: pygobject +Requires: python-xml + +%description test +Scripts for testing Connman and its functionality + +%package devel +Summary: Development Files for connman +Group: Development/Tools +Requires: %{name} = %{version} + +%description devel +Header files and development files for connman. + +%package extension-tv +Summary: Connman service script for TV profile +Requires: %{name} = %{version}-%{release} +Provides: %{name}-profile_tv = %{version}-%{release} +Conflicts: %{name}-extension-ivi +Conflicts: %{name}-extension-disable-eth +%description extension-tv +Supplies Tizen TV profile systemd service scripts instead of the default one. +This overwrites service script of %{name}. + +%package extension-ivi +Summary: Connman configuration for IVI profile +Requires: %{name} = %{version}-%{release} +Provides: %{name}-profile_ivi = %{version}-%{release} +Conflicts: %{name}-extension-tv +Conflicts: %{name}-extension-disable-eth +%description extension-ivi +Supplies Tizen IVI profile configuration instead of the default one. +This overwrites conf file of %{name}. + +%package extension-disable-eth +Summary: Connman configuration for testing which requires the ethernet to be disabled +Requires: %{name} = %{version}-%{release} +Conflicts: %{name}-extension-tv +Conflicts: %{name}-extension-ivi +%description extension-disable-eth +Connman without ethernet support +This overwrites conf file of %{name}. + +%prep +%setup -q + + +%build +%if %{with connman_vpnd} +VPN_CFLAGS+=" -DTIZEN_EXT -lsmack -Werror" +%endif + +chmod +x bootstrap +./bootstrap +%configure \ + --sysconfdir=/etc \ + --enable-client \ + --enable-tizen-ext \ + --enable-pacrunner \ + --enable-wifi=builtin \ +%if %{with connman_openconnect} + --enable-openconnect \ +%endif +%if %{with connman_openvpn} + --enable-openvpn \ +%endif +%if %{with connman_ipsec} + --enable-ipsec \ +%endif +%if 0%{?enable_connman_features} + %connman_features \ +%endif + --disable-ofono \ + --enable-telephony=builtin \ + --enable-test \ + --enable-loopback \ + --enable-ethernet \ + --with-systemdunitdir=%{_libdir}/systemd/system \ + --enable-pie \ + --disable-wispr \ + --disable-backtrace \ + --disable-tools + +make %{?_smp_mflags} + +%install +%make_install + +#Systemd service file +mkdir -p %{buildroot}%{_libdir}/systemd/system/ +%if "%{?_lib}" == "lib64" +mkdir -p %{buildroot}%{_unitdir} +%endif + +%if "%{?_lib}" == "lib64" +cp src/connman_tv.service %{buildroot}%{_unitdir}/connman.service.tv +cp src/connman.service %{buildroot}%{_unitdir}/connman.service +cp vpn/connman-vpn.service %{buildroot}%{_unitdir}/connman-vpn.service +%else +cp src/connman_tv.service %{buildroot}%{_libdir}/systemd/system/connman.service.tv +%endif + +mkdir -p %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants +ln -s ../connman.service %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants/connman.service +%if "%{?_lib}" == "lib64" +mkdir -p %{buildroot}%{_unitdir}/multi-user.target.wants +ln -s ../connman.service %{buildroot}%{_unitdir}/multi-user.target.wants/connman.service +%endif + +#Systemd socket file for DNS proxy +%if "%{?_lib}" == "lib64" +cp src/connman.socket %{buildroot}%{_unitdir}/connman.socket +mkdir -p %{buildroot}%{_unitdir}/sockets.target.wants +ln -s ../connman.socket %{buildroot}%{_unitdir}/sockets.target.wants/connman.socket +%else +cp src/connman.socket %{buildroot}%{_libdir}/systemd/system/connman.socket +mkdir -p %{buildroot}%{_libdir}/systemd/system/sockets.target.wants +ln -s ../connman.socket %{buildroot}%{_libdir}/systemd/system/sockets.target.wants/connman.socket +%endif + +mkdir -p %{buildroot}/%{_localstatedir}/lib/connman +cp resources/var/lib/connman/settings %{buildroot}/%{_localstatedir}/lib/connman/settings +mkdir -p %{buildroot}%{_datadir}/dbus-1/system-services +cp resources/usr/share/dbus-1/system-services/net.connman.service %{buildroot}%{_datadir}/dbus-1/system-services/net.connman.service +mkdir -p %{buildroot}/etc/connman + +cp src/main_ivi.conf %{buildroot}/etc/connman/main.conf.ivi +cp src/main_tv.conf %{buildroot}/etc/connman/main.conf.tv +cp src/main_disable_eth.conf %{buildroot}/etc/connman/main.conf.disable.eth +cp src/main.conf %{buildroot}/etc/connman/main.conf + +rm %{buildroot}%{_sysconfdir}/dbus-1/system.d/*.conf +mkdir -p %{buildroot}%{_sysconfdir}/dbus-1/system.d/ +cp src/connman.conf %{buildroot}%{_sysconfdir}/dbus-1/system.d/ + +%if %{with connman_vpnd} +cp vpn/vpn-dbus.conf %{buildroot}%{_sysconfdir}/dbus-1/system.d/connman-vpn-dbus.conf +%endif + +#OS Upgrade +mkdir -p %{buildroot}%{upgrade_script_path} +cp -f scripts/%{upgrade_script_filename} %{buildroot}%{upgrade_script_path} + +%post +#chsmack -a 'System' /%{_localstatedir}/lib/connman +#chsmack -a 'System' /%{_localstatedir}/lib/connman/settings + +%preun + +%postun +systemctl daemon-reload + +%docs_package + +%files +%manifest connman.manifest +%attr(500,network_fw,network_fw) %{_bindir}/connmand +%attr(500,network_fw,network_fw) %{_bindir}/connmanctl +%attr(755,network_fw,network_fw) /%{_localstatedir}/lib/connman +%attr(600,network_fw,network_fw) /%{_localstatedir}/lib/connman/settings +%attr(644,root,root) %{_datadir}/dbus-1/system-services/net.connman.service +%attr(644,root,root) %{_sysconfdir}/dbus-1/system.d/* +%attr(644,network_fw,network_fw) %{_sysconfdir}/connman/main.conf +%attr(644,root,root) %{_sysconfdir}/dbus-1/system.d/*.conf +%attr(644,root,root) %{_libdir}/systemd/system/connman.service +%attr(644,root,root) %{_libdir}/systemd/system/multi-user.target.wants/connman.service +%if "%{?_lib}" == "lib64" +%attr(644,root,root) %{_unitdir}/connman.service +%attr(644,root,root) %{_unitdir}/multi-user.target.wants/connman.service +%attr(644,root,root) %{_unitdir}/connman.socket +%attr(644,root,root) %{_unitdir}/sockets.target.wants/connman.socket +%else +%attr(644,root,root) %{_libdir}/systemd/system/connman.socket +%attr(644,root,root) %{_libdir}/systemd/system/sockets.target.wants/connman.socket +%endif +%license COPYING +%{upgrade_script_path}/%{upgrade_script_filename} + +%files test +%manifest connman.manifest +%{_libdir}/%{name}/test/* + +%files devel +%manifest connman.manifest +%{_includedir}/* +%{_libdir}/pkgconfig/*.pc + +%if %{with connman_openconnect} +%files plugin-openconnect +%manifest %{name}.manifest +%{_libdir}/connman/plugins-vpn/openconnect.so +%{_libdir}/connman/scripts/openconnect-script +%license COPYING +%endif + +%if %{with connman_openvpn} +%files plugin-openvpn +%manifest %{name}.manifest +%{_libdir}/%{name}/plugins-vpn/openvpn.so +%{_libdir}/%{name}/scripts/openvpn-script +%license COPYING +%endif + +%if %{with connman_ipsec} +%files plugin-ipsec +%manifest %{name}.manifest +%{_libdir}/%{name}/plugins-vpn/ipsec.so +%{_libdir}/%{name}/scripts/ipsec-script +%license COPYING +%endif + +%if %{with connman_vpnd} +%files connman-vpnd +%manifest %{name}.manifest +%{_bindir}/connman-vpnd +%dir %{_libdir}/%{name} +%dir %{_libdir}/%{name}/scripts +%dir %{_libdir}/%{name}/plugins-vpn +%attr(644,root,root) %config %{_sysconfdir}/dbus-1/system.d/connman-vpn-dbus.conf +%{_datadir}/dbus-1/system-services/net.connman.vpn.service +%license COPYING +%attr(644,root,root) %{_libdir}/systemd/system/connman-vpn.service +%if "%{?_lib}" == "lib64" +%attr(644,root,root) %{_unitdir}/connman-vpn.service +%endif +%endif + +%post extension-tv +mv -f %{_libdir}/systemd/system/connman.service.tv %{_libdir}/systemd/system/connman.service +mv -f %{_sysconfdir}/connman/main.conf.tv %{_sysconfdir}/connman/main.conf +%files extension-tv +%attr(644,network_fw,network_fw) %{_sysconfdir}/connman/main.conf.tv +%license COPYING +%if "%{?_lib}" == "lib64" +%attr(644,root,root) %{_unitdir}/connman.service.tv +%else +%attr(644,root,root) %{_libdir}/systemd/system/connman.service.tv +%endif +%post extension-ivi +mv -f %{_sysconfdir}/connman/main.conf.ivi %{_sysconfdir}/connman/main.conf +%files extension-ivi +%attr(644,network_fw,network_fw) %{_sysconfdir}/connman/main.conf.ivi +%license COPYING +%post extension-disable-eth +mv -f %{_sysconfdir}/connman/main.conf.disable.eth %{_sysconfdir}/connman/main.conf +%files extension-disable-eth +%attr(644,network_fw,network_fw) %{_sysconfdir}/connman/main.conf.disable.eth +%license COPYING diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c index f759a902..9e19de08 100644..100755 --- a/plugins/bluetooth.c +++ b/plugins/bluetooth.c @@ -192,8 +192,14 @@ static bool pan_connect(struct bluetooth_pan *pan, return false; } +#if defined TIZEN_EXT + if (pan->network) { +#endif connman_network_set_index(pan->network, index); connman_network_set_connected(pan->network, true); +#if defined TIZEN_EXT + } +#endif return true; } @@ -211,6 +217,18 @@ static void pan_connect_cb(DBusMessage *message, void *user_data) return; } +#ifdef TIZEN_EXT + /* + * Network could be removed because of BT adapter power off + * This is to handle the scenario where network is removed + * before the connect_cb is called + */ + if (!pan->network) { + DBG("network already removed"); + return; + } +#endif + if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) { const char *dbus_error = dbus_message_get_error_name(message); @@ -262,6 +280,9 @@ static int bluetooth_pan_connect(struct connman_network *network) g_strdup(path), g_free)) return -EIO; +#if defined TIZEN_EXT + if (pan->network) +#endif connman_network_set_associating(pan->network, true); return -EINPROGRESS; @@ -286,6 +307,9 @@ static void pan_disconnect_cb(DBusMessage *message, void *user_data) DBG("network %p", pan->network); +#if defined TIZEN_EXT + if (pan->network) +#endif connman_network_set_connected(pan->network, false); } @@ -299,6 +323,11 @@ static int bluetooth_pan_disconnect(struct connman_network *network) if (!pan) return -EINVAL; +#if defined TIZEN_EXT + if (connman_network_get_associating(network) == TRUE) + connman_network_clear_associating(network); +#endif + path = g_dbus_proxy_get_path(pan->btnetwork_proxy); if (!g_dbus_proxy_method_call(pan->btnetwork_proxy, "Disconnect", @@ -524,7 +553,9 @@ static void device_enable_cb(const DBusError *error, void *user_data) goto out; } +#if !defined TIZEN_EXT enable_device(device, path); +#endif out: g_free(path); } @@ -591,7 +622,9 @@ static void device_disable_cb(const DBusError *error, void *user_data) goto out; } +#if !defined TIZEN_EXT disable_device(device, path); +#endif out: g_free(path); diff --git a/plugins/connman-nmcompat.conf b/plugins/connman-nmcompat.conf index 5887a345..a051d927 100644..100755 --- a/plugins/connman-nmcompat.conf +++ b/plugins/connman-nmcompat.conf @@ -5,6 +5,10 @@ <allow own="org.freedesktop.NetworkManager"/> <allow send_destination="org.freedesktop.NetworkManager"/> </policy> + <policy user="network_fw"> + <allow own="org.freedesktop.NetworkManager"/> + <allow send_destination="org.freedesktop.NetworkManager"/> + </policy> <policy at_console="true"> <allow send_destination="org.freedesktop.NetworkManager"/> </policy> diff --git a/plugins/dundee.c b/plugins/dundee.c index b5420acf..b5420acf 100644..100755 --- a/plugins/dundee.c +++ b/plugins/dundee.c diff --git a/plugins/ethernet.c b/plugins/ethernet.c index b0395c83..9e157467 100644 --- a/plugins/ethernet.c +++ b/plugins/ethernet.c @@ -49,6 +49,9 @@ #include <connman/rtnl.h> #include <connman/log.h> #include <connman/setting.h> +#if defined TIZEN_EXT_WIFI_MESH +#include <connman/mesh.h> +#endif static bool eth_tethering = false; @@ -254,6 +257,10 @@ static void ethernet_newlink(unsigned flags, unsigned change, void *user_data) } else { DBG("carrier off"); remove_network(device, ethernet); +#if defined TIZEN_EXT_WIFI_MESH + /* Remove ethernet from mesh bridge */ + __connman_mesh_remove_ethernet_from_bridge(); +#endif } } @@ -432,6 +439,54 @@ static struct connman_technology_driver eth_tech_driver = { .set_tethering = eth_tech_set_tethering, }; +#if defined TIZEN_EXT_WIFI_MESH +static int eth_mesh_add_to_bridge(const char *bridge) +{ + GList *list; + struct ethernet_data *ethernet; + + DBG("Add ethernet to bridge %s", bridge); + + for (list = eth_interface_list; list; list = list->next) { + int index = GPOINTER_TO_INT(list->data); + struct connman_device *device = + connman_device_find_by_index(index); + + if (device) { + ethernet = connman_device_get_data(device); + if (ethernet) + remove_network(device, ethernet); + } + + connman_inet_ifup(index); + + connman_inet_add_to_bridge(index, bridge); + } + + return 0; +} + +static int eth_mesh_remove_from_bridge(const char *bridge) +{ + GList *list; + + DBG("Remove ethernet from bridge %s", bridge); + + for (list = eth_interface_list; list; list = list->next) { + int index = GPOINTER_TO_INT(list->data); + + connman_inet_remove_from_bridge(index, bridge); + } + + return 0; +} + +static struct connman_mesh_eth_driver eth_mesh_driver = { + .add_to_bridge = eth_mesh_add_to_bridge, + .remove_from_bridge = eth_mesh_remove_from_bridge, +}; +#endif + static int ethernet_init(void) { int err; @@ -440,6 +495,12 @@ static int ethernet_init(void) if (err < 0) return err; +#if defined TIZEN_EXT_WIFI_MESH + err = connman_mesh_eth_driver_register(ð_mesh_driver); + if (err < 0) + return err; +#endif + err = connman_network_driver_register(ð_network_driver); if (err < 0) return err; @@ -457,6 +518,10 @@ static void ethernet_exit(void) { connman_technology_driver_unregister(ð_tech_driver); +#if defined TIZEN_EXT_WIFI_MESH + connman_mesh_eth_driver_unregister(ð_mesh_driver); +#endif + connman_network_driver_unregister(ð_network_driver); connman_device_driver_unregister(ð_dev_driver); diff --git a/plugins/gadget.c b/plugins/gadget.c index 1b44bbb5..1b44bbb5 100644..100755 --- a/plugins/gadget.c +++ b/plugins/gadget.c diff --git a/plugins/hh2serial-gps.c b/plugins/hh2serial-gps.c index 99394e1c..99394e1c 100644..100755 --- a/plugins/hh2serial-gps.c +++ b/plugins/hh2serial-gps.c diff --git a/plugins/iospm.c b/plugins/iospm.c index cded9e00..cded9e00 100644..100755 --- a/plugins/iospm.c +++ b/plugins/iospm.c diff --git a/plugins/loopback.c b/plugins/loopback.c index e113887d..55c8a218 100644..100755 --- a/plugins/loopback.c +++ b/plugins/loopback.c @@ -32,8 +32,10 @@ #include <sys/socket.h> #include <arpa/inet.h> #include <net/if.h> +#include <stdio.h> #include <glib.h> +#include <glib/gprintf.h> #define CONNMAN_API_SUBJECT_TO_CHANGE #include <connman/plugin.h> @@ -62,10 +64,42 @@ static int setup_hostname(void) memset(system_hostname, 0, sizeof(system_hostname)); +#if defined TIZEN_EXT + FILE *fp = NULL; +#define WIFI_MAC "/opt/etc/.mac.info" + { + char* rv = 0; + gchar* dev_id = "TIZEN"; + char wifi_mac[HOST_NAME_MAX + 1]; + + fp = fopen(WIFI_MAC, "r"); + if(!fp){ + connman_error("Failed to get current hostname"); + strncpy(system_hostname, dev_id, strlen(dev_id)); + goto host_name_end; + } + + rv = fgets(wifi_mac, HOST_NAME_MAX, fp); + if(!rv){ + connman_error("Failed to get current hostname"); + strncpy(system_hostname, dev_id, strlen(dev_id)); + fclose(fp); + goto host_name_end; + } + + dev_id = g_base64_encode((const guchar *)wifi_mac, strlen(wifi_mac)); + g_sprintf(system_hostname, "TIZEN-%s", dev_id); + g_free(dev_id); + fclose(fp); + } + +host_name_end: +#else if (gethostname(system_hostname, HOST_NAME_MAX) < 0) { connman_error("Failed to get current hostname"); return -EIO; } +#endif if (strlen(system_hostname) > 0 && strcmp(system_hostname, "(none)") != 0) diff --git a/plugins/mcc.h b/plugins/mcc.h index 0e0407c9..0e0407c9 100644..100755 --- a/plugins/mcc.h +++ b/plugins/mcc.h diff --git a/plugins/neard.c b/plugins/neard.c index 69586df6..69586df6 100644..100755 --- a/plugins/neard.c +++ b/plugins/neard.c diff --git a/plugins/nmcompat.c b/plugins/nmcompat.c index 274baab4..274baab4 100644..100755 --- a/plugins/nmcompat.c +++ b/plugins/nmcompat.c diff --git a/plugins/ofono.c b/plugins/ofono.c index 82413b6e..82413b6e 100644..100755 --- a/plugins/ofono.c +++ b/plugins/ofono.c diff --git a/plugins/pacrunner.c b/plugins/pacrunner.c index 9c652f3b..9c652f3b 100644..100755 --- a/plugins/pacrunner.c +++ b/plugins/pacrunner.c diff --git a/plugins/polkit.c b/plugins/polkit.c index ae38364a..ae38364a 100644..100755 --- a/plugins/polkit.c +++ b/plugins/polkit.c diff --git a/plugins/polkit.policy b/plugins/polkit.policy index 0de152ce..0de152ce 100644..100755 --- a/plugins/polkit.policy +++ b/plugins/polkit.policy diff --git a/plugins/session_policy_local.c b/plugins/session_policy_local.c index 9beb0980..9beb0980 100644..100755 --- a/plugins/session_policy_local.c +++ b/plugins/session_policy_local.c diff --git a/plugins/telephony.c b/plugins/telephony.c new file mode 100755 index 00000000..5c37d88a --- /dev/null +++ b/plugins/telephony.c @@ -0,0 +1,1936 @@ +/* + * + * Connection Manager + * + * Copyright (C) 2007-2012 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <gdbus.h> +#include <stdlib.h> +#include <string.h> + +#define CONNMAN_API_SUBJECT_TO_CHANGE +#include <connman/dbus.h> +#include <connman/inet.h> +#include <connman/plugin.h> +#include <connman/network.h> +#include <connman/setting.h> +#include <connman/technology.h> + +#include <connman.h> + +#define PS_DBUS_SERVICE "com.tcore.ps" +#define TELEPHONY_DBUS_SERVICE "org.tizen.telephony" + +#define PS_MASTER_INTERFACE PS_DBUS_SERVICE ".master" +#define PS_MODEM_INTERFACE PS_DBUS_SERVICE ".modem" +#define PS_SERVICE_INTERFACE PS_DBUS_SERVICE ".service" +#define PS_CONTEXT_INTERFACE PS_DBUS_SERVICE ".context" + +/* methods */ +#define GET_MODEMS "GetModems" +#define GET_SERVICES "GetServices" +#define GET_CONTEXTS "GetContexts" +#define ACTIVATE_CONTEXT "Activate" +#define DEACTIVATE_CONTEXT "Deactivate" +#define GET_PROPERTIES "GetProperties" +#define SET_PROPERTY "SetProperties" + +/* signals */ +#define MODEM_ADDED "ModemAdded" +#define MODEM_REMOVED "ModemRemoved" +#define SERVICE_ADDED "ServiceAdded" +#define SERVICE_REMOVED "ServiceRemoved" +#define CONTEXT_ADDED "ContextAdded" +#define CONTEXT_REMOVED "ContextRemoved" +#define PROPERTY_CHANGED "PropertyChanged" + +#define TIMEOUT 130000 + +#define STRING2BOOL(a) (!(g_strcmp0(a, "TRUE")) ? (TRUE):(FALSE)) + +static DBusConnection *connection; +static GHashTable *modem_hash; +static GHashTable *service_hash; +static GHashTable *network_hash; + +struct telephony_service { + char *path; + + gpointer p_modem; + char *act; + gboolean roaming; /* global roaming state */ + gboolean ps_attached; /* packet service is available */ +}; + +struct telephony_modem { + char *path; + + char *operator; + gboolean powered; + gboolean sim_init; + gboolean flight_mode; + gboolean data_allowed; + gboolean roaming_allowed; + + struct connman_device *device; + struct telephony_service *s_service; +}; + +struct telephony_network { + char *path; + int if_index; + gboolean routing_only; + gboolean ipv6_link_only; + + struct connman_network *network; + + enum connman_ipconfig_method ipv4_method; + struct connman_ipaddress *ipv4_address; + + enum connman_ipconfig_method ipv6_method; + struct connman_ipaddress *ipv6_address; +}; + +static int telephony_default_subscription_id = 0; + +/* function prototype */ +static void telephony_connect(DBusConnection *connection, void *user_data); +static void telephony_disconnect(DBusConnection *connection, void *user_data); +static void __remove_modem(gpointer data); +static void __remove_service(gpointer data); +static void __remove_network(gpointer data); + +static int __modem_probe(struct connman_device *device); +static void __modem_remove(struct connman_device *device); +static int __modem_enable(struct connman_device *device); +static int __modem_disable(struct connman_device *device); + +static int __network_probe(struct connman_network *network); +static void __network_remove(struct connman_network *network); +static int __network_connect(struct connman_network *network); +static int __network_disconnect(struct connman_network *network); + + +/* dbus request and reply */ +static int __dbus_request(const char *service, const char *path, const char *interface, + const char *method, + DBusPendingCallNotifyFunction notify, void *user_data, + DBusFreeFunction free_function, int type, ...); + +static int __request_get_modems(void); +static void __response_get_modems(DBusPendingCall *call, void *user_data); +static int __request_get_services(const char *path); +static void __response_get_services(DBusPendingCall *call, void *user_data); +static int __request_get_contexts(struct telephony_modem *modem); +static void __response_get_contexts(DBusPendingCall *call, void *user_data); +static int __request_network_activate(struct connman_network *network); +static void __response_network_activate(DBusPendingCall *call, void *user_data); +static int __request_network_deactivate(struct connman_network *network); + +/* telephony internal function */ +static void __add_modem(const char *path, DBusMessageIter *prop); +static void __add_service(struct telephony_modem *modem, + const char *service_path, DBusMessageIter *prop); +static void __add_connman_device(const char *modem_path, const char *operator); +static void __remove_connman_device(struct telephony_modem *modem); +static void __remove_connman_networks(struct connman_device *device); +static int __add_context(struct connman_device *device, const char *path, + DBusMessageIter *prop); + +/* signal handler */ +static gboolean __changed_modem(DBusConnection *connection, + DBusMessage *message, void *user_data); +static gboolean __added_modem(DBusConnection *connection, + DBusMessage *message, void *user_data); +static gboolean __removed_modem(DBusConnection *connection, + DBusMessage *message, void *user_data); +static gboolean __changed_service(DBusConnection *connection, + DBusMessage *message, void *user_data); +static gboolean __added_service(DBusConnection *connection, + DBusMessage *message, void *user_data); +static gboolean __removed_service(DBusConnection *connection, + DBusMessage *message, void *user_data); +static gboolean __changed_context(DBusConnection *connection, + DBusMessage *message, void *user_data); +static gboolean __added_context(DBusConnection *connection, + DBusMessage *message, void *user_data); +static gboolean __removed_context(DBusConnection *connection, + DBusMessage *message, void *user_data); + +/* device driver */ +static struct connman_device_driver modem_driver = { + .name = "device", + .type = CONNMAN_DEVICE_TYPE_CELLULAR, + .probe = __modem_probe, + .remove = __modem_remove, + .enable = __modem_enable, + .disable = __modem_disable, +}; + +/* network driver */ +static struct connman_network_driver network_driver = { + .name = "network", + .type = CONNMAN_NETWORK_TYPE_CELLULAR, + .probe = __network_probe, + .remove = __network_remove, + .connect = __network_connect, + .disconnect = __network_disconnect, +}; + +static int tech_probe(struct connman_technology *technology) +{ + return 0; +} + +static void tech_remove(struct connman_technology *technology) +{ + return; +} + +static struct connman_technology_driver tech_driver = { + .name = "cellular", + .type = CONNMAN_SERVICE_TYPE_CELLULAR, + .probe = tech_probe, + .remove = tech_remove, +}; + +/* local function */ +static void telephony_connect(DBusConnection *connection, void *user_data) +{ + DBG("connection %p", connection); + modem_hash = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, __remove_modem); + service_hash = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, __remove_service); + network_hash = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, __remove_network); + + __request_get_modems(); +} + +static void telephony_disconnect(DBusConnection *connection, void *user_data) +{ + DBG("connection %p", connection); + + if (modem_hash != NULL) { + g_hash_table_destroy(modem_hash); + modem_hash = NULL; + } + + if (network_hash != NULL) { + g_hash_table_destroy(network_hash); + network_hash = NULL; + } +} + +static void __remove_modem(gpointer data) +{ + struct telephony_modem *modem = data; + + __remove_connman_device(modem); + + g_free(modem->path); + g_free(modem->operator); + g_free(modem); +} + +static void __remove_service(gpointer data) +{ + struct telephony_service *service = data; + + g_free(service->path); + g_free(service->act); + g_free(service); +} + +static void __remove_network(gpointer data) +{ + struct telephony_network *info = data; + struct connman_device *device; + + device = connman_network_get_device(info->network); + if (device != NULL) + connman_device_remove_network(device, info->network); + + connman_network_unref(info->network); + + g_free(info->path); + + connman_ipaddress_free(info->ipv4_address); + connman_ipaddress_free(info->ipv6_address); + + g_free(info); +} + +static void __set_device_powered(struct telephony_modem *modem, + gboolean powered) +{ + DBG("set modem(%s) powered(%d)", modem->path, powered); + + if (modem->device) + connman_device_set_powered(modem->device, powered); +} + +static int __check_device_powered(const char *path, gboolean powered) +{ + struct telephony_modem *modem = g_hash_table_lookup(modem_hash, path); + + if (modem == NULL) + return -ENODEV; + + DBG("check modem (%s) powered (%d)", modem->path, modem->powered); + + if (modem->powered == powered) + return -EALREADY; + + return 0; +} + +static int __modem_probe(struct connman_device *device) +{ + DBG("device %p", device); + return 0; +} + +static void __modem_remove(struct connman_device *device) +{ + DBG("device %p", device); +} + +static int __modem_enable(struct connman_device *device) +{ + const char *path = connman_device_get_string(device, "Path"); + DBG("device %p, path, %s", device, path); + + return __check_device_powered(path, TRUE); +} + +static int __modem_disable(struct connman_device *device) +{ + const char *path = connman_device_get_string(device, "Path"); + DBG("device %p, path, %s", device, path); + + return __check_device_powered(path, FALSE); +} + +static int __network_probe(struct connman_network *network) +{ + DBG("network_prove network(%p)", network); + return 0; +} + +static int __network_connect(struct connman_network *network) +{ + DBG("network %p", network); + + return __request_network_activate(network); +} + +static int __network_disconnect(struct connman_network *network) +{ + DBG("network %p", network); + + if (connman_network_get_associating(network) == TRUE) + connman_network_clear_associating(network); + + connman_network_set_associating(network, FALSE); + + return __request_network_deactivate(network); +} + +static void __network_remove(struct connman_network *network) +{ + char const *path = connman_network_get_string(network, "Path"); + DBG("network %p path %s", network, path); + + g_hash_table_remove(network_hash, path); +} + +static int __dbus_request(const char *service, const char *path, const char *interface, + const char *method, + DBusPendingCallNotifyFunction notify, void *user_data, + DBusFreeFunction free_function, int type, ...) +{ + DBusMessage *message; + DBusPendingCall *call; + dbus_bool_t ok; + va_list va; + + DBG("path %s %s.%s", path, interface, method); + + if (path == NULL) + return -EINVAL; + + message = dbus_message_new_method_call(service, path, interface, method); + if (message == NULL) + return -ENOMEM; + + dbus_message_set_auto_start(message, FALSE); + + va_start(va, type); + ok = dbus_message_append_args_valist(message, type, va); + va_end(va); + + if (!ok) { + dbus_message_unref(message); + return -ENOMEM; + } + + if (dbus_connection_send_with_reply(connection, message, + &call, TIMEOUT) == FALSE) { + connman_error("Failed to call %s.%s", interface, method); + dbus_message_unref(message); + return -EINVAL; + } + + if (call == NULL) { + connman_error("D-Bus connection not available"); + dbus_message_unref(message); + return -EINVAL; + } + + dbus_pending_call_set_notify(call, notify, user_data, free_function); + + dbus_message_unref(message); + + return -EINPROGRESS; +} + +static int __request_get_modems(void) +{ + DBG("request get modem"); + /* call connect master */ + return __dbus_request(PS_DBUS_SERVICE, "/", PS_MASTER_INTERFACE, GET_MODEMS, + __response_get_modems, NULL, NULL, DBUS_TYPE_INVALID); +} + +static void __response_get_modems(DBusPendingCall *call, void *user_data) +{ + DBusMessage *reply; + DBusError error; + DBusMessageIter args, dict; + + DBG(""); + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, reply)) { + connman_error("GetModems() %s %s", error.name, error.message); + dbus_error_free(&error); + goto done; + } + + DBG("message signature (%s)", dbus_message_get_signature(reply)); + + if (dbus_message_iter_init(reply, &args) == FALSE) + goto done; + + dbus_message_iter_recurse(&args, &dict); + + /* DBG("message type (%d) dic(%d)", + * dbus_message_iter_get_arg_type(&dict), DBUS_TYPE_DICT_ENTRY); + */ + + while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) { + DBusMessageIter entry, property; + const char *modem_path; + + dbus_message_iter_recurse(&dict, &entry); + dbus_message_iter_get_basic(&entry, &modem_path); + DBG("modem path (%s)", modem_path); + + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &property); + + __add_modem(modem_path, &property); + + dbus_message_iter_next(&dict); + } + +done: + dbus_message_unref(reply); + dbus_pending_call_unref(call); +} + +static int __request_get_services(const char *path) +{ + DBG("request get service"); + return __dbus_request(PS_DBUS_SERVICE, path, PS_MODEM_INTERFACE, GET_SERVICES, + __response_get_services, g_strdup(path), + g_free, DBUS_TYPE_INVALID); +} + +static void __response_get_services(DBusPendingCall *call, void *user_data) +{ + DBusMessage *reply; + DBusError error; + DBusMessageIter args, dict; + + const char *path = user_data; + struct telephony_modem *modem; + + modem = g_hash_table_lookup(modem_hash, path); + + DBG(""); + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, reply)) { + connman_error("GetServices() %s %s", error.name, error.message); + dbus_error_free(&error); + goto done; + } + + if (modem == NULL || modem->device == NULL) + goto done; + + DBG("message signature (%s)", dbus_message_get_signature(reply)); + + if (dbus_message_iter_init(reply, &args) == FALSE) + goto done; + + dbus_message_iter_recurse(&args, &dict); + + /* DBG("message type (%d) dic(%d)", + * dbus_message_iter_get_arg_type(&dict), DBUS_TYPE_DICT_ENTRY); + */ + + while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) { + DBusMessageIter entry, property; + const char *service_path; + + dbus_message_iter_recurse(&dict, &entry); + dbus_message_iter_get_basic(&entry, &service_path); + DBG("service path (%s)", service_path); + + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &property); + + __add_service(modem, service_path, &property); + + dbus_message_iter_next(&dict); + } + +done: + dbus_message_unref(reply); + dbus_pending_call_unref(call); +} + +static int __request_get_contexts(struct telephony_modem *modem) +{ + DBG("request get contexts"); + return __dbus_request(PS_DBUS_SERVICE, modem->s_service->path, + PS_SERVICE_INTERFACE, GET_CONTEXTS, + __response_get_contexts, g_strdup(modem->path), + g_free, DBUS_TYPE_INVALID); +} + +static void __response_get_contexts(DBusPendingCall *call, void *user_data) +{ + DBusError error; + DBusMessage *reply; + DBusMessageIter args, dict; + + const char *path = user_data; + struct telephony_modem *modem; + + DBG(""); + + modem = g_hash_table_lookup(modem_hash, path); + if (modem == NULL) + return; + if (modem->s_service == NULL) + return; + if (modem->device == NULL) + return; + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, reply)) { + connman_error("GetContexts() %s %s", error.name, error.message); + dbus_error_free(&error); + goto done; + } + + DBG("message signature (%s)", dbus_message_get_signature(reply)); + + if (dbus_message_iter_init(reply, &args) == FALSE) + goto done; + + dbus_message_iter_recurse(&args, &dict); + + while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) { + DBusMessageIter entry, property; + const char *context_path; + + dbus_message_iter_recurse(&dict, &entry); + dbus_message_iter_get_basic(&entry, &context_path); + DBG("context path (%s)", context_path); + + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &property); + + __add_context(modem->device, context_path, &property); + + dbus_message_iter_next(&dict); + } + +done: + dbus_message_unref(reply); + dbus_pending_call_unref(call); +} + +static int __request_network_activate(struct connman_network *network) +{ + int n_modems; + const char *path = NULL; + struct telephony_modem *modem = NULL; + + n_modems = g_hash_table_size(modem_hash); + path = connman_network_get_string(network, "Path"); + modem = connman_device_get_data(connman_network_get_device(network)); + DBG("network %p, path %s, modem %s[%d]", network, path, modem->path, + telephony_default_subscription_id); + + if (modem && n_modems > 1 && g_str_has_suffix(path, "_1") == TRUE) { + char *subscribe_id = g_strdup_printf("%d", telephony_default_subscription_id); + + if (g_str_has_suffix(modem->path, subscribe_id) != TRUE) { + g_free(subscribe_id); + return -ENOLINK; + } + g_free(subscribe_id); + } + + return __dbus_request(PS_DBUS_SERVICE, path, PS_CONTEXT_INTERFACE, ACTIVATE_CONTEXT, + __response_network_activate, + g_strdup(path), NULL, DBUS_TYPE_INVALID); +} + +static gboolean __check_network_available(struct connman_network *network) +{ + if (network == NULL || connman_network_get_device(network) == NULL) + return FALSE; + + return TRUE; +} + +static void __response_network_activate(DBusPendingCall *call, void *user_data) +{ + DBG("network activation response"); + + DBusError error; + DBusMessage *reply; + + struct telephony_network *info; + const char *path = user_data; + + info = g_hash_table_lookup(network_hash, path); + reply = dbus_pending_call_steal_reply(call); + + if (info == NULL) + goto done; + + if (__check_network_available(info->network) == FALSE) { + g_hash_table_remove(network_hash, path); + goto done; + } + + dbus_error_init(&error); + if (dbus_set_error_from_message(&error, reply)) { + connman_error("connection activate() %s %s", + error.name, error.message); + + if (connman_network_get_associating(info->network) == TRUE) + connman_network_set_error(info->network, + CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL); + + if (connman_network_get_connecting(info->network) == TRUE) + connman_network_set_error(info->network, + CONNMAN_NETWORK_ERROR_CONNECT_FAIL); + + if (connman_network_get_index(info->network) < 0) + connman_network_set_error(info->network, + CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL); + + dbus_error_free(&error); + goto done; + } + +done: + dbus_message_unref(reply); + dbus_pending_call_unref(call); +} + +static int __request_network_deactivate(struct connman_network *network) +{ + const char *path = connman_network_get_string(network, "Path"); + DBG("network %p, path %s", network, path); + + return __dbus_request(PS_DBUS_SERVICE, path, PS_CONTEXT_INTERFACE, DEACTIVATE_CONTEXT, + NULL, NULL, NULL, DBUS_TYPE_INVALID); +} + +static void __response_get_default_subscription_id(DBusPendingCall *call, + void *user_data) +{ + DBusMessage *reply; + DBusError error; + DBusMessageIter args; + + DBG(""); + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&error); + if (dbus_set_error_from_message(&error, reply)) { + connman_error("GetDefaultDataSubscription() %s %s", error.name, error.message); + dbus_error_free(&error); + goto done; + } + + DBG("message signature (%s)", dbus_message_get_signature(reply)); + + if (dbus_message_iter_init(reply, &args) == FALSE) + goto done; + + dbus_message_iter_get_basic(&args, &telephony_default_subscription_id); + DBG("default subscription: %d", telephony_default_subscription_id); + +done: + dbus_message_unref(reply); + dbus_pending_call_unref(call); +} + +static int __request_get_default_subscription_id(const char *path) +{ + int ret; + char *telephony_modem_path = NULL; + + telephony_modem_path = g_strdup_printf("/org/tizen/telephony%s", path); + DBG("request get default subscription id %s", telephony_modem_path); + + ret = __dbus_request(TELEPHONY_DBUS_SERVICE, telephony_modem_path, + "org.tizen.telephony.Network", "GetDefaultDataSubscription", + __response_get_default_subscription_id, NULL, NULL, DBUS_TYPE_INVALID); + + g_free(telephony_modem_path); + return ret; +} + +static void __add_modem(const char *path, DBusMessageIter *prop) +{ + struct telephony_modem *modem; + + modem = g_hash_table_lookup(modem_hash, path); + if (modem != NULL) + return; + + modem = g_try_new0(struct telephony_modem, 1); + if (modem == NULL) + return; + + modem->path = g_strdup(path); + modem->device = NULL; + modem->s_service = NULL; + + g_hash_table_insert(modem_hash, g_strdup(path), modem); + + while (dbus_message_iter_get_arg_type(prop) != DBUS_TYPE_INVALID) { + DBusMessageIter entry; + const char *key, *tmp; + + dbus_message_iter_recurse(prop, &entry); + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + dbus_message_iter_get_basic(&entry, &tmp); + + DBG("key (%s) value(%s)", key, tmp); + + if (g_strcmp0(key, "powered") == 0) { + modem->powered = STRING2BOOL(tmp); + } else if (g_strcmp0(key, "operator") == 0) { + modem->operator = g_strdup(tmp); + } else if (g_strcmp0(key, "sim_init") == 0) { + modem->sim_init = STRING2BOOL(tmp); + } else if (g_strcmp0(key, "flight_mode") == 0) { + modem->flight_mode = STRING2BOOL(tmp); + } else if (g_strcmp0(key, "roaming_allowed") == 0) { + modem->roaming_allowed = STRING2BOOL(tmp); + } else if (g_strcmp0(key, "data_allowed") == 0) { + modem->data_allowed = STRING2BOOL(tmp); + } + dbus_message_iter_next(prop); + } + + __add_connman_device(path, modem->operator); + __set_device_powered(modem, modem->powered); + + if (g_hash_table_size(modem_hash) > 1) + __request_get_default_subscription_id(modem->path); + + if (modem->powered != TRUE) { + DBG("modem is not powered"); + return; + } + + __request_get_services(modem->path); +} + +static void __add_service(struct telephony_modem *modem, + const char *service_path, DBusMessageIter *prop) +{ + struct telephony_service *service; + + if (modem->s_service != NULL) + return; + + service = g_try_new0(struct telephony_service, 1); + if (service == NULL) + return; + + service->path = g_strdup(service_path); + service->p_modem = modem; + g_hash_table_insert(service_hash, g_strdup(service_path), service); + + while (dbus_message_iter_get_arg_type(prop) != DBUS_TYPE_INVALID) { + DBusMessageIter entry; + const char *key, *tmp; + + dbus_message_iter_recurse(prop, &entry); + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + dbus_message_iter_get_basic(&entry, &tmp); + + DBG("key (%s) value(%s)", key, tmp); + + if (g_strcmp0(key, "roaming") == 0) { + service->roaming = STRING2BOOL(tmp); + } else if (g_strcmp0(key, "act") == 0) { + service->act = g_strdup(tmp); + } else if (g_strcmp0(key, "ps_attached") == 0) { + service->ps_attached = STRING2BOOL(tmp); + } + + dbus_message_iter_next(prop); + } + + modem->s_service = service; + __request_get_contexts(modem); +} + +static char *__get_ident(const char *path) +{ + char *pos; + + if (*path != '/') + return NULL; + + pos = strrchr(path, '/'); + if (pos == NULL) + return NULL; + + return pos + 1; +} + +static void __add_connman_device(const char *modem_path, const char *operator) +{ + char* ident = NULL; + struct telephony_modem *modem; + struct connman_device *device; + + DBG("path %s operator %s", modem_path, operator); + + if (modem_path == NULL) + return; + + if (operator == NULL) + return; + + modem = g_hash_table_lookup(modem_hash, modem_path); + if (modem == NULL) + return; + + if (modem->device) { + if (!g_strcmp0(operator, + connman_device_get_ident(modem->device))) + return; + + __remove_connman_device(modem); + } + + if (strlen(operator) == 0) + return; + + device = connman_device_create(operator, CONNMAN_DEVICE_TYPE_CELLULAR); + if (device == NULL) + return; + + ident = g_strdup_printf("%s_%s", __get_ident(modem_path), operator); + connman_device_set_ident(device, ident); + g_free(ident); + + connman_device_set_string(device, "Path", modem_path); + connman_device_set_data(device, modem); + + if (connman_device_register(device) < 0) { + connman_error("Failed to register cellular device"); + connman_device_unref(device); + return; + } + + modem->device = device; +} + +static void __remove_connman_device(struct telephony_modem *modem) +{ + DBG("modem %p path %s device %p", modem, modem->path, modem->device); + + if (modem->device == NULL) + return; + + __remove_connman_networks(modem->device); + + connman_device_unregister(modem->device); + connman_device_unref(modem->device); + + modem->device = NULL; +} + +static void __remove_connman_networks(struct connman_device *device) +{ + GHashTableIter iter; + gpointer key, value; + GSList *info_list = NULL; + GSList *list; + + if (network_hash == NULL) + return; + + g_hash_table_iter_init(&iter, network_hash); + + while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) { + struct telephony_network *info = value; + + if (connman_network_get_device(info->network) != device) + continue; + + info_list = g_slist_append(info_list, info); + } + + for (list = info_list; list != NULL; list = list->next) { + struct telephony_network *info = list->data; + connman_device_remove_network(device, info->network); + } + + g_slist_free(info_list); +} + +static gboolean connman_ipaddress_updated(struct connman_ipaddress *ipaddress, + const char *address, const char *gateway) +{ + if (ipaddress == NULL || address == NULL) + return FALSE; + + if (g_strcmp0(ipaddress->local, address) != 0) + return TRUE; + + if (g_strcmp0(ipaddress->gateway, gateway) != 0) + return TRUE; + + return FALSE; +} + +static void __set_network_connected(struct telephony_network *network, + gboolean connected) +{ + gboolean setip = FALSE; + + DBG("network %p connected %d", network, connected); + + connman_network_set_index(network->network, network->if_index); + if (connman_network_get_connected(network->network) == connected) + return; + + switch (network->ipv4_method) { + case CONNMAN_IPCONFIG_METHOD_UNKNOWN: + case CONNMAN_IPCONFIG_METHOD_DHCP: + case CONNMAN_IPCONFIG_METHOD_AUTO: + case CONNMAN_IPCONFIG_METHOD_OFF: + connman_network_set_ipv4_method(network->network, + network->ipv4_method); + break; + case CONNMAN_IPCONFIG_METHOD_MANUAL: + case CONNMAN_IPCONFIG_METHOD_FIXED: + connman_network_set_ipv4_method(network->network, + network->ipv4_method); + connman_network_set_ipaddress(network->network, + network->ipv4_address); + setip = TRUE; + break; + } + + switch (network->ipv6_method) { + case CONNMAN_IPCONFIG_METHOD_UNKNOWN: + case CONNMAN_IPCONFIG_METHOD_OFF: + case CONNMAN_IPCONFIG_METHOD_DHCP: + break; + case CONNMAN_IPCONFIG_METHOD_AUTO: + connman_network_set_ipv6_method(network->network, + network->ipv6_method); + setip = TRUE; + break; + case CONNMAN_IPCONFIG_METHOD_MANUAL: + case CONNMAN_IPCONFIG_METHOD_FIXED: + connman_network_set_ipv6_method(network->network, + network->ipv6_method); + connman_network_set_ipaddress(network->network, + network->ipv6_address); + setip = TRUE; + break; + } + + if (setip == TRUE) + connman_network_set_connected(network->network, connected); +} + +static gboolean __set_network_context( + struct telephony_network *network, + DBusMessageIter *dict) +{ + int index = 0; + gboolean active = FALSE; + gboolean routing_only = FALSE; + gboolean ipv4_updated = FALSE; + gboolean ipv6_updated = FALSE; + gboolean ipv6_link_only = FALSE; + gboolean default_internet = FALSE; + gboolean active_proxy = FALSE; + char **proxies = NULL; + const char *dev_name = NULL; + const char *proxy_addr = NULL; + char *ipv4_addr = NULL, *ipv4_gw = NULL, *ipv4_netmask = NULL, + *ipv4_dns1 = NULL, *ipv4_dns2 = NULL; + char *ipv6_addr = NULL, *ipv6_gw = NULL, *ipv6_netmask = NULL, + *ipv6_dns1 = NULL, *ipv6_dns2 = NULL; + struct connman_service *service; + + while (dbus_message_iter_get_arg_type(dict) != DBUS_TYPE_INVALID) { + DBusMessageIter entry; + const char *key, *value; + + dbus_message_iter_recurse(dict, &entry); + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + + if (g_strcmp0(key, "dev_name") == 0) { + dbus_message_iter_get_basic(&entry, &dev_name); + DBG("dev_name (%s)", dev_name); + } else if (g_strcmp0(key, "proxy") == 0) { + dbus_message_iter_get_basic(&entry, &proxy_addr); + DBG("proxy_addr (%s)", proxy_addr); + } else if (g_strcmp0(key, "ipv4_address") == 0) { + dbus_message_iter_get_basic(&entry, &ipv4_addr); + DBG("ipv4_addr (%s)", ipv4_addr); + } else if (g_strcmp0(key, "ipv4_gateway") == 0) { + dbus_message_iter_get_basic(&entry, &ipv4_gw); + DBG("ipv4_gw (%s)", ipv4_gw); + } else if (g_strcmp0(key, "ipv4_netmask") == 0) { + dbus_message_iter_get_basic(&entry, &ipv4_netmask); + DBG("ipv4_netmask (%s)", ipv4_netmask); + } else if (g_strcmp0(key, "ipv4_dns1") == 0) { + dbus_message_iter_get_basic(&entry, &ipv4_dns1); + DBG("ipv4_dns1 (%s)", ipv4_dns1); + } else if (g_strcmp0(key, "ipv4_dns2") == 0) { + dbus_message_iter_get_basic(&entry, &ipv4_dns2); + DBG("ipv4_dns2 (%s)", ipv4_dns2); + } else if (g_strcmp0(key, "ipv6_address") == 0) { + dbus_message_iter_get_basic(&entry, &ipv6_addr); + DBG("ipv6 address (%s)", ipv6_addr); + } else if (g_strcmp0(key, "ipv6_gateway") == 0) { + dbus_message_iter_get_basic(&entry, &ipv6_gw); + DBG("ipv6_gw (%s)", ipv6_gw); + } else if (g_strcmp0(key, "ipv6_netmask") == 0) { + dbus_message_iter_get_basic(&entry, &ipv6_netmask); + DBG("ipv6_netmask (%s)", ipv6_netmask); + } else if (g_strcmp0(key, "ipv6_dns1") == 0) { + dbus_message_iter_get_basic(&entry, &ipv6_dns1); + DBG("ipv6_dns1 (%s)", ipv6_dns1); + } else if (g_strcmp0(key, "ipv6_dns2") == 0) { + dbus_message_iter_get_basic(&entry, &ipv6_dns2); + DBG("ipv6_dns2 (%s)", ipv6_dns2); + } else if (g_strcmp0(key, "active") == 0) { + dbus_message_iter_get_basic(&entry, &value); + DBG("active (%s)", value); + active = STRING2BOOL(value); + } else if (g_strcmp0(key, "routing_only") == 0) { + dbus_message_iter_get_basic(&entry, &value); + DBG("routing_only (%s)", value); + routing_only = STRING2BOOL(value); + network->routing_only = routing_only; + } else if (g_strcmp0(key, "ipv6_link_only") == 0) { + dbus_message_iter_get_basic(&entry, &value); + DBG("ipv6_link_only (%s)", value); + ipv6_link_only = STRING2BOOL(value); + network->ipv6_link_only = ipv6_link_only; + } + else if (g_strcmp0(key, "default_internet_conn") == 0) { + dbus_message_iter_get_basic(&entry, &value); + DBG("default_internet (%s)", value); + default_internet = STRING2BOOL(value); + } + + dbus_message_iter_next(dict); + } + + if(routing_only){ + //context active does not effect the connman service status. + //it only for setting the routing path. + DBG("routing_only(%d), active(%d)", routing_only, active); + return active; + } + + if (g_strcmp0(proxy_addr, ":") == 0) + proxy_addr = NULL; + if (g_strcmp0(ipv4_addr, "0.0.0.0") == 0) + ipv4_addr = NULL; + if (g_strcmp0(ipv4_gw, "0.0.0.0") == 0) + ipv4_gw = NULL; + if (g_strcmp0(ipv4_netmask, "0.0.0.0") == 0) + ipv4_netmask = NULL; + if (g_strcmp0(ipv4_dns1, "0.0.0.0") == 0) + ipv4_dns1 = NULL; + if (g_strcmp0(ipv4_dns2, "0.0.0.0") == 0) + ipv4_dns2 = NULL; + if (g_strcmp0(ipv6_addr, "::") == 0) + ipv6_addr = NULL; + if (g_strcmp0(ipv6_gw, "::") == 0) + ipv6_gw = NULL; + if (g_strcmp0(ipv6_netmask, "::") == 0) + ipv6_netmask = NULL; + if (g_strcmp0(ipv6_dns1, "::") == 0) + ipv6_dns1 = NULL; + if (g_strcmp0(ipv6_dns2, "::") == 0) + ipv6_dns2 = NULL; + + connman_network_set_bool(network->network, "DefaultInternet", + (bool)default_internet); + + service = connman_service_lookup_from_network(network->network); + if (service == NULL) + return FALSE; + + if (connman_setting_get_bool("SingleConnectedTechnology") == TRUE) { + /* Wi-Fi technology is always a top priority */ + if (active == TRUE && + connman_service_is_no_ref_user_pdn_connection(service) == TRUE && + connman_service_get_type(connman_service_get_default_connection()) + == CONNMAN_SERVICE_TYPE_WIFI) { + __request_network_deactivate(network->network); + + return FALSE; + } + } + + /* interface index set */ + if (dev_name != NULL) { + index = connman_inet_ifindex(dev_name); + network->if_index = index; + DBG("interface index %d", index); + } + + /* proxy set */ + if (active == TRUE && + connman_network_get_connected(network->network) == TRUE) + active_proxy = TRUE; + + proxies = connman_service_get_proxy_servers(service); + if (proxies != NULL) { + if (proxy_addr == NULL) + connman_service_set_proxy(service, proxy_addr, active_proxy); + else if (g_strcmp0(proxy_addr, proxies[0]) != 0) + connman_service_set_proxy(service, proxy_addr, active_proxy); + } else if (proxy_addr != NULL) + connman_service_set_proxy(service, proxy_addr, active_proxy); + + if (proxies != NULL) + g_strfreev(proxies); + + __connman_service_nameserver_clear(service); + + /* ipv4 set */ + if (network->ipv4_address == NULL) + network->ipv4_address = + connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV4); + + if (network->ipv4_address == NULL) + return FALSE; + + if (ipv4_addr == NULL && active == TRUE) + network->ipv4_method = CONNMAN_IPCONFIG_METHOD_OFF; + else + network->ipv4_method = CONNMAN_IPCONFIG_METHOD_FIXED; + + connman_network_set_ipv4_method(network->network, network->ipv4_method); + + ipv4_updated = connman_ipaddress_updated(network->ipv4_address, + ipv4_addr, ipv4_gw); + if (ipv4_updated == TRUE) + connman_ipaddress_set_ipv4(network->ipv4_address, ipv4_addr, + ipv4_netmask, ipv4_gw); + + if (ipv4_dns1) +#if defined TIZEN_EXT + __connman_service_nameserver_append(service, ipv4_dns1, FALSE, + CONNMAN_IPCONFIG_TYPE_IPV4); +#else + __connman_service_nameserver_append(service, ipv4_dns1, FALSE); +#endif + //if (ipv4_dns2) + if (ipv4_dns2 && !ipv4_dns1) +#if defined TIZEN_EXT + __connman_service_nameserver_append(service, ipv4_dns2, FALSE, + CONNMAN_IPCONFIG_TYPE_IPV4); +#else + __connman_service_nameserver_append(service, ipv4_dns2, FALSE); +#endif + /* ipv6 set */ + if (network->ipv6_address == NULL) + network->ipv6_address = + connman_ipaddress_alloc(CONNMAN_IPCONFIG_TYPE_IPV6); + + if (network->ipv6_address == NULL) + return FALSE; + + if(ipv6_link_only) + network->ipv6_method = CONNMAN_IPCONFIG_METHOD_AUTO; + else + network->ipv6_method = CONNMAN_IPCONFIG_METHOD_FIXED; + + if (ipv6_addr == NULL) + network->ipv6_method = CONNMAN_IPCONFIG_METHOD_OFF; + + connman_network_set_ipv6_method(network->network, network->ipv6_method); + + ipv6_updated = connman_ipaddress_updated(network->ipv6_address, + ipv6_addr, ipv6_gw); + if (ipv6_updated == TRUE) + connman_ipaddress_set_ipv6(network->ipv6_address, ipv6_addr, + 64, ipv6_gw); + + if (ipv6_dns1) +#if defined TIZEN_EXT + __connman_service_nameserver_append(service, ipv6_dns1, FALSE, + CONNMAN_IPCONFIG_TYPE_IPV6); +#else + __connman_service_nameserver_append(service, ipv6_dns1, FALSE); +#endif + //if (ipv6_dns2) + if (ipv6_dns2 && !ipv6_dns1) +#if defined TIZEN_EXT + __connman_service_nameserver_append(service, ipv6_dns2, FALSE, + CONNMAN_IPCONFIG_TYPE_IPV6); +#else + __connman_service_nameserver_append(service, ipv6_dns2, FALSE); +#endif + + if (active == TRUE && + connman_network_get_connected(network->network) == TRUE) { + if (ipv4_updated == TRUE || ipv6_updated == TRUE) { + DBG("IPv4 updated %d, IPv6 updated %d", ipv4_updated, ipv6_updated); + + __set_network_connected(network, FALSE); + } else { + DBG("Already connected"); + + return active; + } + } + + if (active == TRUE) + connman_network_set_associating(network->network, TRUE); + + return active; +} + +static int __add_context(struct connman_device *device, const char *path, + DBusMessageIter *prop) +{ + char *ident; + gboolean active = FALSE; + + struct telephony_modem *modem = connman_device_get_data(device); + struct connman_network *network; + struct telephony_network *info; + + DBG("modem %p device %p path %s", modem, device, path); + + ident = __get_ident(path); + + network = connman_device_get_network(device, ident); + if (network != NULL) + return -EALREADY; + + info = g_hash_table_lookup(network_hash, path); + if (info != NULL) { + DBG("path %p already exists with device %p", path, + connman_network_get_device(info->network)); + + if (connman_network_get_device(info->network)) + return -EALREADY; + + g_hash_table_remove(network_hash, path); + } + + network = connman_network_create(ident, CONNMAN_NETWORK_TYPE_CELLULAR); + if (network == NULL) + return -ENOMEM; + + info = g_try_new0(struct telephony_network, 1); + if (info == NULL) { + connman_network_unref(network); + return -ENOMEM; + } + + info->path = g_strdup(path); + + connman_ipaddress_clear(info->ipv4_address); + connman_ipaddress_clear(info->ipv6_address); + + info->network = network; + + connman_network_set_string(network, "Path", path); + connman_network_set_name(network, path); + + connman_network_set_group(network, ident); + + g_hash_table_insert(network_hash, g_strdup(path), info); + + connman_network_set_available(network, TRUE); + connman_network_set_bool(network, "Roaming", (bool)modem->s_service->roaming); + + if (connman_device_add_network(device, network) != 0) { + g_hash_table_remove(network_hash, path); + return -EIO; + } + + active = __set_network_context(info, prop); + if(info->routing_only){ + int err = 0; + struct connman_service *routing_service; + struct connman_ipconfig *routing_ipconfig; + + if(!active) + return TRUE; + + routing_service = connman_service_lookup_from_network(info->network); + routing_ipconfig = __connman_service_get_ip4config(routing_service); + err = __connman_ipconfig_gateway_add(routing_ipconfig, routing_service); + + DBG("set gateway rv(%d)", err); + return TRUE; + } + + if (active == TRUE && (connman_network_get_associating(network) == TRUE || + connman_network_get_connecting(network) == TRUE)) + __set_network_connected(info, active); + + return 0; +} + +static gboolean __changed_modem(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + gboolean old_powered; + DBusMessageIter args, dict; + struct telephony_modem *modem; + const char *path = dbus_message_get_path(message); + + DBG("modem changed signal %s", path); + + modem = g_hash_table_lookup(modem_hash, path); + if (modem == NULL) { + DBG("modem object does not exists"); + return TRUE; + } + + old_powered = modem->powered; + + DBG("message signature (%s)", dbus_message_get_signature(message)); + + if (dbus_message_iter_init(message, &args) == FALSE) { + DBG("error to read message"); + return TRUE; + } + + dbus_message_iter_recurse(&args, &dict); + + while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) { + DBusMessageIter entry; + const char *key, *tmp; + + dbus_message_iter_recurse(&dict, &entry); + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + dbus_message_iter_get_basic(&entry, &tmp); + + DBG("key(%s), value(%s)", key, tmp); + + if (g_strcmp0(key, "powered") == 0) { + modem->powered = STRING2BOOL(tmp); + } else if (g_strcmp0(key, "operator") == 0) { + modem->operator = g_strdup(tmp); + } else if (g_strcmp0(key, "sim_init") == 0) { + modem->sim_init = STRING2BOOL(tmp); + } else if (g_strcmp0(key, "flight_mode") == 0) { + modem->flight_mode = STRING2BOOL(tmp); + } else if (g_strcmp0(key, "roaming_allowed") == 0) { + modem->roaming_allowed = STRING2BOOL(tmp); + } else if (g_strcmp0(key, "data_allowed") == 0) { + modem->data_allowed = STRING2BOOL(tmp); + } + + dbus_message_iter_next(&dict); + } + + if (modem->device == NULL) + __add_connman_device(path, modem->operator); + + if (old_powered != modem->powered) + __set_device_powered(modem, modem->powered); + + if (modem->powered != TRUE) { + DBG("modem is not powered"); + return TRUE; + } + + if (modem->s_service == NULL) { + __request_get_services(modem->path); + return TRUE; + } + + DBG("modem(%s) flight mode(%d) data allowed(%d)", + modem->path, modem->flight_mode, modem->data_allowed); + + return TRUE; +} + +static gboolean __added_modem(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + const char *modem_path = NULL; + DBusMessageIter args, dict, tmp; + + DBG("modem added signal (%s)", dbus_message_get_signature(message)); + + if (dbus_message_iter_init(message, &args) == FALSE) { + DBG("error to read message"); + return TRUE; + } + + dbus_message_iter_recurse(&args, &dict); + memcpy(&tmp, &dict, sizeof(struct DBusMessageIter)); + + while (dbus_message_iter_get_arg_type(&tmp) != DBUS_TYPE_INVALID) { + DBusMessageIter entry; + const char *key, *value; + + dbus_message_iter_recurse(&tmp, &entry); + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + dbus_message_iter_get_basic(&entry, &value); + + DBG("key (%s) value(%s)", key, value); + + if (g_strcmp0(key, "path") == 0) + modem_path = g_strdup(value); + + dbus_message_iter_next(&tmp); + } + + if (modem_path != NULL) + __add_modem(modem_path, &dict); + + return TRUE; +} + +static gboolean __removed_modem(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + DBusMessageIter iter; + const char *modem_path; + + DBG("modem removed signal"); + + if (dbus_message_iter_init(message, &iter) == FALSE) { + DBG("error to read message"); + return TRUE; + } + + dbus_message_iter_get_basic(&iter, &modem_path); + g_hash_table_remove(modem_hash, modem_path); + + return TRUE; +} + +static gboolean __changed_service(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + DBusMessageIter args, dict; + struct telephony_modem *modem; + gboolean roaming_option = TRUE; + struct telephony_service *s_service; + const char *service_path = dbus_message_get_path(message); + + DBG("service changed signal %s", service_path); + + s_service = g_hash_table_lookup(service_hash, service_path); + if (s_service == NULL) { + DBG("service object does not exists"); + return TRUE; + } + + modem = s_service->p_modem; + if (modem == NULL) { + DBG("modem object does not exists"); + return TRUE; + } + + DBG("message signature (%s)", dbus_message_get_signature(message)); + + if (dbus_message_iter_init(message, &args) == FALSE) { + DBG("error to read message"); + return TRUE; + } + + dbus_message_iter_recurse(&args, &dict); + + while (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) { + DBusMessageIter entry; + const char *key, *tmp; + + dbus_message_iter_recurse(&dict, &entry); + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + dbus_message_iter_get_basic(&entry, &tmp); + + DBG("key(%s), value(%s)", key, tmp); + + if (g_strcmp0(key, "roaming") == 0) { + s_service->roaming = STRING2BOOL(tmp); + } else if (g_strcmp0(key, "act") == 0) { + s_service->act = g_strdup(tmp); + } else if (g_strcmp0(key, "ps_attached") == 0) { + s_service->ps_attached = STRING2BOOL(tmp); + } + + dbus_message_iter_next(&dict); + } + + roaming_option &= (!s_service->roaming && !modem->roaming_allowed) + || modem->roaming_allowed; + + return TRUE; +} + +static gboolean __added_service(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + struct telephony_modem *modem; + const char *service_path = NULL; + DBusMessageIter args, dict, tmp; + const char *path = dbus_message_get_path(message); + + DBG("service added signal %s", path); + + modem = g_hash_table_lookup(modem_hash, path); + if (modem == NULL || modem->device == NULL) + return TRUE; + + DBG("message signature (%s)", dbus_message_get_signature(message)); + if (dbus_message_iter_init(message, &args) == FALSE) { + DBG("error to read message"); + return TRUE; + } + + dbus_message_iter_recurse(&args, &dict); + memcpy(&tmp, &dict, sizeof(struct DBusMessageIter)); + + while (dbus_message_iter_get_arg_type(&tmp) != DBUS_TYPE_INVALID) { + DBusMessageIter entry; + const char *key, *value; + + dbus_message_iter_recurse(&tmp, &entry); + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + dbus_message_iter_get_basic(&entry, &value); + + DBG("key (%s) value(%s)", key, value); + + if (g_strcmp0(key, "path") == 0) + service_path = value; + + dbus_message_iter_next(&tmp); + } + + if (service_path != NULL) + __add_service(modem, service_path, &dict); + + return TRUE; +} + +static gboolean __removed_service(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + DBusMessageIter iter; + const char *service_path; + + DBG("service removed signal"); + + if (dbus_message_iter_init(message, &iter) == FALSE) { + DBG("error to read message"); + return TRUE; + } + + dbus_message_iter_get_basic(&iter, &service_path); + g_hash_table_remove(service_hash, service_path); + + return TRUE; +} + +static gboolean __changed_context(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + gboolean active = FALSE; + DBusMessageIter args, dict; + struct telephony_network *info; + const char *path = dbus_message_get_path(message); + + DBG("network changed signal %s", path); + + info = g_hash_table_lookup(network_hash, path); + if (info == NULL) + return TRUE; + + if (__check_network_available(info->network) == FALSE) { + g_hash_table_remove(network_hash, path); + return TRUE; + } + + if (dbus_message_iter_init(message, &args) == FALSE) { + DBG("error to read message"); + return TRUE; + } + + dbus_message_iter_recurse(&args, &dict); + + active = __set_network_context(info, &dict); + if(info->routing_only){ + int err = 0; + struct connman_service *routing_service; + struct connman_ipconfig *routing_ipconfig; + + if(!active) + return TRUE; + + routing_service = connman_service_lookup_from_network(info->network); + routing_ipconfig = __connman_service_get_ip4config(routing_service); + err = __connman_ipconfig_gateway_add(routing_ipconfig, routing_service); + + DBG("set gateway rv(%d)", err); + return TRUE; + } + + __set_network_connected(info, active); + + if (active == FALSE && + connman_network_get_connecting(info->network) == TRUE) + connman_network_set_connected(info->network, FALSE); + + return TRUE; +} + +static gboolean __added_context(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + const char *network_path = NULL; + DBusMessageIter args, dict, tmp; + struct telephony_modem *modem = NULL; + struct telephony_service *service = NULL; + const char *path = dbus_message_get_path(message); + + DBG("network added signal %s", path); + + service = g_hash_table_lookup(service_hash, path); + if (service == NULL || service->p_modem == NULL) + return TRUE; + + modem = service->p_modem; + if (modem == NULL || modem->device == NULL) + return TRUE; + + DBG("message signature (%s)", dbus_message_get_signature(message)); + if (dbus_message_iter_init(message, &args) == FALSE) { + DBG("error to read message"); + return TRUE; + } + + dbus_message_iter_recurse(&args, &dict); + memcpy(&tmp, &dict, sizeof(struct DBusMessageIter)); + + while (dbus_message_iter_get_arg_type(&tmp) != DBUS_TYPE_INVALID) { + DBusMessageIter entry; + const char *key, *value; + + dbus_message_iter_recurse(&tmp, &entry); + dbus_message_iter_get_basic(&entry, &key); + + dbus_message_iter_next(&entry); + dbus_message_iter_get_basic(&entry, &value); + + DBG("key (%s) value(%s)", key, value); + + if (g_strcmp0(key, "path") == 0) + network_path = g_strdup(value); + + dbus_message_iter_next(&tmp); + } + + if (network_path != NULL) + __add_context(modem->device, network_path, &dict); + + return TRUE; +} + +static gboolean __removed_context(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + DBusMessageIter iter; + const char *network_path = NULL; + struct telephony_service *service = NULL; + const char *path = dbus_message_get_path(message); + + DBG("network removed signal %s", path); + + service = g_hash_table_lookup(service_hash, path); + if (service == NULL || service->p_modem == NULL) + return TRUE; + + if (dbus_message_iter_init(message, &iter) == FALSE) { + DBG("error to read message"); + return TRUE; + } + + dbus_message_iter_get_basic(&iter, &network_path); + g_hash_table_remove(network_hash, network_path); + + return TRUE; +} + +static gboolean __changed_default_subscription(DBusConnection *connection, + DBusMessage *message, void *user_data) +{ + DBusMessageIter args; + + DBG("message signature (%s)", dbus_message_get_signature(message)); + if (dbus_message_iter_init(message, &args) == FALSE) + return TRUE; + + dbus_message_iter_get_basic(&args, &telephony_default_subscription_id); + DBG("default subscription: %d", telephony_default_subscription_id); + + return TRUE; +} + +/* telephony initialization */ +static guint watch = 0; +static guint modem_watch = 0; +static guint modem_added_watch = 0; +static guint modem_removed_watch = 0; +static guint service_watch = 0; +static guint service_added_watch = 0; +static guint service_removed_watch = 0; +static guint context_watch = 0; +static guint context_added_watch = 0; +static guint context_removed_watch = 0; +static guint default_subscription_watch = 0; + +static int telephony_init(void) +{ + int err; + + DBG("telephony plugin"); + + connection = connman_dbus_get_connection(); + if (connection == NULL) + return -EIO; + + /* telephony watch */ + watch = g_dbus_add_service_watch(connection, PS_DBUS_SERVICE, + telephony_connect, telephony_disconnect, + NULL, NULL); + + modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL, + PS_MODEM_INTERFACE, + PROPERTY_CHANGED, + __changed_modem, + NULL, NULL); + + modem_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL, + PS_MASTER_INTERFACE, + MODEM_ADDED, + __added_modem, + NULL, NULL); + + modem_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL, + PS_MASTER_INTERFACE, + MODEM_REMOVED, + __removed_modem, + NULL, NULL); + + service_watch = g_dbus_add_signal_watch(connection, NULL, NULL, + PS_SERVICE_INTERFACE, + PROPERTY_CHANGED, + __changed_service, + NULL, NULL); + + service_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL, + PS_MODEM_INTERFACE, + SERVICE_ADDED, + __added_service, + NULL, NULL); + + service_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL, + PS_MODEM_INTERFACE, + SERVICE_REMOVED, + __removed_service, + NULL, NULL); + + context_watch = g_dbus_add_signal_watch(connection, NULL, NULL, + PS_CONTEXT_INTERFACE, + PROPERTY_CHANGED, + __changed_context, + NULL, NULL); + + context_added_watch = g_dbus_add_signal_watch(connection, NULL, NULL, + PS_SERVICE_INTERFACE, + CONTEXT_ADDED, + __added_context, + NULL, NULL); + + context_removed_watch = g_dbus_add_signal_watch(connection, NULL, NULL, + PS_SERVICE_INTERFACE, + CONTEXT_REMOVED, + __removed_context, + NULL, NULL); + + default_subscription_watch = g_dbus_add_signal_watch(connection, NULL, NULL, + "org.tizen.telephony.Network", + "DefaultDataSubscription", + __changed_default_subscription, + NULL, NULL); + + if (watch == 0 || modem_watch == 0 || modem_added_watch == 0 + || modem_removed_watch == 0 || service_watch == 0 + || service_added_watch == 0 || context_watch == 0 + || service_removed_watch == 0 + || context_added_watch == 0 + || context_removed_watch == 0 + || default_subscription_watch == 0) { + err = -EIO; + goto remove; + } + + err = connman_network_driver_register(&network_driver); + if (err < 0) + goto remove; + + err = connman_device_driver_register(&modem_driver); + if (err < 0) { + connman_network_driver_unregister(&network_driver); + goto remove; + } + + err = connman_technology_driver_register(&tech_driver); + if (err < 0) { + connman_device_driver_unregister(&modem_driver); + connman_network_driver_unregister(&network_driver); + goto remove; + } + + return 0; + +remove: + g_dbus_remove_watch(connection, watch); + g_dbus_remove_watch(connection, modem_watch); + g_dbus_remove_watch(connection, modem_added_watch); + g_dbus_remove_watch(connection, modem_removed_watch); + g_dbus_remove_watch(connection, service_watch); + g_dbus_remove_watch(connection, service_added_watch); + g_dbus_remove_watch(connection, service_removed_watch); + g_dbus_remove_watch(connection, context_watch); + g_dbus_remove_watch(connection, context_added_watch); + g_dbus_remove_watch(connection, context_removed_watch); + g_dbus_remove_watch(connection, default_subscription_watch); + + dbus_connection_unref(connection); + return err; +} + +static void telephony_exit(void) +{ + g_dbus_remove_watch(connection, watch); + g_dbus_remove_watch(connection, modem_watch); + g_dbus_remove_watch(connection, modem_added_watch); + g_dbus_remove_watch(connection, modem_removed_watch); + g_dbus_remove_watch(connection, service_watch); + g_dbus_remove_watch(connection, service_added_watch); + g_dbus_remove_watch(connection, service_removed_watch); + g_dbus_remove_watch(connection, context_watch); + g_dbus_remove_watch(connection, context_added_watch); + g_dbus_remove_watch(connection, context_removed_watch); + g_dbus_remove_watch(connection, default_subscription_watch); + + telephony_disconnect(connection, NULL); + + connman_device_driver_unregister(&modem_driver); + connman_network_driver_unregister(&network_driver); + + dbus_connection_unref(connection); +} + +CONNMAN_PLUGIN_DEFINE(telephony, "Samsung Telephony Framework plug-in", VERSION, + CONNMAN_PLUGIN_PRIORITY_DEFAULT, telephony_init, telephony_exit) diff --git a/plugins/tist.c b/plugins/tist.c index cc2800a1..cc2800a1 100644..100755 --- a/plugins/tist.c +++ b/plugins/tist.c diff --git a/plugins/vpn.c b/plugins/vpn.c index 11bab154..11bab154 100644..100755 --- a/plugins/vpn.c +++ b/plugins/vpn.c diff --git a/plugins/wifi.c b/plugins/wifi.c index f8c22be3..f4e6d59f 100644 --- a/plugins/wifi.c +++ b/plugins/wifi.c @@ -73,7 +73,15 @@ #define P2P_LISTEN_INTERVAL 2000 #define ASSOC_STATUS_NO_CLIENT 17 +#if defined TIZEN_EXT +#define LOAD_SHAPING_MAX_RETRIES 7 +#else #define LOAD_SHAPING_MAX_RETRIES 3 +#endif + +#if defined TIZEN_EXT +#define WIFI_EAP_FAST_PAC_FILE "/var/lib/wifi/wifi.pac" /* path of Pac file for EAP-FAST */ +#endif static struct connman_technology *wifi_technology = NULL; static struct connman_technology *p2p_technology = NULL; @@ -159,10 +167,35 @@ struct wifi_data { bool p2p_connecting; bool p2p_device; int servicing; +#if defined TIZEN_EXT + int assoc_retry_count; + struct connman_network *scan_pending_network; + bool allow_full_scan; + unsigned int automaxspeed_timeout; + GSupplicantScanParams *hidden_scan_params; +#endif int disconnect_code; int assoc_code; +#if defined TIZEN_EXT_WIFI_MESH + bool mesh_interface; + struct wifi_mesh_info *mesh_info; +#endif }; +#if defined TIZEN_EXT +#include "connman.h" +#include "dbus.h" + +#define TIZEN_ASSOC_RETRY_COUNT 4 + +static gboolean wifi_first_scan = false; +static gboolean found_with_first_scan = false; +static gboolean is_wifi_notifier_registered = false; +static GHashTable *failed_bssids = NULL; +static unsigned char buff_bssid[WIFI_BSSID_LEN_MAX] = { 0, }; +#endif + + static GList *iface_list = NULL; static GList *pending_wifi_device = NULL; @@ -174,6 +207,123 @@ static int tech_set_tethering(struct connman_technology *technology, const char *identifier, const char *passphrase, const char *bridge, bool enabled); +#if defined TIZEN_EXT +#define NETCONFIG_SERVICE "net.netconfig" +#define NETCONFIG_WIFI_PATH "/net/netconfig/wifi" +#define NETCONFIG_WIFI_INTERFACE NETCONFIG_SERVICE ".wifi" + +struct enc_method_call_data { + DBusConnection *connection; + struct connman_network *network; +}; + +static struct enc_method_call_data encrypt_request_data; + +static void encryption_request_reply(DBusPendingCall *call, + void *user_data) +{ + DBusMessage *reply; + DBusError error; + DBusMessageIter args; + char *out_data; + struct connman_service *service; + gchar* encrypted_value = NULL; + struct connman_network *network = encrypt_request_data.network; + + DBG(""); + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&error); + if (dbus_set_error_from_message(&error, reply)) { + DBG("send_encryption_request() %s %s", error.name, error.message); + dbus_error_free(&error); + goto done; + } + + if (dbus_message_iter_init(reply, &args) == FALSE) + goto done; + + dbus_message_iter_get_basic(&args, &out_data); + + encrypted_value = g_strdup((const gchar *)out_data); + service = connman_service_lookup_from_network(network); + + if (!service) { + DBG("encryption result: no service"); + goto done; + } + + if (connman_service_get_favorite(service)) { + __connman_service_set_passphrase(service, encrypted_value); + __connman_service_save(service); + } else + connman_network_set_string(network, "WiFi.Passphrase", + encrypted_value); + + DBG("encryption result: succeeded"); + +done: + dbus_message_unref(reply); + dbus_pending_call_unref(call); + dbus_connection_unref(encrypt_request_data.connection); + g_free(encrypted_value); + + encrypt_request_data.connection = NULL; + encrypt_request_data.network = NULL; +} + +static int send_encryption_request(const char *passphrase, + struct connman_network *network) +{ + DBusConnection *connection = NULL; + DBusMessage *msg = NULL; + DBusPendingCall *call; + + if (!passphrase) { + DBG("Invalid parameter"); + return -EINVAL; + } + + connection = connman_dbus_get_connection(); + if (!connection) { + DBG("dbus connection does not exist"); + return -EINVAL; + } + + msg = dbus_message_new_method_call(NETCONFIG_SERVICE, NETCONFIG_WIFI_PATH, + NETCONFIG_WIFI_INTERFACE, "EncryptPassphrase"); + if (!msg) { + dbus_connection_unref(connection); + return -EINVAL; + } + + dbus_message_append_args(msg, DBUS_TYPE_STRING, &passphrase, + DBUS_TYPE_INVALID); + + if (!dbus_connection_send_with_reply(connection, msg, + &call, DBUS_TIMEOUT_USE_DEFAULT)) { + dbus_message_unref(msg); + dbus_connection_unref(connection); + return -EIO; + } + + if (!call) { + dbus_message_unref(msg); + dbus_connection_unref(connection); + return -EIO; + } + + encrypt_request_data.connection = connection; + encrypt_request_data.network = network; + + dbus_pending_call_set_notify(call, encryption_request_reply, NULL, NULL); + dbus_message_unref(msg); + + return 0; +} +#endif + static int p2p_tech_probe(struct connman_technology *technology) { p2p_technology = technology; @@ -215,6 +365,506 @@ static void add_pending_wifi_device(struct wifi_data *wifi) pending_wifi_device = g_list_append(pending_wifi_device, wifi); } +#if defined TIZEN_EXT_WIFI_MESH +struct wifi_mesh_info { + struct wifi_data *wifi; + GSupplicantInterface *interface; + struct connman_mesh *mesh; + char *parent_ifname; + char *ifname; + char *identifier; + int index; +}; + +struct mesh_change_peer_status_info { + char *peer_address; + enum connman_mesh_peer_status peer_status; + mesh_change_peer_status_cb_t callback; + void *user_data; +}; + +static struct connman_technology_driver mesh_tech_driver = { + .name = "mesh", + .type = CONNMAN_SERVICE_TYPE_MESH, +}; + +static void mesh_interface_create_callback(int result, + GSupplicantInterface *interface, + void *user_data) +{ + struct wifi_mesh_info *mesh_info = user_data; + struct wifi_data *wifi; + bool success = false; + + DBG("result %d ifname %s, mesh_info %p", result, + g_supplicant_interface_get_ifname(interface), + mesh_info); + + if (result < 0 || !mesh_info) + goto done; + + wifi = mesh_info->wifi; + + mesh_info->interface = interface; + mesh_info->identifier = connman_inet_ifaddr(mesh_info->ifname); + mesh_info->index = connman_inet_ifindex(mesh_info->ifname); + DBG("Mesh Interface identifier %s", mesh_info->identifier); + wifi->mesh_interface = true; + wifi->mesh_info = mesh_info; + g_supplicant_interface_set_data(interface, wifi); + success = true; + +done: + connman_mesh_notify_interface_create(success); +} + +static int add_mesh_interface(const char *ifname, const char *parent_ifname) +{ + GList *list; + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + const char *wifi_ifname; + bool parent_found = false; + const char *driver = "nl80211"; + + for (list = iface_list; list; list = list->next) { + wifi = list->data; + + if (!g_supplicant_interface_has_mesh(wifi->interface)) + continue; + + wifi_ifname = g_supplicant_interface_get_ifname(wifi->interface); + if (!wifi_ifname) + continue; + + if (!g_strcmp0(wifi_ifname, parent_ifname)) { + parent_found = true; + break; + } + } + + if (!parent_found) { + DBG("Parent interface %s doesn't exist", parent_ifname); + return -ENODEV; + } + + mesh_info = g_try_malloc0(sizeof(struct wifi_mesh_info)); + if (!mesh_info) + return -ENOMEM; + + mesh_info->wifi = wifi; + mesh_info->ifname = g_strdup(ifname); + mesh_info->parent_ifname = g_strdup(parent_ifname); + + g_supplicant_mesh_interface_create(ifname, driver, NULL, parent_ifname, + mesh_interface_create_callback, mesh_info); + return -EINPROGRESS; +} + +static void mesh_interface_remove_callback(int result, + GSupplicantInterface *interface, + void *user_data) +{ + struct wifi_data *wifi = user_data; + struct wifi_mesh_info *mesh_info = wifi->mesh_info; + bool success = false; + + DBG("result %d mesh_info %p", result, mesh_info); + + if (result < 0 || !mesh_info) + goto done; + + mesh_info->interface = NULL; + g_free(mesh_info->parent_ifname); + g_free(mesh_info->ifname); + g_free(mesh_info->identifier); + g_free(mesh_info); + wifi->mesh_interface = false; + wifi->mesh_info = NULL; + success = true; + +done: + connman_mesh_notify_interface_remove(success); +} + +static int remove_mesh_interface(const char *ifname) +{ + GList *list; + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + bool mesh_if_found = false; + int ret; + + for (list = iface_list; list; list = list->next) { + wifi = list->data; + + if (wifi->mesh_interface) { + mesh_if_found = true; + break; + } + } + + if (!mesh_if_found) { + DBG("Mesh interface %s doesn't exist", ifname); + return -ENODEV; + } + + mesh_info = wifi->mesh_info; + ret = g_supplicant_interface_remove(mesh_info->interface, + mesh_interface_remove_callback, wifi); + if (ret < 0) + return ret; + + return -EINPROGRESS; +} + +static void mesh_disconnect_callback(int result, + GSupplicantInterface *interface, void *user_data) +{ + struct connman_mesh *mesh = user_data; + + DBG("result %d interface %p mesh %p", result, interface, mesh); +} + +static int mesh_peer_disconnect(struct connman_mesh *mesh) +{ + GList *list; + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + bool mesh_if_found = false; + GSupplicantInterface *interface; + + for (list = iface_list; list; list = list->next) { + wifi = list->data; + + if (wifi->mesh_interface) { + mesh_if_found = true; + break; + } + } + + if (!mesh_if_found) { + DBG("Mesh interface is not created"); + return -ENODEV; + } + + mesh_info = wifi->mesh_info; + + interface = mesh_info->interface; + return g_supplicant_interface_disconnect(interface, + mesh_disconnect_callback, mesh); +} + +static void mesh_connect_callback(int result, GSupplicantInterface *interface, + void *user_data) +{ + struct connman_mesh *mesh = user_data; + DBG("mesh %p result %d", mesh, result); + + if (result < 0) + connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_FAILURE); + else + connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_ASSOCIATION); +} + +static GSupplicantSecurity mesh_network_security(const char *security) +{ + if (g_str_equal(security, "none")) + return G_SUPPLICANT_SECURITY_NONE; + else if (g_str_equal(security, "sae")) + return G_SUPPLICANT_SECURITY_SAE; + + return G_SUPPLICANT_SECURITY_UNKNOWN; +} + +static void mesh_ssid_init(GSupplicantSSID *ssid, struct connman_mesh *mesh) +{ + const char *name; + const char *security; + + if (ssid->ssid) + g_free(ssid->ssid); + + memset(ssid, 0, sizeof(*ssid)); + ssid->mode = G_SUPPLICANT_MODE_MESH; + + security = connman_mesh_get_security(mesh); + ssid->security = mesh_network_security(security); + + if (ssid->security == G_SUPPLICANT_SECURITY_SAE) + ssid->passphrase = connman_mesh_get_passphrase(mesh); + + ssid->freq = connman_mesh_get_frequency(mesh); + name = connman_mesh_get_name(mesh); + if (name) { + ssid->ssid_len = strlen(name); + ssid->ssid = g_malloc0(ssid->ssid_len + 1); + memcpy(ssid->ssid, name, ssid->ssid_len); + ssid->scan_ssid = 1; + } +} + +static int mesh_peer_connect(struct connman_mesh *mesh) +{ + GList *list; + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + bool mesh_if_found = false; + GSupplicantInterface *interface; + GSupplicantSSID *ssid; + + for (list = iface_list; list; list = list->next) { + wifi = list->data; + + if (wifi->mesh_interface) { + mesh_if_found = true; + break; + } + } + + if (!mesh_if_found) { + DBG("Mesh interface is not created"); + return -ENODEV; + } + + mesh_info = wifi->mesh_info; + + interface = mesh_info->interface; + + ssid = g_try_malloc0(sizeof(GSupplicantSSID)); + if (!ssid) + return -ENOMEM; + + mesh_info->mesh = mesh; + + mesh_ssid_init(ssid, mesh); + return g_supplicant_interface_connect(interface, ssid, + mesh_connect_callback, mesh); +} + +static void mesh_peer_change_status_callback(int result, + GSupplicantInterface *interface, + void *user_data) +{ + struct mesh_change_peer_status_info *data = user_data; + + DBG("result %d Peer Status %d", result, data->peer_status); + + if (result == 0 && data->peer_status == CONNMAN_MESH_PEER_REMOVE) { + /* WLAN_REASON_MESH_PEERING_CANCELLED = 52 */ + connman_mesh_remove_connected_peer(data->peer_address, 52); + } + + if (data->callback) + data->callback(result, data->user_data); + + g_free(data->peer_address); + g_free(data); + return; +} + +static int mesh_change_peer_status(const char *peer_address, + enum connman_mesh_peer_status status, + mesh_change_peer_status_cb_t callback, void *user_data) +{ + GList *list; + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + bool mesh_if_found = false; + GSupplicantInterface *interface; + struct mesh_change_peer_status_info *data; + const char *method; + + for (list = iface_list; list; list = list->next) { + wifi = list->data; + + if (wifi->mesh_interface) { + mesh_if_found = true; + break; + } + } + + if (!mesh_if_found) { + DBG("Mesh interface is not created"); + return -ENODEV; + } + + mesh_info = wifi->mesh_info; + + interface = mesh_info->interface; + + switch (status) { + case CONNMAN_MESH_PEER_ADD: + method = "MeshPeerAdd"; + break; + case CONNMAN_MESH_PEER_REMOVE: + method = "MeshPeerRemove"; + break; + default: + DBG("Invalid method"); + return -EINVAL; + } + + data = g_try_malloc0(sizeof(struct mesh_change_peer_status_info)); + if (data == NULL) { + DBG("Memory allocation failed"); + return -ENOMEM; + } + + data->peer_address = g_strdup(peer_address); + data->peer_status = status; + data->callback = callback; + data->user_data = user_data; + + return g_supplicant_interface_mesh_peer_change_status(interface, + mesh_peer_change_status_callback, peer_address, method, + data); +} + +static struct connman_mesh_driver mesh_driver = { + .add_interface = add_mesh_interface, + .remove_interface = remove_mesh_interface, + .connect = mesh_peer_connect, + .disconnect = mesh_peer_disconnect, + .change_peer_status = mesh_change_peer_status, +}; + +static void mesh_support(GSupplicantInterface *interface) +{ + DBG(""); + + if (!g_supplicant_interface_has_mesh(interface)) + return; + + if (connman_technology_driver_register(&mesh_tech_driver) < 0) { + DBG("Could not register Mesh technology driver"); + return; + } + + connman_mesh_driver_register(&mesh_driver); +} + +static void check_mesh_technology(void) +{ + bool mesh_exists = false; + GList *list; + + for (list = iface_list; list; list = list->next) { + struct wifi_data *w = list->data; + + if (w->interface && + g_supplicant_interface_has_mesh(w->interface)) + mesh_exists = true; + } + + if (!mesh_exists) { + connman_technology_driver_unregister(&mesh_tech_driver); + connman_mesh_driver_unregister(&mesh_driver); + } +} + +static void mesh_group_started(GSupplicantInterface *interface) +{ + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + struct connman_mesh *mesh; + const unsigned char *ssid; + unsigned int ssid_len; + char name[33]; + + ssid = g_supplicant_interface_get_mesh_group_ssid(interface, &ssid_len); + memcpy(name, ssid, ssid_len); + name[ssid_len] = '\0'; + DBG("name %s", name); + wifi = g_supplicant_interface_get_data(interface); + DBG("wifi %p", wifi); + + if (!wifi) + return; + + mesh_info = wifi->mesh_info; + if (!mesh_info) + return; + + mesh = mesh_info->mesh; + if (!mesh) + return; + + connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_CONFIGURATION); +} + +static void mesh_group_removed(GSupplicantInterface *interface) +{ + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + struct connman_mesh *mesh; + const unsigned char *ssid; + unsigned int ssid_len; + int disconnect_reason; + char name[33]; + + ssid = g_supplicant_interface_get_mesh_group_ssid(interface, &ssid_len); + memcpy(name, ssid, ssid_len); + name[ssid_len] = '\0'; + DBG("name %s", name); + + disconnect_reason = g_supplicant_mesh_get_disconnect_reason(interface); + DBG("Disconnect Reason %d", disconnect_reason); + + wifi = g_supplicant_interface_get_data(interface); + DBG("wifi %p", wifi); + + if (!wifi) + return; + + mesh_info = wifi->mesh_info; + if (!mesh_info) + return; + + mesh = connman_get_connected_mesh_from_name(name); + if (!mesh) { + DBG("%s is not connected", name); + mesh = connman_get_connecting_mesh_from_name(name); + if (!mesh) { + DBG("%s is not connecting", name); + return; + } + } + + connman_mesh_peer_set_disconnect_reason(mesh, disconnect_reason); + connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_DISCONNECT); +} + +static void mesh_peer_connected(GSupplicantMeshPeer *mesh_peer) +{ + const char *peer_address; + + peer_address = g_supplicant_mesh_peer_get_address(mesh_peer); + + if (!peer_address) + return; + + DBG("Peer %s connected", peer_address); + connman_mesh_add_connected_peer(peer_address); +} + +static void mesh_peer_disconnected(GSupplicantMeshPeer *mesh_peer) +{ + const char *peer_address; + int reason; + + peer_address = g_supplicant_mesh_peer_get_address(mesh_peer); + + if (!peer_address) + return; + + reason = g_supplicant_mesh_peer_get_disconnect_reason(mesh_peer); + + DBG("Peer %s disconnected with reason %d", peer_address, reason); + connman_mesh_remove_connected_peer(peer_address, reason); +} +#endif + static struct wifi_data *get_pending_wifi_data(const char *ifname) { GList *list; @@ -552,6 +1202,11 @@ static void register_peer_service_cb(int result, struct wifi_data *wifi = g_supplicant_interface_get_data(iface); struct peer_service_registration *reg_data = user_data; +#if defined TIZEN_EXT + if (!wifi) + return; +#endif + DBG(""); if (result == 0) @@ -876,6 +1531,35 @@ static void check_p2p_technology(void) } } +struct last_connected { + GTimeVal modified; + gchar *ssid; + int freq; +}; + +static gint sort_entry(gconstpointer a, gconstpointer b, gpointer user_data) +{ + GTimeVal *aval = (GTimeVal *)a; + GTimeVal *bval = (GTimeVal *)b; + + /* Note that the sort order is descending */ + if (aval->tv_sec < bval->tv_sec) + return 1; + + if (aval->tv_sec > bval->tv_sec) + return -1; + + return 0; +} + +static void free_entry(gpointer data) +{ + struct last_connected *entry = data; + + g_free(entry->ssid); + g_free(entry); +} + static void wifi_remove(struct connman_device *device) { struct wifi_data *wifi = connman_device_get_data(device); @@ -893,6 +1577,9 @@ static void wifi_remove(struct connman_device *device) iface_list = g_list_remove(iface_list, wifi); check_p2p_technology(); +#if defined TIZEN_EXT_WIFI_MESH + check_mesh_technology(); +#endif remove_pending_wifi_device(wifi); @@ -904,6 +1591,13 @@ static void wifi_remove(struct connman_device *device) if (wifi->p2p_connection_timeout) g_source_remove(wifi->p2p_connection_timeout); +#if defined TIZEN_EXT + if (wifi->automaxspeed_timeout != 0) { + g_source_remove(wifi->automaxspeed_timeout); + wifi->automaxspeed_timeout = 0; + } +#endif + remove_networks(device, wifi); remove_peers(wifi); @@ -918,6 +1612,16 @@ static void wifi_remove(struct connman_device *device) if (wifi->scan_params) g_supplicant_free_scan_params(wifi->scan_params); +#if defined TIZEN_EXT + if (wifi->hidden_scan_params) { + while (wifi->hidden_scan_params->ssids) { + struct scan_ssid *ssid; + ssid = wifi->hidden_scan_params->ssids->data; + wifi->hidden_scan_params->ssids = g_slist_remove(wifi->hidden_scan_params->ssids, ssid); + } + g_supplicant_free_scan_params(wifi->hidden_scan_params); + } +#endif g_free(wifi->autoscan); g_free(wifi->identifier); @@ -1043,12 +1747,25 @@ static int get_hidden_connections(GSupplicantScanParams *scan_data) { struct connman_config_entry **entries; GKeyFile *keyfile; +#if defined TIZEN_EXT + gchar **services = NULL; +#else gchar **services; +#endif /* defined TIZEN_EXT */ char *ssid, *name; int i, ret; bool value; int num_ssids = 0, add_param_failed = 0; +#if defined TIZEN_EXT + GSequenceIter *iter; + GSequence *latest_list; + struct last_connected *entry; + GTimeVal modified; + latest_list = g_sequence_new(free_entry); + if (!latest_list) + goto out; +#endif services = connman_storage_get_services(); for (i = 0; services && services[i]; i++) { if (strncmp(services[i], "wifi_", 5) != 0) @@ -1072,12 +1789,46 @@ static int get_hidden_connections(GSupplicantScanParams *scan_data) continue; } +#if defined TIZEN_EXT + value = g_key_file_get_boolean(keyfile, + services[i], "AutoConnect", NULL); + if (!value) { + g_key_file_free(keyfile); + continue; + } + + gchar *str = g_key_file_get_string(keyfile, + services[i], "Modified", NULL); + if (!str) { + g_key_file_free(keyfile); + continue; + } + g_time_val_from_iso8601(str, &modified); + g_free(str); +#endif + ssid = g_key_file_get_string(keyfile, services[i], "SSID", NULL); name = g_key_file_get_string(keyfile, services[i], "Name", NULL); +#if defined TIZEN_EXT + entry = g_try_new(struct last_connected, 1); + if (!entry) { + g_sequence_free(latest_list); + g_free(ssid); + g_free(name); + g_key_file_free(keyfile); + goto out; + } + + entry->modified = modified; + entry->ssid = ssid; + + g_sequence_insert_sorted(latest_list, entry, + sort_entry, NULL); +#else ret = add_scan_param(ssid, NULL, 0, 0, scan_data, 0, name); if (ret < 0) add_param_failed++; @@ -1085,10 +1836,30 @@ static int get_hidden_connections(GSupplicantScanParams *scan_data) num_ssids++; g_free(ssid); +#endif g_free(name); g_key_file_free(keyfile); } +#if defined TIZEN_EXT + gint length = g_sequence_get_length(latest_list); + iter = g_sequence_get_begin_iter(latest_list); + + for (i = 0; i < length; i++) { + entry = g_sequence_get(iter); + + ret = add_scan_param(entry->ssid, NULL, 0, 0, scan_data, 0, entry->ssid); + if (ret < 0) + add_param_failed++; + else if (ret > 0) + num_ssids++; + + iter = g_sequence_iter_next(iter); + } + + g_sequence_free(latest_list); +out: +#endif /* * Check if there are any hidden AP that needs to be provisioned. */ @@ -1145,6 +1916,22 @@ static int get_hidden_connections_params(struct wifi_data *wifi, DBG("max ssids %d", driver_max_ssids); +#if defined TIZEN_EXT + if (!wifi->hidden_scan_params) { + wifi->hidden_scan_params = g_try_malloc0(sizeof(GSupplicantScanParams)); + if (!wifi->hidden_scan_params) + return 0; + + if (get_hidden_connections(wifi->hidden_scan_params) == 0) { + g_supplicant_free_scan_params(wifi->hidden_scan_params); + wifi->hidden_scan_params = NULL; + + return 0; + } + } + + orig_params = wifi->hidden_scan_params; +#else if (!wifi->scan_params) { wifi->scan_params = g_try_malloc0(sizeof(GSupplicantScanParams)); if (!wifi->scan_params) @@ -1159,12 +1946,17 @@ static int get_hidden_connections_params(struct wifi_data *wifi, } orig_params = wifi->scan_params; +#endif /* Let's transfer driver_max_ssids params */ for (i = 0; i < driver_max_ssids; i++) { struct scan_ssid *ssid; +#if defined TIZEN_EXT + if (!wifi->hidden_scan_params->ssids) +#else if (!wifi->scan_params->ssids) +#endif break; ssid = orig_params->ssids->data; @@ -1192,8 +1984,13 @@ static int get_hidden_connections_params(struct wifi_data *wifi, err: g_slist_free_full(scan_params->ssids, g_free); +#if defined TIZEN_EXT + g_supplicant_free_scan_params(wifi->hidden_scan_params); + wifi->hidden_scan_params = NULL; +#else g_supplicant_free_scan_params(wifi->scan_params); wifi->scan_params = NULL; +#endif return 0; } @@ -1212,7 +2009,12 @@ static int throw_wifi_scan(struct connman_device *device, if (wifi->tethering) return -EBUSY; +#if defined TIZEN_EXT + if (connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_WIFI) + && !wifi->allow_full_scan) +#else if (connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_WIFI)) +#endif return -EALREADY; connman_device_ref(device); @@ -1241,6 +2043,48 @@ static void hidden_free(struct hidden_params *hidden) g_free(hidden); } +#if defined TIZEN_EXT +static void service_state_changed(struct connman_service *service, + enum connman_service_state state); + +static int network_connect(struct connman_network *network); + +static struct connman_notifier notifier = { + .name = "wifi", + .priority = CONNMAN_NOTIFIER_PRIORITY_DEFAULT, + .service_state_changed = service_state_changed, +}; + +static void service_state_changed(struct connman_service *service, + enum connman_service_state state) +{ + enum connman_service_type type; + + type = connman_service_get_type(service); + if (type != CONNMAN_SERVICE_TYPE_WIFI) + return; + + DBG("service %p state %d", service, state); + + switch (state) { + case CONNMAN_SERVICE_STATE_READY: + case CONNMAN_SERVICE_STATE_ONLINE: + case CONNMAN_SERVICE_STATE_FAILURE: + connman_notifier_unregister(¬ifier); + is_wifi_notifier_registered = FALSE; + + __connman_device_request_scan(type); + break; + + default: + break; + } +} + +static void scan_callback_hidden(int result, + GSupplicantInterface *interface, void *user_data); +#endif + static void scan_callback(int result, GSupplicantInterface *interface, void *user_data) { @@ -1261,6 +2105,13 @@ static void scan_callback(int result, GSupplicantInterface *interface, g_supplicant_free_scan_params(wifi->scan_params); wifi->scan_params = NULL; } + +#if defined TIZEN_EXT + if (wifi->hidden_scan_params && !wifi->hidden_scan_params->ssids) { + g_supplicant_free_scan_params(wifi->hidden_scan_params); + wifi->hidden_scan_params = NULL; + } +#endif } if (result < 0) @@ -1286,6 +2137,22 @@ static void scan_callback(int result, GSupplicantInterface *interface, return scan_callback(ret, interface, user_data); } +#if defined TIZEN_EXT + if (wifi && wifi->allow_full_scan) { + int ret; + DBG("Trigger Full Channel Scan"); + wifi->allow_full_scan = FALSE; + + ret = g_supplicant_interface_scan(wifi->interface, NULL, + scan_callback_hidden, device); + if (ret == 0) + return; + + /* On error, let's recall scan_callback, which will cleanup */ + return scan_callback(ret, interface, user_data); + } +#endif + scanning = connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_WIFI); if (scanning) { @@ -1294,6 +2161,9 @@ static void scan_callback(int result, GSupplicantInterface *interface, } if (result != -ENOLINK) +#if defined TIZEN_EXT + if (result != -EIO) +#endif start_autoscan(device); /* @@ -1305,6 +2175,23 @@ static void scan_callback(int result, GSupplicantInterface *interface, if (scanning) connman_device_unref(device); + +#if defined TIZEN_EXT + if (wifi && wifi->scan_pending_network && result != -EIO) { + network_connect(wifi->scan_pending_network); + wifi->scan_pending_network = NULL; + connman_network_set_connecting(wifi->network); + } + + if (is_wifi_notifier_registered != true && + wifi_first_scan == true && found_with_first_scan == true) { + wifi_first_scan = false; + found_with_first_scan = false; + + connman_notifier_register(¬ifier); + is_wifi_notifier_registered = true; + } +#endif } static void scan_callback_hidden(int result, @@ -1331,7 +2218,11 @@ static void scan_callback_hidden(int result, if (get_hidden_connections_params(wifi, scan_params) > 0) { ret = g_supplicant_interface_scan(wifi->interface, scan_params, +#if defined TIZEN_EXT + scan_callback, +#else scan_callback_hidden, +#endif device); if (ret == 0) return; @@ -1361,7 +2252,11 @@ static gboolean autoscan_timeout(gpointer data) } else interval = autoscan->interval * autoscan->base; +#if defined TIZEN_EXT + if (autoscan->interval >= autoscan->limit) +#else if (interval > autoscan->limit) +#endif interval = autoscan->limit; throw_wifi_scan(wifi->device, scan_callback_hidden); @@ -1593,6 +2488,13 @@ static int wifi_disable(struct connman_device *device) connman_device_unref(wifi->device); } +#if defined TIZEN_EXT + if (wifi->automaxspeed_timeout != 0) { + g_source_remove(wifi->automaxspeed_timeout); + wifi->automaxspeed_timeout = 0; + } +#endif + /* In case of a user scan, device is still referenced */ if (connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_WIFI)) { connman_device_set_scanning(device, @@ -1603,6 +2505,15 @@ static int wifi_disable(struct connman_device *device) remove_networks(device, wifi); remove_peers(wifi); +#if defined TIZEN_EXT + wifi->scan_pending_network = NULL; + + if (is_wifi_notifier_registered == true) { + connman_notifier_unregister(¬ifier); + is_wifi_notifier_registered = false; + } +#endif + ret = g_supplicant_interface_remove(wifi->interface, NULL, NULL); if (ret < 0) return ret; @@ -1610,35 +2521,6 @@ static int wifi_disable(struct connman_device *device) return -EINPROGRESS; } -struct last_connected { - GTimeVal modified; - gchar *ssid; - int freq; -}; - -static gint sort_entry(gconstpointer a, gconstpointer b, gpointer user_data) -{ - GTimeVal *aval = (GTimeVal *)a; - GTimeVal *bval = (GTimeVal *)b; - - /* Note that the sort order is descending */ - if (aval->tv_sec < bval->tv_sec) - return 1; - - if (aval->tv_sec > bval->tv_sec) - return -1; - - return 0; -} - -static void free_entry(gpointer data) -{ - struct last_connected *entry = data; - - g_free(entry->ssid); - g_free(entry); -} - static int get_latest_connections(int max_ssids, GSupplicantScanParams *scan_data) { @@ -1849,6 +2731,341 @@ static int p2p_find(struct connman_device *device) return ret; } +#if defined TIZEN_EXT +static void specific_scan_callback(int result, GSupplicantInterface *interface, + void *user_data) +{ + struct connman_device *device = user_data; + struct wifi_data *wifi = connman_device_get_data(device); + bool scanning; + + DBG("result %d wifi %p", result, wifi); + + if (wifi && wifi->scan_params) { + g_supplicant_free_scan_params(wifi->scan_params); + wifi->scan_params = NULL; + } + + scanning = connman_device_get_scanning(device, + CONNMAN_SERVICE_TYPE_WIFI); + if (scanning) { + connman_device_set_scanning(device, + CONNMAN_SERVICE_TYPE_WIFI, false); + connman_device_unref(device); + } +} + +static int wifi_specific_scan(enum connman_service_type type, + struct connman_device *device, int scan_type, + GSList *specific_scan_list, void *user_data) +{ + GSList *list = NULL; + char *ssid = NULL; + struct wifi_data *wifi = connman_device_get_data(device); + GSupplicantScanParams *scan_params = NULL; + struct scan_ssid *scan_ssid = NULL; + bool scanning; + int ret; + int freq; + int count = 0; + + if (!wifi) + return -ENODEV; + + if (wifi->p2p_device) + return 0; + + if (type == CONNMAN_SERVICE_TYPE_P2P) + return p2p_find(device); + + if (wifi->tethering) + return 0; + + scanning = + connman_device_get_scanning(device, + CONNMAN_SERVICE_TYPE_WIFI); + if (scanning) + return -EALREADY; + + DBG("scan_type: %d", scan_type); + if (scan_type == CONNMAN_MULTI_SCAN_SSID) { /* ssid based scan */ + scan_params = g_try_malloc0(sizeof(GSupplicantScanParams)); + if (!scan_params) { + DBG("Failed to allocate memory."); + return -ENOMEM; + } + + for (list = specific_scan_list; list; list = list->next) { + ssid = (char *)list->data; + int ssid_len = strlen(ssid); + + scan_ssid = g_try_new0(struct scan_ssid, 1); + if (!scan_ssid) { + DBG("Failed to allocate memory."); + g_supplicant_free_scan_params(scan_params); + return -ENOMEM; + } + + memcpy(scan_ssid->ssid, ssid, (ssid_len + 1)); + /* DBG("scan ssid %s len: %d", scan_ssid->ssid, ssid_len); */ + scan_ssid->ssid_len = ssid_len; + scan_params->ssids = g_slist_prepend(scan_params->ssids, scan_ssid); + count++; + } + scan_params->num_ssids = count; + + } else if (scan_type == CONNMAN_MULTI_SCAN_FREQ) { /* frequency based scan */ + + scan_params = g_try_malloc0(sizeof(GSupplicantScanParams)); + if (!scan_params) { + DBG("Failed to allocate memory."); + return -ENOMEM; + } + + guint num_freqs = g_slist_length(specific_scan_list); + DBG("num_freqs: %d", num_freqs); + + scan_params->freqs = g_try_new0(uint16_t, num_freqs); + if (!scan_params->freqs) { + DBG("Failed to allocate memory."); + g_free(scan_params); + return -ENOMEM; + } + + count = 0; + for (list = specific_scan_list; list; list = list->next) { + freq = (int)list->data; + + scan_params->freqs[count] = freq; + DBG("scan_params->freqs[%d]: %d", count, scan_params->freqs[count]); + count++; + } + scan_params->num_freqs = count; + + } else if (scan_type == CONNMAN_MULTI_SCAN_SSID_FREQ) { /* SSID & Frequency mixed scan */ + int freq_count, ap_count; + scan_params = g_try_malloc0(sizeof(GSupplicantScanParams)); + if (!scan_params) { + DBG("Failed to allocate memory."); + return -ENOMEM; + } + + guint size = g_slist_length(specific_scan_list); + + scan_params->freqs = g_try_new0(uint16_t, size/2); + if (!scan_params->freqs) { + DBG("Failed to allocate memory."); + g_free(scan_params); + return -ENOMEM; + } + + ap_count = freq_count = 0; + for (list = specific_scan_list; list; list = list->next) { + if (((connman_multi_scan_ap_s *)list->data)->flag == true) { /** ssid */ + ssid = ((connman_multi_scan_ap_s *)list->data)->str; + int ssid_len = strlen(ssid); + + scan_ssid = g_try_new0(struct scan_ssid, 1); + if (!scan_ssid) { + DBG("Failed to allocate memory."); + g_supplicant_free_scan_params(scan_params); + return -ENOMEM; + } + + memcpy(scan_ssid->ssid, ssid, (ssid_len + 1)); + /* DBG("scan ssid %s len: %d", scan_ssid->ssid, ssid_len); */ + scan_ssid->ssid_len = ssid_len; + scan_params->ssids = g_slist_prepend(scan_params->ssids, scan_ssid); + ap_count++; + + } else { /* freq */ + freq = atoi(((connman_multi_scan_ap_s *)list->data)->str); + scan_params->freqs[freq_count] = freq; + DBG("scan_params->freqs[%d]: %d", freq_count, scan_params->freqs[freq_count]); + freq_count++; + } + } + scan_params->num_ssids = ap_count; + scan_params->num_freqs = freq_count; + } else { + DBG("Invalid scan"); + return -EINVAL; + } + + reset_autoscan(device); + connman_device_ref(device); + + ret = g_supplicant_interface_scan(wifi->interface, scan_params, + specific_scan_callback, device); + + if (ret == 0) { + connman_device_set_scanning(device, + CONNMAN_SERVICE_TYPE_WIFI, true); + } else { + g_supplicant_free_scan_params(scan_params); + connman_device_unref(device); + } + + return ret; +} +#endif + +#if defined TIZEN_EXT_WIFI_MESH +static void mesh_scan_callback(int result, GSupplicantInterface *interface, + void *user_data) +{ + struct connman_device *device = user_data; + struct wifi_data *wifi = connman_device_get_data(device); + bool scanning; + + DBG("result %d wifi %p", result, wifi); + + scanning = connman_device_get_scanning(device, + CONNMAN_SERVICE_TYPE_MESH); + if (scanning) + connman_device_set_scanning(device, + CONNMAN_SERVICE_TYPE_MESH, false); + + if (scanning) + connman_device_unref(device); +} + +static int mesh_scan(struct connman_device *device) +{ + struct wifi_data *wifi; + struct wifi_mesh_info *mesh_info; + int ret; + + DBG(""); + + wifi = connman_device_get_data(device); + + if (!wifi->mesh_interface) + return -ENOTSUP; + + mesh_info = wifi->mesh_info; + reset_autoscan(device); + connman_device_ref(device); + + ret = g_supplicant_interface_scan(mesh_info->interface, NULL, + mesh_scan_callback, device); + if (ret) + connman_device_unref(device); + else + connman_device_set_scanning(device, + CONNMAN_SERVICE_TYPE_MESH, true); + + return ret; +} + +static void abort_scan_callback(int result, GSupplicantInterface *interface, + void *user_data) +{ + struct connman_device *device = user_data; + struct wifi_data *wifi = connman_device_get_data(device); + + DBG("result %d wifi %p", result, wifi); + + __connman_technology_notify_abort_scan(CONNMAN_SERVICE_TYPE_MESH, result); +} + +static int mesh_abort_scan(enum connman_service_type type, + struct connman_device *device) +{ + struct wifi_data *wifi = connman_device_get_data(device); + struct wifi_mesh_info *mesh_info; + bool scanning; + int ret; + + if (!wifi || !wifi->mesh_interface) + return -ENODEV; + + if (type != CONNMAN_SERVICE_TYPE_MESH) + return -EINVAL; + + mesh_info = wifi->mesh_info; + + scanning = connman_device_get_scanning(device, + CONNMAN_SERVICE_TYPE_MESH); + if (!scanning) + return -EEXIST; + + ret = g_supplicant_interface_abort_scan(mesh_info->interface, + abort_scan_callback, device); + + return ret; +} + +static int mesh_specific_scan(enum connman_service_type type, + struct connman_device *device, const char *ssid, + unsigned int freq, void *user_data) +{ + struct wifi_data *wifi = connman_device_get_data(device); + GSupplicantScanParams *scan_params = NULL; + struct wifi_mesh_info *mesh_info; + struct scan_ssid *scan_ssid; + bool scanning; + int ret; + + if (!wifi || !wifi->mesh_interface) + return -ENODEV; + + if (type != CONNMAN_SERVICE_TYPE_MESH) + return -EINVAL; + + if (wifi->p2p_device) + return 0; + + mesh_info = wifi->mesh_info; + + scanning = connman_device_get_scanning(device, + CONNMAN_SERVICE_TYPE_MESH); + if (scanning) + return -EALREADY; + + scan_params = g_try_malloc0(sizeof(GSupplicantScanParams)); + if (!scan_params) + return -ENOMEM; + + scan_ssid = g_try_new(struct scan_ssid, 1); + if (!scan_ssid) { + g_free(scan_params); + return -ENOMEM; + } + + scan_ssid->ssid_len = strlen(ssid); + memcpy(scan_ssid->ssid, ssid, scan_ssid->ssid_len); + scan_params->ssids = g_slist_prepend(scan_params->ssids, scan_ssid); + scan_params->num_ssids = 1; + + scan_params->freqs = g_try_new(uint16_t, 1); + if (!scan_params->freqs) { + g_slist_free_full(scan_params->ssids, g_free); + g_free(scan_params); + return -ENOMEM; + } + + scan_params->freqs[0] = freq; + scan_params->num_freqs = 1; + + reset_autoscan(device); + connman_device_ref(device); + + ret = g_supplicant_interface_scan(mesh_info->interface, scan_params, + mesh_scan_callback, device); + + if (ret == 0) { + connman_device_set_scanning(device, + CONNMAN_SERVICE_TYPE_MESH, true); + } else { + g_supplicant_free_scan_params(scan_params); + connman_device_unref(device); + } + + return ret; +} +#endif + /* * Note that the hidden scan is only used when connecting to this specific * hidden AP first time. It is not used when system autoconnects to hidden AP. @@ -1877,6 +3094,11 @@ static int wifi_scan(struct connman_device *device, if (params->type == CONNMAN_SERVICE_TYPE_P2P) return p2p_find(device); +#if defined TIZEN_EXT_WIFI_MESH + if (params->type == CONNMAN_SERVICE_TYPE_MESH) + return mesh_scan(device); +#endif + DBG("device %p wifi %p hidden ssid %s", device, wifi->interface, params->ssid); @@ -1967,6 +3189,14 @@ static int wifi_scan(struct connman_device *device, if (ret == 0) { connman_device_set_scanning(device, CONNMAN_SERVICE_TYPE_WIFI, true); +#if defined TIZEN_EXT + /*To allow the Full Scan after ssid based scan, set the flag here + It is required because Tizen does not use the ConnMan specific + backgroung Scan feature.Tizen has added the BG Scan feature in + net-config. To sync with up ConnMan, we need to issue the Full Scan + after SSID specific scan.*/ + wifi->allow_full_scan = TRUE; +#endif } else { g_supplicant_free_scan_params(scan_params); connman_device_unref(device); @@ -2039,6 +3269,13 @@ static struct connman_device_driver wifi_ng_driver = { .scan = wifi_scan, .stop_scan = wifi_stop_scan, .set_regdom = wifi_set_regdom, +#if defined TIZEN_EXT + .specific_scan = wifi_specific_scan, +#endif +#if defined TIZEN_EXT_WIFI_MESH + .abort_scan = mesh_abort_scan, + .mesh_specific_scan = mesh_specific_scan, +#endif }; static void system_ready(void) @@ -2078,15 +3315,44 @@ static void network_remove(struct connman_network *network) return; wifi->network = NULL; + +#if defined TIZEN_EXT + wifi->disconnecting = false; + + if (wifi->pending_network == network) + wifi->pending_network = NULL; + + if (wifi->scan_pending_network == network) + wifi->scan_pending_network = NULL; +#endif } static void connect_callback(int result, GSupplicantInterface *interface, void *user_data) { +#if defined TIZEN_EXT + GList *list; + struct wifi_data *wifi; +#endif struct connman_network *network = user_data; DBG("network %p result %d", network, result); +#if defined TIZEN_EXT + set_connman_bssid(RESET_BSSID, NULL); + + for (list = iface_list; list; list = list->next) { + wifi = list->data; + + if (wifi && wifi->network == network) + goto found; + } + + /* wifi_data may be invalid because wifi is already disabled */ + return; + +found: +#endif if (result == -ENOKEY) { connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY); @@ -2112,21 +3378,63 @@ static GSupplicantSecurity network_security(const char *security) return G_SUPPLICANT_SECURITY_PSK; else if (g_str_equal(security, "ieee8021x")) return G_SUPPLICANT_SECURITY_IEEE8021X; +#if defined TIZEN_EXT + else if (g_str_equal(security, "ft_psk") == TRUE) + return G_SUPPLICANT_SECURITY_FT_PSK; + else if (g_str_equal(security, "ft_ieee8021x") == TRUE) + return G_SUPPLICANT_SECURITY_FT_IEEE8021X; + else if (g_str_equal(security, "sae")) + return G_SUPPLICANT_SECURITY_SAE; + else if (g_str_equal(security, "owe")) + return G_SUPPLICANT_SECURITY_OWE; +#endif return G_SUPPLICANT_SECURITY_UNKNOWN; } +#if defined TIZEN_EXT +static GSupplicantEapKeymgmt network_eap_keymgmt(const char *security) +{ + if (security == NULL) + return G_SUPPLICANT_EAP_KEYMGMT_NONE; + + if (g_str_equal(security, "FT") == TRUE) + return G_SUPPLICANT_EAP_KEYMGMT_FT; + else if (g_str_equal(security, "CCKM") == TRUE) + return G_SUPPLICANT_EAP_KEYMGMT_CCKM; + + return G_SUPPLICANT_EAP_KEYMGMT_NONE; +} +#endif + static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network) { const char *security; +#if defined TIZEN_EXT + const void *ssid_data; +#endif memset(ssid, 0, sizeof(*ssid)); ssid->mode = G_SUPPLICANT_MODE_INFRA; +#if defined TIZEN_EXT + ssid_data = connman_network_get_blob(network, "WiFi.SSID", + &ssid->ssid_len); + ssid->ssid = g_try_malloc0(ssid->ssid_len); + + if (!ssid->ssid) + ssid->ssid_len = 0; + else + memcpy(ssid->ssid, ssid_data, ssid->ssid_len); +#else ssid->ssid = connman_network_get_blob(network, "WiFi.SSID", &ssid->ssid_len); +#endif ssid->scan_ssid = 1; security = connman_network_get_string(network, "WiFi.Security"); ssid->security = network_security(security); +#if defined TIZEN_EXT + ssid->ieee80211w = 1; +#endif ssid->passphrase = connman_network_get_string(network, "WiFi.Passphrase"); @@ -2173,6 +3481,72 @@ static void ssid_init(GSupplicantSSID *ssid, struct connman_network *network) ssid->use_wps = connman_network_get_bool(network, "WiFi.UseWPS"); ssid->pin_wps = connman_network_get_string(network, "WiFi.PinWPS"); +#if defined TIZEN_EXT + if (set_connman_bssid(CHECK_BSSID, NULL) == 6) { + ssid->bssid_for_connect_len = 6; + set_connman_bssid(GET_BSSID, (char *)ssid->bssid_for_connect); + DBG("BSSID : %02x:%02x:%02x:%02x:%02x:%02x", + ssid->bssid_for_connect[0], ssid->bssid_for_connect[1], + ssid->bssid_for_connect[2], ssid->bssid_for_connect[3], + ssid->bssid_for_connect[4], ssid->bssid_for_connect[5]); + } else { + ssid->freq = connman_network_get_frequency(network); + } + + GSList *bssid_list = (GSList *)connman_network_get_bssid_list(network); + if (bssid_list && g_slist_length(bssid_list) > 1) { + + /* If there are more than one bssid, + * the user-specified bssid is tried only once at the beginning. + * After that, the bssids in the list are tried in order. + */ + if (set_connman_bssid(CHECK_BSSID, NULL) == 6) { + set_connman_bssid(RESET_BSSID, NULL); + goto done; + } + + GSList *list; + char buff[MAC_ADDRESS_LENGTH]; + for (list = bssid_list; list; list = list->next) { + struct connman_bssids * bssids = (struct connman_bssids *)list->data; + + g_snprintf(buff, MAC_ADDRESS_LENGTH, "%02x:%02x:%02x:%02x:%02x:%02x", + bssids->bssid[0], bssids->bssid[1], bssids->bssid[2], + bssids->bssid[3], bssids->bssid[4], bssids->bssid[5]); + buff[MAC_ADDRESS_LENGTH - 1] = '\0'; + + gchar *curr_bssid = g_strdup((const gchar *)buff); + + if (g_hash_table_contains(failed_bssids, curr_bssid)) { + DBG("bssid match, try next bssid"); + g_free(curr_bssid); + continue; + } else { + g_hash_table_add(failed_bssids, curr_bssid); + + memcpy(buff_bssid, bssids->bssid, WIFI_BSSID_LEN_MAX); + ssid->bssid = buff_bssid; + ssid->freq = (unsigned int)bssids->frequency; + break; + } + } + + if (!list) { + ssid->bssid = connman_network_get_bssid(network); + g_hash_table_remove_all(failed_bssids); + } + } else + ssid->bssid = connman_network_get_bssid(network); + +done: + ssid->eap_keymgmt = network_eap_keymgmt( + connman_network_get_string(network, "WiFi.KeymgmtType")); + ssid->phase1 = connman_network_get_string(network, "WiFi.Phase1"); + + if(g_strcmp0(ssid->eap, "fast") == 0) + ssid->pac_file = g_strdup(WIFI_EAP_FAST_PAC_FILE); +#endif + if (connman_setting_get_bool("BackgroundScanning")) ssid->bgscan = BGSCAN_DEFAULT; } @@ -2203,10 +3577,16 @@ static int network_connect(struct connman_network *network) if (wifi->disconnecting) { wifi->pending_network = network; +#if defined TIZEN_EXT + g_free(ssid->ssid); +#endif g_free(ssid); } else { wifi->network = connman_network_ref(network); wifi->retries = 0; +#if defined TIZEN_EXT + wifi->scan_pending_network = NULL; +#endif return g_supplicant_interface_connect(interface, ssid, connect_callback, network); @@ -2218,7 +3598,30 @@ static int network_connect(struct connman_network *network) static void disconnect_callback(int result, GSupplicantInterface *interface, void *user_data) { +#if defined TIZEN_EXT + GList *list; + struct wifi_data *wifi; + struct connman_network *network = user_data; + + DBG("network %p result %d", network, result); + + for (list = iface_list; list; list = list->next) { + wifi = list->data; + + if (wifi->network == NULL && wifi->disconnecting == true) + wifi->disconnecting = false; + + if (wifi->network == network) + goto found; + } + + /* wifi_data may be invalid because wifi is already disabled */ + return; + +found: +#else struct wifi_data *wifi = user_data; +#endif DBG("result %d supplicant interface %p wifi %p", result, interface, wifi); @@ -2248,6 +3651,9 @@ static int network_disconnect(struct connman_network *network) struct connman_device *device = connman_network_get_device(network); struct wifi_data *wifi; int err; +#if defined TIZEN_EXT + struct connman_service *service; +#endif DBG("network %p", network); @@ -2255,6 +3661,29 @@ static int network_disconnect(struct connman_network *network) if (!wifi || !wifi->interface) return -ENODEV; +#if defined TIZEN_EXT + if (connman_network_get_associating(network) == true) { + connman_network_clear_associating(network); + connman_network_set_bool(network, "WiFi.UseWPS", false); + } else { + service = connman_service_lookup_from_network(network); + + if (service != NULL && + (__connman_service_is_connected_state(service, + CONNMAN_IPCONFIG_TYPE_IPV4) == false && + __connman_service_is_connected_state(service, + CONNMAN_IPCONFIG_TYPE_IPV6) == false) && + (connman_service_get_favorite(service) == false)) + __connman_service_set_passphrase(service, NULL); + } + + if (wifi->pending_network == network) + wifi->pending_network = NULL; + + if (wifi->scan_pending_network == network) + wifi->scan_pending_network = NULL; + +#endif connman_network_set_associating(network, false); if (wifi->disconnecting) @@ -2262,14 +3691,150 @@ static int network_disconnect(struct connman_network *network) wifi->disconnecting = true; +#if defined TIZEN_EXT + err = g_supplicant_interface_disconnect(wifi->interface, + disconnect_callback, network); +#else err = g_supplicant_interface_disconnect(wifi->interface, disconnect_callback, wifi); +#endif + if (err < 0) wifi->disconnecting = false; return err; } +#if defined TIZEN_EXT +static void set_connection_mode(struct connman_network *network, + int linkspeed) +{ + ieee80211_modes_e phy_mode; + connection_mode_e conn_mode; + + phy_mode = connman_network_get_phy_mode(network); + switch (phy_mode) { + case IEEE80211_MODE_B: + if (linkspeed > 0 && linkspeed <= 11) + conn_mode = CONNECTION_MODE_IEEE80211B; + else + conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN; + + break; + case IEEE80211_MODE_BG: + if (linkspeed > 0 && linkspeed <= 11) + conn_mode = CONNECTION_MODE_IEEE80211B; + else if (linkspeed > 11 && linkspeed <= 54) + conn_mode = CONNECTION_MODE_IEEE80211G; + else + conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN; + + break; + case IEEE80211_MODE_BGN: + if (linkspeed > 0 && linkspeed <= 11) + conn_mode = CONNECTION_MODE_IEEE80211B; + else if (linkspeed > 11 && linkspeed <= 54) + conn_mode = CONNECTION_MODE_IEEE80211G; + else if (linkspeed > 54 && linkspeed <= 450) + conn_mode = CONNECTION_MODE_IEEE80211N; + else + conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN; + + break; + case IEEE80211_MODE_A: + if (linkspeed > 0 && linkspeed <= 54) + conn_mode = CONNECTION_MODE_IEEE80211A; + else + conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN; + + break; + case IEEE80211_MODE_AN: + if (linkspeed > 0 && linkspeed <= 54) + conn_mode = CONNECTION_MODE_IEEE80211A; + else if (linkspeed > 54 && linkspeed <= 450) + conn_mode = CONNECTION_MODE_IEEE80211N; + else + conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN; + + break; + case IEEE80211_MODE_ANAC: + if (linkspeed > 0 && linkspeed <= 54) + conn_mode = CONNECTION_MODE_IEEE80211A; + else if (linkspeed > 54 && linkspeed <= 450) + conn_mode = CONNECTION_MODE_IEEE80211N; + else if (linkspeed > 450 && linkspeed <= 1300) + conn_mode = CONNECTION_MODE_IEEE80211AC; + else + conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN; + + break; + default: + conn_mode = CONNECTION_MODE_IEEE80211_UNKNOWN; + break; + } + + DBG("connection mode(%d)", conn_mode); + connman_network_set_connection_mode(network, conn_mode); +} + +static void signalpoll_callback(int result, int maxspeed, uint8_t strength, + void *user_data) +{ + struct connman_network *network = user_data; + + if (result != 0) { + DBG("Failed to get maxspeed from signalpoll !"); + return; + } + + strength += 120; + if (strength > 100) + strength = 100; + + DBG("maxspeed = %d, strength = %d", maxspeed, strength); + if (network) { + connman_network_set_strength(network, strength); + connman_network_set_maxspeed(network, maxspeed); + set_connection_mode(network, maxspeed); + } +} + +static int network_signalpoll(struct wifi_data *wifi) +{ + GSupplicantInterface *interface; + struct connman_network *network; + + if (!wifi || !wifi->network) + return -ENODEV; + + interface = wifi->interface; + network = wifi->network; + + DBG("network %p", network); + + return g_supplicant_interface_signalpoll(interface, signalpoll_callback, network); +} + +static gboolean autosignalpoll_timeout(gpointer data) +{ + struct wifi_data *wifi = data; + + if (!wifi || !wifi->automaxspeed_timeout) { + DBG("automaxspeed_timeout is found to be zero. i.e. currently in disconnected state. !!"); + return FALSE; + } + + int ret = network_signalpoll(wifi); + if (ret < 0) { + DBG("Fail to get max speed !!"); + wifi->automaxspeed_timeout = 0; + return FALSE; + } + + return TRUE; +} +#endif + static struct connman_network_driver network_driver = { .name = "wifi", .type = CONNMAN_NETWORK_TYPE_WIFI, @@ -2284,6 +3849,10 @@ static void interface_added(GSupplicantInterface *interface) { const char *ifname = g_supplicant_interface_get_ifname(interface); const char *driver = g_supplicant_interface_get_driver(interface); +#if defined TIZEN_EXT + bool is_5_0_ghz_supported = g_supplicant_interface_get_is_5_0_ghz_supported(interface); +#endif + struct wifi_data *wifi; wifi = g_supplicant_interface_get_data(interface); @@ -2307,6 +3876,12 @@ static void interface_added(GSupplicantInterface *interface) } connman_device_set_powered(wifi->device, true); +#if defined TIZEN_EXT + connman_techonology_wifi_set_5ghz_supported(wifi_technology, is_5_0_ghz_supported); + /* Max number of SSIDs supported by wlan chipset that can be scanned */ + int max_scan_ssids = g_supplicant_interface_get_max_scan_ssids(interface); + connman_techonology_set_max_scan_ssids(wifi_technology, max_scan_ssids); +#endif } static bool is_idle(struct wifi_data *wifi) @@ -2386,16 +3961,49 @@ static bool handle_wps_completion(GSupplicantInterface *interface, if (!wps_ssid || wps_ssid_len != ssid_len || memcmp(ssid, wps_ssid, ssid_len) != 0) { connman_network_set_associating(network, false); +#if defined TIZEN_EXT + g_supplicant_interface_disconnect(wifi->interface, + disconnect_callback, wifi->network); + + connman_network_set_bool(network, "WiFi.UseWPS", false); + connman_network_set_string(network, "WiFi.PinWPS", NULL); +#else g_supplicant_interface_disconnect(wifi->interface, disconnect_callback, wifi); +#endif return false; } wps_key = g_supplicant_interface_get_wps_key(interface); +#if defined TIZEN_EXT + /* Check the passphrase and encrypt it + */ + int ret; + gchar *passphrase = g_strdup(wps_key); + + connman_network_set_string(network, "WiFi.PinWPS", NULL); + + if (check_passphrase_ext(network, passphrase) < 0) { + DBG("[WPS] Invalid passphrase"); + g_free(passphrase); + return true; + } + + ret = send_encryption_request(passphrase, network); + + g_free(passphrase); + + if (!ret) + DBG("[WPS] Encryption request succeeded"); + else + DBG("[WPS] Encryption request failed %d", ret); + +#else connman_network_set_string(network, "WiFi.Passphrase", wps_key); connman_network_set_string(network, "WiFi.PinWPS", NULL); +#endif } return true; @@ -2405,7 +4013,11 @@ static bool handle_assoc_status_code(GSupplicantInterface *interface, struct wifi_data *wifi) { if (wifi->state == G_SUPPLICANT_STATE_ASSOCIATING && +#if defined TIZEN_EXT + wifi->assoc_code > 0 && +#else wifi->assoc_code == ASSOC_STATUS_NO_CLIENT && +#endif wifi->load_shaping_retries < LOAD_SHAPING_MAX_RETRIES) { wifi->load_shaping_retries ++; return TRUE; @@ -2418,6 +4030,26 @@ static bool handle_4way_handshake_failure(GSupplicantInterface *interface, struct connman_network *network, struct wifi_data *wifi) { +#if defined TIZEN_EXT + const char *security; + struct connman_service *service; + + if (wifi->connected) + return false; + + security = connman_network_get_string(network, "WiFi.Security"); + + if (security && g_str_equal(security, "ieee8021x") == true && + wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) { + wifi->retries = 0; + connman_network_set_error(network, CONNMAN_NETWORK_ERROR_INVALID_KEY); + + return false; + } + + if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE) + return false; +#else struct connman_service *service; if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE) @@ -2425,6 +4057,7 @@ static bool handle_4way_handshake_failure(GSupplicantInterface *interface, if (wifi->connected) return false; +#endif service = connman_service_lookup_from_network(network); if (!service) @@ -2443,6 +4076,47 @@ static bool handle_4way_handshake_failure(GSupplicantInterface *interface, return false; } +#if defined TIZEN_EXT +static bool handle_wifi_assoc_retry(struct connman_network *network, + struct wifi_data *wifi) +{ + const char *security; + + if (!wifi->network || wifi->connected || wifi->disconnecting || + connman_network_get_connecting(network) != true) { + wifi->assoc_retry_count = 0; + return false; + } + + if (wifi->state != G_SUPPLICANT_STATE_ASSOCIATING && + wifi->state != G_SUPPLICANT_STATE_ASSOCIATED) { + wifi->assoc_retry_count = 0; + return false; + } + + security = connman_network_get_string(network, "WiFi.Security"); + if (security && g_str_equal(security, "ieee8021x") == true && + wifi->state == G_SUPPLICANT_STATE_ASSOCIATED) { + wifi->assoc_retry_count = 0; + return false; + } + + if (++wifi->assoc_retry_count >= TIZEN_ASSOC_RETRY_COUNT) { + wifi->assoc_retry_count = 0; + + /* Honestly it's not an invalid-key error, + * however QA team recommends that the invalid-key error + * might be better to display for user experience. + */ + connman_network_set_error(network, CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL); + + return false; + } + + return true; +} +#endif + static void interface_state(GSupplicantInterface *interface) { struct connman_network *network; @@ -2493,7 +4167,11 @@ static void interface_state(GSupplicantInterface *interface) case G_SUPPLICANT_STATE_AUTHENTICATING: case G_SUPPLICANT_STATE_ASSOCIATING: +#if defined TIZEN_EXT + reset_autoscan(device); +#else stop_autoscan(device); +#endif if (!wifi->connected) connman_network_set_associating(network, true); @@ -2501,8 +4179,37 @@ static void interface_state(GSupplicantInterface *interface) break; case G_SUPPLICANT_STATE_COMPLETED: +#if defined TIZEN_EXT + /* though it should be already reset: */ + reset_autoscan(device); + + wifi->assoc_retry_count = 0; + + wifi->scan_pending_network = NULL; + + /* should be cleared scanning flag */ + bool scanning = connman_device_get_scanning(device, + CONNMAN_SERVICE_TYPE_WIFI); + if (scanning){ + connman_device_set_scanning(device, + CONNMAN_SERVICE_TYPE_WIFI, false); + connman_device_unref(device); + } + + if (!wifi->automaxspeed_timeout) { + DBG("Going to start signalpoll timer!!"); + int ret = network_signalpoll(wifi); + if (ret < 0) + DBG("Fail to get max speed !!"); + else + wifi->automaxspeed_timeout = g_timeout_add_seconds(10, autosignalpoll_timeout, wifi); + } + + g_hash_table_remove_all(failed_bssids); +#else /* though it should be already stopped: */ stop_autoscan(device); +#endif if (!handle_wps_completion(interface, network, device, wifi)) break; @@ -2515,6 +4222,16 @@ static void interface_state(GSupplicantInterface *interface) break; case G_SUPPLICANT_STATE_DISCONNECTED: +#if defined TIZEN_EXT + connman_network_set_strength(network, 0); + connman_network_set_maxspeed(network, 0); + + if (wifi->automaxspeed_timeout != 0) { + g_source_remove(wifi->automaxspeed_timeout); + wifi->automaxspeed_timeout = 0; + DBG("Remove signalpoll timer!!"); + } +#endif /* * If we're in one of the idle modes, we have * not started association yet and thus setting @@ -2529,8 +4246,27 @@ static void interface_state(GSupplicantInterface *interface) if (is_idle(wifi)) break; +#if defined TIZEN_EXT + if (handle_assoc_status_code(interface, wifi)) { + GSList *bssid_list = (GSList *)connman_network_get_bssid_list(network); + guint bssid_length = 0; + + if (bssid_list) + bssid_length = g_slist_length(bssid_list); + + if (bssid_length > 1 && bssid_length > g_hash_table_size(failed_bssids)) { + network_connect(network); + break; + } + + wifi->load_shaping_retries = 0; + } + + g_hash_table_remove_all(failed_bssids); +#else if (handle_assoc_status_code(interface, wifi)) break; +#endif /* If previous state was 4way-handshake, then * it's either: psk was incorrect and thus we retry @@ -2554,6 +4290,21 @@ static void interface_state(GSupplicantInterface *interface) break; } +#if defined TIZEN_EXT + /* Some of Wi-Fi networks are not comply Wi-Fi specification. + * Retry association until its retry count is expired */ + if (handle_wifi_assoc_retry(network, wifi) == true) { + throw_wifi_scan(wifi->device, scan_callback); + wifi->scan_pending_network = wifi->network; + break; + } + + if(wifi->disconnect_code > 0){ + DBG("Set disconnect reason code(%d)", wifi->disconnect_code); + connman_network_set_disconnect_reason(network, wifi->disconnect_code); + } +#endif + if (network != wifi->pending_network) { connman_network_set_connected(network, false); connman_network_set_associating(network, false); @@ -2565,6 +4316,10 @@ static void interface_state(GSupplicantInterface *interface) break; case G_SUPPLICANT_STATE_INACTIVE: +#if defined TIZEN_EXT + if (handle_wps_completion(interface, network, device, wifi) == false) + break; +#endif connman_network_set_associating(network, false); start_autoscan(device); @@ -2625,6 +4380,21 @@ static void interface_removed(GSupplicantInterface *interface) wifi = g_supplicant_interface_get_data(interface); +#if defined TIZEN_EXT_WIFI_MESH + if (wifi && wifi->mesh_interface) { + DBG("Notify mesh interface remove"); + connman_mesh_notify_interface_remove(true); + struct wifi_mesh_info *mesh_info = wifi->mesh_info; + g_free(mesh_info->parent_ifname); + g_free(mesh_info->ifname); + g_free(mesh_info->identifier); + g_free(mesh_info); + wifi->mesh_interface = false; + wifi->mesh_info = NULL; + return; + } +#endif + if (wifi) wifi->interface = NULL; @@ -2639,6 +4409,9 @@ static void interface_removed(GSupplicantInterface *interface) connman_device_set_powered(wifi->device, false); check_p2p_technology(); +#if defined TIZEN_EXT_WIFI_MESH + check_mesh_technology(); +#endif } static void set_device_type(const char *type, char dev_type[17]) @@ -2701,7 +4474,38 @@ static void scan_started(GSupplicantInterface *interface) static void scan_finished(GSupplicantInterface *interface) { +#if defined TIZEN_EXT + struct wifi_data *wifi; + bool is_associating = false; + static bool is_scanning = true; +#endif + DBG(""); + +#if defined TIZEN_EXT + wifi = g_supplicant_interface_get_data(interface); + if (wifi && wifi->scan_pending_network) { + network_connect(wifi->scan_pending_network); + wifi->scan_pending_network = NULL; + } + + //service state - associating + if(!wifi || !wifi->network) + return; + + is_associating = connman_network_get_associating(wifi->network); + if(is_associating && is_scanning){ + is_scanning = false; + DBG("send scan for connecting"); + throw_wifi_scan(wifi->device, scan_callback); + + return; + } + is_scanning = true; + + //go scan + +#endif } static void ap_create_fail(GSupplicantInterface *interface) @@ -2737,12 +4541,105 @@ static unsigned char calculate_strength(GSupplicantNetwork *supplicant_network) unsigned char strength; strength = 120 + g_supplicant_network_get_signal(supplicant_network); +#if !defined TIZEN_EXT if (strength > 100) strength = 100; +#endif return strength; } +#if defined TIZEN_EXT_WIFI_MESH +static void mesh_peer_added(GSupplicantNetwork *supplicant_network) +{ + GSupplicantInterface *interface; + struct wifi_data *wifi; + const char *name, *security; + struct connman_mesh *connman_mesh; + struct wifi_mesh_info *mesh_info; + const unsigned char *bssid; + const char *identifier; + char *address; + uint16_t frequency; + int ret; + + interface = g_supplicant_network_get_interface(supplicant_network); + wifi = g_supplicant_interface_get_data(interface); + if (!wifi || !wifi->mesh_interface) { + DBG("Virtual Mesh interface not created"); + return; + } + + bssid = g_supplicant_network_get_bssid(supplicant_network); + address = g_malloc0(19); + snprintf(address, 19, "%02x:%02x:%02x:%02x:%02x:%02x", bssid[0], bssid[1], + bssid[2], bssid[3], bssid[4], bssid[5]); + + identifier = g_supplicant_network_get_identifier(supplicant_network); + name = g_supplicant_network_get_name(supplicant_network); + security = g_supplicant_network_get_security(supplicant_network); + frequency = g_supplicant_network_get_frequency(supplicant_network); + + mesh_info = wifi->mesh_info; + connman_mesh = connman_mesh_get(mesh_info->identifier, identifier); + if (connman_mesh) + goto done; + + DBG("Mesh Peer name %s identifier %s security %s added", name, identifier, + security); + connman_mesh = connman_mesh_create(mesh_info->identifier, identifier); + connman_mesh_set_name(connman_mesh, name); + connman_mesh_set_security(connman_mesh, security); + connman_mesh_set_frequency(connman_mesh, frequency); + connman_mesh_set_address(connman_mesh, address); + connman_mesh_set_index(connman_mesh, mesh_info->index); + connman_mesh_set_strength(connman_mesh, + calculate_strength(supplicant_network)); + connman_mesh_set_peer_type(connman_mesh, CONNMAN_MESH_PEER_TYPE_DISCOVERED); + + ret = connman_mesh_register(connman_mesh); + if (ret == -EALREADY) + DBG("Mesh Peer is already registered"); + +done: + g_free(address); +} + +static void mesh_peer_removed(GSupplicantNetwork *supplicant_network) +{ + GSupplicantInterface *interface; + struct wifi_data *wifi; + struct connman_mesh *connman_mesh; + struct wifi_mesh_info *mesh_info; + const char *identifier; + + interface = g_supplicant_network_get_interface(supplicant_network); + wifi = g_supplicant_interface_get_data(interface); + if (!wifi || !wifi->mesh_interface) { + DBG("Virtual Mesh interface not created"); + return; + } + + identifier = g_supplicant_network_get_identifier(supplicant_network); + if (!identifier) { + DBG("Failed to get Mesh Peer identifier"); + return; + } + + mesh_info = wifi->mesh_info; + connman_mesh = connman_mesh_get(mesh_info->identifier, identifier); + if (connman_mesh) { + /* Do not unregister connected mesh peer */ + if (connman_mesh_peer_is_connected_state(connman_mesh)) { + DBG("Mesh Peer %s is connected", identifier); + return; + } + DBG("Mesh Peer identifier %s removed", identifier); + connman_mesh_unregister(connman_mesh); + } +} +#endif + static void network_added(GSupplicantNetwork *supplicant_network) { struct connman_network *network; @@ -2756,6 +4653,12 @@ static void network_added(GSupplicantNetwork *supplicant_network) bool wps_ready; bool wps_advertizing; +#if defined TIZEN_EXT + GSList *vsie_list = NULL; + const unsigned char *country_code; + ieee80211_modes_e phy_mode; +#endif + mode = g_supplicant_network_get_mode(supplicant_network); identifier = g_supplicant_network_get_identifier(supplicant_network); @@ -2764,6 +4667,13 @@ static void network_added(GSupplicantNetwork *supplicant_network) if (!g_strcmp0(mode, "adhoc")) return; +#if defined TIZEN_EXT_WIFI_MESH + if (!g_strcmp0(mode, "mesh")) { + mesh_peer_added(supplicant_network); + return; + } +#endif + interface = g_supplicant_network_get_interface(supplicant_network); wifi = g_supplicant_interface_get_data(interface); name = g_supplicant_network_get_name(supplicant_network); @@ -2803,6 +4713,17 @@ static void network_added(GSupplicantNetwork *supplicant_network) connman_network_set_blob(network, "WiFi.SSID", ssid, ssid_len); +#if defined TIZEN_EXT + vsie_list = (GSList *)g_supplicant_network_get_wifi_vsie(supplicant_network); + if (vsie_list) + connman_network_set_vsie_list(network, vsie_list); + else + DBG("vsie_list is NULL"); + country_code = g_supplicant_network_get_countrycode(supplicant_network); + connman_network_set_countrycode(network, country_code); + phy_mode = g_supplicant_network_get_phy_mode(supplicant_network); + connman_network_set_phy_mode(network, phy_mode); +#endif connman_network_set_string(network, "WiFi.Security", security); connman_network_set_strength(network, calculate_strength(supplicant_network)); @@ -2815,20 +4736,54 @@ static void network_added(GSupplicantNetwork *supplicant_network) * If so, we decide to use WPS by default */ if (wps_ready && wps_pbc && wps_advertizing) +#if !defined TIZEN_EXT connman_network_set_bool(network, "WiFi.UseWPS", true); +#else + DBG("wps is activating by ap but ignore it."); +#endif } connman_network_set_frequency(network, g_supplicant_network_get_frequency(supplicant_network)); +#if defined TIZEN_EXT + connman_network_set_bssid(network, + g_supplicant_network_get_bssid(supplicant_network)); + connman_network_set_maxrate(network, + g_supplicant_network_get_maxrate(supplicant_network)); + connman_network_set_enc_mode(network, + g_supplicant_network_get_enc_mode(supplicant_network)); + connman_network_set_rsn_mode(network, + g_supplicant_network_get_rsn_mode(supplicant_network)); + connman_network_set_keymgmt(network, + g_supplicant_network_get_keymgmt(supplicant_network)); + connman_network_set_bool(network, "WiFi.HS20AP", + g_supplicant_network_is_hs20AP(supplicant_network)); + connman_network_set_bssid_list(network, + (GSList *)g_supplicant_network_get_bssid_list(supplicant_network)); +#endif connman_network_set_available(network, true); connman_network_set_string(network, "WiFi.Mode", mode); +#if defined TIZEN_EXT + if (group) +#else if (ssid) +#endif connman_network_set_group(network, group); +#if defined TIZEN_EXT + if (wifi_first_scan == true) + found_with_first_scan = true; +#endif + if (wifi->hidden && ssid) { +#if defined TIZEN_EXT + if (network_security(wifi->hidden->security) == + network_security(security) && +#else if (!g_strcmp0(wifi->hidden->security, security) && +#endif wifi->hidden->ssid_len == ssid_len && !memcmp(wifi->hidden->ssid, ssid, ssid_len)) { connman_network_connect_hidden(network, @@ -2849,6 +4804,15 @@ static void network_removed(GSupplicantNetwork *network) const char *name, *identifier; struct connman_network *connman_network; +#if defined TIZEN_EXT_WIFI_MESH + const char *mode; + mode = g_supplicant_network_get_mode(network); + if (!g_strcmp0(mode, "mesh")) { + mesh_peer_removed(network); + return; + } +#endif + interface = g_supplicant_network_get_interface(network); wifi = g_supplicant_interface_get_data(interface); identifier = g_supplicant_network_get_identifier(network); @@ -2863,6 +4827,18 @@ static void network_removed(GSupplicantNetwork *network) if (!connman_network) return; +#if defined TIZEN_EXT + if (connman_network == wifi->scan_pending_network) + wifi->scan_pending_network = NULL; + + if (connman_network == wifi->pending_network) + wifi->pending_network = NULL; + + if(connman_network_get_connecting(connman_network) == true){ + connman_network_set_connected(connman_network, false); + } +#endif + wifi->networks = g_slist_remove(wifi->networks, connman_network); connman_device_remove_network(wifi->device, connman_network); @@ -2877,6 +4853,16 @@ static void network_changed(GSupplicantNetwork *network, const char *property) struct connman_network *connman_network; bool update_needed; +#if defined TIZEN_EXT + const unsigned char *bssid; + unsigned int maxrate; + uint16_t frequency; + bool wps; + const unsigned char *country_code; + ieee80211_modes_e phy_mode; + GSList *bssid_list; +#endif + interface = g_supplicant_network_get_interface(network); wifi = g_supplicant_interface_get_data(interface); identifier = g_supplicant_network_get_identifier(network); @@ -2927,6 +4913,28 @@ static void network_changed(GSupplicantNetwork *network, const char *property) if (update_needed) connman_network_update(connman_network); + +#if defined TIZEN_EXT + bssid = g_supplicant_network_get_bssid(network); + maxrate = g_supplicant_network_get_maxrate(network); + frequency = g_supplicant_network_get_frequency(network); + wps = g_supplicant_network_get_wps(network); + phy_mode = g_supplicant_network_get_phy_mode(network); + + connman_network_set_bssid(connman_network, bssid); + connman_network_set_maxrate(connman_network, maxrate); + connman_network_set_frequency(connman_network, frequency); + connman_network_set_bool(connman_network, "WiFi.WPS", wps); + country_code = g_supplicant_network_get_countrycode(network); + connman_network_set_countrycode(connman_network, country_code); + bssid_list = (GSList *)g_supplicant_network_get_bssid_list(network); + connman_network_set_bssid_list(connman_network, bssid_list); + connman_network_set_phy_mode(connman_network, phy_mode); + + if (g_str_equal(property, "CheckMultiBssidConnect") && + connman_network_get_associating(connman_network)) + network_connect(connman_network); +#endif } static void network_associated(GSupplicantNetwork *network) @@ -3035,6 +5043,10 @@ static void peer_found(GSupplicantPeer *peer) const char *identifier, *name; int ret; +#if defined TIZEN_EXT + if (!wifi) + return; +#endif identifier = g_supplicant_peer_get_identifier(peer); name = g_supplicant_peer_get_name(peer); @@ -3180,6 +5192,11 @@ static void peer_request(GSupplicantPeer *peer) struct connman_peer *connman_peer; const char *identifier; +#if defined TIZEN_EXT + if (!wifi) + return; +#endif + identifier = g_supplicant_peer_get_identifier(peer); DBG("ident: %s", identifier); @@ -3191,6 +5208,100 @@ static void peer_request(GSupplicantPeer *peer) connman_peer_request_connection(connman_peer); } +#if defined TIZEN_EXT +static void system_power_off(void) +{ + GList *list; + struct wifi_data *wifi; + struct connman_service *service; + struct connman_ipconfig *ipconfig_ipv4; + + if (connman_setting_get_bool("WiFiDHCPRelease") == true) { + for (list = iface_list; list; list = list->next) { + wifi = list->data; + + if (wifi->network != NULL) { + service = connman_service_lookup_from_network(wifi->network); + ipconfig_ipv4 = __connman_service_get_ip4config(service); + __connman_dhcp_stop(ipconfig_ipv4); + } + } + } +} + +static void network_merged(GSupplicantNetwork *network) +{ + GSupplicantInterface *interface; + GSupplicantState state; + struct wifi_data *wifi; + const char *identifier; + struct connman_network *connman_network; + bool ishs20AP = 0; + char *temp = NULL; + + interface = g_supplicant_network_get_interface(network); + if (!interface) + return; + + state = g_supplicant_interface_get_state(interface); + if (state < G_SUPPLICANT_STATE_AUTHENTICATING) + return; + + wifi = g_supplicant_interface_get_data(interface); + if (!wifi) + return; + + identifier = g_supplicant_network_get_identifier(network); + + connman_network = connman_device_get_network(wifi->device, identifier); + if (!connman_network) + return; + + DBG("merged identifier %s", identifier); + + if (wifi->connected == FALSE) { + switch (state) { + case G_SUPPLICANT_STATE_AUTHENTICATING: + case G_SUPPLICANT_STATE_ASSOCIATING: + case G_SUPPLICANT_STATE_ASSOCIATED: + case G_SUPPLICANT_STATE_4WAY_HANDSHAKE: + case G_SUPPLICANT_STATE_GROUP_HANDSHAKE: + connman_network_set_associating(connman_network, TRUE); + break; + case G_SUPPLICANT_STATE_COMPLETED: + connman_network_set_connected(connman_network, TRUE); + break; + default: + DBG("Not handled the state : %d", state); + break; + } + } + + ishs20AP = g_supplicant_network_is_hs20AP(network); + + if (ishs20AP && + g_strcmp0(g_supplicant_network_get_security(network), "ieee8021x") == 0) { + temp = g_ascii_strdown(g_supplicant_network_get_eap(network), -1); + connman_network_set_string(connman_network, "WiFi.EAP", + temp); + connman_network_set_string(connman_network, "WiFi.Identity", + g_supplicant_network_get_identity(network)); + connman_network_set_string(connman_network, "WiFi.Phase2", + g_supplicant_network_get_phase2(network)); + + g_free(temp); + } + + wifi->network = connman_network; +} + +static void assoc_failed(void *user_data) +{ + struct connman_network *network = user_data; + connman_network_set_associating(network, false); +} +#endif + static void debug(const char *str) { if (getenv("CONNMAN_SUPPLICANT_DEBUG")) @@ -3236,9 +5347,21 @@ static const GSupplicantCallbacks callbacks = { .peer_lost = peer_lost, .peer_changed = peer_changed, .peer_request = peer_request, +#if defined TIZEN_EXT + .system_power_off = system_power_off, + .network_merged = network_merged, + .assoc_failed = assoc_failed, +#endif .debug = debug, .disconnect_reasoncode = disconnect_reasoncode, .assoc_status_code = assoc_status_code, +#if defined TIZEN_EXT_WIFI_MESH + .mesh_support = mesh_support, + .mesh_group_started = mesh_group_started, + .mesh_group_removed = mesh_group_removed, + .mesh_peer_connected = mesh_peer_connected, + .mesh_peer_disconnected = mesh_peer_disconnected, +#endif }; @@ -3263,7 +5386,11 @@ static GSupplicantSSID *ssid_ap_init(const char *ssid, const char *passphrase) return NULL; ap->mode = G_SUPPLICANT_MODE_MASTER; +#if defined TIZEN_EXT + ap->ssid = (void *) ssid; +#else ap->ssid = ssid; +#endif ap->ssid_len = strlen(ssid); ap->scan_ssid = 0; ap->freq = 2412; @@ -3567,6 +5694,9 @@ static int wifi_init(void) return err; } +#if defined TIZEN_EXT + failed_bssids = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); +#endif return 0; } @@ -3579,6 +5709,10 @@ static void wifi_exit(void) g_supplicant_unregister(&callbacks); connman_network_driver_unregister(&network_driver); + +#if defined TIZEN_EXT + g_hash_table_unref(failed_bssids); +#endif } CONNMAN_PLUGIN_DEFINE(wifi, "WiFi interface plugin", VERSION, diff --git a/resources/usr/share/dbus-1/system-services/net.connman.service b/resources/usr/share/dbus-1/system-services/net.connman.service new file mode 100644 index 00000000..990eb66b --- /dev/null +++ b/resources/usr/share/dbus-1/system-services/net.connman.service @@ -0,0 +1,6 @@ +[D-BUS Service] +Name=net.connman +Exec=/bin/false +User=network_fw +Group=network_fw +SystemdService=connman.service diff --git a/resources/var/lib/connman/settings b/resources/var/lib/connman/settings new file mode 100644 index 00000000..ba476b5d --- /dev/null +++ b/resources/var/lib/connman/settings @@ -0,0 +1,15 @@ + +[global] +OfflineMode=false + +[WiFi] +Enable=false + +[Bluetooth] +Enable=true + +[Wired] +Enable=true + +[Cellular] +Enable=true diff --git a/scripts/500.connman_upgrade.sh b/scripts/500.connman_upgrade.sh new file mode 100644 index 00000000..a21336e2 --- /dev/null +++ b/scripts/500.connman_upgrade.sh @@ -0,0 +1,9 @@ +#!/bin/sh +PATH=/bin:/usr/bin:/sbin:/usr/sbin + +#------------------------------------------------------------# +# connman patch script for upgrade (3.0 -> the latest tizen) # +#------------------------------------------------------------# + +chmod 755 /var/lib/connman +chown -R network_fw:network_fw /var/lib/connman diff --git a/scripts/connman.in b/scripts/connman.in index 0b9f63c5..f3d438f3 100644..100755 --- a/scripts/connman.in +++ b/scripts/connman.in @@ -1,6 +1,6 @@ #!/bin/sh -DAEMON=@sbindir@/connmand +DAEMON=@bindir@/connmand DESC="Connection Manager" . /lib/lsb/init-functions diff --git a/scripts/ipsec-script.c b/scripts/ipsec-script.c new file mode 100755 index 00000000..6ba0d292 --- /dev/null +++ b/scripts/ipsec-script.c @@ -0,0 +1,146 @@ +/* + * + * Connection Manager + * + * Copyright (C) 2007-2012 Intel Corporation. All rights reserved. + * Copyright (C) 2010,2012-2014 BMW Car IT GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <libgen.h> + +#include <dbus/dbus.h> + +extern char **environ; + +static void print(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vsyslog(LOG_INFO, format, ap); + va_end(ap); +} + +static void append(DBusMessageIter *dict, const char *pattern) +{ + DBusMessageIter entry; + const char *key, *value; + char *delim; + + delim = strchr(pattern, '='); + *delim = '\0'; + + key = pattern; + value = delim + 1; + + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, + NULL, &entry); + + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); + + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &value); + + dbus_message_iter_close_container(dict, &entry); +} + +int main(int argc, char *argv[]) +{ + DBusConnection *conn; + DBusError error; + DBusMessage *msg; + DBusMessageIter iter, dict; + char **envp, *busname, *interface, *path, *reason; + int ret = 0; + + openlog(basename(argv[0]), LOG_NDELAY | LOG_PID, LOG_DAEMON); + + busname = getenv("CONNMAN_BUSNAME"); + interface = getenv("CONNMAN_INTERFACE"); + path = getenv("CONNMAN_PATH"); + + reason = getenv("script_type"); + + if (!busname || !interface || !path || !reason) { + print("Required environment variables not set; " + "bus=%s iface=%s path=%s reason=%s", + busname, interface, path, reason); + ret = 1; + goto out; + } + dbus_error_init(&error); + + conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error); + if (!conn) { + if (dbus_error_is_set(&error)) { + print("%s", error.message); + dbus_error_free(&error); + } else + print("Failed to get on system bus"); + + goto out; + } + + msg = dbus_message_new_method_call(busname, path, + interface, "notify"); + if (!msg) { + dbus_connection_unref(conn); + print("Failed to allocate method call"); + goto out; + } + + dbus_message_set_no_reply(msg, TRUE); + + dbus_message_append_args(msg, + DBUS_TYPE_STRING, &reason, + DBUS_TYPE_INVALID); + + dbus_message_iter_init_append(msg, &iter); + + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); + + for (envp = environ; envp && *envp; envp++) + append(&dict, *envp); + + dbus_message_iter_close_container(&iter, &dict); + + if (!dbus_connection_send(conn, msg, NULL)) { + print("Failed to send message"); + goto out; + } + + dbus_connection_flush(conn); + + dbus_message_unref(msg); + + dbus_connection_unref(conn); + +out: + closelog(); + + return ret; +} diff --git a/scripts/libppp-plugin.c b/scripts/libppp-plugin.c index 0dd8b471..0dd8b471 100644..100755 --- a/scripts/libppp-plugin.c +++ b/scripts/libppp-plugin.c diff --git a/scripts/openconnect-script.c b/scripts/openconnect-script.c index 5e04144f..5e04144f 100644..100755 --- a/scripts/openconnect-script.c +++ b/scripts/openconnect-script.c diff --git a/scripts/openvpn-script.c b/scripts/openvpn-script.c index 6ba0d292..6ba0d292 100644..100755 --- a/scripts/openvpn-script.c +++ b/scripts/openvpn-script.c diff --git a/src/6to4.c b/src/6to4.c index 71a28827..71a28827 100644..100755 --- a/src/6to4.c +++ b/src/6to4.c diff --git a/src/agent-connman.c b/src/agent-connman.c index fca7cc1f..e4850a8f 100644..100755 --- a/src/agent-connman.c +++ b/src/agent-connman.c @@ -253,6 +253,9 @@ static void request_input_append_passphrase(DBusMessageIter *iter, value = "wep"; break; case CONNMAN_SERVICE_SECURITY_PSK: +#if defined TIZEN_EXT + case CONNMAN_SERVICE_SECURITY_RSN: +#endif value = "psk"; break; case CONNMAN_SERVICE_SECURITY_8021X: @@ -386,6 +389,9 @@ static void previous_passphrase_handler(DBusMessageIter *iter, data.type = "wep"; break; case CONNMAN_SERVICE_SECURITY_PSK: +#if defined TIZEN_EXT + case CONNMAN_SERVICE_SECURITY_RSN: +#endif data.type = "psk"; break; /* diff --git a/src/agent.c b/src/agent.c index 8f7b19ba..8f7b19ba 100644..100755 --- a/src/agent.c +++ b/src/agent.c diff --git a/src/bridge.c b/src/bridge.c index cd2d9cee..cd2d9cee 100644..100755 --- a/src/bridge.c +++ b/src/bridge.c diff --git a/src/clock.c b/src/clock.c index 0fde2c34..f04cf175 100644..100755 --- a/src/clock.c +++ b/src/clock.c @@ -241,6 +241,11 @@ static DBusMessage *set_property(DBusConnection *conn, type = dbus_message_iter_get_arg_type(&value); if (g_str_equal(name, "Time")) { +#if defined TIZEN_EXT + /* Tizen updates time (ntp) by system service */ + + return __connman_error_permission_denied(msg); +#else struct timeval tv; dbus_uint64_t newval; @@ -261,6 +266,7 @@ static DBusMessage *set_property(DBusConnection *conn, connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH, CONNMAN_CLOCK_INTERFACE, "Time", DBUS_TYPE_UINT64, &newval); +#endif } else if (g_str_equal(name, "TimeUpdates")) { const char *strval; enum time_updates newval; diff --git a/src/config.c b/src/config.c index af4f07e1..ca5957d6 100644 --- a/src/config.c +++ b/src/config.c @@ -746,6 +746,10 @@ static bool load_service(GKeyFile *keyfile, const char *group, if (str) { if (security == CONNMAN_SERVICE_SECURITY_PSK || +#if defined TIZEN_EXT + security == CONNMAN_SERVICE_SECURITY_RSN || + security == CONNMAN_SERVICE_SECURITY_SAE || +#endif security == CONNMAN_SERVICE_SECURITY_WEP) { service->security = security; } else { @@ -1163,6 +1167,10 @@ static void provision_service_wifi(struct connman_config_service *config, if (config->phase2) __connman_service_set_string(service, "Phase2", config->phase2); +#if defined TIZEN_EXT + else + __connman_service_set_string(service, "Phase2", NULL); +#endif if (config->passphrase) __connman_service_set_string(service, "Passphrase", @@ -1190,6 +1198,20 @@ static gboolean remove_virtual_config(gpointer user_data) return FALSE; } +#if defined TIZEN_EXT +static bool __check_address_type(int address_family, const char *address) +{ + unsigned char buf[sizeof(struct in6_addr)] = {0, }; + int err = 0; + + err = inet_pton(address_family, address, buf); + if(err > 0) + return TRUE; + + return FALSE; +} +#endif + static int try_provision_service(struct connman_config_service *config, struct connman_service *service) { @@ -1248,6 +1270,9 @@ static int try_provision_service(struct connman_config_service *config, case CONNMAN_SERVICE_TYPE_GPS: case CONNMAN_SERVICE_TYPE_VPN: case CONNMAN_SERVICE_TYPE_P2P: +#if defined TIZEN_EXT_WIFI_MESH + case CONNMAN_SERVICE_TYPE_MESH: +#endif return -ENOENT; } @@ -1273,6 +1298,12 @@ static int try_provision_service(struct connman_config_service *config, return -ENOENT; } +#if defined TIZEN_EXT + struct connman_ipconfig *ip6config = __connman_service_get_ip6config(service); + enum connman_ipconfig_method ipv6_method = __connman_ipconfig_get_method(ip6config); + if (ipv6_method == CONNMAN_IPCONFIG_METHOD_MANUAL) + goto ipv6_out; +#endif if (!config->ipv6_address) { connman_network_set_ipv6_method(network, CONNMAN_IPCONFIG_METHOD_AUTO); @@ -1309,6 +1340,9 @@ static int try_provision_service(struct connman_config_service *config, connman_ipaddress_free(address); } +#if defined TIZEN_EXT +ipv6_out: +#endif if (config->ipv6_privacy) { struct connman_ipconfig *ipconfig; @@ -1318,6 +1352,12 @@ static int try_provision_service(struct connman_config_service *config, config->ipv6_privacy); } +#if defined TIZEN_EXT + struct connman_ipconfig *ip4config = __connman_service_get_ip4config(service); + enum connman_ipconfig_method ipv4_method = __connman_ipconfig_get_method(ip4config); + if (ipv4_method == CONNMAN_IPCONFIG_METHOD_MANUAL) + goto ipv4_out; +#endif if (!config->ipv4_address) { connman_network_set_ipv4_method(network, CONNMAN_IPCONFIG_METHOD_DHCP); @@ -1354,6 +1394,9 @@ static int try_provision_service(struct connman_config_service *config, connman_ipaddress_free(address); } +#if defined TIZEN_EXT +ipv4_out: +#endif __connman_service_disconnect(service); service_id = connman_service_get_identifier(service); @@ -1375,8 +1418,19 @@ static int try_provision_service(struct connman_config_service *config, __connman_service_nameserver_clear(service); for (i = 0; config->nameservers[i]; i++) { +#if defined TIZEN_EXT + if (__check_address_type(AF_INET, config->nameservers[i])) + __connman_service_nameserver_append(service, + config->nameservers[i], false, + CONNMAN_IPCONFIG_TYPE_IPV4); + else if (__check_address_type(AF_INET6, config->nameservers[i])) + __connman_service_nameserver_append(service, + config->nameservers[i], false, + CONNMAN_IPCONFIG_TYPE_IPV6); +#else __connman_service_nameserver_append(service, config->nameservers[i], false); +#endif } } @@ -1411,7 +1465,9 @@ static int try_provision_service(struct connman_config_service *config, return 0; } +#if !defined TIZEN_EXT __connman_service_set_immutable(service, true); +#endif if (type == CONNMAN_SERVICE_TYPE_ETHERNET || type == CONNMAN_SERVICE_TYPE_GADGET) { @@ -1474,6 +1530,13 @@ int __connman_config_provision_service(struct connman_service *service) type != CONNMAN_SERVICE_TYPE_GADGET) return -ENOSYS; +#if defined TIZEN_EXT + if(type == CONNMAN_SERVICE_TYPE_WIFI && + __connman_service_get_security(service) == + CONNMAN_SERVICE_SECURITY_NONE) + return -ENOSYS; +#endif + return find_and_provision_service(service); } diff --git a/src/connection.c b/src/connection.c index 7a1fbcee..f8194a64 100644..100755 --- a/src/connection.c +++ b/src/connection.c @@ -661,8 +661,15 @@ static void connection_newgateway(int index, const char *gateway) } if (!found) { +#if defined TIZEN_EXT + if (data->ipv4_gateway != NULL){ + set_default_gateway(data, CONNMAN_IPCONFIG_TYPE_IPV4); + connman_check_proxy_setup_and_wispr_start(data->service); + } +#else if (data->ipv4_gateway) set_default_gateway(data, CONNMAN_IPCONFIG_TYPE_IPV4); +#endif if (data->ipv6_gateway) set_default_gateway(data, CONNMAN_IPCONFIG_TYPE_IPV6); @@ -790,6 +797,32 @@ static void add_host_route(int family, int index, const char *gateway, } } +#if defined TIZEN_EXT +static bool __connman_service_is_not_cellular_internet_profile( + struct connman_service *cellular) +{ + char *suffix; + const char *path; + const char internet_suffix[] = "_1"; + const char prepaid_internet_suffix[] = "_3"; + + if (connman_service_get_type(cellular) != CONNMAN_SERVICE_TYPE_CELLULAR) + return FALSE; + + path = __connman_service_get_path(cellular); + + suffix = strrchr(path, '_'); + + if (g_strcmp0(suffix, internet_suffix) != 0 && + g_strcmp0(suffix, prepaid_internet_suffix) != 0) { + DBG("not internet service profile: %s", path); + return TRUE; + } + + return FALSE; +} +#endif + int __connman_connection_gateway_add(struct connman_service *service, const char *gateway, enum connman_ipconfig_type type, @@ -816,6 +849,28 @@ int __connman_connection_gateway_add(struct connman_service *service, if (!gateway && type == CONNMAN_IPCONFIG_TYPE_IPV6) gateway = "::"; +#if defined TIZEN_EXT + if (__connman_service_is_not_cellular_internet_profile(service) == TRUE) { + /* not internet service should not be default gateway */ + + DBG("no internet service %p index %d gateway %s vpn ip %s type %d", + service, index, gateway, peer, type); + + if (type == CONNMAN_IPCONFIG_TYPE_IPV4) { + add_host_route(AF_INET, index, gateway, service_type); + __connman_service_nameserver_add_routes(service, gateway); + type4 = CONNMAN_IPCONFIG_TYPE_IPV4; + } + + if (type == CONNMAN_IPCONFIG_TYPE_IPV6) { + add_host_route(AF_INET6, index, gateway, service_type); + __connman_service_nameserver_add_routes(service, gateway); + type6 = CONNMAN_IPCONFIG_TYPE_IPV6; + } + + goto done; + } +#endif DBG("service %p index %d gateway %s vpn ip %s type %d", service, index, gateway, peer, type); @@ -860,6 +915,12 @@ int __connman_connection_gateway_add(struct connman_service *service, } if (!active_gateway) { +#if defined TIZEN_EXT + if(new_gateway->ipv4_gateway) + DBG("ConnMan, Set default gateway[%s], active[%d]", + new_gateway->ipv4_gateway->gateway, + new_gateway->ipv4_gateway->active); +#endif set_default_gateway(new_gateway, type); goto done; } @@ -975,6 +1036,9 @@ bool __connman_connection_update_gateway(void) bool updated = false; GHashTableIter iter; gpointer value, key; +#if defined TIZEN_EXT + static struct gateway_data *old_default = NULL; +#endif if (!gateway_hash) return updated; @@ -1012,6 +1076,12 @@ bool __connman_connection_update_gateway(void) } } +#if defined TIZEN_EXT + if (updated == false && old_default != default_gateway) { + updated = true; + old_default = default_gateway; + } +#endif /* * Set default gateway if it has been updated or if it has not been * set as active yet. diff --git a/src/connman-dbus.conf b/src/connman-dbus.conf index 98a773ea..29106dc7 100644..100755 --- a/src/connman-dbus.conf +++ b/src/connman-dbus.conf @@ -6,6 +6,19 @@ <allow send_destination="net.connman"/> <allow send_interface="net.connman.Agent"/> <allow send_interface="net.connman.Counter"/> + <allow send_interface="net.connman.Manager"/> + <allow send_interface="net.connman.Service"/> + <allow send_interface="net.connman.Technology"/> + <allow send_interface="net.connman.Notification"/> + </policy> + <policy user="network_fw"> + <allow own="net.connman"/> + <allow send_destination="net.connman"/> + <allow send_interface="net.connman.Agent"/> + <allow send_interface="net.connman.Counter"/> + <allow send_interface="net.connman.Manager"/> + <allow send_interface="net.connman.Service"/> + <allow send_interface="net.connman.Technology"/> <allow send_interface="net.connman.Notification"/> </policy> <policy at_console="true"> diff --git a/src/connman-polkit.conf b/src/connman-polkit.conf index b13d339b..03154faf 100644..100755 --- a/src/connman-polkit.conf +++ b/src/connman-polkit.conf @@ -7,6 +7,12 @@ <allow send_interface="net.connman.Counter"/> <allow send_interface="net.connman.Notification"/> </policy> + <policy user="network_fw"> + <allow own="net.connman"/> + <allow send_interface="net.connman.Agent"/> + <allow send_interface="net.connman.Counter"/> + <allow send_interface="net.connman.Notification"/> + </policy> <policy context="default"> <allow send_destination="net.connman"/> </policy> diff --git a/src/connman.conf b/src/connman.conf new file mode 100644 index 00000000..c1417ebc --- /dev/null +++ b/src/connman.conf @@ -0,0 +1,38 @@ +<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> +<busconfig> + <policy user="root"> + <allow own="net.connman"/> + <allow send_destination="net.connman"/> + </policy> + <policy user="network_fw"> + <allow own="net.connman"/> + <allow send_destination="net.connman"/> + </policy> + <policy context="default"> + <deny own="net.connman"/> + <deny send_destination="net.connman"/> + <allow send_destination="net.connman" send_type="signal"/> + <allow send_destination="net.connman" send_interface="net.connman.Technology" send_member="GetScanState" /> + <allow send_destination="net.connman" send_interface="net.connman.Technology" send_member="Get5GhzSupported" /> + <allow send_destination="net.connman" send_interface="net.connman.Technology" send_member="GetMaxScanSsid" /> + + <check send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetTechnologies" privilege="http://tizen.org/privilege/network.get" /> + <check send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetProperties" privilege="http://tizen.org/privilege/network.get" /> + <check send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetServices" privilege="http://tizen.org/privilege/network.get" /> + <check send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetMeshPeers" privilege="http://tizen.org/privilege/network.get" /> + <check send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetConnectedMeshPeers" privilege="http://tizen.org/privilege/network.get" /> + <check send_destination="net.connman" send_interface="net.connman.Manager" send_member="GetDisconnectedMeshPeers" privilege="http://tizen.org/privilege/network.get" /> + <check send_destination="net.connman" send_interface="net.connman.Manager" send_member="MeshAddPeer" privilege="http://tizen.org/privilege/network.set" /> + <check send_destination="net.connman" send_interface="net.connman.Manager" send_member="MeshRemovePeer" privilege="http://tizen.org/privilege/network.set" /> + <check send_destination="net.connman" send_interface="net.connman.Service" send_member="Connect" privilege="http://tizen.org/privilege/network.set" /> + <check send_destination="net.connman" send_interface="net.connman.Service" send_member="Disconnect" privilege="http://tizen.org/privilege/network.set" /> + <check send_destination="net.connman" send_interface="net.connman.Service" send_member="SetProperty" privilege="http://tizen.org/privilege/network.profile" /> + <check send_destination="net.connman" send_interface="net.connman.Service" send_member="GetProperties" privilege="http://tizen.org/privilege/network.get" /> + <check send_destination="net.connman" send_interface="net.connman.Service" send_member="Remove" privilege="http://tizen.org/privilege/network.profile" /> + <check send_destination="net.connman" send_interface="net.connman.Service" send_member="PropertyChanged" privilege="http://tizen.org/privilege/network.get" /> + <check send_destination="net.connman" send_interface="net.connman.Technology" send_member="Scan" privilege="http://tizen.org/privilege/network.set" /> + <check send_destination="net.connman" send_interface="net.connman.Technology" send_member="SpecificScan" privilege="http://tizen.org/privilege/network.set" /> + <check send_destination="net.connman" send_interface="net.connman.Technology" send_member="MeshCommands" privilege="http://tizen.org/privilege/network.set" /> + </policy> +</busconfig> diff --git a/src/connman.h b/src/connman.h index 8101c7b2..57c30508 100644 --- a/src/connman.h +++ b/src/connman.h @@ -24,6 +24,10 @@ #include <glib.h> #define CONNMAN_API_SUBJECT_TO_CHANGE +#if defined TIZEN_EXT +#define WIFI_COUNTRY_CODE_LEN 2 +#define WIFI_PHY_MODE_LEN 18 +#endif #include <connman/dbus.h> @@ -54,6 +58,10 @@ DBusMessage *__connman_error_operation_aborted(DBusMessage *msg); DBusMessage *__connman_error_operation_timeout(DBusMessage *msg); DBusMessage *__connman_error_invalid_service(DBusMessage *msg); DBusMessage *__connman_error_invalid_property(DBusMessage *msg); +#if defined TIZEN_EXT_WIFI_MESH +DBusMessage *__connman_error_invalid_command(DBusMessage *msg); +DBusMessage *__connman_error_scan_abort_failed(DBusMessage *msg); +#endif int __connman_manager_init(void); void __connman_manager_cleanup(void); @@ -175,6 +183,9 @@ int __connman_inet_ipv6_send_rs(int index, int timeout, __connman_inet_rs_cb_t callback, void *user_data); int __connman_inet_ipv6_send_ra(int index, struct in6_addr *src_addr, GSList *prefixes, int router_lifetime); +#if defined TIZEN_EXT +void __connman_network_set_auto_ipv6_gateway(char *gateway, void *user_data); +#endif typedef void (*__connman_inet_ns_cb_t) (struct nd_neighbor_advert *reply, unsigned int length, @@ -379,6 +390,11 @@ const char *__connman_ipconfig_get_broadcast(struct connman_ipconfig *ipconfig); void __connman_ipconfig_set_broadcast(struct connman_ipconfig *ipconfig, const char *broadcast); const char *__connman_ipconfig_get_gateway(struct connman_ipconfig *ipconfig); void __connman_ipconfig_set_gateway(struct connman_ipconfig *ipconfig, const char *gateway); + +#if defined TIZEN_EXT +void __connman_ipconfig_set_dhcp_lease_duration(struct connman_ipconfig *ipconfig, int dhcp_lease_duration); +#endif + unsigned char __connman_ipconfig_get_prefixlen(struct connman_ipconfig *ipconfig); void __connman_ipconfig_set_prefixlen(struct connman_ipconfig *ipconfig, unsigned char prefixlen); @@ -409,7 +425,15 @@ enum connman_ipconfig_method __connman_ipconfig_get_method( int __connman_ipconfig_address_add(struct connman_ipconfig *ipconfig); int __connman_ipconfig_address_remove(struct connman_ipconfig *ipconfig); int __connman_ipconfig_address_unset(struct connman_ipconfig *ipconfig); +#if defined TIZEN_EXT +/* + * Description: __connman_service_lookup_from_index cannot find correct service + * e.g. same interface or same APN of cellular profile + */ +int __connman_ipconfig_gateway_add(struct connman_ipconfig *ipconfig, struct connman_service *service); +#else int __connman_ipconfig_gateway_add(struct connman_ipconfig *ipconfig); +#endif void __connman_ipconfig_gateway_remove(struct connman_ipconfig *ipconfig); int __connman_ipconfig_set_proxy_autoconfig(struct connman_ipconfig *ipconfig, @@ -458,6 +482,11 @@ enum __connman_dhcpv6_status { CONNMAN_DHCPV6_STATUS_RESTART = 2, }; +#if defined TIZEN_EXT +void set_dhcp_discover_timeout(int timeout_value); +void set_dhcp_discover_retry_count(int retry_count); +#endif + typedef void (* dhcpv6_cb) (struct connman_network *network, enum __connman_dhcpv6_status status, gpointer data); @@ -556,6 +585,17 @@ void __connman_technology_remove_interface(enum connman_service_type type, void __connman_technology_notify_regdom_by_device(struct connman_device *device, int result, const char *alpha2); +#if defined TIZEN_EXT +enum bssid_type { + CHECK_BSSID = 0, + GET_BSSID = 1, + SET_BSSID = 2, + RESET_BSSID = 3, +}; + +int set_connman_bssid(enum bssid_type mode, char *bssid); +#endif + #include <connman/device.h> int __connman_device_init(const char *device, const char *nodevice); @@ -572,6 +612,10 @@ int __connman_device_request_hidden_scan(struct connman_device *device, const char *identity, const char *passphrase, const char *security, void *user_data); void __connman_device_stop_scan(enum connman_service_type type); +#if defined TIZEN_EXT +int __connman_device_request_specific_scan(enum connman_service_type type, + int scan_type, GSList *specific_scan_list); +#endif bool __connman_device_isfiltered(const char *devname); @@ -591,6 +635,11 @@ int __connman_rfkill_init(void); void __connman_rfkill_cleanup(void); int __connman_rfkill_block(enum connman_service_type type, bool block); +#if defined TIZEN_EXT +char *index2ident(int index, const char *prefix); +char *index2addr(int index); +#endif + #include <connman/network.h> int __connman_network_init(void); @@ -675,6 +724,15 @@ int __connman_service_load_modifiable(struct connman_service *service); void __connman_service_list_struct(DBusMessageIter *iter); +#if defined TIZEN_EXT +int connman_service_get_ipv6_dns_method(struct connman_service *service); +enum connman_dnsconfig_method { + CONNMAN_DNSCONFIG_METHOD_UNKNOWN = 0, + CONNMAN_DNSCONFIG_METHOD_MANUAL = 1, + CONNMAN_DNSCONFIG_METHOD_DHCP = 2, +}; +#endif + int __connman_service_compare(const struct connman_service *a, const struct connman_service *b); @@ -682,6 +740,9 @@ struct connman_service *__connman_service_lookup_from_index(int index); struct connman_service *__connman_service_create_from_network(struct connman_network *network); struct connman_service *__connman_service_create_from_provider(struct connman_provider *provider); bool __connman_service_index_is_default(int index); +#if defined TIZEN_EXT +void __connman_service_notify_strength_changed(struct connman_network *network); +#endif void __connman_service_update_from_network(struct connman_network *network); void __connman_service_remove_from_network(struct connman_network *network); void __connman_service_read_ip4config(struct connman_service *service); @@ -705,6 +766,10 @@ struct connman_network *__connman_service_get_network(struct connman_service *se enum connman_service_security __connman_service_get_security(struct connman_service *service); const char *__connman_service_get_phase2(struct connman_service *service); bool __connman_service_wps_enabled(struct connman_service *service); +#if defined TIZEN_EXT +void __connman_service_set_storage_reload(struct connman_service *service, + bool storage_reload); +#endif int __connman_service_set_favorite(struct connman_service *service, bool favorite); int __connman_service_set_favorite_delayed(struct connman_service *service, @@ -730,6 +795,10 @@ enum connman_service_state __connman_service_ipconfig_get_state( struct connman_service *service, enum connman_ipconfig_type type); +#if defined TIZEN_EXT +void connman_check_proxy_setup_and_wispr_start(struct connman_service *service); +#endif + int __connman_service_indicate_error(struct connman_service *service, enum connman_service_error error); int __connman_service_clear_error(struct connman_service *service); @@ -741,6 +810,12 @@ int __connman_service_disconnect(struct connman_service *service); int __connman_service_disconnect_all(void); void __connman_service_set_active_session(bool enable, GSList *list); void __connman_service_auto_connect(enum connman_service_connect_reason reason); + +#if defined TIZEN_EXT +bool __connman_service_get_auto_connect_mode(void); +void __connman_service_set_auto_connect_mode(bool enable); +#endif + bool __connman_service_remove(struct connman_service *service); bool __connman_service_is_provider_pending(struct connman_service *service); void __connman_service_set_provider_pending(struct connman_service *service, @@ -758,10 +833,19 @@ const char *__connman_service_type2string(enum connman_service_type type); enum connman_service_type __connman_service_string2type(const char *str); enum connman_service_security __connman_service_string2security(const char *str); +#if defined TIZEN_EXT +int __connman_service_nameserver_append(struct connman_service *service, + const char *nameserver, bool is_auto, + enum connman_ipconfig_type type); +int __connman_service_nameserver_remove(struct connman_service *service, + const char *nameserver, bool is_auto, + enum connman_ipconfig_type type); +#else int __connman_service_nameserver_append(struct connman_service *service, const char *nameserver, bool is_auto); int __connman_service_nameserver_remove(struct connman_service *service, const char *nameserver, bool is_auto); +#endif void __connman_service_nameserver_clear(struct connman_service *service); void __connman_service_nameserver_add_routes(struct connman_service *service, const char *gw); @@ -777,6 +861,17 @@ void __connman_service_timeserver_changed(struct connman_service *service, GSList *ts_list); void __connman_service_set_pac(struct connman_service *service, const char *pac); +#if defined TIZEN_EXT +/* + * Returns profile count if there is any connected profiles + * that use same interface + */ +int __connman_service_get_connected_count_of_iface(struct connman_service *service); +void __connman_service_set_proxy(struct connman_service *service, + const char *proxies); +int check_passphrase_ext(struct connman_network *network, + const char *passphrase); +#endif bool __connman_service_is_hidden(struct connman_service *service); bool __connman_service_is_split_routing(struct connman_service *service); bool __connman_service_index_is_split_routing(int index); @@ -848,6 +943,30 @@ int __connman_peer_service_unregister(const char *owner, const unsigned char *query, int query_length, int version); +#if defined TIZEN_EXT_WIFI_MESH +#include <connman/mesh.h> + +int __connman_mesh_init(void); +void __connman_mesh_cleanup(void); +bool __connman_technology_get_connected(enum connman_service_type type); +void __connman_technology_mesh_interface_create_finished( + enum connman_service_type type, bool success, + const char *error); +void __connman_technology_mesh_interface_remove_finished( + enum connman_service_type type, bool success); +void __connman_mesh_peer_list_struct(DBusMessageIter *array); +void __connman_mesh_connected_peer_list_struct(DBusMessageIter *array); +void __connman_mesh_disconnected_peer_list_struct(DBusMessageIter *array); +int __connman_mesh_dhcp_start(struct connman_ipconfig *ipconfig, + dhcp_cb callback, gpointer user_data); +int __connman_device_abort_scan(enum connman_service_type type); +void __connman_technology_notify_abort_scan(enum connman_service_type type, + int result); +int __connman_device_request_mesh_specific_scan(enum connman_service_type type, + const char *name, unsigned int freq); +void __connman_mesh_auto_connect(void); +#endif /* TIZEN_EXT_WIFI_MESH */ + #include <connman/session.h> void __connman_service_mark_dirty(); @@ -885,12 +1004,21 @@ int __connman_rtnl_init(void); void __connman_rtnl_start(void); void __connman_rtnl_cleanup(void); +#if defined TIZEN_EXT +void __connman_wifi_vsie_list_struct(DBusMessageIter *iter); +#endif + enum connman_device_type __connman_rtnl_get_device_type(int index); unsigned int __connman_rtnl_update_interval_add(unsigned int interval); unsigned int __connman_rtnl_update_interval_remove(unsigned int interval); int __connman_rtnl_request_update(void); int __connman_rtnl_send(const void *buf, size_t len); +#if defined TIZEN_EXT +void rtnl_nameserver_add_all(struct connman_service *service, + enum connman_ipconfig_type type); +#endif + bool __connman_session_policy_autoconnect(enum connman_service_connect_reason reason); int __connman_session_create(DBusMessage *msg); @@ -1078,3 +1206,12 @@ int __connman_util_get_random(uint64_t *val); unsigned int __connman_util_random_delay_ms(unsigned int secs); int __connman_util_init(void); void __connman_util_cleanup(void); + +#ifdef TIZEN_EXT +__attribute__ ((unused)) static int __tizentvextension = -1; +#define TIZEN_TV_EXT (__builtin_expect(__tizentvextension != -1, 1) ? \ + __tizentvextension : \ + (__tizentvextension = connman_setting_get_bool("TizenTVExtension"))) +#else /* TIZEN_EXT */ +#define TIZEN_TV_EXT (0) /* Always False */ +#endif /* TIZEN_EXT */ diff --git a/src/connman.service.in b/src/connman.service.in index 7376346e..a1ddddc7 100644..100755 --- a/src/connman.service.in +++ b/src/connman.service.in @@ -3,19 +3,21 @@ Description=Connection service DefaultDependencies=false Conflicts=shutdown.target RequiresMountsFor=@localstatedir@/lib/connman -After=dbus.service network-pre.target systemd-sysusers.service +After=dbus.service network-pre.target systemd-sysusers.service net-config.service Before=network.target multi-user.target shutdown.target Wants=network.target [Service] Type=dbus +User=network_fw +Group=network_fw BusName=net.connman Restart=on-failure -ExecStart=@sbindir@/connmand -n +SmackProcessLabel=System +ExecStart=@bindir@/connmand -n --nobacktrace --noplugin vpn StandardOutput=null -CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SYS_TIME CAP_SYS_MODULE CAP_SYS_ADMIN -ProtectHome=true -ProtectSystem=full +Capabilities=cap_setgid,cap_net_admin,cap_net_bind_service,cap_net_broadcast,cap_net_raw,cap_dac_override=i +SecureBits=keep-caps [Install] WantedBy=multi-user.target diff --git a/src/connman.socket b/src/connman.socket new file mode 100644 index 00000000..3e1e64d5 --- /dev/null +++ b/src/connman.socket @@ -0,0 +1,13 @@ +[Unit] +Description=DNS Proxy Socket +Before=connman.service + +[Socket] +ListenStream=127.0.0.1:53 +ListenDatagram=0.0.0.0:53 +FreeBind=yes +SmackLabelIPIn=* +SmackLabelIPOut=@ + +[Install] +WantedBy=sockets.target
\ No newline at end of file diff --git a/src/connman_tv.service.in b/src/connman_tv.service.in new file mode 100644 index 00000000..9eb75b24 --- /dev/null +++ b/src/connman_tv.service.in @@ -0,0 +1,19 @@ +[Unit] +Description=Connection service +After=net-config.service +DefaultDependencies=no + +[Service] +Type=dbus +User=network_fw +Group=network_fw +BusName=net.connman +Restart=on-failure +SmackProcessLabel=System +ExecStart=@bindir@/connmand -n --noplugin vpn +StandardOutput=null +Capabilities=cap_setgid,cap_net_admin,cap_net_bind_service,cap_net_broadcast,cap_net_raw,cap_dac_override=i +SecureBits=keep-caps + +[Install] +WantedBy=multi-user.target diff --git a/src/counter.c b/src/counter.c index 8ea6205b..8ea6205b 100644..100755 --- a/src/counter.c +++ b/src/counter.c diff --git a/src/dbus.c b/src/dbus.c index d80a46ce..d80a46ce 100644..100755 --- a/src/dbus.c +++ b/src/dbus.c diff --git a/src/detect.c b/src/detect.c index 6c039206..7f20870c 100644..100755 --- a/src/detect.c +++ b/src/detect.c @@ -67,8 +67,15 @@ static void detect_newlink(unsigned short type, int index, } device = find_device(index); +#if defined TIZEN_EXT + if (device) { + connman_inet_update_device_ident(device); + return; + } +#else if (device) return; +#endif device = connman_device_create_from_index(index); if (!device) diff --git a/src/device.c b/src/device.c index 264c5e2d..df7b2bbc 100644 --- a/src/device.c +++ b/src/device.c @@ -166,6 +166,11 @@ static bool device_has_service_type(struct connman_device *device, if (device_service_type == CONNMAN_SERVICE_TYPE_UNKNOWN) return true; +#if defined TIZEN_EXT_WIFI_MESH + if (device_service_type == CONNMAN_SERVICE_TYPE_MESH) + return service_type != CONNMAN_SERVICE_TYPE_MESH; +#endif + if (device_service_type == CONNMAN_SERVICE_TYPE_WIFI) { return service_type == CONNMAN_SERVICE_TYPE_WIFI || service_type == CONNMAN_SERVICE_TYPE_P2P; @@ -791,6 +796,11 @@ int connman_device_set_scanning(struct connman_device *device, __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO); +#if defined TIZEN_EXT_WIFI_MESH + if (type == CONNMAN_SERVICE_TYPE_MESH) + __connman_mesh_auto_connect(); +#endif + return 0; } @@ -1090,6 +1100,170 @@ void connman_device_regdom_notify(struct connman_device *device, __connman_technology_notify_regdom_by_device(device, result, alpha2); } +#if defined TIZEN_EXT +static int device_specific_scan(enum connman_service_type type, + struct connman_device *device, + int scan_type, GSList *specific_scan_list) +{ + if (!device->driver || !device->driver->specific_scan) + return -EOPNOTSUPP; + + if (!device->powered) + return -ENOLINK; + + return device->driver->specific_scan(type, device, scan_type, + specific_scan_list, NULL); +} + +int __connman_device_request_specific_scan(enum connman_service_type type, + int scan_type, GSList *specific_scan_list) +{ + bool success = false; + int last_err = -ENOSYS; + GSList *list; + int err; + + switch (type) { + case CONNMAN_SERVICE_TYPE_UNKNOWN: + case CONNMAN_SERVICE_TYPE_SYSTEM: + case CONNMAN_SERVICE_TYPE_ETHERNET: + case CONNMAN_SERVICE_TYPE_BLUETOOTH: + case CONNMAN_SERVICE_TYPE_CELLULAR: + case CONNMAN_SERVICE_TYPE_GPS: + case CONNMAN_SERVICE_TYPE_VPN: + case CONNMAN_SERVICE_TYPE_GADGET: + return -EOPNOTSUPP; + case CONNMAN_SERVICE_TYPE_WIFI: + case CONNMAN_SERVICE_TYPE_P2P: +#if defined TIZEN_EXT_WIFI_MESH + case CONNMAN_SERVICE_TYPE_MESH: +#endif + break; + } + + for (list = device_list; list; list = list->next) { + struct connman_device *device = list->data; + enum connman_service_type service_type = + __connman_device_get_service_type(device); + + if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN) { + if (type == CONNMAN_SERVICE_TYPE_P2P) { + if (service_type != CONNMAN_SERVICE_TYPE_WIFI) + continue; + } else if (service_type != type) + continue; + } + + err = device_specific_scan(type, device, scan_type, specific_scan_list); + if (err == 0 || err == -EINPROGRESS) { + success = true; + } else { + last_err = err; + DBG("device %p err %d", device, err); + } + } + + if (success) + return 0; + + return last_err; +} + +#if defined TIZEN_EXT_WIFI_MESH +static int device_abort_scan(enum connman_service_type type, + struct connman_device *device) +{ + if (!device->driver || !device->driver->scan) + return -EOPNOTSUPP; + + if (!device->powered) + return -ENOLINK; + + return device->driver->abort_scan(type, device); +} + +int __connman_device_abort_scan(enum connman_service_type type) +{ + GSList *list; + int err = -EINVAL; + + if (type != CONNMAN_SERVICE_TYPE_MESH) + return -EINVAL; + + for (list = device_list; list; list = list->next) { + struct connman_device *device = list->data; + enum connman_service_type service_type = + __connman_device_get_service_type(device); + + if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN) { + if (type == CONNMAN_SERVICE_TYPE_MESH) + if (service_type != CONNMAN_SERVICE_TYPE_WIFI) + continue; + + if (!device->scanning) { + err = -EEXIST; + continue; + } + + err = device_abort_scan(type, device); + } + } + return err; +} + +static int device_mesh_specific_scan(enum connman_service_type type, + struct connman_device *device, const char *name, + unsigned int freq) +{ + if (!device->driver || !device->driver->mesh_specific_scan) + return -EOPNOTSUPP; + + if (!device->powered) + return -ENOLINK; + + return device->driver->mesh_specific_scan(type, device, name, freq, NULL); +} + +int __connman_device_request_mesh_specific_scan(enum connman_service_type type, + const char *name, + unsigned int freq) +{ + bool success = false; + int last_err = -ENOSYS; + GSList *list; + int err; + + if (type != CONNMAN_SERVICE_TYPE_MESH) + return -EINVAL; + + for (list = device_list; list; list = list->next) { + struct connman_device *device = list->data; + enum connman_service_type service_type = + __connman_device_get_service_type(device); + + if (service_type != CONNMAN_SERVICE_TYPE_UNKNOWN) { + if (type == CONNMAN_SERVICE_TYPE_MESH) + if (service_type != CONNMAN_SERVICE_TYPE_WIFI) + continue; + } + + err = device_mesh_specific_scan(type, device, name, freq); + if (err == 0 || err == -EALREADY || err == -EINPROGRESS) { + success = true; + } else { + last_err = err; + DBG("device %p err %d", device, err); + } + } + + if (success) + return 0; + + return last_err; +} +#endif /* TIZEN_EXT_WIFI_MESH */ +#endif + static int connman_device_request_scan(enum connman_service_type type, bool force_full_scan) { @@ -1110,6 +1284,9 @@ static int connman_device_request_scan(enum connman_service_type type, return -EOPNOTSUPP; case CONNMAN_SERVICE_TYPE_WIFI: case CONNMAN_SERVICE_TYPE_P2P: +#if defined TIZEN_EXT_WIFI_MESH + case CONNMAN_SERVICE_TYPE_MESH: +#endif break; } @@ -1120,7 +1297,15 @@ static int connman_device_request_scan(enum connman_service_type type, continue; err = device_scan(type, device, force_full_scan); +#if defined TIZEN_EXT + /* When Scan is already in progress then return Error so that + * wifi-manager can block the scan-done signal to be sent to + * application and start requested scan after scan already in progress + * is completed then notify to application about the scan event */ + if (err == 0 || err == -EINPROGRESS) { +#else if (err == 0 || err == -EALREADY || err == -EINPROGRESS) { +#endif success = true; } else { last_err = err; @@ -1183,7 +1368,11 @@ void __connman_device_stop_scan(enum connman_service_type type) } } +#if defined TIZEN_EXT +char *index2ident(int index, const char *prefix) +#else static char *index2ident(int index, const char *prefix) +#endif { struct ifreq ifr; struct ether_addr eth; @@ -1229,7 +1418,11 @@ static char *index2ident(int index, const char *prefix) return str; } +#if defined TIZEN_EXT +char *index2addr(int index) +#else static char *index2addr(int index) +#endif { struct ifreq ifr; struct ether_addr eth; @@ -1469,6 +1662,9 @@ static void cleanup_devices(void) DBG("cleaning up %s index %d", interfaces[i], index); +#if defined TIZEN_EXT + if (strcmp(interfaces[i], "wlan0") != 0) +#endif connman_inet_ifdown(index); /* @@ -67,6 +67,9 @@ static GHashTable *ipconfig_table; static void dhcp_free(struct connman_dhcp *dhcp) { +#if defined TIZEN_EXT + DBG("dhcp_free [%p]", dhcp); +#endif g_strfreev(dhcp->nameservers); g_strfreev(dhcp->timeservers); g_free(dhcp->pac); @@ -76,10 +79,16 @@ static void dhcp_free(struct connman_dhcp *dhcp) dhcp->pac = NULL; g_free(dhcp); +#if defined TIZEN_EXT + dhcp = NULL; +#endif } static void ipv4ll_stop_client(struct connman_dhcp *dhcp) { +#if defined TIZEN_EXT + DBG("dhcp [%p] ipv4ll_client [%p]", dhcp, dhcp->ipv4ll_client); +#endif if (!dhcp->ipv4ll_client) return; @@ -119,8 +128,14 @@ static bool apply_dhcp_invalidate_on_network(struct connman_dhcp *dhcp) } if (dhcp->nameservers) { for (i = 0; dhcp->nameservers[i]; i++) { +#if defined TIZEN_EXT + __connman_service_nameserver_remove(service, + dhcp->nameservers[i], false, + CONNMAN_IPCONFIG_TYPE_IPV4); +#else __connman_service_nameserver_remove(service, dhcp->nameservers[i], false); +#endif } g_strfreev(dhcp->nameservers); dhcp->nameservers = NULL; @@ -193,6 +208,10 @@ static int ipv4ll_start_client(struct connman_dhcp *dhcp) int index; int err; +#if defined TIZEN_EXT + DBG("dhcp %p", dhcp); +#endif + if (dhcp->ipv4ll_client) return -EALREADY; @@ -202,12 +221,16 @@ static int ipv4ll_start_client(struct connman_dhcp *dhcp) if (error != G_DHCP_CLIENT_ERROR_NONE) return -EINVAL; +#if !defined TIZEN_EXT if (getenv("CONNMAN_DHCP_DEBUG")) { +#endif dhcp->ipv4ll_debug_prefix = g_strdup_printf("IPv4LL index %d", index); g_dhcp_client_set_debug(ipv4ll_client, dhcp_debug, dhcp->ipv4ll_debug_prefix); +#if !defined TIZEN_EXT } +#endif g_dhcp_client_set_id(ipv4ll_client); @@ -243,6 +266,10 @@ static gboolean dhcp_retry_cb(gpointer user_data) dhcp->timeout = 0; +#if defined TIZEN_EXT + DBG("dhcp %p", dhcp); + DBG("dhcp->timeout %d", dhcp->timeout); +#endif g_dhcp_client_start(dhcp->dhcp_client, __connman_ipconfig_get_dhcp_address(dhcp->ipconfig)); @@ -382,18 +409,32 @@ static bool apply_lease_available_on_network(GDHCPClient *dhcp_client, if (!compare_string_arrays(nameservers, dhcp->nameservers)) { if (dhcp->nameservers) { +#if defined TIZEN_EXT + for (i = 0; dhcp->nameservers[i] != NULL; i++) { + __connman_service_nameserver_remove(service, + dhcp->nameservers[i], false, + CONNMAN_IPCONFIG_TYPE_IPV4); + } +#else for (i = 0; dhcp->nameservers[i]; i++) { __connman_service_nameserver_remove(service, dhcp->nameservers[i], false); } +#endif g_strfreev(dhcp->nameservers); } dhcp->nameservers = nameservers; for (i = 0; dhcp->nameservers && dhcp->nameservers[i]; i++) { +#if defined TIZEN_EXT + __connman_service_nameserver_append(service, + dhcp->nameservers[i], false, + CONNMAN_IPCONFIG_TYPE_IPV4); +#else __connman_service_nameserver_append(service, dhcp->nameservers[i], false); +#endif } } else { g_strfreev(nameservers); @@ -458,6 +499,10 @@ static void lease_available_cb(GDHCPClient *dhcp_client, gpointer user_data) __connman_ipconfig_set_dhcp_address(dhcp->ipconfig, address); DBG("last address %s", address); +#if defined TIZEN_EXT + int dhcp_lease_duration = g_dhcp_client_get_dhcp_lease_duration(dhcp_client); +#endif + option = g_dhcp_client_get_option(dhcp_client, G_DHCP_SUBNET); if (option) netmask = g_strdup(option->data); @@ -492,6 +537,10 @@ static void lease_available_cb(GDHCPClient *dhcp_client, gpointer user_data) __connman_ipconfig_set_method(dhcp->ipconfig, CONNMAN_IPCONFIG_METHOD_DHCP); +#if defined TIZEN_EXT + __connman_ipconfig_set_dhcp_lease_duration(dhcp->ipconfig, dhcp_lease_duration); +#endif + /* * Notify IPv4.Configuration's method moved back to DHCP. * @@ -580,14 +629,25 @@ static int dhcp_initialize(struct connman_dhcp *dhcp) dhcp_client = g_dhcp_client_new(G_DHCP_IPV4, index, &error); if (error != G_DHCP_CLIENT_ERROR_NONE) +#if defined TIZEN_EXT + { + DBG("failed g_dhcp_client_new(%d), index(%d)", error, index); +#endif return -EINVAL; +#if defined TIZEN_EXT + } +#endif +#if !defined TIZEN_EXT if (getenv("CONNMAN_DHCP_DEBUG")) { +#endif dhcp->dhcp_debug_prefix = g_strdup_printf("DHCP index %d", index); g_dhcp_client_set_debug(dhcp_client, dhcp_debug, dhcp->dhcp_debug_prefix); +#if !defined TIZEN_EXT } +#endif g_dhcp_client_set_id(dhcp_client); @@ -671,11 +731,48 @@ char *__connman_dhcp_get_server_address(struct connman_ipconfig *ipconfig) return g_dhcp_client_get_server_address(dhcp->dhcp_client); } +#if defined TIZEN_EXT_WIFI_MESH +int __connman_mesh_dhcp_start(struct connman_ipconfig *ipconfig, + dhcp_cb callback, gpointer user_data) +{ + struct connman_dhcp *dhcp; + int err; + + DBG(""); + + dhcp = g_hash_table_lookup(ipconfig_table, ipconfig); + if (!dhcp) { + + dhcp = g_try_new0(struct connman_dhcp, 1); + if (!dhcp) + return -ENOMEM; + + dhcp->ipconfig = ipconfig; + __connman_ipconfig_ref(ipconfig); + + err = dhcp_initialize(dhcp); + + if (err < 0) { + g_free(dhcp); + return err; + } + + g_hash_table_insert(ipconfig_table, ipconfig, dhcp); + } + + dhcp->callback = callback; + dhcp->user_data = user_data; + return g_dhcp_client_start(dhcp->dhcp_client, NULL); +} +#endif + int __connman_dhcp_start(struct connman_ipconfig *ipconfig, struct connman_network *network, dhcp_cb callback, gpointer user_data) { +#if !defined TIZEN_EXT const char *last_addr = NULL; +#endif struct connman_dhcp *dhcp; int err; @@ -689,7 +786,9 @@ int __connman_dhcp_start(struct connman_ipconfig *ipconfig, return -EINVAL; } +#if !defined TIZEN_EXT last_addr = __connman_ipconfig_get_dhcp_address(ipconfig); +#endif dhcp = g_hash_table_lookup(ipconfig_table, ipconfig); if (!dhcp) { @@ -721,7 +820,13 @@ int __connman_dhcp_start(struct connman_ipconfig *ipconfig, dhcp->callback = callback; dhcp->user_data = user_data; +#if defined TIZEN_EXT + DBG("Start DHCP with DHCPDISCOVER request"); + + return g_dhcp_client_start(dhcp->dhcp_client, NULL); +#else return g_dhcp_client_start(dhcp->dhcp_client, last_addr); +#endif } void __connman_dhcp_stop(struct connman_ipconfig *ipconfig) diff --git a/src/dhcpv6.c b/src/dhcpv6.c index 2d5f8f6a..4c07c769 100644..100755 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -197,10 +197,23 @@ static int set_duid(struct connman_service *service, int duid_len; ident = connman_service_get_identifier(service); +#if defined TIZEN_EXT + if(ident != NULL) + DBG("ident : %s", ident); +#endif keyfile = connman_storage_load_service(ident); + +#if defined TIZEN_EXT + if (!keyfile) { + keyfile = g_key_file_new(); + if (!keyfile) + return -EIO; + } +#else if (!keyfile) return -EINVAL; +#endif hex_duid = g_key_file_get_string(keyfile, ident, "IPv6.DHCP.DUID", NULL); @@ -322,9 +335,19 @@ static void info_req_cb(GDHCPClient *dhcp_client, gpointer user_data) if (!compare_string_arrays(nameservers, dhcp->nameservers)) { if (dhcp->nameservers) { for (i = 0; dhcp->nameservers[i]; i++) +#if defined TIZEN_EXT + { + __connman_service_nameserver_remove(service, + dhcp->nameservers[i], false, + CONNMAN_IPCONFIG_TYPE_IPV6); +#else __connman_service_nameserver_remove(service, dhcp->nameservers[i], false); +#endif +#if defined TIZEN_EXT + } +#endif g_strfreev(dhcp->nameservers); } @@ -332,9 +355,19 @@ static void info_req_cb(GDHCPClient *dhcp_client, gpointer user_data) for (i = 0; dhcp->nameservers && dhcp->nameservers[i]; i++) +#if defined TIZEN_EXT + { + __connman_service_nameserver_append(service, + dhcp->nameservers[i], false, + CONNMAN_IPCONFIG_TYPE_IPV6); +#else __connman_service_nameserver_append(service, dhcp->nameservers[i], false); +#endif +#if defined TIZEN_EXT + } +#endif } else g_strfreev(nameservers); @@ -392,7 +425,9 @@ static int dhcpv6_info_request(struct connman_dhcpv6 *dhcp) return -EINVAL; } +#if !defined TIZEN_EXT if (getenv("CONNMAN_DHCPV6_DEBUG")) +#endif g_dhcp_client_set_debug(dhcp_client, dhcpv6_debug, "DHCPv6"); service = connman_service_lookup_from_network(dhcp->network); @@ -517,9 +552,19 @@ static int set_other_addresses(GDHCPClient *dhcp_client, if (!compare_string_arrays(nameservers, dhcp->nameservers)) { if (dhcp->nameservers) { for (i = 0; dhcp->nameservers[i]; i++) +#if defined TIZEN_EXT + { + __connman_service_nameserver_remove(service, + dhcp->nameservers[i], + false, CONNMAN_IPCONFIG_TYPE_IPV6); +#else __connman_service_nameserver_remove(service, dhcp->nameservers[i], false); +#endif +#if defined TIZEN_EXT + } +#endif g_strfreev(dhcp->nameservers); } @@ -527,9 +572,19 @@ static int set_other_addresses(GDHCPClient *dhcp_client, for (i = 0; dhcp->nameservers && dhcp->nameservers[i]; i++) +#if defined TIZEN_EXT + { + __connman_service_nameserver_append(service, + dhcp->nameservers[i], + false, CONNMAN_IPCONFIG_TYPE_IPV6); +#else __connman_service_nameserver_append(service, dhcp->nameservers[i], false); +#endif +#if defined TIZEN_EXT + } +#endif } else g_strfreev(nameservers); @@ -638,6 +693,9 @@ static void set_address(int ifindex, struct connman_ipconfig *ipconfig, /* Is this prefix part of the subnet we are suppose to use? */ prefix_len = check_ipv6_addr_prefix(prefixes, address); +#if defined TIZEN_EXT + char *gateway = g_strdup(__connman_ipconfig_get_gateway(ipconfig)); +#endif __connman_ipconfig_address_remove(ipconfig); __connman_ipconfig_set_local(ipconfig, address); __connman_ipconfig_set_prefixlen(ipconfig, prefix_len); @@ -645,6 +703,11 @@ static void set_address(int ifindex, struct connman_ipconfig *ipconfig, DBG("new address %s/%d", address, prefix_len); __connman_ipconfig_set_dhcp_address(ipconfig, address); +#if defined TIZEN_EXT + DBG("Set gateway %s", gateway); + __connman_ipconfig_set_gateway(ipconfig, gateway); + g_free(gateway); +#endif __connman_service_save( __connman_service_lookup_from_index(ifindex)); } @@ -1713,7 +1776,9 @@ static gboolean timeout_solicitation(gpointer user_data) static int dhcpv6_solicitation(struct connman_dhcpv6 *dhcp) { struct connman_service *service; +#if !defined TIZEN_EXT struct connman_ipconfig *ipconfig_ipv6; +#endif GDHCPClient *dhcp_client; GDHCPClientError error; int index, ret; @@ -1728,7 +1793,9 @@ static int dhcpv6_solicitation(struct connman_dhcpv6 *dhcp) return -EINVAL; } +#if !defined TIZEN_EXT if (getenv("CONNMAN_DHCPV6_DEBUG")) +#endif g_dhcp_client_set_debug(dhcp_client, dhcpv6_debug, "DHCPv6"); service = connman_service_lookup_from_network(dhcp->network); @@ -1754,8 +1821,20 @@ static int dhcpv6_solicitation(struct connman_dhcpv6 *dhcp) g_dhcpv6_client_set_oro(dhcp_client, 3, G_DHCPV6_DNS_SERVERS, G_DHCPV6_DOMAIN_LIST, G_DHCPV6_SNTP_SERVERS); +#if defined TIZEN_EXT + /** + When privacy extension is enabled then connman requests + OPTION_IA_TA (4) from DHCPv6 server. This option is used to request + temporary IPv6 address from DHCPv6 server but we found that DHCPv6 + server never provided temporary IPv6 address and connman resend dhcpv6 + requests. So always set OPTION_IA_NA in dhcpv6 request to get IPv6 + address from DHCPv6 server. + */ + dhcp->use_ta = FALSE; +#else ipconfig_ipv6 = __connman_service_get_ip6config(service); dhcp->use_ta = __connman_ipconfig_ipv6_privacy_enabled(ipconfig_ipv6); +#endif g_dhcpv6_client_set_ia(dhcp_client, index, dhcp->use_ta ? G_DHCPV6_IA_TA : G_DHCPV6_IA_NA, @@ -2045,7 +2124,9 @@ static GDHCPClient *create_pd_client(struct connman_dhcpv6 *dhcp, int *err) return NULL; } +#if !defined TIZEN_EXT if (getenv("CONNMAN_DHCPV6_DEBUG")) +#endif g_dhcp_client_set_debug(dhcp_client, dhcpv6_debug, "DHCPv6:PD"); service = connman_service_lookup_from_network(dhcp->network); diff --git a/src/dnsproxy.c b/src/dnsproxy.c index 2dc73408..cb583251 100644..100755 --- a/src/dnsproxy.c +++ b/src/dnsproxy.c @@ -41,6 +41,11 @@ #include "connman.h" +#if defined TIZEN_EXT +#include <sys/smack.h> +#include <systemd/sd-daemon.h> +#endif + #define debug(fmt...) do { } while (0) #if __BYTE_ORDER == __LITTLE_ENDIAN @@ -199,7 +204,11 @@ struct domain_rr { * By default the TTL (time-to-live) of the DNS response is used * when setting the cache entry life time. The value is in seconds. */ +#if defined TIZEN_EXT +#define MAX_CACHE_TTL (60 * 60) +#else #define MAX_CACHE_TTL (60 * 30) +#endif /* * Also limit the other end, cache at least for 30 seconds. */ @@ -218,12 +227,22 @@ static int cache_size; static GHashTable *cache; static int cache_refcount; static GSList *server_list = NULL; +#if defined TIZEN_EXT +static GSList *server_list_sec = NULL; +#endif static GSList *request_list = NULL; static GHashTable *listener_table = NULL; static time_t next_refresh; static GHashTable *partial_tcp_req_table; static guint cache_timer = 0; +#if defined TIZEN_EXT +static void destroy_server_sec(struct server_data *server); +static struct server_data *create_server_sec(int index, + const char *domain, const char *server, + int protocol); +#endif + static guint16 get_id(void) { uint64_t rand; @@ -1652,6 +1671,31 @@ static int ns_resolv(struct server_data *server, struct request_data *req, } } +#if defined TIZEN_EXT + if (server->protocol == IPPROTO_UDP) { + GList *domains; + struct server_data *new_server = NULL; + + new_server = create_server_sec(server->index, NULL, + server->server, IPPROTO_UDP); + + if (new_server != NULL) { + for (domains = server->domains; domains; + domains = domains->next) { + char *dom = domains->data; + + DBG("Adding domain %s to %s", + dom, new_server->server); + + new_server->domains = g_list_append( + new_server->domains, + g_strdup(dom)); + } + + server = new_server; + } + } +#endif sk = g_io_channel_unix_get_fd(server->channel); err = sendto(sk, request, req->request_len, MSG_NOSIGNAL, @@ -2247,6 +2291,19 @@ static gboolean udp_server_event(GIOChannel *channel, GIOCondition condition, if (len >= 12) forward_dns_reply(buf, len, IPPROTO_UDP, data); +#if defined TIZEN_EXT + GSList *list; + + for (list = server_list_sec; list; list = list->next) { + struct server_data *new_data = list->data; + + if (new_data == data) { + destroy_server_sec(data); + return TRUE; + } + } +#endif + return TRUE; } @@ -2557,6 +2614,177 @@ static void enable_fallback(bool enable) } } +#if defined TIZEN_EXT + +static void destroy_server_sec(struct server_data *server) +{ + GList *list; + int fd; + + if (server->channel) + fd = g_io_channel_unix_get_fd(server->channel); + else + fd = -1; + + DBG("index %d server %s sock %d", server->index, server->server, fd); + + server_list_sec = g_slist_remove(server_list_sec, server); + + if (fd > 0) + close(fd); + + server_destroy_socket(server); + + if (server->protocol == IPPROTO_UDP && server->enabled) + DBG("Removing DNS server %s", server->server); + + g_free(server->server); + for (list = server->domains; list; list = list->next) { + char *domain = list->data; + + server->domains = g_list_remove(server->domains, domain); + g_free(domain); + } + g_free(server->server_addr); + + /* + * We do not remove cache right away but delay it few seconds. + * The idea is that when IPv6 DNS server is added via RDNSS, it has a + * lifetime. When the lifetime expires we decrease the refcount so it + * is possible that the cache is then removed. Because a new DNS server + * is usually created almost immediately we would then loose the cache + * without any good reason. The small delay allows the new RDNSS to + * create a new DNS server instance and the refcount does not go to 0. + */ + /* TODO: Need to check this */ + /* g_timeout_add_seconds(3, try_remove_cache, NULL); */ + + g_free(server); +} + +static void destroy_all_server_sec() +{ + GSList *list; + + DBG("remove all dns server"); + + for (list = server_list_sec; list; list = list->next) { + struct server_data *server = list->data; + destroy_server_sec(server); + } + server_list_sec = NULL; +} + +static gboolean sec_udp_idle_timeout(gpointer user_data) +{ + struct server_data *server = user_data; + + DBG(""); + + if (server == NULL) + return FALSE; + + destroy_server_sec(server); + + return FALSE; +} + +static struct server_data *create_server_sec(int index, + const char *domain, const char *server, + int protocol) +{ + struct server_data *data; + struct addrinfo hints, *rp; + int ret; + + DBG("index %d server %s", index, server); + + data = g_try_new0(struct server_data, 1); + if (data == NULL) { + connman_error("Failed to allocate server %s data", server); + return NULL; + } + + data->index = index; + if (domain) + data->domains = g_list_append(data->domains, g_strdup(domain)); + data->server = g_strdup(server); + data->protocol = protocol; + + memset(&hints, 0, sizeof(hints)); + + switch (protocol) { + case IPPROTO_UDP: + hints.ai_socktype = SOCK_DGRAM; + break; + + case IPPROTO_TCP: + hints.ai_socktype = SOCK_STREAM; + break; + + default: + destroy_server_sec(data); + return NULL; + } + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_NUMERICSERV | AI_NUMERICHOST; + + ret = getaddrinfo(data->server, "53", &hints, &rp); + if (ret) { + connman_error("Failed to parse server %s address: %s\n", + data->server, gai_strerror(ret)); + freeaddrinfo(rp); + destroy_server_sec(data); + return NULL; + } + + /* Do not blindly copy this code elsewhere; it doesn't loop over the + results using ->ai_next as it should. That's OK in *this* case + because it was a numeric lookup; we *know* there's only one. */ + + data->server_addr_len = rp->ai_addrlen; + + switch (rp->ai_family) { + case AF_INET: + data->server_addr = (struct sockaddr *) + g_try_new0(struct sockaddr_in, 1); + break; + case AF_INET6: + data->server_addr = (struct sockaddr *) + g_try_new0(struct sockaddr_in6, 1); + break; + default: + connman_error("Wrong address family %d", rp->ai_family); + break; + } + if (data->server_addr == NULL) { + freeaddrinfo(rp); + destroy_server_sec(data); + return NULL; + } + memcpy(data->server_addr, rp->ai_addr, rp->ai_addrlen); + freeaddrinfo(rp); + + if (server_create_socket(data) != 0) { + destroy_server_sec(data); + return NULL; + } + + if (protocol == IPPROTO_UDP) { + /* Enable new servers by default */ + data->enabled = TRUE; + DBG("Adding DNS server %s", data->server); + + data->timeout = g_timeout_add_seconds(30, sec_udp_idle_timeout, + data); + + server_list_sec = g_slist_append(server_list_sec, data); + } + + return data; +} +#endif + static struct server_data *create_server(int index, const char *domain, const char *server, int protocol) @@ -2847,6 +3075,10 @@ int __connman_dnsproxy_remove(int index, const char *domain, remove_server(index, domain, server, IPPROTO_UDP); remove_server(index, domain, server, IPPROTO_TCP); +#if defined TIZEN_EXT + destroy_all_server_sec(); +#endif + return 0; } @@ -3305,6 +3537,23 @@ static gboolean client_timeout(gpointer user_data) return FALSE; } +#if defined TIZEN_EXT +static void recover_listener(GIOChannel *channel, struct listener_data *ifdata) +{ + int sk, index; + + index = ifdata->index; + + sk = g_io_channel_unix_get_fd(channel); + close(sk); + + __connman_dnsproxy_remove_listener(index); + + if (__connman_dnsproxy_add_listener(index) == 0) + DBG("listener %d successfully recovered", index); +} +#endif + static bool tcp_listener_event(GIOChannel *channel, GIOCondition condition, struct listener_data *ifdata, int family, guint *listener_watch) @@ -3325,11 +3574,17 @@ static bool tcp_listener_event(GIOChannel *channel, GIOCondition condition, condition, channel, ifdata, family); if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) { +#if defined TIZEN_EXT + connman_error("Error %d with TCP listener channel", condition); + + recover_listener(channel, ifdata); +#else if (*listener_watch > 0) g_source_remove(*listener_watch); *listener_watch = 0; connman_error("Error with TCP listener channel"); +#endif return false; } @@ -3443,7 +3698,11 @@ static bool tcp_listener_event(GIOChannel *channel, GIOCondition condition, * The packet length bytes do not contain the total message length, * that is the reason to -2 below. */ +#if defined TIZEN_EXT + if (msg_len > (unsigned int)(len - 2)) { +#else if (msg_len != (unsigned int)(len - 2)) { +#endif debug("client %d sent %d bytes but expecting %u pending %d", client_sk, len, msg_len + 2, msg_len + 2 - len); @@ -3488,8 +3747,14 @@ static bool udp_listener_event(GIOChannel *channel, GIOCondition condition, int sk, err, len; if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) { +#if defined TIZEN_EXT + connman_error("Error %d with UDP listener channel", condition); + + recover_listener(channel, ifdata); +#else connman_error("Error with UDP listener channel"); *listener_watch = 0; +#endif return false; } @@ -3548,7 +3813,12 @@ static bool udp_listener_event(GIOChannel *channel, GIOCondition condition, req->name = g_strdup(query); req->request = g_malloc(len); memcpy(req->request, buf, len); +#if defined TIZEN_EXT + DBG("req %p dstid 0x%04x altid 0x%04x", req, req->dstid, req->altid); + req->timeout = g_timeout_add_seconds(30, request_timeout, req); +#else req->timeout = g_timeout_add_seconds(5, request_timeout, req); +#endif request_list = g_slist_append(request_list, req); return true; @@ -3576,14 +3846,24 @@ static GIOChannel *get_listener(int family, int protocol, int index) { GIOChannel *channel; const char *proto; +#if !defined TIZEN_EXT union { struct sockaddr sa; struct sockaddr_in6 sin6; struct sockaddr_in sin; } s; socklen_t slen; +#endif int sk, type; +#if !defined TIZEN_EXT char *interface; +#endif +#if defined TIZEN_EXT + int option; + int sd_num = 0; + int rv; + int is_socket_inet = 0; +#endif debug("family %d protocol %d index %d", family, protocol, index); @@ -3601,7 +3881,33 @@ static GIOChannel *get_listener(int family, int protocol, int index) default: return NULL; } +#if defined TIZEN_EXT + sd_num = sd_listen_fds(0); + DBG("socket type(%s) systemd number of fds(%d)", proto, sd_num); + if(sd_num < 1){ + DBG("fail to get the fd from systemd"); + return NULL; + } + + if(protocol == IPPROTO_TCP) + type = SOCK_STREAM; + else + type = SOCK_DGRAM; + for(sk = SD_LISTEN_FDS_START; sk < SD_LISTEN_FDS_START+sd_num; ++sk){ + rv = sd_is_socket_inet(sk, family, type, -1, 53); + if(rv > 0){ + DBG("socket fd (%d) is passed by systemd", sk); + is_socket_inet = 1; + break; + } + } + + if (!is_socket_inet) { + DBG("socket fd is not matched what connman requests"); + return NULL; + } +#else sk = socket(family, type, protocol); if (sk < 0 && family == AF_INET6 && errno == EAFNOSUPPORT) { connman_error("No IPv6 support"); @@ -3660,15 +3966,29 @@ static GIOChannel *get_listener(int family, int protocol, int index) close(sk); return NULL; } +#endif +#if defined TIZEN_EXT + /* When ConnMan crashed, + * probably DNS listener cannot bind existing address */ + option = 1; + if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option)) < 0) { + connman_error("Failed to set socket option SO_REUSEADDR"); + close(sk); + return NULL; + } +#endif +#if !defined TIZEN_EXT if (bind(sk, &s.sa, slen) < 0) { connman_error("Failed to bind %s listener socket", proto); close(sk); return NULL; } +#endif if (protocol == IPPROTO_TCP) { +#if !defined TIZEN_EXT if (listen(sk, 10) < 0) { connman_error("Failed to listen on TCP socket %d/%s", -errno, strerror(errno)); @@ -3676,6 +3996,7 @@ static GIOChannel *get_listener(int family, int protocol, int index) return NULL; } +#endif fcntl(sk, F_SETFL, O_NONBLOCK); } @@ -3708,40 +4029,68 @@ static int create_dns_listener(int protocol, struct listener_data *ifdata) ifdata->tcp4_listener_channel = get_listener(AF_INET, protocol, ifdata->index); if (ifdata->tcp4_listener_channel) +#if defined TIZEN_EXT + ifdata->tcp4_listener_watch = + g_io_add_watch(ifdata->tcp4_listener_channel, + G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, + tcp4_listener_event, (gpointer)ifdata); +#else ifdata->tcp4_listener_watch = g_io_add_watch(ifdata->tcp4_listener_channel, G_IO_IN, tcp4_listener_event, (gpointer)ifdata); +#endif else ret |= TCP_IPv4_FAILED; ifdata->tcp6_listener_channel = get_listener(AF_INET6, protocol, ifdata->index); if (ifdata->tcp6_listener_channel) +#if defined TIZEN_EXT + ifdata->tcp6_listener_watch = + g_io_add_watch(ifdata->tcp6_listener_channel, + G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, + tcp6_listener_event, (gpointer)ifdata); +#else ifdata->tcp6_listener_watch = g_io_add_watch(ifdata->tcp6_listener_channel, G_IO_IN, tcp6_listener_event, (gpointer)ifdata); +#endif else ret |= TCP_IPv6_FAILED; } else { ifdata->udp4_listener_channel = get_listener(AF_INET, protocol, ifdata->index); if (ifdata->udp4_listener_channel) +#if defined TIZEN_EXT + ifdata->udp4_listener_watch = + g_io_add_watch(ifdata->udp4_listener_channel, + G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, + udp4_listener_event, (gpointer)ifdata); +#else ifdata->udp4_listener_watch = g_io_add_watch(ifdata->udp4_listener_channel, G_IO_IN, udp4_listener_event, (gpointer)ifdata); +#endif else ret |= UDP_IPv4_FAILED; ifdata->udp6_listener_channel = get_listener(AF_INET6, protocol, ifdata->index); if (ifdata->udp6_listener_channel) +#if defined TIZEN_EXT + ifdata->udp6_listener_watch = + g_io_add_watch(ifdata->udp6_listener_channel, + G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, + udp6_listener_event, (gpointer)ifdata); +#else ifdata->udp6_listener_watch = g_io_add_watch(ifdata->udp6_listener_channel, G_IO_IN, udp6_listener_event, (gpointer)ifdata); +#endif else ret |= UDP_IPv6_FAILED; } diff --git a/src/eduroam.config b/src/eduroam.config index 768b7b40..768b7b40 100644..100755 --- a/src/eduroam.config +++ b/src/eduroam.config diff --git a/src/error.c b/src/error.c index 4f24ae25..1a059207 100644 --- a/src/error.c +++ b/src/error.c @@ -185,3 +185,17 @@ DBusMessage *__connman_error_invalid_property(DBusMessage *msg) return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE ".InvalidProperty", "Invalid property"); } + +#if defined TIZEN_EXT_WIFI_MESH +DBusMessage *__connman_error_invalid_command(DBusMessage *msg) +{ + return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE + ".InvalidCommand", "Invalid Mesh Command"); +} + +DBusMessage *__connman_error_scan_abort_failed(DBusMessage *msg) +{ + return g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE + ".ScanAbortFailed", "Scan Abort Failed"); +} +#endif @@ -189,6 +189,78 @@ done: return err; } +#if defined TIZEN_EXT_WIFI_MESH +char *connman_inet_ifaddr(const char *name) +{ + struct ifreq ifr; + struct ether_addr eth; + char *str; + int sk, err; + + sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (sk < 0) + return NULL; + + strncpy(ifr.ifr_name, name, IFNAMSIZ-1); + + err = ioctl(sk, SIOCGIFHWADDR, &ifr); + close(sk); + + if (err < 0) + return NULL; + + str = g_malloc(18); + if (!str) + return NULL; + + memcpy(ð, &ifr.ifr_hwaddr.sa_data, sizeof(eth)); + snprintf(str, 13, "%02x%02x%02x%02x%02x%02x", + eth.ether_addr_octet[0], + eth.ether_addr_octet[1], + eth.ether_addr_octet[2], + eth.ether_addr_octet[3], + eth.ether_addr_octet[4], + eth.ether_addr_octet[5]); + + return str; +} + +char *connman_inet_ifname2addr(const char *name) +{ + struct ifreq ifr; + struct ether_addr eth; + char *str; + int sk, err; + + sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (sk < 0) + return NULL; + + strncpy(ifr.ifr_name, name, IFNAMSIZ-1); + + err = ioctl(sk, SIOCGIFHWADDR, &ifr); + close(sk); + + if (err < 0) + return NULL; + + str = g_malloc(18); + if (!str) + return NULL; + + memcpy(ð, &ifr.ifr_hwaddr.sa_data, sizeof(eth)); + snprintf(str, 18, "%02x:%02x:%02x:%02x:%02x:%02x", + eth.ether_addr_octet[0], + eth.ether_addr_octet[1], + eth.ether_addr_octet[2], + eth.ether_addr_octet[3], + eth.ether_addr_octet[4], + eth.ether_addr_octet[5]); + + return str; +} +#endif + bool __connman_inet_is_any_addr(const char *address, int family) { bool ret = false; @@ -363,6 +435,46 @@ done: return err; } +#if defined TIZEN_EXT +void connman_inet_update_device_ident(struct connman_device *device) +{ + int index; + enum connman_device_type type; + char *ident = NULL, *addr = NULL; + + index = connman_device_get_index(device); + type = connman_device_get_type(device); + + switch (type) { + case CONNMAN_DEVICE_TYPE_UNKNOWN: + return; + case CONNMAN_DEVICE_TYPE_ETHERNET: + case CONNMAN_DEVICE_TYPE_GADGET: + case CONNMAN_DEVICE_TYPE_WIFI: + addr = index2addr(index); + ident = index2ident(index, NULL); + break; + case CONNMAN_DEVICE_TYPE_CELLULAR: + ident = index2ident(index, NULL); + break; + case CONNMAN_DEVICE_TYPE_BLUETOOTH: + case CONNMAN_DEVICE_TYPE_GPS: + case CONNMAN_DEVICE_TYPE_VENDOR: + break; + } + + if (ident != NULL) { + connman_device_set_ident(device, ident); + g_free(ident); + } + + if (addr != NULL) { + connman_device_set_string(device, "Address", addr); + g_free(addr); + } +} +#endif + bool connman_inet_is_ifup(int index) { int sk; @@ -1366,6 +1478,36 @@ static int icmpv6_recv(int fd, struct xs_cb_data *data) return -errno; } +#if defined TIZEN_EXT + /* Set Received Source Address from router as IPv6 Gateway Address */ + char src_addr[INET6_ADDRSTRLEN]; + if(inet_ntop(AF_INET6, &(saddr.sin6_addr), src_addr, INET6_ADDRSTRLEN) + == NULL) + return -errno; + + DBG("Received Source Address %s from router", src_addr); + + /* icmpv6_recv() function can be called in two scenarios : + * 1. When __connman_inet_ipv6_send_rs() is called from check_dhcpv6() + * 2. When __connman_inet_ipv6_send_rs() is called from + * __connman_6to4_probe() + * In the second case it is not required to set DHCPv6 Gateway Address + * as DHCPv6 was not started and network structure was not passed as + * user_data. If it is tried to add Source Address as Gateway Address + * then it will lead to crash because of user_data being ip_address + * instead of network structure. So Adding Gateway Address in case 1st + * case only. + */ + char *address = data->user_data; + int err = 0; + unsigned char buffer[sizeof(struct in6_addr)] = {0, }; + /* Checking if user_data is an ip_address */ + err = inet_pton(AF_INET, address, buffer); + /* Setting Received Source Address from + * router as Gateway Address */ + if(err <= 0) + __connman_network_set_auto_ipv6_gateway(src_addr, data->user_data); +#endif hdr = (struct nd_router_advert *)buf; DBG("code %d len %zd hdr %zd", hdr->nd_ra_code, len, sizeof(struct nd_router_advert)); @@ -1465,6 +1607,9 @@ static int ndisc_send_unspec(int type, int oif, const struct in6_addr *dest, char cbuf[CMSG_SPACE(sizeof(*pinfo))]; struct iovec iov[2]; int fd, datalen, ret, iovlen = 1; +#if defined TIZEN_EXT + char ebuf[256]; +#endif DBG(""); @@ -1543,6 +1688,9 @@ static int ndisc_send_unspec(int type, int oif, const struct in6_addr *dest, msgh.msg_controllen = cmsg->cmsg_len; ret = sendmsg(fd, &msgh, 0); +#if defined TIZEN_EXT + DBG("sendmsg errno: %d/%s", errno, strerror_r(errno, ebuf, sizeof(ebuf))); +#endif close(fd); return ret; diff --git a/src/inotify.c b/src/inotify.c index c251c6ff..c251c6ff 100644..100755 --- a/src/inotify.c +++ b/src/inotify.c diff --git a/src/ipaddress.c b/src/ipaddress.c index d63d95c3..d63d95c3 100644..100755 --- a/src/ipaddress.c +++ b/src/ipaddress.c diff --git a/src/ipconfig.c b/src/ipconfig.c index 25657733..fb39f64d 100644..100755 --- a/src/ipconfig.c +++ b/src/ipconfig.c @@ -52,6 +52,10 @@ struct connman_ipconfig { struct connman_ipaddress *address; struct connman_ipaddress *system; +#if defined TIZEN_EXT + int dhcp_lease_duration; +#endif + int ipv6_privacy_config; char *last_dhcp_address; char **last_dhcpv6_prefixes; @@ -488,6 +492,16 @@ void __connman_ipconfig_newlink(int index, unsigned short type, index, type, type2str(type)); update: +#if defined TIZEN_EXT + if (g_strcmp0(ipdevice->address, address) != 0) { + /* If an original address is built-in physical device, + * it's hardly get an address at a initial creation + */ + g_free(ipdevice->address); + ipdevice->address = g_strdup(address); + } +#endif + ipdevice->mtu = mtu; update_stats(ipdevice, ifname, stats); @@ -1047,16 +1061,32 @@ void __connman_ipconfig_set_gateway(struct connman_ipconfig *ipconfig, ipconfig->address->gateway = g_strdup(gateway); } +#if defined TIZEN_EXT +void __connman_ipconfig_set_dhcp_lease_duration(struct connman_ipconfig *ipconfig, + int dhcp_lease_duration) +{ + ipconfig->dhcp_lease_duration = dhcp_lease_duration; +} +#endif + +#if defined TIZEN_EXT +int __connman_ipconfig_gateway_add(struct connman_ipconfig *ipconfig, struct connman_service *service) +#else int __connman_ipconfig_gateway_add(struct connman_ipconfig *ipconfig) +#endif { +#if !defined TIZEN_EXT struct connman_service *service; +#endif DBG(""); if (!ipconfig->address) return -EINVAL; +#if !defined TIZEN_EXT service = __connman_service_lookup_from_index(ipconfig->index); +#endif if (!service) return -EINVAL; @@ -1122,7 +1152,11 @@ static struct connman_ipconfig *create_ipv6config(int index) ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index)); if (ipdevice) +#if !defined TIZEN_EXT ipv6config->ipv6_privacy_config = ipdevice->ipv6_privacy; +#else + ipv6config->ipv6_privacy_config = ipdevice->ipv6_privacy = 2; +#endif ipv6config->address = connman_ipaddress_alloc(AF_INET6); if (!ipv6config->address) { @@ -1353,6 +1387,12 @@ int __connman_ipconfig_address_unset(struct connman_ipconfig *ipconfig) if (!ipconfig) return 0; +#if defined TIZEN_EXT + DBG("ipconfig method %d type %d", ipconfig->method, ipconfig->type); +#else + DBG("method %d", ipconfig->method); +#endif + switch (ipconfig->method) { case CONNMAN_IPCONFIG_METHOD_UNKNOWN: case CONNMAN_IPCONFIG_METHOD_OFF: @@ -1639,6 +1679,11 @@ int __connman_ipconfig_disable(struct connman_ipconfig *ipconfig) if (ipdevice->config_ipv6 == ipconfig) { ipconfig_list = g_list_remove(ipconfig_list, ipconfig); +#if defined TIZEN_EXT + if (ipdevice->config_ipv6->method == + CONNMAN_IPCONFIG_METHOD_AUTO) + disable_ipv6(ipdevice->config_ipv6); +#endif connman_ipaddress_clear(ipdevice->config_ipv6->system); __connman_ipconfig_unref(ipdevice->config_ipv6); ipdevice->config_ipv6 = NULL; @@ -1772,6 +1817,11 @@ void __connman_ipconfig_append_ipv4(struct connman_ipconfig *ipconfig, case CONNMAN_IPCONFIG_METHOD_MANUAL: case CONNMAN_IPCONFIG_METHOD_DHCP: append_addr = ipconfig->system; +#if defined TIZEN_EXT + /* TIZEN enables get_properties before __connman_ipconfig_newaddr */ + if (append_addr && append_addr->local == NULL) + append_addr = ipconfig->address; +#endif break; } @@ -1796,6 +1846,20 @@ void __connman_ipconfig_append_ipv4(struct connman_ipconfig *ipconfig, if (append_addr->gateway) connman_dbus_dict_append_basic(iter, "Gateway", DBUS_TYPE_STRING, &append_addr->gateway); + +#if defined TIZEN_EXT + if (ipconfig->method == CONNMAN_IPCONFIG_METHOD_DHCP) { + char *server_ip; + server_ip = __connman_dhcp_get_server_address(ipconfig); + if (server_ip) { + connman_dbus_dict_append_basic(iter, "DHCPServerIP", + DBUS_TYPE_STRING, &server_ip); + g_free(server_ip); + } + connman_dbus_dict_append_basic(iter, "DHCPLeaseDuration", + DBUS_TYPE_INT32, &ipconfig->dhcp_lease_duration); + } +#endif } void __connman_ipconfig_append_ipv6(struct connman_ipconfig *ipconfig, @@ -1833,6 +1897,11 @@ void __connman_ipconfig_append_ipv6(struct connman_ipconfig *ipconfig, case CONNMAN_IPCONFIG_METHOD_DHCP: case CONNMAN_IPCONFIG_METHOD_AUTO: append_addr = ipconfig->system; +#if defined TIZEN_EXT + /* TIZEN enables get_properties before __connman_ipconfig_newaddr */ + if (append_addr && append_addr->local == NULL) + append_addr = ipconfig->address; +#endif break; } @@ -2032,6 +2101,10 @@ int __connman_ipconfig_set_config(struct connman_ipconfig *ipconfig, case CONNMAN_IPCONFIG_METHOD_OFF: ipconfig->method = method; +#if defined TIZEN_EXT + if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6) + disable_ipv6(ipconfig); +#endif break; @@ -2042,6 +2115,9 @@ int __connman_ipconfig_set_config(struct connman_ipconfig *ipconfig, ipconfig->method = method; if (privacy_string) ipconfig->ipv6_privacy_config = privacy; +#if defined TIZEN_EXT + enable_ipv6(ipconfig); +#endif break; diff --git a/src/ippool.c b/src/ippool.c index f2e9b000..f2e9b000 100644..100755 --- a/src/ippool.c +++ b/src/ippool.c diff --git a/src/iptables.c b/src/iptables.c index 9cfd80f8..9cfd80f8 100644..100755 --- a/src/iptables.c +++ b/src/iptables.c diff --git a/src/ipv6pd.c b/src/ipv6pd.c index 8cd2a33e..8cd2a33e 100644..100755 --- a/src/ipv6pd.c +++ b/src/ipv6pd.c diff --git a/src/log.c b/src/log.c index 554b046b..444e75f6 100644..100755 --- a/src/log.c +++ b/src/log.c @@ -37,6 +37,143 @@ static const char *program_exec; static const char *program_path; +#if defined TIZEN_EXT +#include <sys/stat.h> +#include <sys/time.h> + +#define LOG_FILE_PATH "/opt/usr/data/network/connman.log" +#define MAX_LOG_SIZE 1 * 1024 * 1024 +#define MAX_LOG_COUNT 15 + +#define openlog __connman_log_open +#define closelog __connman_log_close +#define vsyslog __connman_log +#define syslog __connman_log_s + +static FILE *log_file = NULL; + +void __connman_log_open(const char *ident, int option, int facility) +{ + if (!log_file) + log_file = (FILE *)fopen(LOG_FILE_PATH, "a+"); +} + +void __connman_log_close(void) +{ + fclose(log_file); + log_file = NULL; +} + +static void __connman_log_update_file_revision(int rev) +{ + int next_log_rev = 0; + char *log_file = NULL; + char *next_log_file = NULL; + + next_log_rev = rev + 1; + + log_file = g_strdup_printf("%s.%d", LOG_FILE_PATH, rev); + next_log_file = g_strdup_printf("%s.%d", LOG_FILE_PATH, next_log_rev); + + if (next_log_rev >= MAX_LOG_COUNT) + if (remove(next_log_file) != 0) + goto error; + + if (access(next_log_file, F_OK) == 0) + __connman_log_update_file_revision(next_log_rev); + + if (rename(log_file, next_log_file) != 0) + remove(log_file); + +error: + g_free(log_file); + g_free(next_log_file); +} + +static int __connman_log_make_backup(void) +{ + const int rev = 0; + char *backup = NULL; + int ret = 0; + + backup = g_strdup_printf("%s.%d", LOG_FILE_PATH, rev); + + if (access(backup, F_OK) == 0) + __connman_log_update_file_revision(rev); + + if (rename(LOG_FILE_PATH, backup) != 0) + if (remove(LOG_FILE_PATH) != 0) + ret = -1; + + g_free(backup); + return ret; +} + +static void __connman_log_get_local_time(char *strtime, const int size) +{ + struct timeval tv; + struct tm *local_ptm; + char buf[32]; + + gettimeofday(&tv, NULL); + local_ptm = localtime(&tv.tv_sec); + + strftime(buf, sizeof(buf), "%m/%d %H:%M:%S", local_ptm); + snprintf(strtime, size, "%s.%03ld", buf, tv.tv_usec / 1000); +} + +void __connman_log(const int log_priority, const char *format, va_list ap) +{ + int log_size = 0; + struct stat buf; + char str[256]; + char strtime[40]; + + if (!log_file) + log_file = (FILE *)fopen(LOG_FILE_PATH, "a+"); + + if (!log_file) + return; + + if (fstat(fileno(log_file), &buf) < 0) { + fclose(log_file); + log_file = NULL; + return; + } + + log_size = buf.st_size; + + if (log_size >= MAX_LOG_SIZE) { + fclose(log_file); + log_file = NULL; + + if (__connman_log_make_backup() != 0) + return; + + log_file = (FILE *)fopen(LOG_FILE_PATH, "a+"); + + if (!log_file) + return; + } + + __connman_log_get_local_time(strtime, sizeof(strtime)); + + if (vsnprintf(str, sizeof(str), format, ap) > 0) + fprintf(log_file, "%s %s\n", strtime, str); +} + +void __connman_log_s(int log_priority, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + + vsyslog(LOG_DEBUG, format, ap); + + va_end(ap); +} +#endif + /* This makes sure we always have a __debug section. */ CONNMAN_DEBUG_DEFINE(dummy); diff --git a/src/machine.c b/src/machine.c index 14ea3667..14ea3667 100644..100755 --- a/src/machine.c +++ b/src/machine.c @@ -34,6 +34,8 @@ #include <sys/stat.h> #include <net/if.h> #include <netdb.h> +#include <sys/time.h> +#include <sys/resource.h> #include <gdbus.h> @@ -91,6 +93,10 @@ static struct { bool auto_connect_roaming_services; bool acd; bool use_gateways_as_timeservers; +#if defined TIZEN_EXT + char **cellular_interfaces; + bool tizen_tv_extension; +#endif } connman_settings = { .bg_scan = true, .pref_timeservers = NULL, @@ -113,6 +119,10 @@ static struct { .auto_connect_roaming_services = false, .acd = false, .use_gateways_as_timeservers = false, +#if defined TIZEN_EXT + .cellular_interfaces = NULL, + .tizen_tv_extension = false, +#endif }; #define CONF_BG_SCAN "BackgroundScanning" @@ -136,6 +146,10 @@ static struct { #define CONF_AUTO_CONNECT_ROAMING_SERVICES "AutoConnectRoamingServices" #define CONF_ACD "AddressConflictDetection" #define CONF_USE_GATEWAYS_AS_TIMESERVERS "UseGatewaysAsTimeservers" +#if defined TIZEN_EXT +#define CONF_CELLULAR_INTERFACE "NetworkCellularInterfaceList" +#define CONF_TIZEN_TV_EXT "TizenTVExtension" +#endif static const char *supported_options[] = { CONF_BG_SCAN, @@ -158,6 +172,10 @@ static const char *supported_options[] = { CONF_AUTO_CONNECT_ROAMING_SERVICES, CONF_ACD, CONF_USE_GATEWAYS_AS_TIMESERVERS, +#if defined TIZEN_EXT + CONF_CELLULAR_INTERFACE, + CONF_TIZEN_TV_EXT, +#endif NULL }; @@ -272,6 +290,46 @@ static void check_config(GKeyFile *config) g_strfreev(keys); } +#if defined TIZEN_EXT +static void check_Tizen_configuration(GKeyFile *config) +{ + GError *error = NULL; + char **cellular_interfaces; + bool boolean; + gsize len; + + cellular_interfaces = g_key_file_get_string_list(config, "General", + CONF_CELLULAR_INTERFACE, &len, &error); + + if (error == NULL) + connman_settings.cellular_interfaces = cellular_interfaces; + + g_clear_error(&error); + + boolean = __connman_config_get_bool(config, "General", + CONF_TIZEN_TV_EXT, &error); + if (!error) + connman_settings.tizen_tv_extension = boolean; + + g_clear_error(&error); +} + +static void set_nofile_inc(void) +{ + int err; + struct rlimit rlim; + + rlim.rlim_cur = 8192; + rlim.rlim_max = 8192; + + err = setrlimit(RLIMIT_NOFILE, &rlim); + if (err) + DBG("fail to increase FILENO err(%d)", err); + + return; +} +#endif + static void parse_config(GKeyFile *config) { GError *error = NULL; @@ -476,12 +534,19 @@ static void parse_config(GKeyFile *config) connman_settings.use_gateways_as_timeservers = boolean; g_clear_error(&error); + +#if defined TIZEN_EXT + check_Tizen_configuration(config); +#endif } static int config_init(const char *file) { GKeyFile *config; +#if defined TIZEN_EXT + set_nofile_inc(); +#endif config = load_config(file); check_config(config); parse_config(config); @@ -712,6 +777,11 @@ char **connman_setting_get_string_list(const char *key) if (g_str_equal(key, CONF_TETHERING_TECHNOLOGIES)) return connman_settings.tethering_technologies; +#if defined TIZEN_EXT + if (g_str_equal(key, CONF_CELLULAR_INTERFACE)) + return connman_settings.cellular_interfaces; +#endif + return NULL; } @@ -820,6 +890,9 @@ int main(int argc, char *argv[]) __connman_service_init(); __connman_peer_service_init(); __connman_peer_init(); +#if defined TIZEN_EXT_WIFI_MESH + __connman_mesh_init(); +#endif /* TIZEN_EXT_WIFI_MESH */ __connman_provider_init(); __connman_network_init(); __connman_config_init(); @@ -851,8 +924,10 @@ int main(int argc, char *argv[]) __connman_dhcpv6_init(); __connman_wpad_init(); __connman_wispr_init(); +#if !defined TIZEN_EXT __connman_rfkill_init(); __connman_machine_init(); +#endif g_free(option_config); g_free(option_device); @@ -864,8 +939,10 @@ int main(int argc, char *argv[]) g_source_remove(signal); +#if !defined TIZEN_EXT __connman_machine_cleanup(); __connman_rfkill_cleanup(); +#endif __connman_wispr_cleanup(); __connman_wpad_cleanup(); __connman_dhcpv6_cleanup(); @@ -890,6 +967,9 @@ int main(int argc, char *argv[]) __connman_firewall_cleanup(); __connman_peer_service_cleanup(); __connman_peer_cleanup(); +#if defined TIZEN_EXT_WIFI_MESH + __connman_mesh_cleanup(); +#endif /* TIZEN_EXT_WIFI_MESH */ __connman_ippool_cleanup(); __connman_device_cleanup(); __connman_network_cleanup(); diff --git a/src/main.conf b/src/main.conf index 14965e12..c3190ca3 100644..100755 --- a/src/main.conf +++ b/src/main.conf @@ -24,6 +24,7 @@ # regardless of wifi is connected or not, unless it is requested by # the user through a D-Bus call. # BackgroundScanning = true +BackgroundScanning = false # Assume that service gateways also function as timeservers. # UseGatewaysAsTimeservers = false @@ -35,6 +36,7 @@ # mixed combination of fully qualified domain names, IPv4 # and IPv6 addresses. # FallbackTimeservers = +#FallbackTimeservers = pool.ntp.org # List of fallback nameservers separated by "," used if no # nameservers are otherwise provided by the service. The @@ -61,6 +63,7 @@ # the default route when compared to either a non-preferred # type or a preferred type further down in the list. # PreferredTechnologies = +PreferredTechnologies = wifi, ethernet # List of blacklisted network interfaces separated by ",". # Found interfaces will be compared to the list and will @@ -68,6 +71,7 @@ # match any of the list entries. Default value is # vmnet,vboxnet,virbr,ifb,ve-,vb-. # NetworkInterfaceBlacklist = vmnet,vboxnet,virbr,ifb,ve-,vb- +NetworkInterfaceBlacklist = veth,vmnet,vboxnet,virbr,usb,rndis,rmnet,rev_rmnet,dummy,seth_td,seth_w # Allow ConnMan to change the system hostname. This can # happen for example if we receive DHCP hostname option. @@ -90,6 +94,7 @@ # setting enabled applications will notice more network breaks than # normal. Default value is false. # SingleConnectedTechnology = false +SingleConnectedTechnology = true # List of technologies for which tethering is allowed separated by ",". # The default value is wifi,bluetooth,gadget. Only those technologies @@ -132,6 +137,10 @@ # This setting has no effect if SingleConnectedTechnologies is enabled. # AlwaysConnectedTechnologies = +# Allow connman to add service gateway to the time server list. +# Default value is false. +# UseGatewaysAsTimeservers = false + # Enable auto connection of services in roaming. # If this setting is false, roaming services are not auto-connected by ConnMan. # Default value is false. @@ -143,3 +152,5 @@ # to an interface (in accordance with RFC 5227). # Default value is false. # AddressConflictDetection = false + +NetworkCellularInterfaceList = pdp,rmnet,seth_td,seth_w diff --git a/src/main_disable_eth.conf b/src/main_disable_eth.conf new file mode 100755 index 00000000..4cc22f1d --- /dev/null +++ b/src/main_disable_eth.conf @@ -0,0 +1,114 @@ +[General] + +# Set input request timeout. Default is 120 seconds +# The request for inputs like passphrase will timeout +# after certain amount of time. Use this setting to +# increase the value in case of different user +# interface designs. +# InputRequestTimeout = 120 + +# Set browser launch timeout. Default is 300 seconds +# The request for launching a browser for portal pages +# will timeout after certain amount of time. Use this +# setting to increase the value in case of different +# user interface designs. +# BrowserLaunchTimeout = 300 + +# Enable background scanning. Default is true. +# Background scanning will start every 5 minutes unless +# the scan list is empty. In that case, a simple backoff +# mechanism starting from 10s up to 5 minutes will run. +# BackgroundScanning = true +BackgroundScanning = false + +# List of Fallback timeservers separated by ",". +# These timeservers are used for NTP sync when there are +# no timeserver set by the user or by the service. +# These can contain mixed combination of fully qualified +# domain names, IPv4 and IPv6 addresses. +# FallbackTimeservers = +#FallbackTimeservers = pool.ntp.org + +# List of fallback nameservers separated by "," used if no +# nameservers are otherwise provided by the service. The +# nameserver entries must be in numeric format, host +# names are ignored. +# FallbackNameservers = + +# List of technologies that are marked autoconnectable +# by default, separated by commas ",". The default value +# for this entry when empty is ethernet,wifi,cellular. +# Services that are automatically connected must have been +# set up and saved to storage beforehand. +# DefaultAutoConnectTechnologies = + +# List of preferred technologies from the most preferred +# one to the least preferred one separated by commas ",". +# Services of the listed technology type will be tried one +# by one in the order given, until one of them gets connected +# or they are all tried. A service of a preferred technology +# type in state 'ready' will get the default route when +# compared to another preferred type further down the list +# with state 'ready' or with a non-preferred type; a service +# of a preferred technology type in state 'online' will get +# the default route when compared to either a non-preferred +# type or a preferred type further down in the list. +# PreferredTechnologies = +PreferredTechnologies = wifi, ethernet + +# List of blacklisted network interfaces separated by ",". +# Found interfaces will be compared to the list and will +# not be handled by connman, if their first characters +# match any of the list entries. Default value is +# vmnet,vboxnet,virbr,ifb. +# NetworkInterfaceBlacklist = vmnet,vboxnet,virbr,ifb +NetworkInterfaceBlacklist = veth, vmnet,vboxnet,virbr,usb,rndis,rmnet,rev_rmnet,dummy,seth_td,seth_w,eth + +# Allow connman to change the system hostname. This can +# happen for example if we receive DHCP hostname option. +# Default value is true. +# AllowHostnameUpdates = true + +# Keep only a single connected technology at any time. When a new +# service is connected by the user or a better one is found according +# to PreferredTechnologies, the new service is kept connected and all +# the other previously connected services are disconnected. With this +# setting it does not matter whether the previously connected services +# are in 'online' or 'ready' states, the newly connected service is +# the only one that will be kept connected. A service connected by the +# user will be used until going out of network coverage. With this +# setting enabled applications will notice more network breaks than +# normal. Default value is false. +# SingleConnectedTechnology = false +SingleConnectedTechnology = true + +# List of technologies for which tethering is allowed separated by ",". +# The default value is wifi,bluetooth,gadget. Only those technologies +# listed here are used for tethering. If ethernet tethering is desired, +# then ethernet should be added to the list. The technologies listed here +# have to support tethering, currently tethering is implemented for wifi, +# bluetooth, gadget and ethernet. +# NOTE that if ethernet tethering is enabled, then a DHCP server is +# started on all ethernet interfaces. Tethered ethernet should +# never be connected to corporate or home network as it will disrupt +# normal operation of these networks. Due to this ethernet is not +# tethered by default. Do not activate ethernet tethering unless you +# really know what you are doing. +# TetheringTechnologies = wifi,bluetooth,gadget + +# Restore earlier tethering status when returning from offline mode, +# re-enabling a technology, and after restarts and reboots. +# Default value is false. +# PersistentTetheringMode = false + +# Automatically enable Anycast 6to4 if possible. This is not recommended, as +# the use of 6to4 will generally lead to a severe degradation of connection +# quality. See RFC6343. Default value is false (as recommended by RFC6343 +# section 4.1). +# Enable6to4 = false + +NetworkCellularInterfaceList = pdp,rmnet,seth_td,seth_w + +# Allow connman to add service gateway to the time server list. +# Default value is false. +# UseGatewaysAsTimeservers = false diff --git a/src/main_ivi.conf b/src/main_ivi.conf new file mode 100755 index 00000000..8ac0d589 --- /dev/null +++ b/src/main_ivi.conf @@ -0,0 +1,114 @@ +[General] + +# Set input request timeout. Default is 120 seconds +# The request for inputs like passphrase will timeout +# after certain amount of time. Use this setting to +# increase the value in case of different user +# interface designs. +# InputRequestTimeout = 120 + +# Set browser launch timeout. Default is 300 seconds +# The request for launching a browser for portal pages +# will timeout after certain amount of time. Use this +# setting to increase the value in case of different +# user interface designs. +# BrowserLaunchTimeout = 300 + +# Enable background scanning. Default is true. +# Background scanning will start every 5 minutes unless +# the scan list is empty. In that case, a simple backoff +# mechanism starting from 10s up to 5 minutes will run. +# BackgroundScanning = true +BackgroundScanning = false + +# List of Fallback timeservers separated by ",". +# These timeservers are used for NTP sync when there are +# no timeserver set by the user or by the service. +# These can contain mixed combination of fully qualified +# domain names, IPv4 and IPv6 addresses. +# FallbackTimeservers = +#FallbackTimeservers = pool.ntp.org + +# List of fallback nameservers separated by "," used if no +# nameservers are otherwise provided by the service. The +# nameserver entries must be in numeric format, host +# names are ignored. +# FallbackNameservers = + +# List of technologies that are marked autoconnectable +# by default, separated by commas ",". The default value +# for this entry when empty is ethernet,wifi,cellular. +# Services that are automatically connected must have been +# set up and saved to storage beforehand. +# DefaultAutoConnectTechnologies = + +# List of preferred technologies from the most preferred +# one to the least preferred one separated by commas ",". +# Services of the listed technology type will be tried one +# by one in the order given, until one of them gets connected +# or they are all tried. A service of a preferred technology +# type in state 'ready' will get the default route when +# compared to another preferred type further down the list +# with state 'ready' or with a non-preferred type; a service +# of a preferred technology type in state 'online' will get +# the default route when compared to either a non-preferred +# type or a preferred type further down in the list. +# PreferredTechnologies = +PreferredTechnologies = wifi, ethernet + +# List of blacklisted network interfaces separated by ",". +# Found interfaces will be compared to the list and will +# not be handled by connman, if their first characters +# match any of the list entries. Default value is +# vmnet,vboxnet,virbr,ifb. +# NetworkInterfaceBlacklist = vmnet,vboxnet,virbr,ifb +NetworkInterfaceBlacklist = veth, vmnet,vboxnet,virbr,usb,rndis,rmnet,rev_rmnet,dummy,seth_td,seth_w,eth0 + +# Allow connman to change the system hostname. This can +# happen for example if we receive DHCP hostname option. +# Default value is true. +# AllowHostnameUpdates = true + +# Keep only a single connected technology at any time. When a new +# service is connected by the user or a better one is found according +# to PreferredTechnologies, the new service is kept connected and all +# the other previously connected services are disconnected. With this +# setting it does not matter whether the previously connected services +# are in 'online' or 'ready' states, the newly connected service is +# the only one that will be kept connected. A service connected by the +# user will be used until going out of network coverage. With this +# setting enabled applications will notice more network breaks than +# normal. Default value is false. +# SingleConnectedTechnology = false +SingleConnectedTechnology = true + +# List of technologies for which tethering is allowed separated by ",". +# The default value is wifi,bluetooth,gadget. Only those technologies +# listed here are used for tethering. If ethernet tethering is desired, +# then ethernet should be added to the list. The technologies listed here +# have to support tethering, currently tethering is implemented for wifi, +# bluetooth, gadget and ethernet. +# NOTE that if ethernet tethering is enabled, then a DHCP server is +# started on all ethernet interfaces. Tethered ethernet should +# never be connected to corporate or home network as it will disrupt +# normal operation of these networks. Due to this ethernet is not +# tethered by default. Do not activate ethernet tethering unless you +# really know what you are doing. +# TetheringTechnologies = wifi,bluetooth,gadget + +# Restore earlier tethering status when returning from offline mode, +# re-enabling a technology, and after restarts and reboots. +# Default value is false. +# PersistentTetheringMode = false + +# Automatically enable Anycast 6to4 if possible. This is not recommended, as +# the use of 6to4 will generally lead to a severe degradation of connection +# quality. See RFC6343. Default value is false (as recommended by RFC6343 +# section 4.1). +# Enable6to4 = false + +NetworkCellularInterfaceList = pdp,rmnet,seth_td,seth_w + +# Allow connman to add service gateway to the time server list. +# Default value is false. +# UseGatewaysAsTimeservers = false diff --git a/src/main_tv.conf b/src/main_tv.conf new file mode 100755 index 00000000..7a72dbe1 --- /dev/null +++ b/src/main_tv.conf @@ -0,0 +1,118 @@ +[General] + +# Set input request timeout. Default is 120 seconds +# The request for inputs like passphrase will timeout +# after certain amount of time. Use this setting to +# increase the value in case of different user +# interface designs. +# InputRequestTimeout = 120 + +# Set browser launch timeout. Default is 300 seconds +# The request for launching a browser for portal pages +# will timeout after certain amount of time. Use this +# setting to increase the value in case of different +# user interface designs. +# BrowserLaunchTimeout = 300 + +# Enable background scanning. Default is true. +# Background scanning will start every 5 minutes unless +# the scan list is empty. In that case, a simple backoff +# mechanism starting from 10s up to 5 minutes will run. +# BackgroundScanning = true +BackgroundScanning = false + +# List of Fallback timeservers separated by ",". +# These timeservers are used for NTP sync when there are +# no timeserver set by the user or by the service. +# These can contain mixed combination of fully qualified +# domain names, IPv4 and IPv6 addresses. +# FallbackTimeservers = +#FallbackTimeservers = pool.ntp.org + +# List of fallback nameservers separated by "," used if no +# nameservers are otherwise provided by the service. The +# nameserver entries must be in numeric format, host +# names are ignored. +# FallbackNameservers = + +# List of technologies that are marked autoconnectable +# by default, separated by commas ",". The default value +# for this entry when empty is ethernet,wifi,cellular. +# Services that are automatically connected must have been +# set up and saved to storage beforehand. +# DefaultAutoConnectTechnologies = + +# List of preferred technologies from the most preferred +# one to the least preferred one separated by commas ",". +# Services of the listed technology type will be tried one +# by one in the order given, until one of them gets connected +# or they are all tried. A service of a preferred technology +# type in state 'ready' will get the default route when +# compared to another preferred type further down the list +# with state 'ready' or with a non-preferred type; a service +# of a preferred technology type in state 'online' will get +# the default route when compared to either a non-preferred +# type or a preferred type further down in the list. +# PreferredTechnologies = +PreferredTechnologies = wifi, ethernet + +# List of blacklisted network interfaces separated by ",". +# Found interfaces will be compared to the list and will +# not be handled by connman, if their first characters +# match any of the list entries. Default value is +# vmnet,vboxnet,virbr,ifb. +# NetworkInterfaceBlacklist = vmnet,vboxnet,virbr,ifb +NetworkInterfaceBlacklist = veth, vmnet,vboxnet,virbr,usb,rndis,rmnet,rev_rmnet,dummy,seth_td,seth_w + +# Allow connman to change the system hostname. This can +# happen for example if we receive DHCP hostname option. +# Default value is true. +# AllowHostnameUpdates = true + +# Keep only a single connected technology at any time. When a new +# service is connected by the user or a better one is found according +# to PreferredTechnologies, the new service is kept connected and all +# the other previously connected services are disconnected. With this +# setting it does not matter whether the previously connected services +# are in 'online' or 'ready' states, the newly connected service is +# the only one that will be kept connected. A service connected by the +# user will be used until going out of network coverage. With this +# setting enabled applications will notice more network breaks than +# normal. Default value is false. +# SingleConnectedTechnology = false +SingleConnectedTechnology = true + +# List of technologies for which tethering is allowed separated by ",". +# The default value is wifi,bluetooth,gadget. Only those technologies +# listed here are used for tethering. If ethernet tethering is desired, +# then ethernet should be added to the list. The technologies listed here +# have to support tethering, currently tethering is implemented for wifi, +# bluetooth, gadget and ethernet. +# NOTE that if ethernet tethering is enabled, then a DHCP server is +# started on all ethernet interfaces. Tethered ethernet should +# never be connected to corporate or home network as it will disrupt +# normal operation of these networks. Due to this ethernet is not +# tethered by default. Do not activate ethernet tethering unless you +# really know what you are doing. +# TetheringTechnologies = wifi,bluetooth,gadget + +# Restore earlier tethering status when returning from offline mode, +# re-enabling a technology, and after restarts and reboots. +# Default value is false. +# PersistentTetheringMode = false + +# Automatically enable Anycast 6to4 if possible. This is not recommended, as +# the use of 6to4 will generally lead to a severe degradation of connection +# quality. See RFC6343. Default value is false (as recommended by RFC6343 +# section 4.1). +# Enable6to4 = false + +NetworkCellularInterfaceList = pdp,rmnet,seth_td,seth_w + +# Allow connman to add service gateway to the time server list. +# Default value is false. +# UseGatewaysAsTimeservers = false + +# Enable Tizen TV Profile Features +TizenTVExtension = true + diff --git a/src/manager.c b/src/manager.c index 3bf8f4e4..583b2ad1 100644 --- a/src/manager.c +++ b/src/manager.c @@ -41,6 +41,9 @@ static DBusMessage *get_properties(DBusConnection *conn, DBusMessageIter array, dict; dbus_bool_t offlinemode; const char *str; +#if defined TIZEN_EXT + dbus_bool_t autoconnectmode; +#endif DBG("conn %p", conn); @@ -63,6 +66,12 @@ static DBusMessage *get_properties(DBusConnection *conn, connman_dbus_dict_append_basic(&dict, "SessionMode", DBUS_TYPE_BOOLEAN, &sessionmode); +#if defined TIZEN_EXT + autoconnectmode = __connman_service_get_auto_connect_mode(); + connman_dbus_dict_append_basic(&dict, "AutoConnectMode", + DBUS_TYPE_BOOLEAN, + &autoconnectmode); +#endif connman_dbus_dict_close(&array, &dict); @@ -109,7 +118,17 @@ static DBusMessage *set_property(DBusConnection *conn, return __connman_error_invalid_arguments(msg); dbus_message_iter_get_basic(&value, &sessionmode); +#if defined TIZEN_EXT + } else if (g_str_equal(name, "AutoConnectMode") == TRUE) { + bool automode; + + if (type != DBUS_TYPE_BOOLEAN) + return __connman_error_invalid_arguments(msg); + dbus_message_iter_get_basic(&value, &automode); + + __connman_service_set_auto_connect_mode(automode); +#endif } else return __connman_error_invalid_property(msg); @@ -126,7 +145,9 @@ static DBusMessage *get_technologies(DBusConnection *conn, { DBusMessage *reply; +#if !defined TIZEN_EXT DBG(""); +#endif reply = dbus_message_new_method_return(msg); if (!reply) @@ -521,6 +542,114 @@ error: } +#if defined TIZEN_EXT_WIFI_MESH +static void append_mesh_peer_structs(DBusMessageIter *iter, void *user_data) +{ + __connman_mesh_peer_list_struct(iter); +} + +static DBusMessage *get_mesh_peers(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + DBusMessage *reply; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return NULL; + + __connman_dbus_append_objpath_dict_array(reply, + append_mesh_peer_structs, NULL); + return reply; +} + +static DBusMessage *get_connected_mesh_peers(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + DBusMessage *reply; + DBusMessageIter iter, array; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return NULL; + + dbus_message_iter_init_append(reply, &iter); + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_STRUCT_BEGIN_CHAR_AS_STRING + DBUS_TYPE_ARRAY_AS_STRING + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING + DBUS_STRUCT_END_CHAR_AS_STRING, &array); + + __connman_mesh_connected_peer_list_struct(&array); + dbus_message_iter_close_container(&iter, &array); + return reply; +} + +static DBusMessage *get_disconnected_mesh_peers(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + DBusMessage *reply; + DBusMessageIter iter, array; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return NULL; + + dbus_message_iter_init_append(reply, &iter); + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + DBUS_STRUCT_BEGIN_CHAR_AS_STRING + DBUS_TYPE_ARRAY_AS_STRING + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING + DBUS_STRUCT_END_CHAR_AS_STRING, &array); + + __connman_mesh_disconnected_peer_list_struct(&array); + dbus_message_iter_close_container(&iter, &array); + return reply; +} + +static DBusMessage *mesh_add_peer(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + const char *addr; + int err; + + dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &addr, + DBUS_TYPE_INVALID); + + DBG("Address %s", addr); + + err = __connman_mesh_change_peer_status(msg, addr, CONNMAN_MESH_PEER_ADD); + if (err < 0) + return __connman_error_failed(msg, -err); + + return NULL; +} + +static DBusMessage *mesh_remove_peer(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + const char *addr; + int err; + + dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &addr, + DBUS_TYPE_INVALID); + + DBG("Address %s", addr); + + err = __connman_mesh_change_peer_status(msg, addr, + CONNMAN_MESH_PEER_REMOVE); + if (err < 0) + return __connman_error_failed(msg, -err); + + return NULL; +} +#endif + static const GDBusMethodTable manager_methods[] = { { GDBUS_METHOD("GetProperties", NULL, GDBUS_ARGS({ "properties", "a{sv}" }), @@ -583,6 +712,21 @@ static const GDBusMethodTable manager_methods[] = { { GDBUS_METHOD("UnregisterPeerService", GDBUS_ARGS({ "specification", "a{sv}" }), NULL, unregister_peer_service) }, +#if defined TIZEN_EXT_WIFI_MESH + { GDBUS_METHOD("GetMeshPeers", + NULL, GDBUS_ARGS({ "peers", "a(oa{sv})" }), + get_mesh_peers) }, + { GDBUS_METHOD("GetConnectedMeshPeers", + NULL, GDBUS_ARGS({ "peers", "a(a{sv})" }), + get_connected_mesh_peers) }, + { GDBUS_METHOD("GetDisconnectedMeshPeers", + NULL, GDBUS_ARGS({ "peers", "a(a{sv})" }), + get_disconnected_mesh_peers) }, + { GDBUS_ASYNC_METHOD("MeshAddPeer", GDBUS_ARGS({ "address", "s" }), NULL, + mesh_add_peer) }, + { GDBUS_ASYNC_METHOD("MeshRemovePeer", GDBUS_ARGS({ "address", "s" }), NULL, + mesh_remove_peer) }, +#endif { }, }; diff --git a/src/mesh-netlink.c b/src/mesh-netlink.c new file mode 100644 index 00000000..22d69254 --- /dev/null +++ b/src/mesh-netlink.c @@ -0,0 +1,187 @@ +/* + * + * Connection Manager + * + * + * Copyright (C) 2017 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "connman.h" +#include <connman/mesh-netlink.h> +#include <netlink/genl/genl.h> +#include <netlink/genl/family.h> +#include <netlink/genl/ctrl.h> +#include <netlink/msg.h> +#include <netlink/attr.h> +#include <netlink/netlink.h> + +static int seq_check_cb(struct nl_msg *msg, void *arg) +{ + DBG(""); + + return NL_OK; +} + +static int finish_cb(struct nl_msg *msg, void *arg) +{ + int *ret = arg; + + DBG(""); + + *ret = 0; + + return NL_SKIP; +} + +static int ack_cb(struct nl_msg *msg, void *arg) +{ + int *ret = arg; + + DBG(""); + + *ret = 0; + + return NL_STOP; +} + +static int valid_cb(struct nl_msg *msg, void *arg) +{ + DBG(""); + + return NL_SKIP; +} + +static int error_cb(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) +{ + int *ret = arg; + + *ret = err->error; + + DBG("error %d", *ret); + + return NL_STOP; +} + +int __connman_mesh_netlink_set_gate_announce(mesh_nl80211_global *global, + int mesh_if_index, bool gate_announce, int hwmp_rootmode) +{ + struct nl_msg *msg; + struct nlattr *container; + struct nl_cb *cb; + int err = -1; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + cb = nl_cb_clone(global->cb); + if (!cb) + goto out; + + genlmsg_put(msg, 0, 0, global->id, 0, 0, NL80211_CMD_SET_MESH_CONFIG, 0); + nla_put_u32(msg, NL80211_ATTR_IFINDEX, mesh_if_index); + + container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG); + + nla_put_u8(msg, NL80211_MESHCONF_HWMP_ROOTMODE, hwmp_rootmode); + + nla_put_u8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS, gate_announce); + + nla_nest_end(msg, container); + + err = nl_send_auto_complete(global->nl_socket, msg); + if (err < 0) { + DBG("Failed to send msg"); + goto out; + } + + err = 1; + + nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_cb, &err); + nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_cb, &err); + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_cb, &err); + nl_cb_err(cb, NL_CB_CUSTOM, error_cb, &err); + + while (err > 0) { + int res = nl_recvmsgs(global->nl_socket, cb); + if (res < 0) + DBG("nl_recvmsgs failed: %d", res); + } + +out: + nl_cb_put(cb); + nlmsg_free(msg); + return err; +} + +mesh_nl80211_global *__connman_mesh_nl80211_global_init(void) +{ + mesh_nl80211_global *global; + + DBG(""); + + global = g_malloc0(sizeof(mesh_nl80211_global)); + + global->nl_socket = nl_socket_alloc(); + if (!global->nl_socket) { + DBG("Failed to allocate netlink socket"); + g_free(global); + return NULL; + } + + if (genl_connect(global->nl_socket)) { + DBG("Failed to connect to generic netlink"); + nl_socket_free(global->nl_socket); + g_free(global); + return NULL; + } + + nl_socket_set_buffer_size(global->nl_socket, 8192, 8192); + + global->id = genl_ctrl_resolve(global->nl_socket, "nl80211"); + if (global->id < 0) { + DBG("nl80211 generic netlink not found"); + nl_socket_free(global->nl_socket); + g_free(global); + return NULL; + } + + global->cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!global->cb) { + DBG("Failed to allocate netwlink callbacks"); + nl_socket_free(global->nl_socket); + g_free(global); + return NULL; + } + + nl_cb_set(global->cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, seq_check_cb, NULL); + + return global; +} + +void __connman_mesh_nl80211_global_deinit(mesh_nl80211_global *global) +{ + DBG(""); + + nl_cb_put(global->cb); + nl_socket_free(global->nl_socket); + g_free(global); +} diff --git a/src/mesh.c b/src/mesh.c new file mode 100644 index 00000000..b9029343 --- /dev/null +++ b/src/mesh.c @@ -0,0 +1,1660 @@ +/* + * + * Connection Manager + * + * + * Copyright (C) 2017 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <gdbus.h> + +#include <connman/storage.h> +#include "connman.h" +#include <sys/types.h> +#include <dirent.h> +#include <linux/if_bridge.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <unistd.h> +#include "mesh-netlink.h" + +static DBusConnection *connection; + +static GHashTable *mesh_table; +static GHashTable *connected_peer_table; +static GHashTable *disconnected_peer_table; + +static struct connman_mesh_driver *mesh_driver; +static struct connman_mesh_eth_driver *mesh_eth_driver; + +char *mesh_ifname; +char *bridge_interface; +static unsigned int mesh_autoconnect_timeout; +static bool is_mesh_if_created; +bool eth_if_bridged; +mesh_nl80211_global *nl80211_global; + +struct connman_mesh { + int refcount; + char *identifier; + char *name; + char *path; + char *address; + char *interface_addr; + enum connman_mesh_security security; + char *passphrase; + enum connman_mesh_state state; + enum connman_mesh_peer_type peer_type; + enum connman_mesh_peer_disconnect_reason disconnect_reason; + uint16_t frequency; + uint8_t strength; + bool registered; + bool favorite; + DBusMessage *pending; + int index; + int br_index; + uint16_t ieee80211w; + struct connman_ipconfig *ipconfig; +}; + +struct connman_mesh_connected_peer { + char *peer_address; +}; + +struct connman_mesh_disconnected_peer { + char *peer_address; + enum connman_mesh_peer_disconnect_reason disconnect_reason; +}; + +struct connman_mesh_change_peer_data { + DBusMessage *pending; + char *peer_address; + enum connman_mesh_peer_status status; +}; + +static void mesh_dhcp_callback(struct connman_ipconfig *ipconfig, + struct connman_network *network, bool success, gpointer data); + +static void mesh_free(gpointer data) +{ + struct connman_mesh *mesh = data; + + connman_mesh_unregister(mesh); + + g_free(mesh->path); + + if (mesh->state == CONNMAN_MESH_STATE_CONFIGURATION || + mesh->state == CONNMAN_MESH_STATE_READY) + __connman_dhcp_stop(mesh->ipconfig); + + if (mesh->ipconfig) { + __connman_ipconfig_set_ops(mesh->ipconfig, NULL); + __connman_ipconfig_set_data(mesh->ipconfig, NULL); + __connman_ipconfig_unref(mesh->ipconfig); + mesh->ipconfig = NULL; + } + g_free(mesh->identifier); + g_free(mesh->name); + g_free(mesh->passphrase); + g_free(mesh->interface_addr); + g_free(mesh->address); + g_free(mesh); +} + +static void mesh_connected_peer_free(gpointer data) +{ + struct connman_mesh_connected_peer *peer = data; + + g_free(peer->peer_address); + g_free(peer); +} + +static void mesh_disconnected_peer_free(gpointer data) +{ + struct connman_mesh_disconnected_peer *peer = data; + + g_free(peer->peer_address); + g_free(peer); +} + +static void __mesh_load_and_create_network(char *mesh_id) +{ + GKeyFile *keyfile; + GString *str; + struct connman_mesh *connman_mesh; + gchar *name, *passphrase, *peer_type; + char *identifier, *group, *address; + const char *sec_type, *mesh_ifname; + int freq, i; + + keyfile = connman_storage_load_service(mesh_id); + if (!keyfile) { + DBG("Mesh profile doesn't exist"); + return; + } + + peer_type = g_key_file_get_string(keyfile, mesh_id, "PeerType", NULL); + if (g_strcmp0(peer_type, "created")) { + DBG("Mesh Profile was not created"); + goto done; + } + + name = g_key_file_get_string(keyfile, mesh_id, "Name", NULL); + if (!name) { + DBG("Failed to get Mesh Profile Name"); + goto done; + } + + passphrase = g_key_file_get_string(keyfile, mesh_id, "Passphrase", NULL); + if (passphrase) + sec_type = "sae"; + else + sec_type = "none"; + + freq = g_key_file_get_integer(keyfile, mesh_id, "Frequency", NULL); + + mesh_ifname = connman_mesh_get_interface_name(); + + str = g_string_sized_new((strlen(name) * 2) + 24); + + for (i = 0; name[i]; i++) + g_string_append_printf(str, "%02x", name[i]); + + g_string_append_printf(str, "_mesh"); + + if (g_strcmp0(sec_type, "none") == 0) + g_string_append_printf(str, "_none"); + else if (g_strcmp0(sec_type, "sae") == 0) + g_string_append_printf(str, "_sae"); + + group = g_string_free(str, FALSE); + + identifier = connman_inet_ifaddr(mesh_ifname); + address = connman_inet_ifname2addr(mesh_ifname); + + connman_mesh = connman_mesh_create(identifier, group); + connman_mesh_set_name(connman_mesh, name); + connman_mesh_set_address(connman_mesh, address); + connman_mesh_set_security(connman_mesh, sec_type); + connman_mesh_set_frequency(connman_mesh, freq); + connman_mesh_set_index(connman_mesh, connman_inet_ifindex(mesh_ifname)); + connman_mesh_set_peer_type(connman_mesh, CONNMAN_MESH_PEER_TYPE_CREATED); + + connman_mesh_register(connman_mesh); + g_free(group); + g_free(identifier); + g_free(address); +done: + g_key_file_free(keyfile); +} + +static bool is_connected(struct connman_mesh *mesh) +{ + if (mesh->state == CONNMAN_MESH_STATE_READY) + return true; + + return false; +} + +static void mesh_peer_dhcp_refresh(gpointer key, gpointer value, + gpointer user_data) +{ + struct connman_mesh *mesh = value; + + DBG("mesh %p state %d", mesh, mesh->state); + + if (is_connected(mesh)) + __connman_mesh_dhcp_start(mesh->ipconfig, mesh_dhcp_callback, mesh); +} + +int connman_inet_set_stp(int stp) +{ + int sk, err = 0; + struct ifreq ifr; + unsigned long args[4]; + + if (!bridge_interface) + return -EINVAL; + + sk = socket(AF_LOCAL, SOCK_STREAM, 0); + if (sk < 0) { + err = -errno; + goto out; + } + + args[0] = BRCTL_SET_BRIDGE_STP_STATE; + args[1] = stp; + args[2] = args[3] = 0; + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_name, bridge_interface, sizeof(ifr.ifr_name) - 1); + ifr.ifr_data = (char *)args; + + if (ioctl(sk, SIOCDEVPRIVATE, &ifr) < 0) + err = -errno; + + close(sk); + +out: + if (err < 0) + DBG("Set STP Failed error %s", strerror(-err)); + + return err; +} + +int __connman_mesh_set_stp_gate_announce(bool gate_announce, int hwmp_rootmode, + int stp) +{ + int err; + + if (!mesh_ifname) + return -EINVAL; + + err = connman_inet_set_stp(stp); + if (err < 0) + return err; + + err = __connman_mesh_netlink_set_gate_announce(nl80211_global, + connman_inet_ifindex(mesh_ifname), gate_announce, + hwmp_rootmode); + + return err; +} + +void __connman_mesh_add_ethernet_to_bridge(void) +{ + if (is_mesh_if_created) { + DBG(""); + mesh_eth_driver->add_to_bridge(bridge_interface); + eth_if_bridged = true; + g_hash_table_foreach(mesh_table, mesh_peer_dhcp_refresh, NULL); + connman_inet_set_stp(1); + __connman_mesh_netlink_set_gate_announce(nl80211_global, + connman_inet_ifindex(mesh_ifname), true, + MESH_HWMP_ROOTMODE_RANN); + } +} + +void __connman_mesh_remove_ethernet_from_bridge(void) +{ + if (eth_if_bridged) { + DBG(""); + mesh_eth_driver->remove_from_bridge(bridge_interface); + eth_if_bridged = false; + g_hash_table_foreach(mesh_table, mesh_peer_dhcp_refresh, NULL); + connman_inet_set_stp(0); + __connman_mesh_netlink_set_gate_announce(nl80211_global, + connman_inet_ifindex(mesh_ifname), false, + MESH_HWMP_ROOTMODE_NO_ROOT); + } +} + +int connman_mesh_notify_interface_create(bool success) +{ + int ret; + int index; + const char *error = NULL; + DIR *dir; + struct dirent *d; + + if (!success) { + error = "Operation Failed"; + goto done; + } + + if (!bridge_interface) { + DBG("Don't create bridge interface"); + goto done; + } + + DBG("Creating bridge [%s]", bridge_interface); + + /* Create bridge interface */ + ret = __connman_bridge_create(bridge_interface); + if (0 != ret) { + DBG("Failed to create bridge [%s] : [%s]", bridge_interface, + strerror(-ret)); + error = "Bridge Creation"; + success = false; + goto done; + } + + /* Get Mesh Interface Index */ + index = connman_inet_ifindex(mesh_ifname); + if (index < 0) { + DBG("Failed to get interface index for %s", mesh_ifname); + error = "Operation Failed"; + success = false; + goto done; + } + + /* Add mesh interface into bridge */ + ret = connman_inet_add_to_bridge(index, bridge_interface); + if (0 != ret) { + DBG("Failed to add interface[%s] into bridge[%s]", mesh_ifname, + bridge_interface); + error = "Add Mesh into bridge"; + success = false; + goto done; + } + + if (__connman_technology_get_connected(CONNMAN_SERVICE_TYPE_ETHERNET)) { + mesh_eth_driver->add_to_bridge(bridge_interface); + eth_if_bridged = true; + } + + index = connman_inet_ifindex(bridge_interface); + if (index < 0) { + DBG("Failed to get interface index for %s", bridge_interface); + error = "Operation Failed"; + success = false; + goto done; + } + + /* Make bridge interface UP */ + ret = connman_inet_ifup(index); + if (0 != ret) { + DBG("Failed to change bridge interface state"); + error = "Make bridge interface UP"; + success = false; + } + +done: + if (success) { + is_mesh_if_created = true; + + /* Load previously created mesh profiles */ + dir = opendir(STORAGEDIR); + if (!dir) { + DBG("Failed to open %s directory", STORAGEDIR); + __connman_technology_mesh_interface_create_finished( + CONNMAN_SERVICE_TYPE_MESH, success, error); + return 0; + } + + while ((d = readdir(dir))) { + if (g_str_has_prefix(d->d_name, "mesh_")) { + DBG("%s is a mesh profile", d->d_name); + __mesh_load_and_create_network(d->d_name); + __connman_mesh_auto_connect(); + } + } + + closedir(dir); + + } else { + if (eth_if_bridged) + mesh_eth_driver->remove_from_bridge(bridge_interface); + + __connman_bridge_disable(bridge_interface); + + __connman_bridge_remove(bridge_interface); + + mesh_driver->remove_interface(mesh_ifname); + } + __connman_technology_mesh_interface_create_finished( + CONNMAN_SERVICE_TYPE_MESH, success, error); + return 0; +} + +int __connman_mesh_add_virtual_interface(const char *ifname, + const char *parent_ifname, const char *bridge_ifname) +{ + int ret; + + if (!ifname || !parent_ifname) + return -EINVAL; + + ret = mesh_driver->add_interface(ifname, parent_ifname); + if (ret != -EINPROGRESS) { + DBG("Failed to add virtual mesh interface"); + return ret; + } + + mesh_ifname = g_strdup(ifname); + bridge_interface = g_strdup(bridge_ifname); + DBG("Success adding virtual mesh interface"); + return 0; +} + +int connman_mesh_notify_interface_remove(bool success) +{ + struct connman_device *device; + int index; + if (success) { + g_free(mesh_ifname); + mesh_ifname = NULL; + g_hash_table_remove_all(mesh_table); + is_mesh_if_created = false; + + if (eth_if_bridged) { + if (bridge_interface) + mesh_eth_driver->remove_from_bridge(bridge_interface); + + device = __connman_device_find_device( + CONNMAN_SERVICE_TYPE_ETHERNET); + if (device) { + index = connman_device_get_index(device); + connman_inet_ifup(index); + } + eth_if_bridged = false; + } + + if (bridge_interface) { + __connman_bridge_disable(bridge_interface); + if (__connman_bridge_remove(bridge_interface)) + DBG("Failed to remove bridge [%s]", bridge_interface); + + g_free(bridge_interface); + bridge_interface = NULL; + } + } + + __connman_technology_mesh_interface_remove_finished( + CONNMAN_SERVICE_TYPE_MESH, success); + return 0; +} + +int __connman_mesh_remove_virtual_interface(const char *ifname) +{ + int ret; + int index; + + if (!ifname) + return -EINVAL; + + if (bridge_interface) { + index = connman_inet_ifindex(mesh_ifname); + if (index < 0) { + DBG("Failed to get interface index for %s", mesh_ifname); + return -EINVAL; + } + + ret = connman_inet_remove_from_bridge(index, bridge_interface); + if (0 != ret) { + DBG("Failed to remove interface[%s] freom bridge[%s]", mesh_ifname, + bridge_interface); + return -EINVAL; + } + + if (eth_if_bridged) + mesh_eth_driver->remove_from_bridge(bridge_interface); + + __connman_bridge_disable(bridge_interface); + + ret = __connman_bridge_remove(bridge_interface); + if (0 != ret) { + DBG("Failed to remove bridge [%s]", bridge_interface); + return -EINVAL; + } + + g_free(bridge_interface); + bridge_interface = NULL; + } + + ret = mesh_driver->remove_interface(ifname); + if (ret != -EINPROGRESS) { + DBG("Failed to remove virtual mesh interface"); + return ret; + } + + DBG("Success removing virtual mesh interface"); + return 0; +} + +const char *connman_mesh_get_interface_name(void) +{ + return mesh_ifname; +} + +bool connman_mesh_is_interface_created(void) +{ + DBG("Mesh interface is %screated", is_mesh_if_created ? "" : "not "); + return is_mesh_if_created; +} + +struct connman_mesh *connman_mesh_create(const char *interface_addr, + const char *identifier) +{ + struct connman_mesh *mesh; + + mesh = g_malloc0(sizeof(struct connman_mesh)); + mesh->identifier = g_strdup_printf("mesh_%s_%s", interface_addr, + identifier); + mesh->interface_addr = g_strdup(interface_addr); + mesh->state = CONNMAN_MESH_STATE_IDLE; + + mesh->refcount = 1; + + return mesh; +} + +void connman_mesh_set_name(struct connman_mesh *mesh, const char *name) +{ + g_free(mesh->name); + mesh->name = g_strdup(name); +} + +const char *connman_mesh_get_name(struct connman_mesh *mesh) +{ + return mesh->name; +} + +void connman_mesh_set_passphrase(struct connman_mesh *mesh, + const char *passphrase) +{ + g_free(mesh->passphrase); + mesh->passphrase = g_strdup(passphrase); +} + +const char *connman_mesh_get_passphrase(struct connman_mesh *mesh) +{ + return mesh->passphrase; +} + +void connman_mesh_set_address(struct connman_mesh *mesh, const char *address) +{ + g_free(mesh->address); + mesh->address = g_strdup(address); +} + +void connman_mesh_set_security(struct connman_mesh *mesh, const char *security) +{ + if (!g_strcmp0(security, "none")) + mesh->security = CONNMAN_MESH_SECURITY_NONE; + else if (!g_strcmp0(security, "sae")) + mesh->security = CONNMAN_MESH_SECURITY_SAE; + else + mesh->security = CONNMAN_MESH_SECURITY_UNKNOWN; +} + +static const char *security2string(enum connman_mesh_security security) +{ + switch (security) { + case CONNMAN_MESH_SECURITY_UNKNOWN: + break; + case CONNMAN_MESH_SECURITY_NONE: + return "none"; + case CONNMAN_MESH_SECURITY_SAE: + return "sae"; + } + + return NULL; +} + +const char *connman_mesh_get_security(struct connman_mesh *mesh) +{ + return security2string(mesh->security); +} + +void connman_mesh_set_frequency(struct connman_mesh *mesh, uint16_t frequency) +{ + mesh->frequency = frequency; +} + +uint16_t connman_mesh_get_frequency(struct connman_mesh *mesh) +{ + return mesh->frequency; +} + +void connman_mesh_set_ieee80211w(struct connman_mesh *mesh, uint16_t ieee80211w) +{ + mesh->ieee80211w = ieee80211w; +} + +uint16_t connman_mesh_get_ieee80211w(struct connman_mesh *mesh) +{ + return mesh->ieee80211w; +} + +void connman_mesh_set_index(struct connman_mesh *mesh, int index) +{ + mesh->index = index; + + if (bridge_interface) + mesh->br_index = connman_inet_ifindex(bridge_interface); +} + +void connman_mesh_set_strength(struct connman_mesh *mesh, uint8_t strength) +{ + mesh->strength = strength; +} + +static const char *peertype2string(enum connman_mesh_peer_type type) +{ + switch (type) { + case CONNMAN_MESH_PEER_TYPE_CREATED: + return "created"; + case CONNMAN_MESH_PEER_TYPE_DISCOVERED: + return "discovered"; + } + + return NULL; +} + +void connman_mesh_set_peer_type(struct connman_mesh *mesh, + enum connman_mesh_peer_type type) +{ + mesh->peer_type = type; +} + +static const char *state2string(enum connman_mesh_state state) +{ + switch (state) { + case CONNMAN_MESH_STATE_UNKNOWN: + break; + case CONNMAN_MESH_STATE_IDLE: + return "idle"; + case CONNMAN_MESH_STATE_ASSOCIATION: + return "association"; + case CONNMAN_MESH_STATE_CONFIGURATION: + return "configuration"; + case CONNMAN_MESH_STATE_READY: + return "ready"; + case CONNMAN_MESH_STATE_DISCONNECT: + return "disconnect"; + case CONNMAN_MESH_STATE_FAILURE: + return "failure"; + } + + return NULL; +} + +static enum connman_mesh_peer_disconnect_reason convert_to_disconnect_reason( + int reason) +{ + switch (reason) { + case 3: + return CONNMAN_MESH_DEAUTH_LEAVING; + case 52: + return CONNMAN_MESH_PEERING_CANCELLED; + case 53: + return CONNMAN_MESH_MAX_PEERS; + case 54: + return CONNMAN_MESH_CONFIG_POLICY_VIOLATION; + case 55: + return CONNMAN_MESH_CLOSE_RCVD; + case 56: + return CONNMAN_MESH_MAX_RETRIES; + case 57: + return CONNMAN_MESH_CONFIRM_TIMEOUT; + case 58: + return CONNMAN_MESH_INVALID_GTK; + case 59: + return CONNMAN_MESH_INCONSISTENT_PARAMS; + case 60: + return CONNMAN_MESH_INVALID_SECURITY_CAP; + } + + return CONNMAN_MESH_REASON_UNKNOWN; +} + +void connman_mesh_peer_set_disconnect_reason(struct connman_mesh *mesh, + int disconnect_reason) +{ + mesh->disconnect_reason = convert_to_disconnect_reason(disconnect_reason); +} + +static bool is_connecting(struct connman_mesh *mesh) +{ + if (mesh->state == CONNMAN_MESH_STATE_ASSOCIATION || + mesh->state == CONNMAN_MESH_STATE_CONFIGURATION) + return true; + + return false; +} + +static int mesh_load(struct connman_mesh *mesh) +{ + GKeyFile *keyfile; + bool favorite; + GError *error = NULL; + gchar *str; + + keyfile = connman_storage_load_service(mesh->identifier); + if (!keyfile) { + DBG("Mesh profile is new"); + return -EIO; + } + + favorite = g_key_file_get_boolean(keyfile, + mesh->identifier, "Favorite", &error); + + if (!error) + mesh->favorite = favorite; + + g_clear_error(&error); + + str = g_key_file_get_string(keyfile, mesh->identifier, "Passphrase", NULL); + + if (str) { + g_free(mesh->passphrase); + mesh->passphrase = str; + } + + return 0; +} + +static int mesh_save(struct connman_mesh *mesh) +{ + GKeyFile *keyfile; + + keyfile = __connman_storage_open_service(mesh->identifier); + if (!keyfile) + return -EIO; + + g_key_file_set_string(keyfile, mesh->identifier, "Name", mesh->name); + g_key_file_set_integer(keyfile, mesh->identifier, "Frequency", + mesh->frequency); + g_key_file_set_boolean(keyfile, mesh->identifier, "Favorite", + mesh->favorite); + + if (mesh->passphrase) + g_key_file_set_string(keyfile, mesh->identifier, "Passphrase", + mesh->passphrase); + + g_key_file_set_string(keyfile, mesh->identifier, "PeerType", + peertype2string(mesh->peer_type)); + + __connman_storage_save_service(keyfile, mesh->identifier); + + g_key_file_free(keyfile); + + return 0; +} + +static void reply_pending(struct connman_mesh *mesh, int error) +{ + if (!mesh->pending) + return; + + connman_dbus_reply_pending(mesh->pending, error, NULL); + mesh->pending = NULL; +} + +static void state_changed(struct connman_mesh *mesh) +{ + const char *state; + + state = state2string(mesh->state); + if (!state) + return; + + connman_dbus_property_changed_basic(mesh->path, + CONNMAN_MESH_INTERFACE, "State", + DBUS_TYPE_STRING, &state); +} + +static void mesh_dhcp_callback(struct connman_ipconfig *ipconfig, + struct connman_network *network, bool success, gpointer data) +{ + struct connman_mesh *mesh = data; + int err; + + if (!success) + goto error; + + err = __connman_ipconfig_address_add(ipconfig); + if (err < 0) + goto error; + + return; + +error: + connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_FAILURE); +} + +static int mesh_start_dhcp_client(struct connman_mesh *mesh) +{ + DBG(""); + + __connman_ipconfig_enable(mesh->ipconfig); + + return __connman_mesh_dhcp_start(mesh->ipconfig, mesh_dhcp_callback, mesh); +} + +static void mesh_remove_connected_peer(gpointer key, gpointer value, + gpointer user_data) +{ + struct connman_mesh_connected_peer *peer = value; + + DBG("Remove Peer %s", peer->peer_address); + g_hash_table_remove(connected_peer_table, key); +} + +static void mesh_remove_disconnected_peer(gpointer key, gpointer value, + gpointer user_data) +{ + struct connman_mesh_disconnected_peer *peer = value; + + DBG("Remove Peer %s", peer->peer_address); + g_hash_table_remove(disconnected_peer_table, key); +} + +int connman_mesh_peer_set_state(struct connman_mesh *mesh, + enum connman_mesh_state new_state) +{ + enum connman_mesh_state old_state = mesh->state; + + DBG("mesh peer %s old state %s new state %s", mesh->name, + state2string(old_state), state2string(new_state)); + + if (old_state == new_state) + return -EALREADY; + + switch (new_state) { + case CONNMAN_MESH_STATE_UNKNOWN: + return -EINVAL; + case CONNMAN_MESH_STATE_IDLE: + case CONNMAN_MESH_STATE_ASSOCIATION: + break; + case CONNMAN_MESH_STATE_CONFIGURATION: + /* Start Link Local IP Address */ + mesh_start_dhcp_client(mesh); + break; + case CONNMAN_MESH_STATE_READY: + reply_pending(mesh, 0); + mesh->favorite = true; + __connman_notifier_connect(CONNMAN_SERVICE_TYPE_MESH); + + /* Set Gate Announce option */ + if (eth_if_bridged) { + connman_inet_set_stp(1); + __connman_mesh_netlink_set_gate_announce(nl80211_global, + connman_inet_ifindex(mesh_ifname), true, + MESH_HWMP_ROOTMODE_RANN); + } + + mesh_save(mesh); + break; + case CONNMAN_MESH_STATE_DISCONNECT: + __connman_dhcp_stop(mesh->ipconfig); + g_hash_table_foreach(connected_peer_table, mesh_remove_connected_peer, + NULL); + g_hash_table_foreach(disconnected_peer_table, + mesh_remove_disconnected_peer, NULL); + __connman_notifier_disconnect(CONNMAN_SERVICE_TYPE_MESH); + break; + case CONNMAN_MESH_STATE_FAILURE: + reply_pending(mesh, ECONNABORTED); + break; + } + + mesh->state = new_state; + state_changed(mesh); + + return 0; +} + +bool connman_mesh_peer_is_connected_state(struct connman_mesh *mesh) +{ + switch (mesh->state) { + case CONNMAN_MESH_STATE_UNKNOWN: + case CONNMAN_MESH_STATE_IDLE: + case CONNMAN_MESH_STATE_ASSOCIATION: + case CONNMAN_MESH_STATE_CONFIGURATION: + case CONNMAN_MESH_STATE_DISCONNECT: + case CONNMAN_MESH_STATE_FAILURE: + break; + case CONNMAN_MESH_STATE_READY: + return true; + } + + return false; +} + +struct connman_mesh *connman_get_connected_mesh_from_name(char *name) +{ + GList *list, *start; + + list = g_hash_table_get_values(mesh_table); + start = list; + for (; list; list = list->next) { + struct connman_mesh *mesh = list->data; + + if (!g_strcmp0(mesh->name, name) && + mesh->state == CONNMAN_MESH_STATE_READY) { + g_list_free(start); + return mesh; + } + } + + g_list_free(start); + + return NULL; +} + +struct connman_mesh *connman_get_connecting_mesh_from_name(char *name) +{ + GList *list, *start; + + list = g_hash_table_get_values(mesh_table); + start = list; + for (; list; list = list->next) { + struct connman_mesh *mesh = list->data; + + if (!g_strcmp0(mesh->name, name) && is_connecting(mesh)) { + g_list_free(start); + return mesh; + } + } + + g_list_free(start); + + return NULL; +} + +static void mesh_append_ethernet(DBusMessageIter *iter, void *user_data) +{ + struct connman_mesh *mesh = user_data; + + if (mesh->ipconfig) + __connman_ipconfig_append_ethernet(mesh->ipconfig, iter); +} + +static void mesh_append_ipv4(DBusMessageIter *iter, void *user_data) +{ + struct connman_mesh *mesh = user_data; + + if (!is_connected(mesh)) + return; + + if (mesh->ipconfig) + __connman_ipconfig_append_ipv4(mesh->ipconfig, iter); +} + +static void mesh_append_ipv4config(DBusMessageIter *iter, void *user_data) +{ + struct connman_mesh *mesh = user_data; + + if (mesh->ipconfig) + __connman_ipconfig_append_ipv4config(mesh->ipconfig, iter); +} + +static void append_properties(DBusMessageIter *iter, struct connman_mesh *mesh) +{ + const char *state = state2string(mesh->state); + const char *security = security2string(mesh->security); + const char *peer_type = peertype2string(mesh->peer_type); + const char *type = "mesh"; + DBusMessageIter dict; + + connman_dbus_dict_open(iter, &dict); + + connman_dbus_dict_append_basic(&dict, "Type", DBUS_TYPE_STRING, &type); + connman_dbus_dict_append_basic(&dict, "Name", + DBUS_TYPE_STRING, &mesh->name); + connman_dbus_dict_append_basic(&dict, "BSSID", + DBUS_TYPE_STRING, &mesh->address); + connman_dbus_dict_append_basic(&dict, "State", DBUS_TYPE_STRING, &state); + if (security) + connman_dbus_dict_append_basic(&dict, "Security", + DBUS_TYPE_STRING, &security); + connman_dbus_dict_append_basic(&dict, "Frequency", + DBUS_TYPE_UINT16, &mesh->frequency); + connman_dbus_dict_append_basic(&dict, "Favorite", + DBUS_TYPE_BOOLEAN, &mesh->favorite); + connman_dbus_dict_append_basic(&dict, "Strength", + DBUS_TYPE_BYTE, &mesh->strength); + connman_dbus_dict_append_basic(&dict, "PeerType", + DBUS_TYPE_STRING, &peer_type); + connman_dbus_dict_append_basic(&dict, "DisconnectReason", + DBUS_TYPE_INT32, &mesh->disconnect_reason); + + connman_dbus_dict_append_dict(&dict, "Ethernet", mesh_append_ethernet, + mesh); + + connman_dbus_dict_append_dict(&dict, "IPv4", mesh_append_ipv4, mesh); + + connman_dbus_dict_append_dict(&dict, "IPv4.Configuration", + mesh_append_ipv4config, mesh); + + connman_dbus_dict_close(iter, &dict); +} + +static void append_mesh_peer_struct(gpointer key, gpointer value, + gpointer user_data) +{ + DBusMessageIter *array = user_data; + struct connman_mesh *mesh = value; + DBusMessageIter entry; + + DBG("Mesh Peer path %s", mesh->path); + dbus_message_iter_open_container(array, DBUS_TYPE_STRUCT, + NULL, &entry); + dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH, + &mesh->path); + append_properties(&entry, mesh); + dbus_message_iter_close_container(array, &entry); +} + +void __connman_mesh_peer_list_struct(DBusMessageIter *array) +{ + g_hash_table_foreach(mesh_table, append_mesh_peer_struct, array); +} + +static DBusMessage *get_mesh_peer_properties(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct connman_mesh *mesh = data; + DBusMessageIter dict; + DBusMessage *reply; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return NULL; + + dbus_message_iter_init_append(reply, &dict); + append_properties(&dict, mesh); + + return reply; +} + +static void append_mesh_disconnected_peer_struct(gpointer key, gpointer value, + gpointer user_data) +{ + DBusMessageIter *array = user_data; + struct connman_mesh_disconnected_peer *peer = value; + DBusMessageIter entry; + DBusMessageIter dict; + + dbus_message_iter_open_container(array, DBUS_TYPE_STRUCT, + NULL, &entry); + + connman_dbus_dict_open(&entry, &dict); + + connman_dbus_dict_append_basic(&dict, "PeerAddress", + DBUS_TYPE_STRING, &peer->peer_address); + + connman_dbus_dict_append_basic(&dict, "DisconnectReason", + DBUS_TYPE_INT32, &peer->disconnect_reason); + + connman_dbus_dict_close(&entry, &dict); + dbus_message_iter_close_container(array, &entry); +} + +void __connman_mesh_disconnected_peer_list_struct(DBusMessageIter *array) +{ + g_hash_table_foreach(disconnected_peer_table, + append_mesh_disconnected_peer_struct, array); +} + +static void append_mesh_connected_peer_struct(gpointer key, gpointer value, + gpointer user_data) +{ + DBusMessageIter *array = user_data; + struct connman_mesh_connected_peer *peer = value; + DBusMessageIter entry; + DBusMessageIter dict; + + dbus_message_iter_open_container(array, DBUS_TYPE_STRUCT, + NULL, &entry); + + connman_dbus_dict_open(&entry, &dict); + + connman_dbus_dict_append_basic(&dict, "PeerAddress", + DBUS_TYPE_STRING, &peer->peer_address); + + connman_dbus_dict_close(&entry, &dict); + dbus_message_iter_close_container(array, &entry); +} + +void __connman_mesh_connected_peer_list_struct(DBusMessageIter *array) +{ + g_hash_table_foreach(connected_peer_table, + append_mesh_connected_peer_struct, array); +} + +int connman_mesh_add_connected_peer(const char *peer_address) +{ + struct connman_mesh_connected_peer *peer; + struct connman_mesh_connected_peer *temp_peer; + struct connman_mesh_disconnected_peer *disconn_peer; + + temp_peer = g_hash_table_lookup(connected_peer_table, peer_address); + + if (temp_peer) { + DBG("Mesh Peer %s is already connected", peer_address); + return 0; + } + + peer = g_malloc0(sizeof(struct connman_mesh_connected_peer)); + peer->peer_address = g_strdup(peer_address); + DBG("Peer %s", peer->peer_address); + + g_hash_table_insert(connected_peer_table, peer->peer_address, peer); + + /* Remove from disconnected Peer Table */ + disconn_peer = g_hash_table_lookup(disconnected_peer_table, peer_address); + if (!disconn_peer) { + DBG("Peer %s was never disconnected", peer_address); + goto done; + } + + g_hash_table_remove(disconnected_peer_table, peer_address); +done: + return 0; +} + +int connman_mesh_remove_connected_peer(const char *peer_address, int reason) +{ + struct connman_mesh_connected_peer *peer; + struct connman_mesh_disconnected_peer *disconn_peer; + + peer = g_hash_table_lookup(connected_peer_table, peer_address); + + if (!peer) { + DBG("Peer %s not connected", peer_address); + return 0; + } + + g_hash_table_remove(connected_peer_table, peer_address); + + /* Add to Disconnected Peer Table */ + disconn_peer = g_malloc0(sizeof(struct connman_mesh_disconnected_peer)); + disconn_peer->peer_address = g_strdup(peer_address); + disconn_peer->disconnect_reason = convert_to_disconnect_reason(reason); + + g_hash_table_insert(disconnected_peer_table, disconn_peer->peer_address, + disconn_peer); + + DBG("Mesh Peer %s removed due to reason %d", peer_address, reason); + return 0; +} + +static void __mesh_change_peer_status_cb(int result, void *user_data) +{ + struct connman_mesh_change_peer_data *data = user_data; + + DBG("Status %d Peer Address %s result %d", data->status, data->peer_address, + result); + + connman_dbus_reply_pending(data->pending, -result, NULL); + + data->pending = NULL; + g_free(data->peer_address); + g_free(data); +} + +int __connman_mesh_change_peer_status(DBusMessage *msg, + const char *peer_address, + enum connman_mesh_peer_status status) +{ + struct connman_mesh_connected_peer *conn_peer; + struct connman_mesh_disconnected_peer *disconn_peer; + int err = -ENOTSUP; + struct connman_mesh_change_peer_data *data; + + switch (status) { + case CONNMAN_MESH_PEER_ADD: + conn_peer = g_hash_table_lookup(connected_peer_table, peer_address); + + if (conn_peer) { + DBG("Peer %s already connected", peer_address); + return -EEXIST; + } + + break; + + case CONNMAN_MESH_PEER_REMOVE: + disconn_peer = g_hash_table_lookup(disconnected_peer_table, + peer_address); + + if (disconn_peer) { + DBG("Peer %s already disconnected", peer_address); + return -EEXIST; + } + + break; + + default: + DBG("Invalid Status type"); + return err; + } + + if (mesh_driver->change_peer_status) { + data = g_try_malloc0(sizeof(struct connman_mesh_disconnected_peer)); + if (data == NULL) { + DBG("Memory allocation failed"); + return -ENOMEM; + } + + data->pending = dbus_message_ref(msg); + data->peer_address = g_strdup(peer_address); + data->status = status; + + err = mesh_driver->change_peer_status(peer_address, status, + __mesh_change_peer_status_cb, data); + + if (err < 0) { + dbus_message_unref(data->pending); + g_free(data->peer_address); + g_free(data); + } + } + + return err; +} + +static int mesh_peer_connect(struct connman_mesh *mesh) +{ + int err = -ENOTSUP; + if (mesh_driver->connect) + err = mesh_driver->connect(mesh); + + /* Reset Disconnect Reason */ + mesh->disconnect_reason = CONNMAN_MESH_REASON_UNKNOWN; + return err; +} + +static DBusMessage *connect_mesh_peer(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + struct connman_mesh *mesh = user_data; + int err; + + DBG("mesh %p", mesh); + + if (mesh->state == CONNMAN_MESH_STATE_READY) { + DBG("mesh %s already connected", mesh->name); + return __connman_error_already_exists(msg); + } + + if (mesh->pending) + return __connman_error_in_progress(msg); + + mesh->pending = dbus_message_ref(msg); + + err = mesh_peer_connect(mesh); + if (err == -EINPROGRESS) + return NULL; + + if (err < 0) { + dbus_message_unref(mesh->pending); + mesh->pending = NULL; + return __connman_error_failed(msg, -err); + } + + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); +} + +static void auto_connect_mesh_peer(gpointer key, gpointer value, + gpointer user_data) +{ + bool *conn_started = user_data; + struct connman_mesh *mesh = value; + int err; + + if (*conn_started) + return; + + if (!mesh->favorite || mesh->state != CONNMAN_MESH_STATE_IDLE) + return; + + err = mesh_peer_connect(mesh); + if (err == -EINPROGRESS) + *conn_started = 1; +} + +static gboolean run_mesh_auto_connect(gpointer data) +{ + bool conn_started; + + mesh_autoconnect_timeout = 0; + DBG(""); + + conn_started = false; + g_hash_table_foreach(mesh_table, auto_connect_mesh_peer, &conn_started); + return FALSE; +} + +void __connman_mesh_auto_connect(void) +{ + DBG(""); + + if (mesh_autoconnect_timeout != 0) + return; + + mesh_autoconnect_timeout = g_idle_add(run_mesh_auto_connect, NULL); +} + +static void mesh_peer_up(struct connman_ipconfig *ipconfig, const char *ifname) +{ + DBG("%s up", ifname); +} + +static void mesh_peer_down(struct connman_ipconfig *ipconfig, + const char *ifname) +{ + DBG("%s down", ifname); +} + +static void mesh_peer_lower_up(struct connman_ipconfig *ipconfig, + const char *ifname) +{ + DBG("%s lower up", ifname); +} + +static void mesh_peer_lower_down(struct connman_ipconfig *ipconfig, + const char *ifname) +{ + DBG("%s lower down", ifname); +} + +static void mesh_peer_ip_bound(struct connman_ipconfig *ipconfig, + const char *ifname) +{ + struct connman_mesh *mesh = __connman_ipconfig_get_data(ipconfig); + + DBG("%s ip bound", ifname); + + connman_mesh_peer_set_state(mesh, CONNMAN_MESH_STATE_READY); +} + +static void mesh_peer_ip_release(struct connman_ipconfig *ipconfig, + const char *ifname) +{ + DBG("%s ip release", ifname); +} + +static const struct connman_ipconfig_ops mesh_peer_ip_ops = { + .up = mesh_peer_up, + .down = mesh_peer_down, + .lower_up = mesh_peer_lower_up, + .lower_down = mesh_peer_lower_down, + .ip_bound = mesh_peer_ip_bound, + .ip_release = mesh_peer_ip_release, + .route_set = NULL, + .route_unset = NULL, +}; + +static struct connman_ipconfig *create_ipconfig(int index, void *user_data) +{ + struct connman_ipconfig *ipconfig; + + ipconfig = __connman_ipconfig_create(index, + CONNMAN_IPCONFIG_TYPE_IPV4); + if (!ipconfig) + return NULL; + + __connman_ipconfig_set_method(ipconfig, CONNMAN_IPCONFIG_METHOD_DHCP); + __connman_ipconfig_set_data(ipconfig, user_data); + __connman_ipconfig_set_ops(ipconfig, &mesh_peer_ip_ops); + + return ipconfig; +} + +static int __connman_mesh_peer_disconnect(struct connman_mesh *mesh) +{ + int err; + + reply_pending(mesh, ECONNABORTED); + + if (!is_connected(mesh) && !is_connecting(mesh)) + return -ENOTCONN; + + err = mesh_driver->disconnect(mesh); + if (err < 0 && err != -EINPROGRESS) + return err; + + return err; +} + +static DBusMessage *disconnect_mesh_peer(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + struct connman_mesh *mesh = user_data; + int err; + + DBG("mesh %p", mesh); + err = __connman_mesh_peer_disconnect(mesh); + if (err < 0 && err != -EINPROGRESS) + return __connman_error_failed(msg, -err); + + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); +} + +static bool __connman_mesh_peer_remove(struct connman_mesh *mesh) +{ + if (!mesh->favorite) + return false; + + __connman_mesh_peer_disconnect(mesh); + + mesh->favorite = false; + + __connman_storage_remove_service(mesh->identifier); + + return true; +} + +static DBusMessage *remove_mesh_peer(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + struct connman_mesh *mesh = user_data; + + DBG("mesh %p", mesh); + + if (!__connman_mesh_peer_remove(mesh)) + return __connman_error_not_supported(msg); + + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); +} + +static DBusMessage *set_mesh_peer_property(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + struct connman_mesh *mesh = user_data; + DBusMessageIter iter, value; + const char *name; + int type; + + DBG("mesh %p", mesh); + + if (!dbus_message_iter_init(msg, &iter)) + return __connman_error_invalid_arguments(msg); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&iter, &name); + dbus_message_iter_next(&iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_recurse(&iter, &value); + + type = dbus_message_iter_get_arg_type(&value); + + if (g_str_equal(name, "Passphrase")) { + char *passphrase; + + if (type != DBUS_TYPE_STRING) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&value, &passphrase); + + connman_mesh_set_passphrase(mesh, passphrase); + } else { + DBG("Invalid Property %s", name); + return __connman_error_invalid_property(msg); + } + + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); +} + +static const GDBusMethodTable mesh_methods[] = { + { GDBUS_METHOD("GetProperties", + NULL, GDBUS_ARGS({ "properties", "a{sv}" }), + get_mesh_peer_properties) }, + { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, connect_mesh_peer) }, + { GDBUS_METHOD("Disconnect", NULL, NULL, disconnect_mesh_peer) }, + { GDBUS_METHOD("Remove", NULL, NULL, remove_mesh_peer) }, + { GDBUS_METHOD("SetProperty", + GDBUS_ARGS({ "name", "s" }, { "value", "v" }), + NULL, set_mesh_peer_property) }, + { }, +}; + +static const GDBusSignalTable mesh_signals[] = { + { GDBUS_SIGNAL("PropertyChanged", + GDBUS_ARGS({ "name", "s" }, { "value", "v" })) }, + { }, +}; + +int connman_mesh_register(struct connman_mesh *mesh) +{ + struct connman_mesh *temp; + DBG("mesh %p", mesh); + + if (mesh->path) + return -EALREADY; + + mesh->path = g_strdup_printf("%s/mesh/%s", CONNMAN_PATH, + mesh->identifier); + DBG("path %s", mesh->path); + + temp = g_hash_table_lookup(mesh_table, mesh->path); + if (temp) { + DBG("mesh path %s already exists", mesh->path); + + if (mesh->frequency != temp->frequency) { + DBG("Update frequency for mesh network %s", mesh->name); + connman_mesh_set_frequency(temp, mesh->frequency); + } + + mesh_free(mesh); + return -EALREADY; + } + + if (mesh->br_index > 0) + mesh->ipconfig = create_ipconfig(mesh->br_index, mesh); + else + mesh->ipconfig = create_ipconfig(mesh->index, mesh); + + if (!mesh->ipconfig) + return -ENOMEM; + + g_hash_table_insert(mesh_table, mesh->path, mesh); + + mesh_load(mesh); + + g_dbus_register_interface(connection, mesh->path, + CONNMAN_MESH_INTERFACE, + mesh_methods, mesh_signals, + NULL, mesh, NULL); + mesh->registered = true; + return 0; +} + +void connman_mesh_unregister(struct connman_mesh *mesh) +{ + DBG("mesh %p", mesh); + + if (!mesh->path || !mesh->registered) + return; + + g_dbus_unregister_interface(connection, mesh->path, + CONNMAN_MESH_INTERFACE); + mesh->registered = false; + + g_hash_table_remove(mesh_table, mesh->path); +} + +struct connman_mesh *connman_mesh_get(const char *interface_addr, + const char *identifier) +{ + char *ident = g_strdup_printf("%s/mesh/mesh_%s_%s", CONNMAN_PATH, + interface_addr, identifier); + struct connman_mesh *mesh; + + mesh = g_hash_table_lookup(mesh_table, ident); + g_free(ident); + + return mesh; +} + +int connman_mesh_driver_register(struct connman_mesh_driver *driver) +{ + if (mesh_driver && mesh_driver != driver) + return -EINVAL; + + mesh_driver = driver; + + return 0; +} + +void connman_mesh_driver_unregister(struct connman_mesh_driver *driver) +{ + if (mesh_driver != driver) + return; + + mesh_driver = NULL; +} + +int connman_mesh_eth_driver_register(struct connman_mesh_eth_driver *driver) +{ + if (mesh_eth_driver && mesh_eth_driver != driver) + return -EINVAL; + + mesh_eth_driver = driver; + + return 0; +} + +void connman_mesh_eth_driver_unregister(struct connman_mesh_eth_driver *driver) +{ + if (mesh_eth_driver != driver) + return; + + mesh_eth_driver = NULL; +} + +int __connman_mesh_init(void) +{ + DBG(""); + + connection = connman_dbus_get_connection(); + + mesh_table = g_hash_table_new_full(g_str_hash, g_str_equal, + NULL, mesh_free); + + connected_peer_table = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, + mesh_connected_peer_free); + + disconnected_peer_table = g_hash_table_new_full(g_str_hash, g_str_equal, + NULL, mesh_disconnected_peer_free); + + nl80211_global = __connman_mesh_nl80211_global_init(); + return 0; +} + +void __connman_mesh_cleanup(void) +{ + DBG(""); + + __connman_mesh_nl80211_global_deinit(nl80211_global); + g_hash_table_destroy(mesh_table); + g_hash_table_destroy(connected_peer_table); + g_hash_table_destroy(disconnected_peer_table); + dbus_connection_unref(connection); +} diff --git a/src/nat.c b/src/nat.c index 681acb21..681acb21 100644..100755 --- a/src/nat.c +++ b/src/nat.c diff --git a/src/net.connman.service.in b/src/net.connman.service.in index f7f6a7c0..990eb66b 100644..100755 --- a/src/net.connman.service.in +++ b/src/net.connman.service.in @@ -1,5 +1,6 @@ [D-BUS Service] Name=net.connman -Exec=@sbindir@/connmand -n -User=root +Exec=/bin/false +User=network_fw +Group=network_fw SystemdService=connman.service diff --git a/src/network.c b/src/network.c index 56fe24ff..a6d635ec 100644..100755 --- a/src/network.c +++ b/src/network.c @@ -107,8 +107,34 @@ struct connman_network { bool wps_advertizing; bool use_wps; char *pin_wps; +#if defined TIZEN_EXT + char encryption_mode[WIFI_ENCYPTION_MODE_LEN_MAX]; + unsigned char bssid[WIFI_BSSID_LEN_MAX]; + unsigned int maxrate; + int maxspeed; + bool isHS20AP; + unsigned int keymgmt; + char *keymgmt_type; + bool rsn_mode; + int disconnect_reason; + int assoc_status_code; + GSList *vsie_list; + /* + * Only for EAP-FAST + */ + char *phase1; + unsigned char country_code[WIFI_COUNTRY_CODE_LEN]; + GSList *bssid_list; + ieee80211_modes_e phy_mode; + connection_mode_e connection_mode; +#endif } wifi; +#if defined TIZEN_EXT + /* Multiple APN services and a default APN which a user selected */ + bool default_internet; +#endif + }; static const char *type2string(enum connman_network_type type) @@ -204,7 +230,11 @@ static void acd_host_ipv4_available(struct acd_host *acd, gpointer user_data) if (err < 0) goto err; +#if defined TIZEN_EXT + err = __connman_ipconfig_gateway_add(ipconfig_ipv4, service); +#else err = __connman_ipconfig_gateway_add(ipconfig_ipv4); +#endif if (err < 0) goto err; @@ -444,7 +474,11 @@ static void dhcp_success(struct connman_network *network) if (err < 0) goto err; +#if defined TIZEN_EXT + err = __connman_ipconfig_gateway_add(ipconfig_ipv4, service); +#else err = __connman_ipconfig_gateway_add(ipconfig_ipv4); +#endif if (err < 0) goto err; @@ -518,7 +552,11 @@ static int set_connected_manual(struct connman_network *network) if (err < 0) goto err; +#if defined TIZEN_EXT + err = __connman_ipconfig_gateway_add(ipconfig, service); +#else err = __connman_ipconfig_gateway_add(ipconfig); +#endif if (err < 0) goto err; @@ -619,7 +657,11 @@ static int manual_ipv6_set(struct connman_network *network, return err; } +#if defined TIZEN_EXT + err = __connman_ipconfig_gateway_add(ipconfig_ipv6, service); +#else err = __connman_ipconfig_gateway_add(ipconfig_ipv6); +#endif if (err < 0) return err; @@ -763,6 +805,9 @@ static void check_dhcpv6(struct nd_router_advert *reply, check_dhcpv6, network); return; } +#if defined TIZEN_EXT + DBG("RA message is not received from server in reply of RS."); +#endif connman_network_unref(network); return; } @@ -775,6 +820,9 @@ static void check_dhcpv6(struct nd_router_advert *reply, */ if (!network->connected) { connman_network_unref(network); +#if defined TIZEN_EXT + DBG("Network is not connected"); +#endif return; } @@ -803,11 +851,21 @@ static void check_dhcpv6(struct nd_router_advert *reply, * We do stateful/stateless DHCPv6 if router advertisement says so. */ if (reply->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) { +#if defined TIZEN_EXT + DBG("IPv6 ND_RA_FLAG_MANAGED"); +#endif __connman_dhcpv6_start(network, prefixes, dhcpv6_callback); } else { if (reply->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) +#if defined TIZEN_EXT + { + DBG("IPv6 ND_RA_FLAG_OTHER"); +#endif __connman_dhcpv6_start_info(network, dhcpv6_info_callback); +#if defined TIZEN_EXT + } +#endif g_slist_free_full(prefixes, g_free); network->connecting = false; @@ -888,6 +946,11 @@ static void autoconf_ipv6_set(struct connman_network *network) __connman_device_set_network(network->device, network); +#if defined TIZEN_EXT + if(network->type == CONNMAN_NETWORK_TYPE_CELLULAR) + return; +#endif + service = connman_service_lookup_from_network(network); if (!service) return; @@ -1023,12 +1086,23 @@ static void set_disconnected(struct connman_network *network) CONNMAN_IPCONFIG_TYPE_IPV6); if (network->connected) { +#if defined TIZEN_EXT + /** + * Do not remove gateway and its address, + * if there are connected profiles that use same interface (multiple PDN) + */ + if (connman_service_get_type(service) != CONNMAN_SERVICE_TYPE_CELLULAR || + __connman_service_get_connected_count_of_iface(service) <= 0) { +#endif __connman_connection_gateway_remove(service, CONNMAN_IPCONFIG_TYPE_ALL); __connman_ipconfig_address_unset(ipconfig_ipv4); __connman_ipconfig_address_unset(ipconfig_ipv6); +#if defined TIZEN_EXT + } +#endif /* * Special handling for IPv6 autoconfigured address. * The simplest way to remove autoconfigured routes is to @@ -1239,6 +1313,10 @@ static void network_destruct(struct connman_network *network) g_free(network->wifi.phase2_auth); g_free(network->wifi.pin_wps); +#if defined TIZEN_EXT + g_slist_free_full(network->wifi.vsie_list, g_free); + g_slist_free_full(network->wifi.bssid_list, g_free); +#endif g_free(network->path); g_free(network->group); g_free(network->node); @@ -1485,6 +1563,15 @@ bool __connman_network_get_weakness(struct connman_network *network) return false; } +#if defined TIZEN_EXT +void connman_network_set_connecting(struct connman_network *network) +{ + DBG("set network connecting true"); + network->connecting = TRUE; + return; +} +#endif + bool connman_network_get_connecting(struct connman_network *network) { return network->connecting; @@ -1500,7 +1587,9 @@ bool connman_network_get_connecting(struct connman_network *network) int connman_network_set_available(struct connman_network *network, bool available) { +#if !defined TIZEN_EXT DBG("network %p available %d", network, available); +#endif if (network->available == available) return -EALREADY; @@ -1521,6 +1610,113 @@ bool connman_network_get_available(struct connman_network *network) return network->available; } +#if defined TIZEN_EXT +void connman_network_clear_associating(struct connman_network *network) +{ + struct connman_service *service; + enum connman_service_state state; + + DBG("network %p", network); + + network->connecting = FALSE; + network->associating = FALSE; + + service = connman_service_lookup_from_network(network); + if (!service) + return; + + state = __connman_service_ipconfig_get_state(service, + CONNMAN_IPCONFIG_TYPE_IPV4); + if (state != CONNMAN_SERVICE_STATE_IDLE && + state != CONNMAN_SERVICE_STATE_FAILURE) + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_DISCONNECT, + CONNMAN_IPCONFIG_TYPE_IPV4); + + state = __connman_service_ipconfig_get_state(service, + CONNMAN_IPCONFIG_TYPE_IPV6); + if (state != CONNMAN_SERVICE_STATE_IDLE && + state != CONNMAN_SERVICE_STATE_FAILURE) + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_DISCONNECT, + CONNMAN_IPCONFIG_TYPE_IPV6); + + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_IDLE, + CONNMAN_IPCONFIG_TYPE_IPV4); + + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_IDLE, + CONNMAN_IPCONFIG_TYPE_IPV6); +} + +static gboolean __connman_network_clear_associating_delayed(gpointer user_data) +{ + GSList *list; + gboolean found = FALSE; + enum connman_service_state state_ipv4; + enum connman_service_state state_ipv6; + struct connman_service *service; + struct connman_network *network = (struct connman_network *)user_data; + + for (list = network_list; list != NULL; list = list->next) { + struct connman_network *item = list->data; + + if (item == network) { + found = TRUE; + break; + } + } + + if (found != TRUE) + return FALSE; + + DBG("network %p name %s", network, network->name); + service = connman_service_lookup_from_network(network); + + state_ipv4 = __connman_service_ipconfig_get_state(service, + CONNMAN_IPCONFIG_TYPE_IPV4); + state_ipv6 = __connman_service_ipconfig_get_state(service, + CONNMAN_IPCONFIG_TYPE_IPV6); + + DBG("service %p state %d/%d", service, state_ipv4, state_ipv6); + + if (network->associating == FALSE && + state_ipv4 == CONNMAN_SERVICE_STATE_ASSOCIATION && + state_ipv6 == CONNMAN_SERVICE_STATE_ASSOCIATION) { + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_IDLE, + CONNMAN_IPCONFIG_TYPE_IPV4); + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_IDLE, + CONNMAN_IPCONFIG_TYPE_IPV6); + } else { + if (network->associating == FALSE) { + struct connman_ipconfig *ipconfig_ipv4, *ipconfig_ipv6; + enum connman_ipconfig_method ipv4_method, ipv6_method; + + ipconfig_ipv4 = __connman_service_get_ip4config(service); + ipv4_method = __connman_ipconfig_get_method(ipconfig_ipv4); + ipconfig_ipv6 = __connman_service_get_ip4config(service); + ipv6_method = __connman_ipconfig_get_method(ipconfig_ipv6); + + if((ipv4_method == CONNMAN_IPCONFIG_METHOD_UNKNOWN || ipv4_method == CONNMAN_IPCONFIG_METHOD_OFF) && + (state_ipv6 == CONNMAN_SERVICE_STATE_ASSOCIATION)) + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_IDLE, + CONNMAN_IPCONFIG_TYPE_IPV6); + if((ipv6_method == CONNMAN_IPCONFIG_METHOD_UNKNOWN || ipv6_method == CONNMAN_IPCONFIG_METHOD_OFF) && + (state_ipv4 == CONNMAN_SERVICE_STATE_ASSOCIATION)) + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_IDLE, + CONNMAN_IPCONFIG_TYPE_IPV4); + } + } + + return FALSE; +} +#endif + /** * connman_network_set_associating: * @network: network structure @@ -1550,6 +1746,14 @@ int connman_network_set_associating(struct connman_network *network, CONNMAN_IPCONFIG_TYPE_IPV6); } +#if defined TIZEN_EXT + if (associating == FALSE && + connman_network_get_bool(network, "WiFi.UseWPS") == FALSE) + g_timeout_add_seconds(1, + __connman_network_clear_associating_delayed, + network); +#endif + return 0; } @@ -1559,8 +1763,13 @@ static void set_associate_error(struct connman_network *network) service = connman_service_lookup_from_network(network); +#if defined TIZEN_EXT + __connman_service_indicate_error(service, + CONNMAN_SERVICE_ERROR_AUTH_FAILED); +#else __connman_service_indicate_error(service, CONNMAN_SERVICE_ERROR_CONNECT_FAILED); +#endif } static void set_configure_error(struct connman_network *network) @@ -1579,6 +1788,10 @@ static void set_invalid_key_error(struct connman_network *network) service = connman_service_lookup_from_network(network); +#if defined TIZEN_EXT + if (service) + __connman_service_set_favorite(service, false); +#endif __connman_service_indicate_error(service, CONNMAN_SERVICE_ERROR_INVALID_KEY); } @@ -1603,6 +1816,22 @@ static void set_blocked_error(struct connman_network *network) CONNMAN_SERVICE_ERROR_BLOCKED); } + +#if defined TIZEN_EXT +static void set_dhcp_error(struct connman_network *network) +{ + struct connman_service *service; + + if (network->associating != FALSE) + network->associating = FALSE; + + service = connman_service_lookup_from_network(network); + + __connman_service_indicate_error(service, + CONNMAN_SERVICE_ERROR_DHCP_FAILED); +} +#endif + void connman_network_set_ipv4_method(struct connman_network *network, enum connman_ipconfig_method method) { @@ -1657,6 +1886,12 @@ void connman_network_set_error(struct connman_network *network, case CONNMAN_NETWORK_ERROR_CONNECT_FAIL: set_connect_error(network); break; +#if defined TIZEN_EXT + case CONNMAN_NETWORK_ERROR_DHCP_FAIL: + set_dhcp_error(network); + break; +#endif + case CONNMAN_NETWORK_ERROR_BLOCKED: set_blocked_error(network); break; @@ -1797,15 +2032,25 @@ int __connman_network_connect(struct connman_network *network) if (!network->device) return -ENODEV; +#if defined TIZEN_EXT + if (network->type != CONNMAN_NETWORK_TYPE_CELLULAR) +#endif __connman_device_disconnect(network->device); network->connecting = true; +#if defined TIZEN_EXT + DBG("ConnMan, Connect Request [%s]", network->name); +#endif + err = network->driver->connect(network); if (err < 0) { - if (err == -EINPROGRESS) + if (err == -EINPROGRESS) { +#if defined TIZEN_EXT + if (network->type != CONNMAN_NETWORK_TYPE_CELLULAR) +#endif connman_network_set_associating(network, true); - else + } else network->connecting = false; return err; @@ -1841,6 +2086,11 @@ int __connman_network_disconnect(struct connman_network *network) network->connecting = false; +#if defined TIZEN_EXT + DBG("ConnMan, Disconnect request"); + struct connman_service *service = connman_service_lookup_from_network(network); + connman_service_set_disconnection_requested(service, true); +#endif if (network->driver->disconnect) err = network->driver->disconnect(network); @@ -1897,12 +2147,38 @@ int __connman_network_clear_ipconfig(struct connman_network *network, return 0; } +#if defined TIZEN_EXT +void __connman_network_set_auto_ipv6_gateway(char *gateway, void *user_data) +{ + DBG(""); + + struct connman_network *network = user_data; + struct connman_service *service; + struct connman_ipconfig *ipconfig = NULL; + + service = connman_service_lookup_from_network(network); + if (service == NULL) + return; + + ipconfig = __connman_service_get_ipconfig(service, AF_INET6); + if (ipconfig == NULL) + return; + + __connman_ipconfig_set_gateway(ipconfig, gateway); + + return; +} +#endif + int __connman_network_enable_ipconfig(struct connman_network *network, struct connman_ipconfig *ipconfig) { int r = 0; enum connman_ipconfig_type type; enum connman_ipconfig_method method; +#if defined TIZEN_EXT + struct connman_service *service; +#endif if (!network || !ipconfig) return -EINVAL; @@ -1930,6 +2206,14 @@ int __connman_network_enable_ipconfig(struct connman_network *network, break; case CONNMAN_IPCONFIG_METHOD_AUTO: +#if defined TIZEN_EXT + service = connman_service_lookup_from_network(network); + + if(network->type == CONNMAN_NETWORK_TYPE_CELLULAR) + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_CONFIGURATION, + CONNMAN_IPCONFIG_TYPE_IPV6); +#endif autoconf_ipv6_set(network); break; @@ -2006,6 +2290,224 @@ int connman_network_set_ipaddress(struct connman_network *network, return 0; } +#if defined TIZEN_EXT +/* + * Description: Network client requires additional wifi specific info + */ +int connman_network_set_bssid(struct connman_network *network, + const unsigned char *bssid) +{ + int i = 0; + + if (bssid == NULL) + return -EINVAL; + + DBG("network %p bssid %02x:%02x:%02x:%02x:%02x:%02x", network, + bssid[0], bssid[1], bssid[2], + bssid[3], bssid[4], bssid[5]); + + for (;i < WIFI_BSSID_LEN_MAX;i++) + network->wifi.bssid[i] = bssid[i]; + + return 0; +} + +unsigned char *connman_network_get_bssid(struct connman_network *network) +{ + return (unsigned char *)network->wifi.bssid; +} + +int connman_network_set_maxspeed(struct connman_network *network, + int maxspeed) +{ + network->wifi.maxspeed = maxspeed; + return 0; +} + +int connman_network_get_maxspeed(struct connman_network *network) +{ + if (!network->driver) + return 0; + + if (network->connected) + return network->wifi.maxspeed; + + return 0; +} + +int connman_network_set_maxrate(struct connman_network *network, + unsigned int maxrate) +{ +#if !defined TIZEN_EXT + DBG("network %p maxrate %d", network, maxrate); +#endif + + network->wifi.maxrate = maxrate; + + return 0; +} + +unsigned int connman_network_get_maxrate(struct connman_network *network) +{ + return network->wifi.maxrate; +} + +int connman_network_set_enc_mode(struct connman_network *network, + const char *encryption_mode) +{ + if (encryption_mode == NULL) + return -EINVAL; + + DBG("network %p encryption mode %s", network, encryption_mode); + + g_strlcpy(network->wifi.encryption_mode, encryption_mode, + WIFI_ENCYPTION_MODE_LEN_MAX); + + return 0; +} + +const char *connman_network_get_enc_mode(struct connman_network *network) +{ + return (const char *)network->wifi.encryption_mode; +} + +int connman_network_set_rsn_mode(struct connman_network *network, + bool rsn_mode) +{ + network->wifi.rsn_mode = rsn_mode; + + return 0; +} + +int connman_network_set_proxy(struct connman_network *network, + const char *proxies) +{ + struct connman_service *service; + + DBG("network %p proxies %s", network, proxies); + + service = connman_service_lookup_from_network(network); + if (service == NULL) + return -EINVAL; + + __connman_service_set_proxy(service, proxies); + + connman_service_set_proxy_method(service, + CONNMAN_SERVICE_PROXY_METHOD_MANUAL); + + return 0; +} + +int connman_network_set_keymgmt(struct connman_network *network, + unsigned int keymgmt) +{ + if (network == NULL) + return 0; + + network->wifi.keymgmt = keymgmt; + + return 0; +} + +unsigned int connman_network_get_keymgmt(struct connman_network *network) +{ + if (network == NULL) + return 0; + + return network->wifi.keymgmt; +} + +int connman_network_set_disconnect_reason(struct connman_network *network, + int reason_code) +{ + if (network == NULL) + return 0; + + network->wifi.disconnect_reason = reason_code; + + return 0; +} + +int connman_network_get_disconnect_reason(struct connman_network *network) +{ + if (network == NULL) + return 0; + + return network->wifi.disconnect_reason; +} +int connman_network_get_assoc_status_code(struct connman_network *network) +{ + if (network == NULL) + return 0; + + return network->wifi.assoc_status_code; +} + +int connman_network_set_countrycode(struct connman_network *network, + const unsigned char *country_code) +{ + int i = 0; + + if (country_code == NULL) + return -EINVAL; + + DBG("network %p Country Code %02x:%02x",network, + country_code[0],country_code[1]); + + for (; i < WIFI_COUNTRY_CODE_LEN; i++) + network->wifi.country_code[i] = country_code[i]; + + return 0; +} + +unsigned char *connman_network_get_countrycode(struct connman_network *network) +{ + return (unsigned char *)network->wifi.country_code; +} + +int connman_network_set_bssid_list(struct connman_network *network, + GSList *bssids) +{ + g_slist_free_full(network->wifi.bssid_list, g_free); + network->wifi.bssid_list = bssids; + + return 0; +} + +int connman_network_set_phy_mode(struct connman_network *network, + ieee80211_modes_e mode) +{ + DBG("network %p phy mode %d", network, mode); + network->wifi.phy_mode = mode; + + return 0; +} + +ieee80211_modes_e connman_network_get_phy_mode(struct connman_network *network) +{ + return network->wifi.phy_mode; +} + +int connman_network_set_connection_mode(struct connman_network *network, + connection_mode_e mode) +{ + DBG("network %p connection mode %d", network, mode); + network->wifi.connection_mode = mode; + + return 0; +} + +connection_mode_e connman_network_get_connection_mode(struct connman_network *network) +{ + return network->wifi.connection_mode; +} + +void *connman_network_get_bssid_list(struct connman_network *network) +{ + return network->wifi.bssid_list; +} +#endif + int connman_network_set_nameservers(struct connman_network *network, const char *nameservers) { @@ -2027,8 +2529,14 @@ int connman_network_set_nameservers(struct connman_network *network, nameservers_array = g_strsplit(nameservers, " ", 0); for (i = 0; nameservers_array[i]; i++) { +#if defined TIZEN_EXT + __connman_service_nameserver_append(service, + nameservers_array[i], false, + CONNMAN_IPCONFIG_TYPE_ALL); +#else __connman_service_nameserver_append(service, nameservers_array[i], false); +#endif } g_strfreev(nameservers_array); @@ -2082,6 +2590,9 @@ int connman_network_set_strength(struct connman_network *network, uint8_t strength) { network->strength = strength; +#if defined TIZEN_EXT + __connman_service_notify_strength_changed(network); +#endif return 0; } @@ -2144,6 +2655,9 @@ int connman_network_set_string(struct connman_network *network, g_free(network->wifi.security); network->wifi.security = g_strdup(value); } else if (g_str_equal(key, "WiFi.Passphrase")) { +#if defined TIZEN_EXT + DBG("ConnMan, %p key %s", network, key); +#endif g_free(network->wifi.passphrase); network->wifi.passphrase = g_strdup(value); } else if (g_str_equal(key, "WiFi.EAP")) { @@ -2214,7 +2728,15 @@ const char *connman_network_get_string(struct connman_network *network, else if (g_str_equal(key, "WiFi.Mode")) return network->wifi.mode; else if (g_str_equal(key, "WiFi.Security")) +#if defined TIZEN_EXT + if (network->wifi.rsn_mode != true || + g_str_equal(network->wifi.security, "ieee8021x")) + return network->wifi.security; + else + return "rsn"; +#else return network->wifi.security; +#endif else if (g_str_equal(key, "WiFi.Passphrase")) return network->wifi.passphrase; else if (g_str_equal(key, "WiFi.EAP")) @@ -2268,6 +2790,12 @@ int connman_network_set_bool(struct connman_network *network, network->wifi.wps_advertizing = value; else if (g_strcmp0(key, "WiFi.UseWPS") == 0) network->wifi.use_wps = value; +#if defined TIZEN_EXT + else if (g_strcmp0(key, "DefaultInternet") == 0) + network->default_internet = value; + else if (g_strcmp0(key, "WiFi.HS20AP") == 0) + network->wifi.isHS20AP = value; +#endif return -EINVAL; } @@ -2290,10 +2818,42 @@ bool connman_network_get_bool(struct connman_network *network, return network->wifi.wps_advertizing; else if (g_str_equal(key, "WiFi.UseWPS")) return network->wifi.use_wps; +#if defined TIZEN_EXT + else if (g_str_equal(key, "DefaultInternet")) + return network->default_internet; + else if (g_str_equal(key, "WiFi.HS20AP")) + return network->wifi.isHS20AP; +#endif return false; } +#if defined TIZEN_EXT +/** + * connman_network_set_vsie_list: + * @network: network structure + * @vsie_list: GSList pointer + * + * Set vendor specific list pointer + */ +void connman_network_set_vsie_list(struct connman_network *network, GSList *vsie_list) +{ + g_slist_free_full(network->wifi.vsie_list, g_free); + network->wifi.vsie_list = vsie_list; +} + +/** + * connman_network_get_vsie_list: + * @network: network structure + * + * Get vendor specific list pointer + */ +void *connman_network_get_vsie_list(struct connman_network *network) +{ + return network->wifi.vsie_list; +} +#endif + /** * connman_network_set_blob: * @network: network structure diff --git a/src/notifier.c b/src/notifier.c index 47eb72f1..d1be47f6 100644 --- a/src/notifier.c +++ b/src/notifier.c @@ -153,6 +153,9 @@ void __connman_notifier_connect(enum connman_service_type type) case CONNMAN_SERVICE_TYPE_BLUETOOTH: case CONNMAN_SERVICE_TYPE_CELLULAR: case CONNMAN_SERVICE_TYPE_P2P: +#if defined TIZEN_EXT_WIFI_MESH + case CONNMAN_SERVICE_TYPE_MESH: +#endif break; } @@ -200,6 +203,9 @@ void __connman_notifier_disconnect(enum connman_service_type type) case CONNMAN_SERVICE_TYPE_BLUETOOTH: case CONNMAN_SERVICE_TYPE_CELLULAR: case CONNMAN_SERVICE_TYPE_P2P: +#if defined TIZEN_EXT_WIFI_MESH + case CONNMAN_SERVICE_TYPE_MESH: +#endif break; } diff --git a/src/ntp.c b/src/ntp.c index e7fee22a..e72a57c4 100644..100755 --- a/src/ntp.c +++ b/src/ntp.c @@ -253,7 +253,9 @@ static void decode_msg(struct ntp_data *nd, void *base, size_t len, double m_delta, org, rec, xmt, dst; double delay, offset; static guint transmit_delay; +#if !defined TIZEN_EXT struct timex tmx = {}; +#endif if (len < sizeof(*msg)) { connman_error("Invalid response from time server"); @@ -347,6 +349,66 @@ static void decode_msg(struct ntp_data *nd, void *base, size_t len, nd->poll_id = g_timeout_add_seconds(transmit_delay, next_poll, nd); +#if defined TIZEN_EXT + //send the dbus message to alram-manager + { +#define TIME_BUS_NAME "org.tizen.alarm.manager" +#define TIME_INTERFACE "org.tizen.alarm.manager" +#define TIME_PATH "/org/tizen/alarm/manager" +#define TIME_METHOD "alarm_set_time_with_propagation_delay" + + struct timespec cur = {0}; + struct timespec req = {0}; + double dtime; + + DBusConnection *connection = NULL; + DBusMessage *msg = NULL, *reply = NULL; + DBusError error; + + dbus_error_init(&error); + + connection = connman_dbus_get_connection(); + if(!connection){ + DBG("dbus connection does not exist"); + return; + } + + clock_gettime(CLOCK_REALTIME, &cur); + dtime = offset + cur.tv_sec + 1.0e-9 * cur.tv_nsec; + cur.tv_sec = (long) dtime; + cur.tv_nsec = (dtime - cur.tv_sec) * 1000000000; + + clock_gettime(CLOCK_REALTIME, &req); + msg = dbus_message_new_method_call(TIME_BUS_NAME, TIME_PATH, + TIME_INTERFACE, TIME_METHOD); + dbus_message_append_args(msg, DBUS_TYPE_UINT32, &(cur.tv_sec), + DBUS_TYPE_UINT32, &(cur.tv_nsec), + DBUS_TYPE_UINT32, &(req.tv_sec), + DBUS_TYPE_UINT32, &(req.tv_nsec), DBUS_TYPE_INVALID); + reply = dbus_connection_send_with_reply_and_block(connection, msg, + DBUS_TIMEOUT_USE_DEFAULT, &error); + if(reply == NULL){ + if(dbus_error_is_set(&error)){ + DBG("%s", error.message); + dbus_error_free(&error); + } + else{ + DBG("Failed to request set time"); + } + dbus_connection_unref(connection); + dbus_message_unref(msg); + return; + } + + dbus_message_unref(msg); + dbus_message_unref(reply); + dbus_connection_unref(connection); + + DBG("%lu cur seconds, %lu cur nsecs, %lu req seconds, %lu req nsecs", + cur.tv_sec, cur.tv_nsec, req.tv_sec, req.tv_nsec); + DBG("setting time"); + } +#else if (offset < STEPTIME_MIN_OFFSET && offset > -STEPTIME_MIN_OFFSET) { tmx.modes = ADJ_STATUS | ADJ_NANO | ADJ_OFFSET | ADJ_TIMECONST | ADJ_MAXERROR | ADJ_ESTERROR; tmx.status = STA_PLL; @@ -389,6 +451,7 @@ static void decode_msg(struct ntp_data *nd, void *base, size_t len, LOGTOD(msg->poll), offset, delay, tmx.freq / 65536); nd->cb(true, nd->user_data); +#endif } static gboolean received_data(GIOChannel *channel, GIOCondition condition, diff --git a/src/peer.c b/src/peer.c index 2102f119..2102f119 100644..100755 --- a/src/peer.c +++ b/src/peer.c diff --git a/src/peer_service.c b/src/peer_service.c index a457bff7..a457bff7 100644..100755 --- a/src/peer_service.c +++ b/src/peer_service.c diff --git a/src/plugin.c b/src/plugin.c index 7d730582..7d730582 100644..100755 --- a/src/plugin.c +++ b/src/plugin.c diff --git a/src/provider.c b/src/provider.c index 9d9741e1..f1e4a067 100644..100755 --- a/src/provider.c +++ b/src/provider.c @@ -243,7 +243,11 @@ static int set_connected(struct connman_provider *provider, } __connman_ipconfig_address_add(ipconfig); +#if defined TIZEN_EXT + __connman_ipconfig_gateway_add(ipconfig, service); +#else __connman_ipconfig_gateway_add(ipconfig); +#endif provider_indicate_state(provider, CONNMAN_SERVICE_STATE_READY); @@ -573,8 +577,14 @@ int connman_provider_set_nameservers(struct connman_provider *provider, return 0; for (i = 0; nameservers[i]; i++) +#if defined TIZEN_EXT + __connman_service_nameserver_append(provider->vpn_service, + nameservers[i], false, + CONNMAN_IPCONFIG_TYPE_ALL); +#else __connman_service_nameserver_append(provider->vpn_service, nameservers[i], false); +#endif return 0; } diff --git a/src/proxy.c b/src/proxy.c index e1bc420a..e1bc420a 100644..100755 --- a/src/proxy.c +++ b/src/proxy.c diff --git a/src/resolver.c b/src/resolver.c index 10121aa5..7ec2150b 100644..100755 --- a/src/resolver.c +++ b/src/resolver.c @@ -34,6 +34,16 @@ #include "connman.h" +/* + * Just to avoid build failure due to missing STATEDIR + */ +#if defined TIZEN_EXT +#ifdef STATEDIR +#undef STATEDIR +#endif +#define STATEDIR "/etc" +#endif + #define RESOLV_CONF_STATEDIR STATEDIR"/resolv.conf" #define RESOLV_CONF_ETC "/etc/resolv.conf" @@ -311,8 +321,14 @@ static gboolean resolver_expire_cb(gpointer user_data) struct connman_service *service; service = __connman_service_lookup_from_index(entry->index); if (service) +#if defined TIZEN_EXT + __connman_service_nameserver_remove(service, + entry->server, true, + CONNMAN_IPCONFIG_TYPE_ALL); +#else __connman_service_nameserver_remove(service, entry->server, true); +#endif } remove_entries(list); @@ -366,6 +382,11 @@ static int append_resolver(int index, const char *domain, if (!server && !domain) return -EINVAL; +#ifdef TIZEN_EXT + if (g_strcmp0(server, "0.0.0.0") == 0) + return -EINVAL; +#endif + entry = g_try_new0(struct entry_data, 1); if (!entry) return -ENOMEM; @@ -408,8 +429,14 @@ static int append_resolver(int index, const char *domain, struct connman_service *service; service = __connman_service_lookup_from_index(entry->index); if (service) +#if defined TIZEN_EXT + __connman_service_nameserver_append(service, + server, true, + CONNMAN_IPCONFIG_TYPE_ALL); +#else __connman_service_nameserver_append(service, server, true); +#endif } return 0; diff --git a/src/rfkill.c b/src/rfkill.c index b2514c41..99b337d2 100644..100755 --- a/src/rfkill.c +++ b/src/rfkill.c @@ -72,6 +72,7 @@ static enum connman_service_type convert_type(uint8_t type) return CONNMAN_SERVICE_TYPE_UNKNOWN; } +#if !defined TIZEN_EXT static enum rfkill_type convert_service_type(enum connman_service_type type) { switch (type) { @@ -94,6 +95,7 @@ static enum rfkill_type convert_service_type(enum connman_service_type type) return NUM_RFKILL_TYPES; } +#endif static GIOStatus rfkill_process(GIOChannel *chan) { @@ -156,13 +158,20 @@ static guint watch = 0; int __connman_rfkill_block(enum connman_service_type type, bool block) { +#if !defined TIZEN_EXT uint8_t rfkill_type; struct rfkill_event event; ssize_t len; int fd, err = 0; +#endif DBG("type %d block %d", type, block); +#if defined TIZEN_EXT + DBG("try to set rfkill block %d, but it's not permitted", block); + + return 0; +#else rfkill_type = convert_service_type(type); if (rfkill_type == NUM_RFKILL_TYPES) return -EINVAL; @@ -185,6 +194,7 @@ int __connman_rfkill_block(enum connman_service_type type, bool block) close(fd); return err; +#endif } int __connman_rfkill_init(void) @@ -46,6 +46,12 @@ #define ARPHDR_PHONET_PIPE (821) #endif +#if defined TIZEN_EXT +#ifndef ARPHDR_RMNET +#define ARPHDR_RMNET (530) +#endif +#endif + #define print(arg...) do { if (0) connman_info(arg); } while (0) //#define print(arg...) connman_info(arg) @@ -94,6 +100,7 @@ static bool ether_blacklisted(const char *name) return false; } +#if !defined TIZEN_EXT static bool wext_interface(char *ifname) { struct iwreq wrq; @@ -115,6 +122,30 @@ static bool wext_interface(char *ifname) return true; } +#endif + +#if defined TIZEN_EXT +static bool __connman_rtnl_is_cellular_device(const char *name) +{ + char **pattern; + char **cellular_interfaces; + + cellular_interfaces = + connman_setting_get_string_list( + "NetworkCellularInterfaceList"); + if (!cellular_interfaces) + return false; + + for (pattern = cellular_interfaces; *pattern; pattern++) { + if (g_str_has_prefix(name, *pattern)) { + DBG("Cellular interface: %s", name); + return true; + } + } + + return false; +} +#endif static void read_uevent(struct interface_data *interface) { @@ -124,6 +155,15 @@ static void read_uevent(struct interface_data *interface) name = connman_inet_ifname(interface->index); +#if defined TIZEN_EXT + if (__connman_rtnl_is_cellular_device(name)) { + interface->service_type = CONNMAN_SERVICE_TYPE_CELLULAR; + interface->device_type = CONNMAN_DEVICE_TYPE_CELLULAR; + g_free(name); + return; + } +#endif + if (ether_blacklisted(name)) { interface->service_type = CONNMAN_SERVICE_TYPE_UNKNOWN; interface->device_type = CONNMAN_DEVICE_TYPE_UNKNOWN; @@ -188,6 +228,8 @@ static void read_uevent(struct interface_data *interface) if (found_devtype) goto out; +#if !defined TIZEN_EXT + /* TIZEN does not use old wext interface */ /* We haven't got a DEVTYPE, let's check if it's a wireless device */ if (wext_interface(name)) { interface->service_type = CONNMAN_SERVICE_TYPE_WIFI; @@ -195,6 +237,7 @@ static void read_uevent(struct interface_data *interface) connman_error("%s runs an unsupported 802.11 driver", name); } +#endif out: g_free(name); @@ -420,6 +463,28 @@ static void process_newlink(unsigned short type, int index, unsigned flags, if (!extract_link(msg, bytes, &address, &ifname, &mtu, &operstate, &stats)) return; +#if defined TIZEN_EXT_WIFI_MESH + /* Do not accept Wi-Fi Mesh interface */ + if (g_strrstr(ifname, "mesh") != NULL) { + DBG("Newlink event for Wi-Fi Mesh interface ignored"); + return; + } + + /* Do not accept Wi-Fi WLAN1 interface "dedicated for softAP */ + if (!g_strcmp0(ifname, "wlan1")) { + DBG("Newlink event for Wi-Fi WLAN1 interface ignored"); + return; + } +#endif + +#if defined TIZEN_EXT + /* Do not accept Wi-Fi P2P interface */ + if (g_strrstr(ifname, "p2p") != NULL) { + DBG("Newlink event for Wi-Fi P2P interface ignored"); + return; + } +#endif + snprintf(ident, 13, "%02x%02x%02x%02x%02x%02x", address.ether_addr_octet[0], address.ether_addr_octet[1], @@ -442,12 +507,25 @@ static void process_newlink(unsigned short type, int index, unsigned flags, return; } +#ifdef TIZEN_EXT + if (TIZEN_TV_EXT && g_strcmp0(ident, "eeeeeeeeeeee") == 0) { + DBG("Newlink event with Dummy MAC. Ignored!"); + return; + } +#endif + switch (type) { case ARPHRD_ETHER: case ARPHRD_LOOPBACK: case ARPHDR_PHONET_PIPE: case ARPHRD_PPP: case ARPHRD_NONE: +#if defined TIZEN_EXT +/* + * Description: ARPHDR_RMNET for QC modem using QMI + */ + case ARPHDR_RMNET: +#endif __connman_ipconfig_newlink(index, type, flags, str, mtu, &stats); break; @@ -472,6 +550,25 @@ static void process_newlink(unsigned short type, int index, unsigned flags, if (type == ARPHRD_ETHER) read_uevent(interface); +#if defined TIZEN_EXT + if (type == ARPHRD_PPP || type == ARPHDR_RMNET) + read_uevent(interface); + + } else if (g_strcmp0(interface->ident, ident) != 0) { + /* If an original address is built-in physical device, + * it's hardly get an address at a initial creation + */ + __connman_technology_remove_interface(interface->service_type, + interface->index, interface->ident); + + g_free(interface->ident); + interface->ident = g_strdup(ident); + + __connman_technology_add_interface(interface->service_type, + interface->index, interface->ident); + + interface = NULL; +#endif } else if (type == ARPHRD_ETHER && interface->device_type == CONNMAN_DEVICE_TYPE_UNKNOWN) read_uevent(interface); else @@ -535,6 +632,13 @@ static void process_dellink(unsigned short type, int index, unsigned flags, case ARPHDR_PHONET_PIPE: case ARPHRD_PPP: case ARPHRD_NONE: +#if defined TIZEN_EXT + /* + * Description: SLP requires ARPHRD_PPP for PPP type device + * ARPHDR_RMNET for QC modem using QMI + */ + case ARPHDR_RMNET: +#endif __connman_ipconfig_dellink(index, &stats); break; } @@ -1230,6 +1334,37 @@ static void rtnl_newnduseropt(struct nlmsghdr *hdr) if (index < 0) return; +#if defined TIZEN_EXT + struct connman_service *service; + enum connman_service_state state; + enum connman_dnsconfig_method ipv6_dns_method; + + service = __connman_service_lookup_from_index(index); + if (!service) { + DBG("Invalid service"); + return; + } + + DBG("service: %p index: %d\n", service, index); + + if (connman_setting_get_bool("SingleConnectedTechnology") == TRUE) { + state = __connman_service_ipconfig_get_state(service, CONNMAN_IPCONFIG_TYPE_IPV6); + if (state != CONNMAN_SERVICE_STATE_ASSOCIATION && + state != CONNMAN_SERVICE_STATE_CONFIGURATION && + state != CONNMAN_SERVICE_STATE_READY && + state != CONNMAN_SERVICE_STATE_ONLINE) { + DBG("Service state[%d] is not connecting/connected", state); + return; + } + } + + ipv6_dns_method = connman_service_get_ipv6_dns_method(service); + if (ipv6_dns_method != CONNMAN_DNSCONFIG_METHOD_DHCP) { + DBG("IPv6 DNS method is not Auto ignore RA!!! [DNS method: %d]", ipv6_dns_method); + return; + } +#endif + for (opt = (void *)&msg[1]; msglen > 0; msglen -= opt->nd_opt_len * 8, @@ -1240,7 +1375,12 @@ static void rtnl_newnduseropt(struct nlmsghdr *hdr) if (opt->nd_opt_type == 25) { /* ND_OPT_RDNSS */ char buf[40]; +#if defined TIZEN_EXT + struct connman_service *service; + service = __connman_service_lookup_from_index(index); + DBG("service: %p\n",service); +#endif servers = rtnl_nd_opt_rdnss(opt, &lifetime, &nr_servers); for (i = 0; i < nr_servers; i++) { @@ -1248,6 +1388,14 @@ static void rtnl_newnduseropt(struct nlmsghdr *hdr) sizeof(buf))) continue; +#if defined TIZEN_EXT + __connman_service_nameserver_remove(service, + buf, false, + CONNMAN_IPCONFIG_TYPE_IPV6); + __connman_service_nameserver_append(service, + buf, false, + CONNMAN_IPCONFIG_TYPE_IPV6); +#endif connman_resolver_append_lifetime(index, NULL, buf, lifetime); } diff --git a/src/service.c b/src/service.c index 3202f26c..0c6e6235 100644 --- a/src/service.c +++ b/src/service.c @@ -39,6 +39,10 @@ #define CONNECT_TIMEOUT 120 +#if defined TIZEN_EXT +#define WIFI_BSSID_STR_LEN 18 +#endif + static DBusConnection *connection = NULL; static GList *service_list = NULL; @@ -49,6 +53,10 @@ static unsigned int vpn_autoconnect_id = 0; static struct connman_service *current_default = NULL; static bool services_dirty = false; +#if defined TIZEN_EXT +static bool auto_connect_mode = TRUE; +#endif + struct connman_stats { bool valid; bool enabled; @@ -135,6 +143,35 @@ struct connman_service { bool hidden_service; char *config_file; char *config_entry; +#if defined TIZEN_EXT + /* + * Description: TIZEN implements system global connection management. + * It's only for PDP (cellular) bearer. Wi-Fi is managed + * by ConnMan automatically. Reference count can help to + * manage open/close connection requests by each application. + */ + int user_pdn_connection_refcount; + bool storage_reload; + /* + * Description: In case of EAP security type, + * user can select the keymgmt type for roaming(802.11r). + * - FT, CCKM, OKC, ... + */ + char *keymgmt_type; + int disconnect_reason; + int assoc_status_code; + /* + * Only for EAP-FAST + */ + char *phase1; + /* + * Description: To indicate that disconnection triggered by user. + */ + bool disconnection_requested; + + enum connman_dnsconfig_method dns_config_method_ipv4; + enum connman_dnsconfig_method dns_config_method_ipv6; +#endif }; static bool allow_property_changed(struct connman_service *service); @@ -150,6 +187,50 @@ struct find_data { struct connman_service *service; }; +#if defined TIZEN_EXT +/* + * Public APIs to use user_pdn_connection_refcount + */ +void connman_service_user_pdn_connection_ref(struct connman_service *service) +{ + __sync_fetch_and_add(&service->user_pdn_connection_refcount, 1); + + DBG("User made PDN connection referenced: %d", + service->user_pdn_connection_refcount); +} + +gboolean connman_service_user_pdn_connection_unref_and_test( + struct connman_service *service) +{ + __sync_synchronize(); + + DBG("User made PDN connection referenced: %d, which will be decreased", + service->user_pdn_connection_refcount); + + if (service->user_pdn_connection_refcount < 1) + return TRUE; + + if (__sync_sub_and_fetch(&service->user_pdn_connection_refcount, 1) == 0) + return TRUE; + + return FALSE; +} + +gboolean connman_service_is_no_ref_user_pdn_connection( + struct connman_service *cellular) +{ + if (cellular == NULL) + return TRUE; + + __sync_synchronize(); + if (cellular->type == CONNMAN_SERVICE_TYPE_CELLULAR && + cellular->user_pdn_connection_refcount == 0) + return TRUE; + + return FALSE; +} +#endif + static void compare_path(gpointer value, gpointer user_data) { struct connman_service *service = value; @@ -213,6 +294,10 @@ const char *__connman_service_type2string(enum connman_service_type type) return "gadget"; case CONNMAN_SERVICE_TYPE_P2P: return "p2p"; +#if defined TIZEN_EXT_WIFI_MESH + case CONNMAN_SERVICE_TYPE_MESH: + return "mesh"; +#endif } return NULL; @@ -258,6 +343,14 @@ enum connman_service_security __connman_service_string2security(const char *str) return CONNMAN_SERVICE_SECURITY_NONE; if (!strcmp(str, "wep")) return CONNMAN_SERVICE_SECURITY_WEP; +#if defined TIZEN_EXT + if (!strcmp(str, "rsn")) + return CONNMAN_SERVICE_SECURITY_RSN; + if (!strcmp(str, "sae")) + return CONNMAN_SERVICE_SECURITY_SAE; + if (!strcmp(str, "owe")) + return CONNMAN_SERVICE_SECURITY_OWE; +#endif return CONNMAN_SERVICE_SECURITY_UNKNOWN; } @@ -273,8 +366,18 @@ static const char *security2string(enum connman_service_security security) return "wep"; case CONNMAN_SERVICE_SECURITY_PSK: case CONNMAN_SERVICE_SECURITY_WPA: +#if defined TIZEN_EXT + return "psk"; + case CONNMAN_SERVICE_SECURITY_RSN: + return "rsn"; + case CONNMAN_SERVICE_SECURITY_SAE: + return "sae"; + case CONNMAN_SERVICE_SECURITY_OWE: + return "owe"; +#else case CONNMAN_SERVICE_SECURITY_RSN: return "psk"; +#endif case CONNMAN_SERVICE_SECURITY_8021X: return "ieee8021x"; } @@ -360,6 +463,33 @@ static enum connman_service_proxy_method string2proxymethod(const char *method) return CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN; } +#ifdef TIZEN_EXT +static const char *__connman_dnsconfig_method2string(enum connman_dnsconfig_method method) +{ + switch (method) { + case CONNMAN_DNSCONFIG_METHOD_UNKNOWN: + return "unknown"; + case CONNMAN_DNSCONFIG_METHOD_MANUAL: + return "manual"; + case CONNMAN_DNSCONFIG_METHOD_DHCP: + return "dhcp"; + } + + return NULL; +} + +static enum connman_dnsconfig_method __connman_dnsconfig_string2method( + const char *method) +{ + if (g_strcmp0(method, "manual") == 0) + return CONNMAN_DNSCONFIG_METHOD_MANUAL; + else if (g_strcmp0(method, "dhcp") == 0) + return CONNMAN_DNSCONFIG_METHOD_DHCP; + else + return CONNMAN_DNSCONFIG_METHOD_UNKNOWN; +} +#endif + static void set_split_routing(struct connman_service *service, bool value) { if (service->type != CONNMAN_SERVICE_TYPE_VPN) @@ -391,6 +521,9 @@ int __connman_service_load_modifiable(struct connman_service *service) case CONNMAN_SERVICE_TYPE_SYSTEM: case CONNMAN_SERVICE_TYPE_GPS: case CONNMAN_SERVICE_TYPE_P2P: +#if defined TIZEN_EXT_WIFI_MESH + case CONNMAN_SERVICE_TYPE_MESH: +#endif break; case CONNMAN_SERVICE_TYPE_VPN: set_split_routing(service, g_key_file_get_boolean(keyfile, @@ -447,6 +580,9 @@ static int service_load(struct connman_service *service) case CONNMAN_SERVICE_TYPE_SYSTEM: case CONNMAN_SERVICE_TYPE_GPS: case CONNMAN_SERVICE_TYPE_P2P: +#if defined TIZEN_EXT_WIFI_MESH + case CONNMAN_SERVICE_TYPE_MESH: +#endif break; case CONNMAN_SERVICE_TYPE_VPN: set_split_routing(service, g_key_file_get_boolean(keyfile, @@ -557,6 +693,24 @@ static int service_load(struct connman_service *service) service->nameservers_config = NULL; } +#ifdef TIZEN_EXT + char *dns_method; + + dns_method = g_key_file_get_string(keyfile, service->identifier, + "Nameservers.IPv4method", NULL); + if (dns_method) { + service->dns_config_method_ipv4 = __connman_dnsconfig_string2method(dns_method); + g_free(dns_method); + } + + dns_method = g_key_file_get_string(keyfile, service->identifier, + "Nameservers.IPv6method", NULL); + if (dns_method) { + service->dns_config_method_ipv6 = __connman_dnsconfig_string2method(dns_method); + g_free(dns_method); + } +#endif + service->timeservers_config = g_key_file_get_string_list(keyfile, service->identifier, "Timeservers", &length, NULL); if (service->timeservers_config && length == 0) { @@ -605,6 +759,60 @@ static int service_load(struct connman_service *service) service->hidden_service = g_key_file_get_boolean(keyfile, service->identifier, "Hidden", NULL); +#if defined TIZEN_EXT + if (service->type == CONNMAN_SERVICE_TYPE_WIFI && + service->security == CONNMAN_SERVICE_SECURITY_8021X) { + str = g_key_file_get_string(keyfile, + service->identifier, "EAP", NULL); + if (str != NULL) { + g_free(service->eap); + service->eap = str; + } + + str = g_key_file_get_string(keyfile, + service->identifier, "Phase2", NULL); + if (str != NULL) { + g_free(service->phase2); + service->phase2 = str; + } + + str = g_key_file_get_string(keyfile, + service->identifier, "Identity", NULL); + if (str != NULL) { + g_free(service->identity); + service->identity = str; + } + + str = g_key_file_get_string(keyfile, + service->identifier, "CACertFile", NULL); + if (str != NULL) { + g_free(service->ca_cert_file); + service->ca_cert_file = str; + } + + str = g_key_file_get_string(keyfile, + service->identifier, "ClientCertFile", NULL); + if (str != NULL) { + g_free(service->client_cert_file); + service->client_cert_file = str; + } + + str = g_key_file_get_string(keyfile, + service->identifier, "PrivateKeyFile", NULL); + if (str != NULL) { + g_free(service->private_key_file); + service->private_key_file = str; + } + + str = g_key_file_get_string(keyfile, + service->identifier, "PrivateKeyPassphrase", NULL); + if (str != NULL) { + g_free(service->private_key_passphrase); + service->private_key_passphrase = str; + } + } +#endif + done: g_key_file_free(keyfile); @@ -637,6 +845,9 @@ static int service_save(struct connman_service *service) case CONNMAN_SERVICE_TYPE_SYSTEM: case CONNMAN_SERVICE_TYPE_GPS: case CONNMAN_SERVICE_TYPE_P2P: +#if defined TIZEN_EXT_WIFI_MESH + case CONNMAN_SERVICE_TYPE_MESH: +#endif break; case CONNMAN_SERVICE_TYPE_VPN: g_key_file_set_boolean(keyfile, service->identifier, @@ -730,6 +941,28 @@ static int service_save(struct connman_service *service) g_key_file_remove_key(keyfile, service->identifier, "Nameservers", NULL); +#if defined TIZEN_EXT + if(service->dns_config_method_ipv4 != 0) { + const char *method; + method = __connman_dnsconfig_method2string( + service->dns_config_method_ipv4); + g_key_file_set_string(keyfile, service->identifier, + "Nameservers.IPv4method", method); + } else + g_key_file_remove_key(keyfile, service->identifier, + "Nameservers.IPv4method", NULL); + + if(service->dns_config_method_ipv6 != 0) { + const char *method; + method = __connman_dnsconfig_method2string( + service->dns_config_method_ipv6); + g_key_file_set_string(keyfile, service->identifier, + "Nameservers.IPv6method", method); + } else + g_key_file_remove_key(keyfile, service->identifier, + "Nameservers.IPv6method", NULL); +#endif + if (service->timeservers_config) { guint len = g_strv_length(service->timeservers_config); @@ -802,6 +1035,60 @@ static int service_save(struct connman_service *service) g_key_file_set_string(keyfile, service->identifier, "Config.ident", service->config_entry); +#if defined TIZEN_EXT + if (service->type == CONNMAN_SERVICE_TYPE_WIFI && + service->security == CONNMAN_SERVICE_SECURITY_8021X) { + if (service->eap != NULL && strlen(service->eap) > 0) + g_key_file_set_string(keyfile, service->identifier, + "EAP", service->eap); + else + g_key_file_remove_key(keyfile, service->identifier, + "EAP", NULL); + + if (service->phase2 != NULL && strlen(service->phase2) > 0) + g_key_file_set_string(keyfile, service->identifier, + "Phase2", service->phase2); + else + g_key_file_remove_key(keyfile, service->identifier, + "Phase2", NULL); + + if (service->identity != NULL && strlen(service->identity) > 0) + g_key_file_set_string(keyfile, service->identifier, + "Identity", service->identity); + else + g_key_file_remove_key(keyfile, service->identifier, + "Identity", NULL); + + if (service->ca_cert_file != NULL && strlen(service->ca_cert_file) > 0) + g_key_file_set_string(keyfile, service->identifier, + "CACertFile", service->ca_cert_file); + else + g_key_file_remove_key(keyfile, service->identifier, + "CACertFile", NULL); + + if (service->client_cert_file != NULL && strlen(service->client_cert_file) > 0) + g_key_file_set_string(keyfile, service->identifier, + "ClientCertFile", service->client_cert_file); + else + g_key_file_remove_key(keyfile, service->identifier, + "ClientCertFile", NULL); + + if (service->private_key_file != NULL && strlen(service->private_key_file) > 0) + g_key_file_set_string(keyfile, service->identifier, + "PrivateKeyFile", service->private_key_file); + else + g_key_file_remove_key(keyfile, service->identifier, + "PrivateKeyFile", NULL); + + if (service->private_key_passphrase != NULL && strlen(service->private_key_passphrase) > 0) + g_key_file_set_string(keyfile, service->identifier, + "PrivateKeyPassphrase", service->private_key_passphrase); + else + g_key_file_remove_key(keyfile, service->identifier, + "PrivateKeyPassphrase", NULL); + } +#endif + done: __connman_storage_save_service(keyfile, service->identifier); @@ -1068,6 +1355,9 @@ static int nameserver_add(struct connman_service *service, if (index < 0) return -ENXIO; +#if defined TIZEN_EXT + DBG("Resolver append nameserver: %s", nameserver); +#endif ret = connman_resolver_append(index, NULL, nameserver); if (ret >= 0) nameservers_changed(service); @@ -1082,14 +1372,115 @@ static int nameserver_add_all(struct connman_service *service, if (service->nameservers_config) { while (service->nameservers_config[i]) { +#if defined TIZEN_EXT + DBG("type %d add service->nameservers_config[%d]:%s",type, + i, service->nameservers_config[i]); + if(strncmp(service->nameservers_config[i], "::", 2) == 0) { + DBG("Invalid nameserver"); + i++; + continue; + } + + switch(type) { + case CONNMAN_IPCONFIG_TYPE_IPV4: + if (connman_inet_check_ipaddress( + service->nameservers_config[i]) == AF_INET && + service->dns_config_method_ipv4 == + CONNMAN_DNSCONFIG_METHOD_MANUAL) { + nameserver_add(service, type, + service->nameservers_config[i]); + } + break; + case CONNMAN_IPCONFIG_TYPE_IPV6: + if (connman_inet_check_ipaddress( + service->nameservers_config[i]) == AF_INET6 && + service->dns_config_method_ipv6 == + CONNMAN_DNSCONFIG_METHOD_MANUAL) { + nameserver_add(service, type, + service->nameservers_config[i]); + } + break; + case CONNMAN_IPCONFIG_TYPE_ALL: + if (connman_inet_check_ipaddress( + service->nameservers_config[i]) == AF_INET && + service->dns_config_method_ipv4 == + CONNMAN_DNSCONFIG_METHOD_MANUAL) { + nameserver_add(service, type, + service->nameservers_config[i]); + } + if (connman_inet_check_ipaddress( + service->nameservers_config[i]) == AF_INET6 && + service->dns_config_method_ipv6 == + CONNMAN_DNSCONFIG_METHOD_MANUAL) { + nameserver_add(service, type, + service->nameservers_config[i]); + } + break; + case CONNMAN_IPCONFIG_TYPE_UNKNOWN: + DBG("CONNMAN_IPCONFIG_TYPE_UNKNOWN do nothing"); + break; + default: + DBG("default case do nothing"); + break; + } +#else nameserver_add(service, type, service->nameservers_config[i]); +#endif i++; } } else if (service->nameservers) { while (service->nameservers[i]) { +#if defined TIZEN_EXT + DBG("type %d service->nameservers[%d]: %s",type, + i, service->nameservers[i]); + + switch(type) { + case CONNMAN_IPCONFIG_TYPE_IPV4: + if (connman_inet_check_ipaddress( + service->nameservers[i]) == AF_INET && + service->dns_config_method_ipv4 == + CONNMAN_DNSCONFIG_METHOD_DHCP) { + nameserver_add(service, type, + service->nameservers[i]); + } + break; + case CONNMAN_IPCONFIG_TYPE_IPV6: + if (connman_inet_check_ipaddress( + service->nameservers[i]) == AF_INET6 && + service->dns_config_method_ipv6 == + CONNMAN_DNSCONFIG_METHOD_DHCP) { + nameserver_add(service, type, + service->nameservers[i]); + } + break; + case CONNMAN_IPCONFIG_TYPE_ALL: + if (connman_inet_check_ipaddress( + service->nameservers[i]) == AF_INET && + service->dns_config_method_ipv4 == + CONNMAN_DNSCONFIG_METHOD_DHCP) { + nameserver_add(service, type, + service->nameservers[i]); + } + if (connman_inet_check_ipaddress( + service->nameservers[i]) == AF_INET6 && + service->dns_config_method_ipv6 == + CONNMAN_DNSCONFIG_METHOD_DHCP) { + nameserver_add(service, type, + service->nameservers[i]); + } + break; + case CONNMAN_IPCONFIG_TYPE_UNKNOWN: + DBG("CONNMAN_IPCONFIG_TYPE_UNKNOWN do nothing"); + break; + default: + DBG("default case do nothing"); + break; + } +#else nameserver_add(service, type, service->nameservers[i]); +#endif i++; } } @@ -1115,6 +1506,9 @@ static int nameserver_remove(struct connman_service *service, if (index < 0) return -ENXIO; +#if defined TIZEN_EXT + DBG("Resolver remove nameserver: %s", nameserver); +#endif ret = connman_resolver_remove(index, NULL, nameserver); if (ret >= 0) nameservers_changed(service); @@ -1125,6 +1519,15 @@ static int nameserver_remove(struct connman_service *service, static int nameserver_remove_all(struct connman_service *service, enum connman_ipconfig_type type) { +#if defined TIZEN_EXT + /** + * Skip this function if there is any connected profiles + * that use same interface + */ + if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR && + __connman_service_get_connected_count_of_iface(service) > 0) + return 0; +#endif int index, i = 0; index = __connman_service_get_index(service); @@ -1133,14 +1536,124 @@ static int nameserver_remove_all(struct connman_service *service, while (service->nameservers_config && service->nameservers_config[i]) { +#if defined TIZEN_EXT + DBG("type %d Remove service->nameservers_config[%d]: %s", + type, i, service->nameservers_config[i]); + switch(type) { + case CONNMAN_IPCONFIG_TYPE_IPV4: + if (connman_inet_check_ipaddress( + service->nameservers_config[i]) == AF_INET && + (service->dns_config_method_ipv4 == + CONNMAN_DNSCONFIG_METHOD_DHCP || + service->dns_config_method_ipv4 == + CONNMAN_DNSCONFIG_METHOD_MANUAL)) { + nameserver_remove(service, type, + service->nameservers_config[i]); + } + break; + case CONNMAN_IPCONFIG_TYPE_IPV6: + if (connman_inet_check_ipaddress( + service->nameservers_config[i]) == AF_INET6 && + (service->dns_config_method_ipv6 == + CONNMAN_DNSCONFIG_METHOD_DHCP || + service->dns_config_method_ipv6 == + CONNMAN_DNSCONFIG_METHOD_MANUAL)) { + nameserver_remove(service, type, + service->nameservers_config[i]); + } + break; + case CONNMAN_IPCONFIG_TYPE_ALL: + if (connman_inet_check_ipaddress( + service->nameservers_config[i]) == AF_INET && + (service->dns_config_method_ipv4 == + CONNMAN_DNSCONFIG_METHOD_DHCP || + service->dns_config_method_ipv4 == + CONNMAN_DNSCONFIG_METHOD_MANUAL)) { + nameserver_remove(service, type, + service->nameservers_config[i]); + } + if (connman_inet_check_ipaddress( + service->nameservers_config[i]) == AF_INET6 && + (service->dns_config_method_ipv6 == + CONNMAN_DNSCONFIG_METHOD_DHCP || + service->dns_config_method_ipv6 == + CONNMAN_DNSCONFIG_METHOD_MANUAL)) { + nameserver_remove(service, type, + service->nameservers_config[i]); + } + break; + case CONNMAN_IPCONFIG_TYPE_UNKNOWN: + DBG("CONNMAN_IPCONFIG_TYPE_UNKNOWN do nothing"); + break; + default: + DBG("default case do nothing"); + break; + } +#else nameserver_remove(service, type, service->nameservers_config[i]); +#endif i++; } i = 0; while (service->nameservers && service->nameservers[i]) { +#if defined TIZEN_EXT + DBG("type %d Remove service->nameservers[%d]: %s",type, i, + service->nameservers[i]); + switch(type) { + case CONNMAN_IPCONFIG_TYPE_IPV4: + if (connman_inet_check_ipaddress( + service->nameservers[i]) == AF_INET && + (service->dns_config_method_ipv4 == + CONNMAN_DNSCONFIG_METHOD_MANUAL || + service->dns_config_method_ipv4 == + CONNMAN_DNSCONFIG_METHOD_DHCP)) { + nameserver_remove(service, type, + service->nameservers[i]); + } + break; + case CONNMAN_IPCONFIG_TYPE_IPV6: + if (connman_inet_check_ipaddress( + service->nameservers[i]) == AF_INET6 && + (service->dns_config_method_ipv6 == + CONNMAN_DNSCONFIG_METHOD_MANUAL || + service->dns_config_method_ipv6 == + CONNMAN_DNSCONFIG_METHOD_DHCP)) { + nameserver_remove(service, type, + service->nameservers[i]); + } + break; + case CONNMAN_IPCONFIG_TYPE_ALL: + if (connman_inet_check_ipaddress( + service->nameservers[i]) == AF_INET && + (service->dns_config_method_ipv4 == + CONNMAN_DNSCONFIG_METHOD_MANUAL || + service->dns_config_method_ipv4 == + CONNMAN_DNSCONFIG_METHOD_DHCP)) { + nameserver_remove(service, type, + service->nameservers[i]); + } + if (connman_inet_check_ipaddress( + service->nameservers[i]) == AF_INET6 && + (service->dns_config_method_ipv6 == + CONNMAN_DNSCONFIG_METHOD_MANUAL || + service->dns_config_method_ipv6 == + CONNMAN_DNSCONFIG_METHOD_DHCP)) { + nameserver_remove(service, type, + service->nameservers[i]); + } + break; + case CONNMAN_IPCONFIG_TYPE_UNKNOWN: + DBG("CONNMAN_IPCONFIG_TYPE_UNKNOWN do nothing"); + break; + default: + DBG("default case do nothing"); + break; + } +#else nameserver_remove(service, type, service->nameservers[i]); +#endif i++; } @@ -1154,8 +1667,14 @@ static int nameserver_remove_all(struct connman_service *service, * inserted to resolver via netlink message (see rtnl.c:rtnl_newnduseropt() * for details) and not through service.c */ +#if defined TIZEN_EXT +int __connman_service_nameserver_append(struct connman_service *service, + const char *nameserver, bool is_auto, + enum connman_ipconfig_type type) +#else int __connman_service_nameserver_append(struct connman_service *service, const char *nameserver, bool is_auto) +#endif { char **nameservers; int len, i; @@ -1171,8 +1690,15 @@ int __connman_service_nameserver_append(struct connman_service *service, nameservers = service->nameservers; for (i = 0; nameservers && nameservers[i]; i++) +#if defined TIZEN_EXT + { + DBG("nameservers[%d] %s, nameserver %s", i, nameservers[i], nameserver); +#endif if (g_strcmp0(nameservers[i], nameserver) == 0) return -EEXIST; +#if defined TIZEN_EXT + } +#endif if (nameservers) { len = g_strv_length(nameservers); @@ -1188,6 +1714,16 @@ int __connman_service_nameserver_append(struct connman_service *service, nameservers[len] = g_strdup(nameserver); nameservers[len + 1] = NULL; +#ifdef TIZEN_EXT + if(type == CONNMAN_IPCONFIG_TYPE_IPV4 && + service->dns_config_method_ipv4 == CONNMAN_DNSCONFIG_METHOD_UNKNOWN) + service->dns_config_method_ipv4 = CONNMAN_DNSCONFIG_METHOD_DHCP; + + if(type == CONNMAN_IPCONFIG_TYPE_IPV6 && + service->dns_config_method_ipv6 == CONNMAN_DNSCONFIG_METHOD_UNKNOWN) + service->dns_config_method_ipv6 = CONNMAN_DNSCONFIG_METHOD_DHCP; +#endif + if (is_auto) { service->nameservers_auto = nameservers; } else { @@ -1202,8 +1738,14 @@ int __connman_service_nameserver_append(struct connman_service *service, return 0; } +#if defined TIZEN_EXT +int __connman_service_nameserver_remove(struct connman_service *service, + const char *nameserver, bool is_auto, + enum connman_ipconfig_type type) +#else int __connman_service_nameserver_remove(struct connman_service *service, const char *nameserver, bool is_auto) +#endif { char **servers, **nameservers; bool found = false; @@ -1261,8 +1803,14 @@ set_servers: service->nameservers_auto = nameservers; } else { service->nameservers = nameservers; +#if defined TIZEN_EXT + DBG("nameserver remove ip_type: %d", type); + nameserver_remove(service, type, + nameserver); +#else nameserver_remove(service, CONNMAN_IPCONFIG_TYPE_ALL, nameserver); +#endif } return 0; @@ -1488,8 +2036,68 @@ static void reset_stats(struct connman_service *service) g_timer_reset(service->stats_roaming.timer); } +#if defined TIZEN_EXT +static gboolean __connman_service_is_internet_profile( + struct connman_service *cellular) +{ + const char internet_suffix[] = "_1"; + + DBG("Service path: %s", cellular->path); + + if (g_str_has_suffix(cellular->path, internet_suffix) == TRUE) + return TRUE; + + return FALSE; +} + +struct connman_service *connman_service_get_default_connection(void) +{ + GList *list; + struct connman_service *service; + struct connman_service *default_service = NULL; + + for (list = service_list; list; list = list->next) { + service = list->data; + + DBG("service: %p %s %s %s", service, service->name, + state2string(service->state), + __connman_service_type2string(service->type)); + +#if defined TIZEN_MAINTAIN_ONLINE + if (service->type == CONNMAN_SERVICE_TYPE_WIFI && + service->state == CONNMAN_SERVICE_STATE_ONLINE) { +#else + if (service->type == CONNMAN_SERVICE_TYPE_WIFI && + is_connected(service->state) == TRUE) { +#endif + return service; + } else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR && + __connman_service_is_internet_profile(service) == TRUE) { + if (default_service == NULL) + default_service = service; + else if (is_connected(service->state) == TRUE && + is_connected(default_service->state) == FALSE) + default_service = service; + } else if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET && + is_connected(service->state) == TRUE) { + if (default_service == NULL) + default_service = service; + } else if (service->type == CONNMAN_SERVICE_TYPE_BLUETOOTH && + is_connected(service->state) == TRUE) { + if (default_service == NULL) + default_service = service; + } + } + + return default_service; +} +#endif + struct connman_service *connman_service_get_default(void) { +#if defined TIZEN_MAINTAIN_ONLINE + return connman_service_get_default_connection(); +#else struct connman_service *service; if (!service_list) @@ -1501,6 +2109,7 @@ struct connman_service *connman_service_get_default(void) return NULL; return service; +#endif } bool __connman_service_index_is_default(int index) @@ -1526,9 +2135,15 @@ static void default_changed(void) current_default ? current_default->identifier : ""); DBG("new default %p %s", service, service ? service->identifier : ""); +#if defined TIZEN_EXT + current_default = service; + + __connman_service_timeserver_changed(service, NULL); +#else __connman_service_timeserver_changed(current_default, NULL); current_default = service; +#endif if (service) { if (service->hostname && @@ -1553,14 +2168,64 @@ static void state_changed(struct connman_service *service) if (!str) return; +#if !defined TIZEN_EXT if (!allow_property_changed(service)) return; +#endif +#if defined TIZEN_EXT + DBG(" %s, %s", str, service->path); +#endif connman_dbus_property_changed_basic(service->path, CONNMAN_SERVICE_INTERFACE, "State", DBUS_TYPE_STRING, &str); } +#if defined TIZEN_EXT +static void connect_reason_changed(struct connman_service *service) +{ + if (!service->path) + return; + + if (!allow_property_changed(service)) + return; + + connman_dbus_property_changed_basic(service->path, + CONNMAN_SERVICE_INTERFACE, + "ConnectReason", + DBUS_TYPE_INT32, + &service->connect_reason); +} + +static void disconnection_requested_changed(struct connman_service *service) +{ + dbus_bool_t disconnection_requested; + + if (!service->path) + return; + + if (!allow_property_changed(service)) + return; + + disconnection_requested = service->disconnection_requested; + connman_dbus_property_changed_basic(service->path, + CONNMAN_SERVICE_INTERFACE, + "DisconnectionRequested", + DBUS_TYPE_BOOLEAN, + &disconnection_requested); +} + +void connman_service_set_disconnection_requested(struct connman_service *service, + bool disconnection_requested) +{ + if (service == NULL) + return; + + service->disconnection_requested = disconnection_requested; + disconnection_requested_changed(service); +} +#endif + static void strength_changed(struct connman_service *service) { if (service->strength == 0) @@ -1658,10 +2323,16 @@ static void append_security(DBusMessageIter *iter, void *user_data) case CONNMAN_SERVICE_SECURITY_PSK: case CONNMAN_SERVICE_SECURITY_WPA: case CONNMAN_SERVICE_SECURITY_RSN: +#if defined TIZEN_EXT + case CONNMAN_SERVICE_SECURITY_SAE: +#endif str = "wps"; dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str); break; +#if defined TIZEN_EXT + case CONNMAN_SERVICE_SECURITY_OWE: +#endif case CONNMAN_SERVICE_SECURITY_UNKNOWN: case CONNMAN_SERVICE_SECURITY_NONE: case CONNMAN_SERVICE_SECURITY_WEP: @@ -1761,20 +2432,143 @@ static void append_nameservers(DBusMessageIter *iter, } } +#if defined TIZEN_EXT +static void append_nameserver_manual(DBusMessageIter *iter, + struct connman_service *service, const char *server) +{ + bool available = true; + + if (service) + available = nameserver_available(service, + CONNMAN_IPCONFIG_TYPE_ALL, server); + + if (available) + dbus_message_iter_append_basic(iter, + DBUS_TYPE_STRING, &server); +} + +static void append_nameserver_dhcp(DBusMessageIter *iter, + struct connman_service *service, const char *server) +{ + bool available = true; + + if (service) + available = nameserver_available(service, + CONNMAN_IPCONFIG_TYPE_ALL, server); + + if (available) + dbus_message_iter_append_basic(iter, + DBUS_TYPE_STRING, &server); +} +#endif + static void append_dns(DBusMessageIter *iter, void *user_data) { struct connman_service *service = user_data; +#if defined TIZEN_EXT + int i; +#endif if (!is_connected(service->state)) return; +#ifdef TIZEN_EXT + const char *str; + + str = __connman_dnsconfig_method2string(service->dns_config_method_ipv4); + if(str != NULL) { + char *str1 = g_strdup_printf("ipv4.%s", str); + dbus_message_iter_append_basic(iter, + DBUS_TYPE_STRING, &str1); + g_free(str1); + } + + str = __connman_dnsconfig_method2string(service->dns_config_method_ipv6); + if(str != NULL) { + char *str1 = g_strdup_printf("ipv6.%s", str); + dbus_message_iter_append_basic(iter, + DBUS_TYPE_STRING, &str1); + g_free(str1); + } +#endif + if (service->nameservers_config) { +#if defined TIZEN_EXT + i = 0; + while (service->nameservers_config[i]) { + if (connman_inet_check_ipaddress( + service->nameservers_config[i]) == AF_INET && + service->dns_config_method_ipv4 == + CONNMAN_DNSCONFIG_METHOD_MANUAL) { + append_nameserver_manual(iter, service, + service->nameservers_config[i]); + } + + if (connman_inet_check_ipaddress( + service->nameservers_config[i]) == AF_INET6 && + service->dns_config_method_ipv6 == + CONNMAN_DNSCONFIG_METHOD_MANUAL) { + append_nameserver_manual(iter, service, + service->nameservers_config[i]); + } + i++; + } + /* In case of mixed DNS Config Type one of IPv4/IPv6 can be + * dynamic while other is static so try to append the DNS + * Address which is dynamic also */ + if (service->nameservers != NULL) { + i = 0; + while (service->nameservers[i]) { + if (connman_inet_check_ipaddress( + service->nameservers[i]) == AF_INET && + service->dns_config_method_ipv4 == + CONNMAN_DNSCONFIG_METHOD_DHCP) { + append_nameserver_dhcp(iter, service, + service->nameservers[i]); + } + + if (connman_inet_check_ipaddress( + service->nameservers[i]) == AF_INET6 && + service->dns_config_method_ipv6 == + CONNMAN_DNSCONFIG_METHOD_DHCP) { + append_nameserver_dhcp(iter, service, + service->nameservers[i]); + } + i++; + } + } +#else append_nameservers(iter, service, service->nameservers_config); +#endif return; } else { if (service->nameservers) +#if defined TIZEN_EXT + { + i = 0; + while (service->nameservers[i]) { + if (connman_inet_check_ipaddress( + service->nameservers[i]) == AF_INET && + service->dns_config_method_ipv4 == + CONNMAN_DNSCONFIG_METHOD_DHCP) { + append_nameserver_dhcp(iter, service, + service->nameservers[i]); + } + + if (connman_inet_check_ipaddress( + service->nameservers[i]) == AF_INET6 && + service->dns_config_method_ipv6 == + CONNMAN_DNSCONFIG_METHOD_DHCP) { + append_nameserver_dhcp(iter, service, + service->nameservers[i]); + } + i++; + } + } +#else append_nameservers(iter, service, service->nameservers); +#endif if (service->nameservers_auto) append_nameservers(iter, service, @@ -1796,10 +2590,46 @@ static void append_dnsconfig(DBusMessageIter *iter, void *user_data) { struct connman_service *service = user_data; +#ifdef TIZEN_EXT + /* Append DNS Config Type */ + const char *str; + str = __connman_dnsconfig_method2string(service->dns_config_method_ipv4); + if(str != NULL) { + char *str1 = g_strdup_printf("ipv4.%s", str); + dbus_message_iter_append_basic(iter, + DBUS_TYPE_STRING, &str1); + g_free(str1); + } + + str = __connman_dnsconfig_method2string(service->dns_config_method_ipv6); + if(str != NULL) { + char *str1 = g_strdup_printf("ipv6.%s", str); + dbus_message_iter_append_basic(iter, + DBUS_TYPE_STRING, &str1); + g_free(str1); + } +#endif + if (!service->nameservers_config) return; +#if defined TIZEN_EXT + int i = 0; + while (service->nameservers_config[i]) { + if (connman_inet_check_ipaddress(service->nameservers_config[i]) == AF_INET && + service->dns_config_method_ipv4 == CONNMAN_DNSCONFIG_METHOD_MANUAL) { + append_nameserver_manual(iter, NULL, service->nameservers_config[i]); + } + + if (connman_inet_check_ipaddress(service->nameservers_config[i]) == AF_INET6 && + service->dns_config_method_ipv6 == CONNMAN_DNSCONFIG_METHOD_MANUAL) { + append_nameserver_manual(iter, NULL, service->nameservers_config[i]); + } + i++; + } +#else append_nameservers(iter, NULL, service->nameservers_config); +#endif } static void append_ts(DBusMessageIter *iter, void *user_data) @@ -2414,6 +3244,133 @@ int connman_service_iterate_services(connman_service_iterate_cb cb, return ret; } +#if defined TIZEN_EXT +static void append_wifi_ext_info(DBusMessageIter *dict, + struct connman_network *network) +{ + char bssid_buff[WIFI_BSSID_STR_LEN] = {0,}; + char *bssid_str = bssid_buff; + const void *ssid; + unsigned int ssid_len; + unsigned char *bssid; + unsigned int maxrate; + int maxspeed; + unsigned int keymgmt; + uint16_t frequency; + const char *enc_mode; + const char *str; + gboolean passpoint; + char country_code_buff[WIFI_COUNTRY_CODE_LEN + 1] = {0,}; + char *country_code_str = country_code_buff; + unsigned char *country_code; + uint16_t connection_mode; + + ssid = connman_network_get_blob(network, "WiFi.SSID", &ssid_len); + bssid = connman_network_get_bssid(network); + maxrate = connman_network_get_maxrate(network); + maxspeed = connman_network_get_maxspeed(network); + frequency = connman_network_get_frequency(network); + enc_mode = connman_network_get_enc_mode(network); + passpoint = connman_network_get_bool(network, "WiFi.HS20AP"); + keymgmt = connman_network_get_keymgmt(network); + country_code = connman_network_get_countrycode(network); + connection_mode = connman_network_get_connection_mode(network); + + snprintf(bssid_str, WIFI_BSSID_STR_LEN, "%02x:%02x:%02x:%02x:%02x:%02x", + bssid[0], bssid[1], bssid[2], + bssid[3], bssid[4], bssid[5]); + + snprintf(country_code_str, (WIFI_COUNTRY_CODE_LEN + 1), "%c%c", + country_code[0], country_code[1]); + + + connman_dbus_dict_append_fixed_array(dict, "SSID", + DBUS_TYPE_BYTE, &ssid, ssid_len); + connman_dbus_dict_append_basic(dict, "BSSID", + DBUS_TYPE_STRING, &bssid_str); + connman_dbus_dict_append_basic(dict, "MaxRate", + DBUS_TYPE_UINT32, &maxrate); + connman_dbus_dict_append_basic(dict, "MaxSpeed", + DBUS_TYPE_INT32, &maxspeed); + connman_dbus_dict_append_basic(dict, "Frequency", + DBUS_TYPE_UINT16, &frequency); + connman_dbus_dict_append_basic(dict, "EncryptionMode", + DBUS_TYPE_STRING, &enc_mode); + connman_dbus_dict_append_basic(dict, "Passpoint", + DBUS_TYPE_BOOLEAN, &passpoint); + connman_dbus_dict_append_basic(dict, "Keymgmt", + DBUS_TYPE_UINT32, &keymgmt); + connman_dbus_dict_append_basic(dict, "Country", DBUS_TYPE_STRING, + &country_code_str); + connman_dbus_dict_append_basic(dict, "ConnMode", + DBUS_TYPE_UINT16, &connection_mode); + + str = connman_network_get_string(network, "WiFi.Security"); + if (str != NULL && g_str_equal(str, "ieee8021x") == TRUE) { + str = connman_network_get_string(network, "WiFi.EAP"); + if (str != NULL) + connman_dbus_dict_append_basic(dict, "EAP", + DBUS_TYPE_STRING, &str); + + str = connman_network_get_string(network, "WiFi.Phase2"); + if (str != NULL) + connman_dbus_dict_append_basic(dict, "Phase2", + DBUS_TYPE_STRING, &str); + + str = connman_network_get_string(network, "WiFi.Identity"); + if (str != NULL) + connman_dbus_dict_append_basic(dict, "Identity", + DBUS_TYPE_STRING, &str); + + str = connman_network_get_string(network, "WiFi.CACertFile"); + if (str != NULL) + connman_dbus_dict_append_basic(dict, "CACertFile", + DBUS_TYPE_STRING, &str); + + str = connman_network_get_string(network, + "WiFi.ClientCertFile"); + if (str != NULL) + connman_dbus_dict_append_basic(dict, "ClientCertFile", + DBUS_TYPE_STRING, &str); + + str = connman_network_get_string(network, + "WiFi.PrivateKeyFile"); + if (str != NULL) + connman_dbus_dict_append_basic(dict, "PrivateKeyFile", + DBUS_TYPE_STRING, &str); + } +} + +static void append_bssid_info(DBusMessageIter *iter, void *user_data) +{ + GSList *bssid_list = NULL; + struct connman_network *network = user_data; + struct connman_bssids *bssids; + char bssid_buf[MAC_ADDRESS_LENGTH] = {0,}; + char *bssid_str = bssid_buf; + + bssid_list = (GSList *)connman_network_get_bssid_list(network); + if(bssid_list) { + GSList *list; + for (list = bssid_list; list; list = list->next) { + bssids = (struct connman_bssids *)list->data; + g_snprintf(bssid_buf, MAC_ADDRESS_LENGTH, "%02x:%02x:%02x:%02x:%02x:%02x", + bssids->bssid[0], bssids->bssid[1], bssids->bssid[2], + bssids->bssid[3], bssids->bssid[4], bssids->bssid[5]); + + connman_dbus_dict_append_basic(iter, "BSSID", + DBUS_TYPE_STRING, &bssid_str); + + connman_dbus_dict_append_basic(iter, "Strength", + DBUS_TYPE_UINT16, &bssids->strength); + + connman_dbus_dict_append_basic(iter, "Frequency", + DBUS_TYPE_UINT16, &bssids->frequency); + } + } +} +#endif + static void append_properties(DBusMessageIter *dict, dbus_bool_t limited, struct connman_service *service) { @@ -2421,6 +3378,33 @@ static void append_properties(DBusMessageIter *dict, dbus_bool_t limited, const char *str; GSList *list; +#if defined TIZEN_EXT + unsigned int frequency = 0U; + if (service && service->network) { + frequency = connman_network_get_frequency(service->network); + connman_dbus_dict_append_basic(dict, "Frequency", + DBUS_TYPE_UINT16, &frequency); + } + + unsigned char *wifi_vsie; + unsigned int wifi_vsie_len; + GSList *vsie_list = NULL; + + if (service->network) + vsie_list = (GSList *)connman_network_get_vsie_list(service->network); + + if (vsie_list) { + GSList *list; + for (list = vsie_list; list; list = list->next) { + wifi_vsie = (unsigned char *)list->data; + wifi_vsie_len = wifi_vsie[1] + 2; + + connman_dbus_dict_append_fixed_array(dict, "Vsie", DBUS_TYPE_BYTE, + &wifi_vsie, wifi_vsie_len); + } + } +#endif + str = __connman_service_type2string(service->type); if (str) connman_dbus_dict_append_basic(dict, "Type", @@ -2434,6 +3418,13 @@ static void append_properties(DBusMessageIter *dict, dbus_bool_t limited, connman_dbus_dict_append_basic(dict, "State", DBUS_TYPE_STRING, &str); +#ifdef TIZEN_EXT + str = state2string(service->state_ipv6); + if (str != NULL) + connman_dbus_dict_append_basic(dict, "StateIPv6", + DBUS_TYPE_STRING, &str); +#endif + str = error2string(service->error); if (str) connman_dbus_dict_append_basic(dict, "Error", @@ -2469,6 +3460,9 @@ static void append_properties(DBusMessageIter *dict, dbus_bool_t limited, case CONNMAN_SERVICE_TYPE_GPS: case CONNMAN_SERVICE_TYPE_VPN: case CONNMAN_SERVICE_TYPE_P2P: +#if defined TIZEN_EXT_WIFI_MESH + case CONNMAN_SERVICE_TYPE_MESH: +#endif break; case CONNMAN_SERVICE_TYPE_CELLULAR: val = service->roaming; @@ -2479,6 +3473,28 @@ static void append_properties(DBusMessageIter *dict, dbus_bool_t limited, append_ethernet, service); break; case CONNMAN_SERVICE_TYPE_WIFI: +#if defined TIZEN_EXT + if (service->network != NULL) { + append_wifi_ext_info(dict, service->network); + connman_dbus_dict_append_dict(dict, "BSSID.List", + append_bssid_info, service->network); + } + + connman_dbus_dict_append_dict(dict, "Ethernet", + append_ethernet, service); + + service->disconnect_reason = connman_network_get_disconnect_reason(service->network); + connman_dbus_dict_append_basic(dict, "DisconnectReason", + DBUS_TYPE_INT32, &service->disconnect_reason); + + connman_dbus_dict_append_basic(dict, "AssocStatusCode", + DBUS_TYPE_INT32, &service->assoc_status_code); + + connman_dbus_dict_append_basic(dict, "Hidden", + DBUS_TYPE_BOOLEAN, &service->hidden_service); + + break; +#endif case CONNMAN_SERVICE_TYPE_ETHERNET: case CONNMAN_SERVICE_TYPE_BLUETOOTH: case CONNMAN_SERVICE_TYPE_GADGET: @@ -2736,6 +3752,54 @@ char **connman_service_get_timeservers(struct connman_service *service) return service->timeservers; } +#if defined TIZEN_EXT +/* + * Description: Telephony plug-in requires manual PROXY setting function + */ +int connman_service_set_proxy(struct connman_service *service, + const char *proxy, gboolean active) +{ + char **proxies_array = NULL; + + if (service == NULL) + return -EINVAL; + + switch (service->type) { + case CONNMAN_SERVICE_TYPE_CELLULAR: + case CONNMAN_SERVICE_TYPE_ETHERNET: + case CONNMAN_SERVICE_TYPE_WIFI: + break; + + default: + return -EINVAL; + } + + g_strfreev(service->proxies); + service->proxies = NULL; + + if (proxy != NULL) + proxies_array = g_strsplit(proxy, " ", 0); + + service->proxies = proxies_array; + + if (proxy == NULL) { + service->proxy_config = CONNMAN_SERVICE_PROXY_METHOD_DIRECT; + DBG("proxy changed (%d)", active); + } else { + service->proxy_config = CONNMAN_SERVICE_PROXY_METHOD_MANUAL; + DBG("proxy chagned %s (%d)", proxy, active); + } + + if (active == TRUE) { + proxy_changed(service); + + __connman_notifier_proxy_changed(service); + } + + return 0; +} +#endif + void connman_service_set_proxy_method(struct connman_service *service, enum connman_service_proxy_method method) { @@ -2823,6 +3887,18 @@ const char *connman_service_get_proxy_autoconfig(struct connman_service *service return NULL; } +#if defined TIZEN_EXT +int connman_service_get_ipv6_dns_method(struct connman_service *service) +{ + if (!service) { + DBG("Service is NULL"); + return -1; + } + + return service->dns_config_method_ipv6; +} +#endif + void __connman_service_set_timeservers(struct connman_service *service, char **timeservers) { @@ -2950,6 +4026,22 @@ void __connman_service_set_pac(struct connman_service *service, proxy_changed(service); } +#if defined TIZEN_EXT +void __connman_service_set_proxy(struct connman_service *service, + const char *proxies) +{ + char **proxies_array = NULL; + + g_strfreev(service->proxies); + service->proxies = NULL; + + if (proxies != NULL) + proxies_array = g_strsplit(proxies, " ", 0); + + service->proxies = proxies_array; +} +#endif + void __connman_service_set_identity(struct connman_service *service, const char *identity) { @@ -3069,7 +4161,9 @@ int __connman_service_check_passphrase(enum connman_service_security security, case CONNMAN_SERVICE_SECURITY_UNKNOWN: case CONNMAN_SERVICE_SECURITY_NONE: case CONNMAN_SERVICE_SECURITY_WPA: +#if !defined TIZEN_EXT case CONNMAN_SERVICE_SECURITY_RSN: +#endif DBG("service security '%s' (%d) not handled", security2string(security), security); @@ -3077,6 +4171,11 @@ int __connman_service_check_passphrase(enum connman_service_security security, return -EOPNOTSUPP; case CONNMAN_SERVICE_SECURITY_PSK: +#if defined TIZEN_EXT + case CONNMAN_SERVICE_SECURITY_RSN: + /* TO CHECK: We need to check the key length supported by SAE */ + case CONNMAN_SERVICE_SECURITY_SAE: +#endif /* A raw key is always 64 bytes length, * its content is in hex representation. * A PSK key must be between [8..63]. @@ -3103,6 +4202,9 @@ int __connman_service_check_passphrase(enum connman_service_security security, break; case CONNMAN_SERVICE_SECURITY_8021X: +#if defined TIZEN_EXT + case CONNMAN_SERVICE_SECURITY_OWE: +#endif break; } @@ -3121,6 +4223,16 @@ int __connman_service_set_passphrase(struct connman_service *service, service->security != CONNMAN_SERVICE_SECURITY_8021X) return -EINVAL; +#if defined TIZEN_EXT + /* The encrypted passphrase is used here + * and validation is done by net-config before being encrypted. + */ + err = 0; + if (service->security != CONNMAN_SERVICE_SECURITY_PSK && + service->security != CONNMAN_SERVICE_SECURITY_RSN && + service->security != CONNMAN_SERVICE_SECURITY_SAE && + service->security != CONNMAN_SERVICE_SECURITY_WEP) +#endif err = __connman_service_check_passphrase(service->security, passphrase); if (err < 0) @@ -3508,6 +4620,10 @@ static DBusMessage *set_property(DBusConnection *conn, GString *str; int index; const char *gw; +#if defined TIZEN_EXT + enum connman_ipconfig_type ip_type = CONNMAN_IPCONFIG_TYPE_ALL; + DBG("%s", name); +#endif if (__connman_provider_is_immutable(service->provider) || service->immutable) @@ -3524,17 +4640,65 @@ static DBusMessage *set_property(DBusConnection *conn, gw = __connman_ipconfig_get_gateway_from_index(index, CONNMAN_IPCONFIG_TYPE_ALL); +#if !defined TIZEN_EXT if (gw && strlen(gw)) __connman_service_nameserver_del_routes(service, CONNMAN_IPCONFIG_TYPE_ALL); +#endif dbus_message_iter_recurse(&value, &entry); +#if defined TIZEN_EXT + /* IPv4/IPv6 Last DNS config method */ + int last_dns_ipv4 = service->dns_config_method_ipv4; + int last_dns_ipv6 = service->dns_config_method_ipv6; + DBG("Last DNS Config Method IPv4: %d IPv6: %d", last_dns_ipv4, last_dns_ipv6); +#endif + while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) { const char *val; dbus_message_iter_get_basic(&entry, &val); dbus_message_iter_next(&entry); +#ifdef TIZEN_EXT + /* First unpack the DNS Config Method */ + DBG("DNS Config Method: %s", val); + if((g_strcmp0(val, "ipv4.manual") == 0)) { + service->dns_config_method_ipv4 = + CONNMAN_DNSCONFIG_METHOD_MANUAL; + + if(last_dns_ipv4 != CONNMAN_DNSCONFIG_METHOD_MANUAL) { + if(ip_type == CONNMAN_IPCONFIG_TYPE_UNKNOWN) + ip_type = CONNMAN_IPCONFIG_TYPE_IPV4; + else + ip_type = CONNMAN_IPCONFIG_TYPE_ALL; + } + continue; + } else if(g_strcmp0(val, "ipv4.dhcp") == 0) { + service->dns_config_method_ipv4 = + CONNMAN_DNSCONFIG_METHOD_DHCP; + if(last_dns_ipv4 == CONNMAN_DNSCONFIG_METHOD_MANUAL) + ip_type = CONNMAN_IPCONFIG_TYPE_IPV4; + + continue; + } else if(g_strcmp0(val, "ipv6.manual") == 0) { + service->dns_config_method_ipv6 = + CONNMAN_DNSCONFIG_METHOD_MANUAL; + if(last_dns_ipv6 != CONNMAN_DNSCONFIG_METHOD_MANUAL) { + if(ip_type == CONNMAN_IPCONFIG_TYPE_UNKNOWN) + ip_type = CONNMAN_IPCONFIG_TYPE_IPV6; + else + ip_type = CONNMAN_IPCONFIG_TYPE_ALL; + } + continue; + } else if(g_strcmp0(val, "ipv6.dhcp") == 0) { + service->dns_config_method_ipv6 = + CONNMAN_DNSCONFIG_METHOD_DHCP; + if(last_dns_ipv6 == CONNMAN_DNSCONFIG_METHOD_MANUAL) + ip_type = CONNMAN_IPCONFIG_TYPE_IPV6; + continue; + } +#endif if (!val[0]) continue; @@ -3544,7 +4708,21 @@ static DBusMessage *set_property(DBusConnection *conn, g_string_append(str, val); } +#if defined TIZEN_EXT + if (service->dns_config_method_ipv4 == CONNMAN_DNSCONFIG_METHOD_DHCP && + service->dns_config_method_ipv6 == CONNMAN_DNSCONFIG_METHOD_DHCP) { + DBG("Both IPv4 and IPv6 DNS Method DHCP"); + ip_type = CONNMAN_IPCONFIG_TYPE_ALL; + } + if (gw && strlen(gw)) + __connman_service_nameserver_del_routes(service, + ip_type); + + DBG("%s ip_type: %d nameserver remove all", name, ip_type); + nameserver_remove_all(service, ip_type); +#else nameserver_remove_all(service, CONNMAN_IPCONFIG_TYPE_ALL); +#endif g_strfreev(service->nameservers_config); if (str->len > 0) { @@ -3567,7 +4745,12 @@ static DBusMessage *set_property(DBusConnection *conn, if (gw && strlen(gw)) __connman_service_nameserver_add_routes(service, gw); +#if defined TIZEN_EXT + DBG("%s ip_type: %d nameserver add all", name, ip_type); + nameserver_add_all(service, ip_type); +#else nameserver_add_all(service, CONNMAN_IPCONFIG_TYPE_ALL); +#endif dns_configuration_changed(service); if (__connman_service_is_connected_state(service, @@ -3765,6 +4948,19 @@ static DBusMessage *set_property(DBusConnection *conn, } service_save(service); +#if defined TIZEN_EXT + /* When AP is connected using WPS without SSID then its password needs + * to be saved for autoconnection */ + } else if (g_str_equal(name, "Passphrase")) { + char *passphrase; + + if (type != DBUS_TYPE_STRING) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&value, &passphrase); + + __connman_service_set_passphrase(service, passphrase); +#endif } else return __connman_error_invalid_property(msg); @@ -3784,8 +4980,10 @@ static void set_error(struct connman_service *service, if (!service->path) return; +#if !defined TIZEN_EXT if (!allow_property_changed(service)) return; +#endif str = error2string(service->error); @@ -3936,6 +5134,9 @@ void __connman_service_set_active_session(bool enable, GSList *list) case CONNMAN_SERVICE_TYPE_GPS: case CONNMAN_SERVICE_TYPE_VPN: case CONNMAN_SERVICE_TYPE_P2P: +#if defined TIZEN_EXT_WIFI_MESH + case CONNMAN_SERVICE_TYPE_MESH: +#endif break; } @@ -3995,6 +5196,17 @@ static GList *preferred_tech_list_get(void) CONNMAN_SERVICE_CONNECT_REASON_USER) { DBG("service %p name %s is user connected", service, service->name); +#if defined TIZEN_EXT + /* We can connect to a favorite service like + * wifi even we have a userconnect for cellular + * because we have refount for cellular service + */ + if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR) + break; + + if (service->type == CONNMAN_SERVICE_TYPE_BLUETOOTH) + break; +#endif return NULL; } } @@ -4060,6 +5272,12 @@ static bool auto_connect_service(GList *services, ignore[CONNMAN_SERVICE_TYPE_VPN] = true; +#if defined TIZEN_EXT_WIFI_MESH + /* Don't auto connect wifi if mesh interface is created */ + if (connman_mesh_is_interface_created()) + ignore[CONNMAN_SERVICE_TYPE_WIFI] = true; +#endif + for (list = services; list; list = list->next) { service = list->data; @@ -4069,6 +5287,20 @@ static bool auto_connect_service(GList *services, continue; } +#if defined TIZEN_EXT + DBG("service %p %s %s %s, favorite(%d), ignore(%d), hidden(%d, %d)", + service, service->name, + state2string(service->state), + __connman_service_type2string(service->type), + service->favorite, is_ignore(service), + service->hidden, service->hidden_service); + + /* Tizen takes Wi-Fi as the highest priority into consideration. */ + if (service->type != CONNMAN_SERVICE_TYPE_WIFI) + if (is_connecting(service->state) == TRUE || is_connected(service->state) == TRUE) + continue; +#endif + if (service->pending || is_connecting(service->state) || is_connected(service->state)) { @@ -4088,9 +5320,21 @@ static bool auto_connect_service(GList *services, if (preferred) continue; +#if defined TIZEN_EXT + DBG("Service is not favorite, autoconnecting %d", + autoconnecting); +#endif return autoconnecting; } +#if defined TIZEN_EXT + DBG("service %p identifier %s roaming %d ignore %d " + "ipconfig_usable %d autoconnect %d state %d", + service, + service->identifier, service->roaming, + service->ignore, is_ipconfig_usable(service), + service->autoconnect, service->state); +#endif if (is_ignore(service) || service->state != CONNMAN_SERVICE_STATE_IDLE) continue; @@ -4138,6 +5382,21 @@ static gboolean run_auto_connect(gpointer data) return FALSE; } +#if defined TIZEN_EXT +bool __connman_service_get_auto_connect_mode(void) +{ + return auto_connect_mode; +} + +void __connman_service_set_auto_connect_mode(bool enable) +{ + DBG("set auto_connect_mode = %d", enable); + + if (auto_connect_mode != enable) + auto_connect_mode = enable; +} +#endif + void __connman_service_auto_connect(enum connman_service_connect_reason reason) { DBG(""); @@ -4145,10 +5404,33 @@ void __connman_service_auto_connect(enum connman_service_connect_reason reason) if (autoconnect_id != 0) return; +#if defined TIZEN_EXT + if (auto_connect_mode == FALSE) { + DBG("Currently, not auto connection mode"); + return; + } +#endif + if (!__connman_session_policy_autoconnect(reason)) return; +#if defined TIZEN_EXT + /* Adding Timeout of 500ms before trying to auto connect. + * This is done because of below scenario + * 1. Device is connected to AP1 + * 2. WPS Connection request is initiated for AP2 + * 3. Immediately WPS Connection is Cancelled + * When WPS Connection Connection is initiated for AP2 then + * sometimes there is a scenario where connman gets in ASSOCIATED + * state with AP1 due to autoconnect and subsequently the connection + * initiated by AP1 fails and connman service for AP1 comes in + * FAILURE state due to this when connection with AP2 is cancelled + * then autoconnect with AP1 doesn't works because its autoconnection + * is ignored as its last state was FAILURE rather than IDLE */ + autoconnect_id = g_timeout_add(500, run_auto_connect, +#else autoconnect_id = g_idle_add(run_auto_connect, +#endif GUINT_TO_POINTER(reason)); } @@ -4311,19 +5593,45 @@ static DBusMessage *connect_service(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct connman_service *service = user_data; +#if defined TIZEN_EXT + int err = 0; +#else int index, err = 0; GList *list; +#endif DBG("service %p", service); +#if defined TIZEN_EXT + /* + * Description: TIZEN implements system global connection management. + */ + if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR) + connman_service_user_pdn_connection_ref(service); + + /*Reset the Disconnect Reason while issue connect request*/ + service->disconnect_reason = 0; + + /*Reset the association status code while issue connect request*/ + service->assoc_status_code = 0; + + /* Reset the disconnection_requested while issue connect request*/ + connman_service_set_disconnection_requested(service, false); +#endif + if (service->pending) return __connman_error_in_progress(msg); +#if !defined TIZEN_EXT index = __connman_service_get_index(service); for (list = service_list; list; list = list->next) { struct connman_service *temp = list->data; +#if defined TIZEN_EXT + if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR) + break; +#endif if (!is_connecting(temp->state) && !is_connected(temp->state)) break; @@ -4340,6 +5648,7 @@ static DBusMessage *connect_service(DBusConnection *conn, } if (err == -EINPROGRESS) return __connman_error_operation_timeout(msg); +#endif service->ignore = false; @@ -4362,6 +5671,20 @@ static DBusMessage *disconnect_service(DBusConnection *conn, DBG("service %p", service); +#if defined TIZEN_EXT + /* + * Description: TIZEN implements system global connection management. + */ + if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR) { + if (connman_service_user_pdn_connection_unref_and_test(service) != TRUE) + return __connman_error_failed(msg, EISCONN); + + if (is_connected(service->state) == TRUE && + service == connman_service_get_default_connection()) + return __connman_error_failed(msg, EISCONN); + } +#endif + service->ignore = true; err = __connman_service_disconnect(service); @@ -4371,6 +5694,25 @@ static DBusMessage *disconnect_service(DBusConnection *conn, return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } +#if defined TIZEN_EXT +static void __connman_service_cleanup_network_8021x(struct connman_service *service) +{ + if (service == NULL) + return; + + DBG("service %p ", service); + + connman_network_set_string(service->network, "WiFi.EAP", NULL); + connman_network_set_string(service->network, "WiFi.Identity", NULL); + connman_network_set_string(service->network, "WiFi.CACertFile", NULL); + connman_network_set_string(service->network, "WiFi.ClientCertFile", NULL); + connman_network_set_string(service->network, "WiFi.PrivateKeyFile", NULL); + connman_network_set_string(service->network, "WiFi.PrivateKeyPassphrase", NULL); + connman_network_set_string(service->network, "WiFi.Phase2", NULL); + connman_network_set_string(service->network, "WiFi.AnonymousIdentity", NULL); +} +#endif + bool __connman_service_remove(struct connman_service *service) { if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET || @@ -4381,8 +5723,10 @@ bool __connman_service_remove(struct connman_service *service) __connman_provider_is_immutable(service->provider)) return false; +#if !defined TIZEN_EXT if (!service->favorite && !is_idle(service->state)) return false; +#endif __connman_service_disconnect(service); @@ -4413,13 +5757,55 @@ bool __connman_service_remove(struct connman_service *service) g_free(service->eap); service->eap = NULL; +#if defined TIZEN_EXT + g_free(service->ca_cert_file); + service->ca_cert_file = NULL; + + g_free(service->client_cert_file); + service->client_cert_file = NULL; + + g_free(service->private_key_file); + service->private_key_file = NULL; + + g_free(service->private_key_passphrase); + service->private_key_passphrase = NULL; + + g_free(service->phase2); + service->phase2 = NULL; + + __connman_service_cleanup_network_8021x(service); + + __connman_ipconfig_set_method(service->ipconfig_ipv4, CONNMAN_IPCONFIG_METHOD_DHCP); + __connman_ipconfig_set_method(service->ipconfig_ipv6, CONNMAN_IPCONFIG_METHOD_AUTO); + connman_service_set_proxy(service, NULL, false); + + __connman_service_nameserver_clear(service); + + g_strfreev(service->nameservers_config); + service->nameservers_config = NULL; + +#endif + service->error = CONNMAN_SERVICE_ERROR_UNKNOWN; __connman_service_set_favorite(service, false); __connman_ipconfig_ipv6_reset_privacy(service->ipconfig_ipv6); +#if defined TIZEN_EXT + /* Reset IP Method and DNS Method to DHCP */ + __connman_ipconfig_set_method(service->ipconfig_ipv4, + CONNMAN_IPCONFIG_METHOD_DHCP); + service->dns_config_method_ipv4 = CONNMAN_DNSCONFIG_METHOD_DHCP; + g_strfreev(service->nameservers_config); + service->nameservers_config = NULL; +#endif + +#if defined TIZEN_EXT + __connman_storage_remove_service(service->identifier); +#else service_save(service); +#endif return true; } @@ -4725,6 +6111,19 @@ static DBusMessage *reset_counters(DBusConnection *conn, return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } +#if defined TIZEN_MAINTAIN_ONLINE +static DBusMessage *downgrade_service(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + struct connman_service *service = user_data; + + downgrade_state(service); + __connman_connection_update_gateway(); + + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); +} +#endif + static void service_schedule_added(struct connman_service *service) { DBG("service %p", service); @@ -4753,6 +6152,10 @@ static void service_schedule_removed(struct connman_service *service) static bool allow_property_changed(struct connman_service *service) { +#if defined TIZEN_EXT + if (service->path == NULL) + return FALSE; +#endif if (g_hash_table_lookup_extended(services_notify->add, service->path, NULL, NULL)) return false; @@ -4782,6 +6185,9 @@ static const GDBusMethodTable service_methods[] = { GDBUS_ARGS({ "service", "o" }), NULL, move_after) }, { GDBUS_METHOD("ResetCounters", NULL, NULL, reset_counters) }, +#if defined TIZEN_MAINTAIN_ONLINE + { GDBUS_METHOD("Downgrade", NULL, NULL, downgrade_service) }, +#endif { }, }; @@ -4932,6 +6338,15 @@ static void service_initialize(struct connman_service *service) service->wps = false; service->wps_advertizing = false; +#if defined TIZEN_EXT + service->disconnection_requested = false; + service->storage_reload = false; + /* + * Description: TIZEN implements system global connection management. + */ + service->user_pdn_connection_refcount = 0; + __sync_synchronize(); +#endif } /** @@ -5263,6 +6678,53 @@ void __connman_service_mark_dirty(void) services_dirty = true; } +#if defined TIZEN_EXT +/** + * Returns profile count if there is any connected profiles + * that use same interface + */ +int __connman_service_get_connected_count_of_iface( + struct connman_service *service) +{ + GList *list; + int count = 0; + int index1 = 0; + int index2 = 0; + + DBG(""); + + index1 = __connman_service_get_index(service); + + if (index1 <= 0) + return 0; + + for (list = service_list; list; list = list->next) { + struct connman_service *service2 = list->data; + + if (service == service2) + continue; + + index2 = __connman_service_get_index(service2); + + if (is_connected(service2->state) && index2 > 0 && index1 == index2) + count++; + + index2 = 0; + } + + DBG("Interface index %d, count %d", index1, count); + + return count; +} + +void __connman_service_set_storage_reload(struct connman_service *service, + bool storage_reload) +{ + if (service != NULL) + service->storage_reload = storage_reload; +} +#endif + /** * __connman_service_set_favorite_delayed: * @service: service structure @@ -5275,6 +6737,10 @@ int __connman_service_set_favorite_delayed(struct connman_service *service, bool favorite, bool delay_ordering) { +#if defined TIZEN_EXT + if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR) + return -EIO; +#endif if (service->hidden) return -EOPNOTSUPP; @@ -5424,7 +6890,14 @@ static void report_error_cb(void *user_context, bool retry, /* It is not relevant to stay on Failure state * when failing is due to wrong user input */ __connman_service_clear_error(service); +#if defined TIZEN_EXT + /* Reseting the state back in case of failure state */ + service->state_ipv4 = service->state_ipv6 = + CONNMAN_SERVICE_STATE_IDLE; + if (service->error != CONNMAN_SERVICE_ERROR_AUTH_FAILED) + set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN); +#endif service_complete(service); __connman_connection_update_gateway(); } @@ -5606,6 +7079,136 @@ static int service_update_preferred_order(struct connman_service *default_servic return -EALREADY; } +#if defined TIZEN_EXT +static gboolean __connman_service_can_drop(struct connman_service *service) +{ + if (is_connected(service->state) == TRUE || is_connecting(service->state) == TRUE) { + if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR) + return TRUE; + else if (connman_service_is_no_ref_user_pdn_connection(service) == TRUE) + return TRUE; + } + return FALSE; +} + +static struct connman_device *default_connecting_device = NULL; + +static void __connman_service_disconnect_default(struct connman_service *service) +{ + struct connman_device *default_device = NULL; + + if (default_connecting_device == NULL) + return; + + default_device = connman_network_get_device( + __connman_service_get_network(service)); + + DBG("Disconnecting service %p %s", service, service->path); + DBG("Disconnecting device %p %p %s", + default_connecting_device, + default_device, + connman_device_get_string(default_device, "Name")); + + if (default_connecting_device == default_device) + default_connecting_device = NULL; +} + +#if defined TIZEN_MAINTAIN_ONLINE +static void __connman_service_connect_default(struct connman_service *current, + enum connman_service_state old_state) +#else +static void __connman_service_connect_default(struct connman_service *current) +#endif +{ + int err; + GList *list; + bool default_internet; + struct connman_service *service; + struct connman_service *default_service = NULL; + struct connman_device *default_device = NULL; + + if (current->type == CONNMAN_SERVICE_TYPE_CELLULAR) { + switch (current->state) { + case CONNMAN_SERVICE_STATE_UNKNOWN: + case CONNMAN_SERVICE_STATE_ASSOCIATION: + case CONNMAN_SERVICE_STATE_CONFIGURATION: + return; + default: + break; + } + + if (default_connecting_device && + __connman_service_is_internet_profile(current) == TRUE) { + if (current->network == NULL) + return; + + default_device = connman_network_get_device(current->network); + if (default_connecting_device == default_device) { + DBG("Cellular service[%s] %p %s", + state2string(current->state), current, current->path); + DBG("Cellular device %p %p %s", + default_connecting_device, default_device, + connman_device_get_string(default_device, "Name")); + + default_connecting_device = NULL; + } + } + + return; +#if defined TIZEN_MAINTAIN_ONLINE + } else if (current->state == CONNMAN_SERVICE_STATE_READY && + old_state == CONNMAN_SERVICE_STATE_ONLINE) { + DBG("Device is downgraded: online --> ready"); +#endif + } else if (is_connected(current->state) == TRUE || is_connecting(current->state) == TRUE) + return; + + /* Always-on: keep default cellular connection as possible */ + for (list = service_list; list; list = list->next) { + service = list->data; + + if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR || + __connman_service_is_internet_profile(service) != TRUE || + service->network == NULL) { + continue; + } + + default_internet = + connman_network_get_bool(service->network, "DefaultInternet"); + + DBG("service: %p %s %s %s (default: %d)", service, service->name, + __connman_service_type2string(service->type), + state2string(service->state), default_internet); + + if (default_internet) { + default_service = service; + if (is_connected(default_service->state) == TRUE || + is_connecting(default_service->state) == TRUE) + return; + + default_device = connman_network_get_device(default_service->network); + if (default_connecting_device == default_device) { + DBG("Device is connecting (%p)", default_connecting_device); + return; + } + + default_connecting_device = default_device; + default_service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_USER; + + err = __connman_network_connect(default_service->network); + DBG("Connecting default service %p %s [%d]", + default_service, default_service->path, err); + DBG("Connecting device %p %s", default_connecting_device, + connman_device_get_string(default_connecting_device, "Name")); + if (err < 0 && err != -EINPROGRESS) { + default_connecting_device = NULL; + } else + break; + } + } +} +#endif + static void single_connected_tech(struct connman_service *allowed) { struct connman_service *service; @@ -5614,14 +7217,24 @@ static void single_connected_tech(struct connman_service *allowed) DBG("keeping %p %s", allowed, allowed->path); +#if defined TIZEN_EXT + if (!allowed || allowed->type == CONNMAN_SERVICE_TYPE_CELLULAR) + return; +#endif + for (iter = service_list; iter; iter = iter->next) { service = iter->data; +#if defined TIZEN_EXT + if (service != allowed && service->type != allowed->type && + __connman_service_can_drop(service) == TRUE) +#else if (!is_connected(service->state)) break; if (service == allowed) continue; +#endif services = g_slist_prepend(services, service); } @@ -5630,12 +7243,44 @@ static void single_connected_tech(struct connman_service *allowed) service = list->data; DBG("disconnecting %p %s", service, service->path); +#if defined TIZEN_EXT + __connman_service_disconnect_default(service); +#endif __connman_service_disconnect(service); } g_slist_free(services); } +#if defined TIZEN_EXT +static void set_priority_connected_service(void) +{ + struct connman_service *service; + GList *list; + + for (list = service_list; list; list = list->next) { + service = list->data; + + if (is_connected(service->state) == FALSE) + service->order = 5; + else +#if defined TIZEN_MAINTAIN_ONLINE + { + if (service->type == CONNMAN_SERVICE_TYPE_WIFI && + service->state == CONNMAN_SERVICE_STATE_ONLINE) + service->order = 6; + else if (service->type != CONNMAN_SERVICE_TYPE_WIFI) + service->order = 6; + else + service->order = 5; + } +#else + service->order = 6; +#endif + } +} +#endif + static const char *get_dbus_sender(struct connman_service *service) { if (!service->pending) @@ -5774,14 +7419,33 @@ static int service_indicate_state(struct connman_service *service) __connman_ipconfig_disable_ipv6( service->ipconfig_ipv6); +#if !defined TIZEN_MAINTAIN_ONLINE if (connman_setting_get_bool("SingleConnectedTechnology")) single_connected_tech(service); else if (service->type != CONNMAN_SERVICE_TYPE_VPN) vpn_auto_connect(); +#else + if (service->type != CONNMAN_SERVICE_TYPE_VPN) + vpn_auto_connect(); +#endif + +#if defined TIZEN_EXT + if (service->type == CONNMAN_SERVICE_TYPE_WIFI) + set_priority_connected_service(); +#endif break; case CONNMAN_SERVICE_STATE_ONLINE: +#if defined TIZEN_MAINTAIN_ONLINE +#if defined TIZEN_EXT + if (service->type == CONNMAN_SERVICE_TYPE_WIFI) + set_priority_connected_service(); +#endif + + if (connman_setting_get_bool("SingleConnectedTechnology")) + single_connected_tech(service); +#endif break; @@ -5796,8 +7460,20 @@ static int service_indicate_state(struct connman_service *service) __connman_wpad_stop(service); +#if defined TIZEN_EXT + /** + * Skip the functions if there is any connected profiles + * that use same interface + */ + if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR || + __connman_service_get_connected_count_of_iface( + service) <= 0) { +#endif domain_changed(service); proxy_changed(service); +#if defined TIZEN_EXT + } +#endif /* * Previous services which are connected and which states @@ -5810,6 +7486,11 @@ static int service_indicate_state(struct connman_service *service) break; case CONNMAN_SERVICE_STATE_FAILURE: +#if defined TIZEN_EXT + if (service->type == CONNMAN_SERVICE_TYPE_WIFI) + service->order = 5; + __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO); +#endif if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER) { connman_agent_report_error(service, service->path, error2string(service->error), @@ -5823,6 +7504,14 @@ static int service_indicate_state(struct connman_service *service) service_list_sort(); +#if defined TIZEN_EXT +#if defined TIZEN_MAINTAIN_ONLINE + __connman_service_connect_default(service, old_state); +#else + __connman_service_connect_default(service); +#endif +#endif + __connman_connection_update_gateway(); if ((old_state == CONNMAN_SERVICE_STATE_ONLINE && @@ -5853,6 +7542,23 @@ int __connman_service_indicate_error(struct connman_service *service, set_error(service, error); +/* default internet service: fix not cleared if pdp activation*/ +#if defined TIZEN_EXT + /* + * If connection failed for default service(DefaultInternet), + * default_connecting_device should be cleared. + */ + if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR && + service->error == CONNMAN_SERVICE_ERROR_CONNECT_FAILED) + __connman_service_disconnect_default(service); + + if (service->type == CONNMAN_SERVICE_TYPE_WIFI && + service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY) { + g_free(service->passphrase); + service->passphrase = NULL; + } +#endif + __connman_service_ipconfig_indicate_state(service, CONNMAN_SERVICE_STATE_FAILURE, CONNMAN_IPCONFIG_TYPE_IPV4); @@ -5955,6 +7661,15 @@ done: __connman_service_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4); } +#if defined TIZEN_EXT +void connman_check_proxy_setup_and_wispr_start(struct connman_service *service){ + + DBG("check the proxy and start wispr"); + check_proxy_setup(service); + return; +} +#endif + /* * How many networks are connected at the same time. If more than 1, * then set the rp_filter setting properly (loose mode routing) so that network @@ -6039,6 +7754,19 @@ static gboolean redo_wispr_ipv6(gpointer user_data) return FALSE; } +#if defined TIZEN_MAINTAIN_ONLINE +static gboolean redo_wispr_ipv4(gpointer user_data) +{ + struct connman_service *service = user_data; + + DBG(""); + + __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4); + + return FALSE; +} +#endif + int __connman_service_online_check_failed(struct connman_service *service, enum connman_ipconfig_type type) { @@ -6119,6 +7847,10 @@ int __connman_service_ipconfig_indicate_state(struct connman_service *service, connman_warn("ipconfig state %d ipconfig method %d", new_state, method); +#if defined TIZEN_EXT + if (old_state != CONNMAN_SERVICE_STATE_READY && + old_state != CONNMAN_SERVICE_STATE_ONLINE) +#endif new_state = CONNMAN_SERVICE_STATE_IDLE; break; @@ -6134,6 +7866,18 @@ int __connman_service_ipconfig_indicate_state(struct connman_service *service, if (old_state == new_state) return -EALREADY; +#if defined TIZEN_EXT + __sync_synchronize(); + if (service->user_pdn_connection_refcount > 0 && + service->type == CONNMAN_SERVICE_TYPE_CELLULAR) + if (new_state == CONNMAN_SERVICE_STATE_FAILURE || + new_state == CONNMAN_SERVICE_STATE_DISCONNECT || + new_state == CONNMAN_SERVICE_STATE_IDLE) { + service->user_pdn_connection_refcount = 0; + __sync_synchronize(); + } +#endif + DBG("service %p (%s) old state %d (%s) new state %d (%s) type %d (%s)", service, service ? service->identifier : NULL, old_state, state2string(old_state), @@ -6147,9 +7891,24 @@ int __connman_service_ipconfig_indicate_state(struct connman_service *service, case CONNMAN_SERVICE_STATE_CONFIGURATION: break; case CONNMAN_SERVICE_STATE_READY: +#if defined TIZEN_EXT + if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR && + __connman_service_is_internet_profile(service) != TRUE) { + if (type == CONNMAN_IPCONFIG_TYPE_IPV4) + service_rp_filter(service, TRUE); + + break; + } +#endif if (connman_setting_get_bool("EnableOnlineCheck")) if (type == CONNMAN_IPCONFIG_TYPE_IPV4) { +#if !defined TIZEN_EXT check_proxy_setup(service); +#endif +#if defined TIZEN_MAINTAIN_ONLINE +/* if (old_state == CONNMAN_SERVICE_STATE_ONLINE) */ + check_proxy_setup(service); +#endif } else { __connman_service_wispr_start(service, type); } @@ -6193,6 +7952,19 @@ int __connman_service_ipconfig_indicate_state(struct connman_service *service, __connman_timeserver_sync(service); +#if defined TIZEN_EXT + int ret = service_indicate_state(service); + /*Sent the Ready changed signal again in case IPv4 IP set + after IPv6 IP set*/ + + if(ret == -EALREADY && type == CONNMAN_IPCONFIG_TYPE_IPV4 + && new_state == CONNMAN_SERVICE_STATE_READY) { + DBG("Notify IPv4 state new/old %d/%d", new_state,old_state); + state_changed(service); + } + + return ret; +#endif return service_indicate_state(service); } @@ -6280,6 +8052,17 @@ static void prepare_8021x(struct connman_service *service) if (service->phase2) connman_network_set_string(service->network, "WiFi.Phase2", service->phase2); + +#if defined TIZEN_EXT + if (service->keymgmt_type) + connman_network_set_string(service->network, "WiFi.KeymgmtType", + service->keymgmt_type); + + DBG("service->phase1 : %s", service->phase1); + if (service->phase1) + connman_network_set_string(service->network, "WiFi.Phase1", + service->phase1); +#endif } static int service_connect(struct connman_service *service) @@ -6289,11 +8072,41 @@ static int service_connect(struct connman_service *service) if (service->hidden) return -EPERM; +#if defined TIZEN_EXT + GList *list; + int index; + + index = __connman_service_get_index(service); + + for (list = service_list; list; list = list->next) { + struct connman_service *temp = list->data; + + if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR) + break; + + if (!is_connecting(temp->state) && !is_connected(temp->state)) + break; + + if (service == temp) + continue; + + if (service->type != temp->type) + continue; + + if (__connman_service_get_index(temp) == index && + __connman_service_disconnect(temp) == -EINPROGRESS) + return -EINPROGRESS; + } +#endif + switch (service->type) { case CONNMAN_SERVICE_TYPE_UNKNOWN: case CONNMAN_SERVICE_TYPE_SYSTEM: case CONNMAN_SERVICE_TYPE_GPS: case CONNMAN_SERVICE_TYPE_P2P: +#if defined TIZEN_EXT_WIFI_MESH + case CONNMAN_SERVICE_TYPE_MESH: +#endif return -EINVAL; case CONNMAN_SERVICE_TYPE_ETHERNET: case CONNMAN_SERVICE_TYPE_GADGET: @@ -6305,11 +8118,17 @@ static int service_connect(struct connman_service *service) switch (service->security) { case CONNMAN_SERVICE_SECURITY_UNKNOWN: case CONNMAN_SERVICE_SECURITY_NONE: +#if defined TIZEN_EXT + case CONNMAN_SERVICE_SECURITY_OWE: +#endif break; case CONNMAN_SERVICE_SECURITY_WEP: case CONNMAN_SERVICE_SECURITY_PSK: case CONNMAN_SERVICE_SECURITY_WPA: case CONNMAN_SERVICE_SECURITY_RSN: +#if defined TIZEN_EXT + case CONNMAN_SERVICE_SECURITY_SAE: +#endif if (service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY) return -ENOKEY; @@ -6334,6 +8153,21 @@ static int service_connect(struct connman_service *service) return -EINVAL; } +#if defined TIZEN_EXT + /* + * never request credentials if using EAP-TLS, EAP-SIM + * or EAP-AKA (EAP-TLS, EAP-SIM and EAP-AKA networks + * need to be fully provisioned) + */ + DBG("service eap: %s", service->eap); + if (g_str_equal(service->eap, "tls") || + g_str_equal(service->eap, "sim") || + g_str_equal(service->eap, "aka") || + g_str_equal(service->eap, "aka'") || + g_str_equal(service->eap, "pwd") || + g_str_equal(service->eap, "fast")) + break; +#else /* * never request credentials if using EAP-TLS * (EAP-TLS networks need to be fully provisioned) @@ -6341,6 +8175,7 @@ static int service_connect(struct connman_service *service) if (g_str_equal(service->eap, "tls")) break; +#endif /* * Return -ENOKEY if either identity or passphrase is * missing. Agent provided credentials can be used as @@ -6368,6 +8203,10 @@ static int service_connect(struct connman_service *service) case CONNMAN_SERVICE_SECURITY_PSK: case CONNMAN_SERVICE_SECURITY_WPA: case CONNMAN_SERVICE_SECURITY_RSN: +#if defined TIZEN_EXT + case CONNMAN_SERVICE_SECURITY_SAE: + case CONNMAN_SERVICE_SECURITY_OWE: +#endif break; case CONNMAN_SERVICE_SECURITY_8021X: prepare_8021x(service); @@ -6425,6 +8264,9 @@ int __connman_service_connect(struct connman_service *service, case CONNMAN_SERVICE_TYPE_SYSTEM: case CONNMAN_SERVICE_TYPE_GPS: case CONNMAN_SERVICE_TYPE_P2P: +#if defined TIZEN_EXT_WIFI_MESH + case CONNMAN_SERVICE_TYPE_MESH: +#endif return -EINVAL; case CONNMAN_SERVICE_TYPE_ETHERNET: @@ -6446,6 +8288,9 @@ int __connman_service_connect(struct connman_service *service, DBG("service %p err %d", service, err); service->connect_reason = reason; +#if defined TIZEN_EXT + connect_reason_changed(service); +#endif if (err >= 0) return 0; @@ -6527,6 +8372,14 @@ int __connman_service_disconnect(struct connman_service *service) __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv6, NULL); +#if defined TIZEN_EXT + /** + * Skip the functions If there is any connected profiles + * that use same interface + */ + if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR || + __connman_service_get_connected_count_of_iface(service) <= 0) { +#endif __connman_ipconfig_address_remove(service->ipconfig_ipv4); settings_changed(service, service->ipconfig_ipv4); @@ -6535,6 +8388,9 @@ int __connman_service_disconnect(struct connman_service *service) __connman_ipconfig_disable(service->ipconfig_ipv4); __connman_ipconfig_disable(service->ipconfig_ipv6); +#if defined TIZEN_EXT + } +#endif return err; } @@ -6684,8 +8540,15 @@ static int service_register(struct connman_service *service) DBG("path %s", service->path); +#if defined TIZEN_EXT + service_load(service); + int ret = __connman_config_provision_service(service); + if (ret < 0) + DBG("Failed to provision service"); +#else if (__connman_config_provision_service(service) < 0) service_load(service); +#endif g_dbus_register_interface(connection, service->path, CONNMAN_SERVICE_INTERFACE, @@ -6745,6 +8608,9 @@ static void service_ip_bound(struct connman_ipconfig *ipconfig, struct connman_service *service = __connman_ipconfig_get_data(ipconfig); enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN; enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN; +#if defined TIZEN_EXT + int err; +#endif DBG("%s ip bound", ifname); @@ -6756,9 +8622,18 @@ static void service_ip_bound(struct connman_ipconfig *ipconfig, if (type == CONNMAN_IPCONFIG_TYPE_IPV6 && method == CONNMAN_IPCONFIG_METHOD_AUTO) +#if defined TIZEN_EXT + { + err = __connman_ipconfig_gateway_add(ipconfig, service); + + if(err < 0) + DBG("Failed to add gateway"); + } +#else __connman_service_ipconfig_indicate_state(service, CONNMAN_SERVICE_STATE_READY, CONNMAN_IPCONFIG_TYPE_IPV6); +#endif settings_changed(service, ipconfig); address_updated(service, type); @@ -7022,10 +8897,34 @@ static enum connman_service_security convert_wifi_security(const char *security) return CONNMAN_SERVICE_SECURITY_WPA; else if (g_str_equal(security, "rsn")) return CONNMAN_SERVICE_SECURITY_RSN; +#if defined TIZEN_EXT + else if (g_str_equal(security, "sae")) + return CONNMAN_SERVICE_SECURITY_SAE; + else if (g_str_equal(security, "owe")) + return CONNMAN_SERVICE_SECURITY_OWE; + else if (g_str_equal(security, "ft_psk") == TRUE) + return CONNMAN_SERVICE_SECURITY_PSK; + else if (g_str_equal(security, "ft_ieee8021x") == TRUE) + return CONNMAN_SERVICE_SECURITY_8021X; +#endif else return CONNMAN_SERVICE_SECURITY_UNKNOWN; } +#if defined TIZEN_EXT +int check_passphrase_ext(struct connman_network *network, + const char *passphrase) +{ + const char *str; + enum connman_service_security security; + + str = connman_network_get_string(network, "WiFi.Security"); + security = convert_wifi_security(str); + + return __connman_service_check_passphrase(security, passphrase); +} +#endif + static void update_wps_values(struct connman_service *service, struct connman_network *network) { @@ -7188,6 +9087,9 @@ struct connman_service * __connman_service_create_from_network(struct connman_ne case CONNMAN_SERVICE_TYPE_UNKNOWN: case CONNMAN_SERVICE_TYPE_SYSTEM: case CONNMAN_SERVICE_TYPE_P2P: +#if defined TIZEN_EXT_WIFI_MESH + case CONNMAN_SERVICE_TYPE_MESH: +#endif break; case CONNMAN_SERVICE_TYPE_GADGET: @@ -7208,6 +9110,19 @@ struct connman_service * __connman_service_create_from_network(struct connman_ne break; } } + +#if defined TIZEN_EXT + /* TIZEN synchronizes below information when the service creates */ + if (service->eap != NULL) + connman_network_set_string(service->network, "WiFi.EAP", + service->eap); + if (service->identity != NULL) + connman_network_set_string(service->network, "WiFi.Identity", + service->identity); + if (service->phase2 != NULL) + connman_network_set_string(service->network, "WiFi.Phase2", + service->phase2); +#endif } __connman_notifier_service_add(service, service->name); @@ -7215,6 +9130,30 @@ struct connman_service * __connman_service_create_from_network(struct connman_ne return service; } +#if defined TIZEN_EXT +void __connman_service_notify_strength_changed(struct connman_network *network) +{ + struct connman_service *service; + uint8_t strength = 0; + + service = connman_service_lookup_from_network(network); + if (!service) + return; + + if (!service->network) + return; + + strength = connman_network_get_strength(service->network); + if (strength == service->strength) + return; + + service->strength = strength; + DBG("Strength %d", strength); + strength_changed(service); + service_list_sort(); +} +#endif + void __connman_service_update_from_network(struct connman_network *network) { bool need_sort = false; @@ -7231,6 +9170,13 @@ void __connman_service_update_from_network(struct connman_network *network) if (!service->network) return; +#if defined TIZEN_EXT + if (service->storage_reload) { + service_load(service); + __connman_service_set_storage_reload(service, false); + } +#endif + name = connman_network_get_string(service->network, "Name"); if (g_strcmp0(service->name, name) != 0) { g_free(service->name); diff --git a/src/session.c b/src/session.c index 2a1dd9aa..808931a8 100644 --- a/src/session.c +++ b/src/session.c @@ -195,6 +195,9 @@ static char *service2bearer(enum connman_service_type type) case CONNMAN_SERVICE_TYPE_GPS: case CONNMAN_SERVICE_TYPE_P2P: case CONNMAN_SERVICE_TYPE_UNKNOWN: +#if defined TIZEN_EXT_WIFI_MESH + case CONNMAN_SERVICE_TYPE_MESH: +#endif return ""; } diff --git a/src/shared/arp.h b/src/shared/arp.h index 03e2168c..03e2168c 100644..100755 --- a/src/shared/arp.h +++ b/src/shared/arp.h diff --git a/src/shared/netlink.c b/src/shared/netlink.c index b32ab854..b32ab854 100644..100755 --- a/src/shared/netlink.c +++ b/src/shared/netlink.c diff --git a/src/shared/netlink.h b/src/shared/netlink.h index 62bb3e01..62bb3e01 100644..100755 --- a/src/shared/netlink.h +++ b/src/shared/netlink.h diff --git a/src/shared/util.c b/src/shared/util.c index df045c5b..df045c5b 100644..100755 --- a/src/shared/util.c +++ b/src/shared/util.c diff --git a/src/shared/util.h b/src/shared/util.h index 293fb3a4..293fb3a4 100644..100755 --- a/src/shared/util.h +++ b/src/shared/util.h diff --git a/src/stats.c b/src/stats.c index 6f7ce208..6f7ce208 100644..100755 --- a/src/stats.c +++ b/src/stats.c diff --git a/src/storage.c b/src/storage.c index 5e877ef1..6ca600b2 100644..100755 --- a/src/storage.c +++ b/src/storage.c @@ -27,6 +27,7 @@ #include <unistd.h> #include <sys/stat.h> #include <dirent.h> +#include <stdio.h> #include <connman/storage.h> @@ -71,6 +72,19 @@ static int storage_save(GKeyFile *keyfile, char *pathname) ret = -EIO; } +#if defined TIZEN_EXT + { + FILE *fp = NULL; + fp = fopen(pathname, "a+"); + if(fp){ + fflush(fp); + fsync(fp->_fileno); + fclose(fp); + DBG("sync the file to disk"); + } + } +#endif + g_free(data); return ret; diff --git a/src/task.c b/src/task.c index 953cc409..953cc409 100644..100755 --- a/src/task.c +++ b/src/task.c diff --git a/src/technology.c b/src/technology.c index 4e053fc9..782ce15c 100644 --- a/src/technology.c +++ b/src/technology.c @@ -25,6 +25,10 @@ #include <errno.h> #include <string.h> +#if defined TIZEN_EXT +#include <stdio.h> +#include <stdlib.h> +#endif #include <gdbus.h> @@ -43,6 +47,16 @@ static GHashTable *rfkill_list; static bool global_offlinemode; +#if defined TIZEN_EXT +typedef enum { + CONNMAN_SCAN_TYPE_FULL_CHANNEL = 0x00, + CONNMAN_SCAN_TYPE_SPECIFIC_AP, + CONNMAN_SCAN_TYPE_MULTI_AP, +} connman_scan_type_e; + +static connman_scan_type_e g_scan_type = -1; +#endif + struct connman_rfkill { unsigned int index; enum connman_service_type type; @@ -80,6 +94,13 @@ struct connman_technology { bool softblocked; bool hardblocked; bool dbus_registered; +#if defined TIZEN_EXT_WIFI_MESH + DBusMessage *mesh_dbus_msg; +#endif +#if defined TIZEN_EXT + bool is_5_0_ghz_supported; + int max_scan_ssids; +#endif }; static GSList *driver_list = NULL; @@ -150,6 +171,10 @@ static const char *get_name(enum connman_service_type type) return "Cellular"; case CONNMAN_SERVICE_TYPE_P2P: return "P2P"; +#if defined TIZEN_EXT_WIFI_MESH + case CONNMAN_SERVICE_TYPE_MESH: + return "Mesh"; +#endif } return NULL; @@ -377,6 +402,16 @@ bool connman_technology_get_wifi_tethering(const char **ssid, return true; } +#if defined TIZEN_EXT +void connman_techonology_wifi_set_5ghz_supported(struct connman_technology *wifi_technology, + bool is_5_0_ghz_supported) +{ + DBG(""); + + wifi_technology->is_5_0_ghz_supported = is_5_0_ghz_supported; +} +#endif + static void free_rfkill(gpointer data) { struct connman_rfkill *rfkill = data; @@ -651,6 +686,11 @@ static int technology_affect_devices(struct connman_technology *technology, return 0; } +#if defined TIZEN_EXT_WIFI_MESH + if (technology->type == CONNMAN_SERVICE_TYPE_MESH) + return 0; +#endif + for (list = technology->device_list; list; list = list->next) { struct connman_device *device = list->data; @@ -685,6 +725,10 @@ static void powered_changed(struct connman_technology *technology) __sync_synchronize(); enabled = technology->enabled; +#if defined TIZEN_EXT + DBG("ConnMan, Powered : %s, %s", + enabled ? "TRUE" : "FALSE",technology->path); +#endif connman_dbus_property_changed_basic(technology->path, CONNMAN_TECHNOLOGY_INTERFACE, "Powered", DBUS_TYPE_BOOLEAN, &enabled); @@ -859,6 +903,49 @@ make_reply: return reply; } +#if defined TIZEN_EXT +int set_connman_bssid(enum bssid_type mode, char *bssid) +{ + static unsigned char bssid_for_connect[6]; + static int bssid_len; + + DBG("mode : %d", mode); + + if (mode == CHECK_BSSID) { + return bssid_len; + } + + if (mode == GET_BSSID && bssid) { + memcpy(bssid, bssid_for_connect, 6); + return bssid_len; + } + + if (mode == RESET_BSSID) { + bssid_len = 0; + return bssid_len; + } + + if (mode != SET_BSSID || !bssid) { + DBG("Invalid parameter"); + return 0; + } + + bssid_len = sscanf(bssid, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", + &bssid_for_connect[0], &bssid_for_connect[1], &bssid_for_connect[2], + &bssid_for_connect[3], &bssid_for_connect[4], &bssid_for_connect[5]); + if (bssid_len != 6) { + DBG("Incorrect BSSID format. bssid_len = %d", bssid_len); + bssid_len = 0; + } + + DBG("SET BSSID len : %d, BSSID : %02x:%02x:%02x:%02x:%02x:%02x", bssid_len, + bssid_for_connect[0], bssid_for_connect[1], bssid_for_connect[2], + bssid_for_connect[3], bssid_for_connect[4], bssid_for_connect[5]); + + return bssid_len; +} +#endif + static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -972,6 +1059,17 @@ static DBusMessage *set_property(DBusConnection *conn, dbus_message_iter_get_basic(&value, &enable); return set_powered(technology, msg, enable); +#if defined TIZEN_EXT + } else if (g_str_equal(name, "SetBSSID")) { + char *key; + + if (type != DBUS_TYPE_STRING) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&value, &key); + DBG("BSSID %s", key); + set_connman_bssid(SET_BSSID, key); +#endif } else return __connman_error_invalid_property(msg); @@ -1002,9 +1100,38 @@ static void reply_scan_pending(struct connman_technology *technology, int err) } } +#if defined TIZEN_EXT +dbus_bool_t __connman_technology_notify_scan_changed(const char *key, void *val) +{ + DBG("key %s", key); + DBusMessage *signal; + DBusMessageIter iter; + dbus_bool_t result = FALSE; + + signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH, + CONNMAN_MANAGER_INTERFACE, "ScanChanged"); + if (!signal) + return result; + + dbus_message_iter_init_append(signal, &iter); + connman_dbus_property_append_basic(&iter, key, DBUS_TYPE_BOOLEAN, val); + + result = dbus_connection_send(connection, signal, NULL); + dbus_message_unref(signal); + + DBG("Successfuly sent signal"); + + return result; +} +#endif + void __connman_technology_scan_started(struct connman_device *device) { DBG("device %p", device); +#if defined TIZEN_EXT + dbus_bool_t status = 1; + __connman_technology_notify_scan_changed("scan_started", &status); +#endif } void __connman_technology_scan_stopped(struct connman_device *device, @@ -1031,8 +1158,32 @@ void __connman_technology_scan_stopped(struct connman_device *device, count += 1; } +#if defined TIZEN_EXT + if (count == 0) { + DBusMessage *signal; + DBusMessageIter iter; + dbus_bool_t status = 0; + __connman_technology_notify_scan_changed("scan_done", &status); + + signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH, + CONNMAN_MANAGER_INTERFACE, "ScanDone"); + if (!signal) + return; + + dbus_message_iter_init_append(signal, &iter); + connman_dbus_property_append_basic(&iter, "Scantype", + DBUS_TYPE_INT32, &g_scan_type); + + dbus_connection_send(connection, signal, NULL); + dbus_message_unref(signal); + reply_scan_pending(technology, 0); + + DBG("Successfuly sent ScanDone signal"); + } +#else if (count == 0) reply_scan_pending(technology, 0); +#endif } void __connman_technology_notify_regdom_by_device(struct connman_device *device, @@ -1084,15 +1235,713 @@ static DBusMessage *scan(DBusConnection *conn, DBusMessage *msg, void *data) return __connman_error_permission_denied(msg); dbus_message_ref(msg); +#if !defined TIZEN_EXT technology->scan_pending = g_slist_prepend(technology->scan_pending, msg); +#endif err = __connman_device_request_scan_full(technology->type); if (err < 0) +#if defined TIZEN_EXT + return __connman_error_failed(msg, -err); +#else reply_scan_pending(technology, err); +#endif + +#if defined TIZEN_EXT + if (err == 0) { + g_scan_type = CONNMAN_SCAN_TYPE_FULL_CHANNEL; + DBG("g_scan_type %d", g_scan_type); + } + technology->scan_pending = + g_slist_prepend(technology->scan_pending, msg); +#endif + return NULL; +} + +#if defined TIZEN_EXT +static DBusMessage *specific_scan(DBusConnection *conn, DBusMessage *msg, void *data) +{ + struct connman_technology *technology = data; + GSList *specific_scan_list = NULL; + int scan_type = 0; + const char *name = NULL; + const char *freq = NULL; + DBusMessageIter iter, dict; + int err; + + DBG("technology %p request from %s", technology, + dbus_message_get_sender(msg)); + + if (!dbus_message_iter_init(msg, &iter)) + return __connman_error_invalid_arguments(msg); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_recurse(&iter, &dict); + while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { + DBusMessageIter entry, value2; + const char *key; + int type; + + dbus_message_iter_recurse(&dict, &entry); + if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) { + g_slist_free_full(specific_scan_list, g_free); + return __connman_error_invalid_arguments(msg); + } + + dbus_message_iter_get_basic(&entry, &key); + dbus_message_iter_next(&entry); + + if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) { + g_slist_free_full(specific_scan_list, g_free); + return __connman_error_invalid_arguments(msg); + } + + dbus_message_iter_recurse(&entry, &value2); + type = dbus_message_iter_get_arg_type(&value2); + if (g_str_equal(key, "SSID")) { + if (type != DBUS_TYPE_STRING) { + g_slist_free_full(specific_scan_list, g_free); + return __connman_error_invalid_arguments(msg); + } + + scan_type = CONNMAN_MULTI_SCAN_SSID; /* SSID based scan */ + dbus_message_iter_get_basic(&value2, &name); + DBG("name %s", name); + specific_scan_list = g_slist_append(specific_scan_list, g_strdup(name)); + } else if (g_str_equal(key, "Frequency")) { + if (type != DBUS_TYPE_STRING) { + g_slist_free_full(specific_scan_list, g_free); + return __connman_error_invalid_arguments(msg); + } + + scan_type = CONNMAN_MULTI_SCAN_FREQ; /* Frequency based scan */ + dbus_message_iter_get_basic(&value2, &freq); + DBG("freq %s", freq); + specific_scan_list = g_slist_append(specific_scan_list, GINT_TO_POINTER(atoi(freq))); + } else if (g_str_equal(key, "SSID_Mixed")) { + if (type != DBUS_TYPE_STRING) { + g_slist_free_full(specific_scan_list, g_free); + return __connman_error_invalid_arguments(msg); + } + + scan_type = CONNMAN_MULTI_SCAN_SSID_FREQ; /* SSID & Frequency mixed scan */ + dbus_message_iter_get_basic(&value2, &name); + + connman_multi_scan_ap_s *ap = (connman_multi_scan_ap_s*)g_try_malloc0(sizeof(connman_multi_scan_ap_s)); + if (ap) { + g_strlcpy(ap->str, name, strlen(name) + 1); + ap->flag = true; + specific_scan_list = g_slist_append(specific_scan_list, ap); + } else + DBG("Failed to allocate memory"); + + } else if (g_str_equal(key, "Frequency_Mixed")) { + if (type != DBUS_TYPE_STRING) { + g_slist_free_full(specific_scan_list, g_free); + return __connman_error_invalid_arguments(msg); + } + + scan_type = CONNMAN_MULTI_SCAN_SSID_FREQ; /* SSID & Frequency mixed scan */ + dbus_message_iter_get_basic(&value2, &freq); + + connman_multi_scan_ap_s *ap = (connman_multi_scan_ap_s*)g_try_malloc0(sizeof(connman_multi_scan_ap_s)); + if (ap) { + g_strlcpy(ap->str, freq, strlen(freq) + 1); + ap->flag = false; + specific_scan_list = g_slist_append(specific_scan_list, ap); + } else + DBG("Failed to allocate memory"); + } + dbus_message_iter_next(&dict); + } + + dbus_message_ref(msg); + + err = __connman_device_request_specific_scan(technology->type, scan_type, specific_scan_list); + if (err < 0) + return __connman_error_failed(msg, -err); + + if (err == 0) { + guint list_size = g_slist_length(specific_scan_list); + if (list_size == 1) + g_scan_type = CONNMAN_SCAN_TYPE_SPECIFIC_AP; + else + g_scan_type = CONNMAN_SCAN_TYPE_MULTI_AP; + DBG("list_size %u g_scan_type %d", list_size, g_scan_type); + } + technology->scan_pending = + g_slist_prepend(technology->scan_pending, msg); + + if (scan_type == CONNMAN_MULTI_SCAN_SSID || + scan_type == CONNMAN_MULTI_SCAN_SSID_FREQ) { + g_slist_free_full(specific_scan_list, g_free); + scan_type = 0; + } + return NULL; +} + +#if defined TIZEN_EXT +static DBusMessage *get_5ghz_supported(DBusConnection *conn, DBusMessage *msg, void *data) +{ + DBusMessage *reply; + DBusMessageIter iter, dict; + struct connman_technology *technology = data; + dbus_bool_t supported = technology->is_5_0_ghz_supported; + + DBG("technology %p", technology); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return NULL; + + dbus_message_iter_init_append(reply, &iter); + + connman_dbus_dict_open(&iter, &dict); + connman_dbus_dict_append_basic(&dict, "Is5GhzSupported", + DBUS_TYPE_BOOLEAN, + &supported); + + connman_dbus_dict_close(&iter, &dict); + + return reply; +} +#endif + +static DBusMessage *get_scan_state(DBusConnection *conn, DBusMessage *msg, void *data) +{ + DBusMessage *reply; + DBusMessageIter iter, dict; + GSList *list; + struct connman_technology *technology = data; + dbus_bool_t scanning = false; + + DBG("technology %p", technology); + + for (list = technology->device_list; list; list = list->next) { + struct connman_device *device = list->data; + scanning = connman_device_get_scanning(device, + connman_device_get_type(device)); + if(scanning) + break; + } + + DBG("scanning : %d", scanning); + reply = dbus_message_new_method_return(msg); + if (!reply) + return NULL; + + dbus_message_iter_init_append(reply, &iter); + + connman_dbus_dict_open(&iter, &dict); + connman_dbus_dict_append_basic(&dict, "Scanstate", + DBUS_TYPE_BOOLEAN, + &scanning); + + connman_dbus_dict_close(&iter, &dict); + + return reply; +} + +void connman_techonology_set_max_scan_ssids(struct connman_technology *technology, + int max_scan_ssids) +{ + DBG(""); + technology->max_scan_ssids = max_scan_ssids; +} + +static DBusMessage *get_max_scan_ssid(DBusConnection *conn, DBusMessage *msg, void *data) +{ + DBusMessage *reply; + DBusMessageIter iter, dict; + struct connman_technology *technology = data; + dbus_int32_t max_scan_ssids = technology->max_scan_ssids; + + DBG("technology %p", technology); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return NULL; + + dbus_message_iter_init_append(reply, &iter); + + connman_dbus_dict_open(&iter, &dict); + connman_dbus_dict_append_basic(&dict, "MaxScanSSID", + DBUS_TYPE_INT32, + &max_scan_ssids); + + connman_dbus_dict_close(&iter, &dict); + + return reply; +} +#endif + +#if defined TIZEN_EXT_WIFI_MESH +bool __connman_technology_get_connected(enum connman_service_type type) +{ + struct connman_technology *technology; + + technology = technology_find(type); + + if (!technology) + return false; + + return technology->connected; +} + +void __connman_technology_mesh_interface_create_finished( + enum connman_service_type type, bool success, + const char *error) +{ + DBusMessage *reply; + struct connman_technology *technology; + DBusMessage *msg; + technology = technology_find(type); + + DBG("technology %p success %d", technology, success); + + if (!technology) + return; + + msg = technology->mesh_dbus_msg; + if (!msg) { + DBG("No pending dbus message"); + return; + } + + if (success) { + reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + __connman_device_request_scan(technology->type); + } else + reply = g_dbus_create_error(msg, CONNMAN_ERROR_INTERFACE + ".MeshInterfaceAddFailed", "%s", error); + g_dbus_send_message(connection, reply); + dbus_message_unref(msg); + technology->mesh_dbus_msg = NULL; +} + +void __connman_technology_mesh_interface_remove_finished( + enum connman_service_type type, bool success) +{ + DBusMessage *reply; + struct connman_technology *technology; + DBusMessage *msg; + technology = technology_find(type); + + DBG("technology %p success %d", technology, success); + + if (!technology || !technology->mesh_dbus_msg) + return; + + msg = technology->mesh_dbus_msg; + if (!msg) { + DBG("No pending dbus message"); + return; + } + + if (success) + reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + else + reply = __connman_error_failed(msg, EINVAL); + g_dbus_send_message(connection, reply); + dbus_message_unref(msg); + technology->mesh_dbus_msg = NULL; +} + +void __connman_technology_notify_abort_scan(enum connman_service_type type, + int result) +{ + DBusMessage *reply; + struct connman_technology *technology; + DBusMessage *msg; + technology = technology_find(type); + + DBG("technology %p result %d", technology, result); + + if (!technology || !technology->mesh_dbus_msg) + return; + + msg = technology->mesh_dbus_msg; + if (!msg) { + DBG("No pending dbus message"); + return; + } + + if (result < 0) + reply = __connman_error_scan_abort_failed(msg); + else + reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + + g_dbus_send_message(connection, reply); + dbus_message_unref(msg); + technology->mesh_dbus_msg = NULL; +} + +static DBusMessage *mesh_commands(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct connman_technology *technology = data; + DBusMessageIter iter, value, dict; + const char *cmd = NULL, *ifname = NULL, *parent_ifname = NULL; + int err; + + DBG("conn %p", conn); + + if (technology->type != CONNMAN_SERVICE_TYPE_MESH) + return __connman_error_invalid_arguments(msg); + + if (!dbus_message_iter_init(msg, &iter)) + return __connman_error_invalid_arguments(msg); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&iter, &cmd); + dbus_message_iter_next(&iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_recurse(&iter, &value); + + if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_ARRAY) + return __connman_error_invalid_arguments(msg); + + DBG("Mesh Command %s", cmd); + if (g_str_equal(cmd, "MeshInterfaceAdd")) { + dbus_message_iter_recurse(&value, &dict); + const char *bridge_ifname = NULL; + while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { + DBusMessageIter entry, value2; + const char *key; + int type; + + dbus_message_iter_recurse(&dict, &entry); + + if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&entry, &key); + dbus_message_iter_next(&entry); + + if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_recurse(&entry, &value2); + + type = dbus_message_iter_get_arg_type(&value2); + + if (g_str_equal(key, "Ifname")) { + if (type != DBUS_TYPE_STRING) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&value2, &ifname); + } else if (g_str_equal(key, "ParentIfname")) { + if (type != DBUS_TYPE_STRING) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&value2, &parent_ifname); + } else if (g_str_equal(key, "BridgeIfname")) { + if (type != DBUS_TYPE_STRING) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&value2, &bridge_ifname); + } + dbus_message_iter_next(&dict); + } + DBG("Mesh Ifname %s parent %s bridge %s", ifname, parent_ifname, + bridge_ifname ? bridge_ifname : "NULL"); + err = __connman_mesh_add_virtual_interface(ifname, parent_ifname, + bridge_ifname); + + if (err != 0) { + DBG("Failed to add virtual mesh interface"); + return __connman_error_failed(msg, -err); + } + + DBG("Successfully added virtual mesh interface"); + + dbus_message_ref(msg); + technology->mesh_dbus_msg = msg; + + } else if (g_str_equal(cmd, "MeshInterfaceRemove")) { + dbus_message_iter_recurse(&value, &dict); + while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { + DBusMessageIter entry, value2; + const char *key; + int type; + + dbus_message_iter_recurse(&dict, &entry); + + if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&entry, &key); + dbus_message_iter_next(&entry); + + if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_recurse(&entry, &value2); + + type = dbus_message_iter_get_arg_type(&value2); + + if (g_str_equal(key, "Ifname")) { + if (type != DBUS_TYPE_STRING) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&value2, &ifname); + } + dbus_message_iter_next(&dict); + } + DBG("Mesh Ifname %s", ifname); + err = __connman_mesh_remove_virtual_interface(ifname); + + if (err != 0) { + DBG("Failed to remove virtual mesh interface"); + return __connman_error_failed(msg, -err); + } + + DBG("Successfully removed virtual mesh interface"); + + dbus_message_ref(msg); + technology->mesh_dbus_msg = msg; + + } else if (g_str_equal(cmd, "MeshCreateNetwork")) { + struct connman_mesh *connman_mesh; + const char *name = NULL; + const char *sec_type = NULL; + const char *mesh_ifname = NULL; + char *identifier, *group, *address; + unsigned int freq = 0; + unsigned int ieee80211w = 0; + GString *str; + int i; + dbus_message_iter_recurse(&value, &dict); + while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { + DBusMessageIter entry, value2; + const char *key; + int type; + dbus_message_iter_recurse(&dict, &entry); + + if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&entry, &key); + dbus_message_iter_next(&entry); + + if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_recurse(&entry, &value2); + + type = dbus_message_iter_get_arg_type(&value2); + + if (g_str_equal(key, "Name")) { + if (type != DBUS_TYPE_STRING) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&value2, &name); + } else if (g_str_equal(key, "Frequency")) { + if (type != DBUS_TYPE_UINT16) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&value2, &freq); + } else if (g_str_equal(key, "Security")) { + if (type != DBUS_TYPE_STRING) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&value2, &sec_type); + } else if (g_str_equal(key, "Pmf")) { + if (type != DBUS_TYPE_UINT16) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&value2, &ieee80211w); + } + dbus_message_iter_next(&dict); + } + + if (name == NULL || sec_type == NULL || freq == 0) + return __connman_error_invalid_arguments(msg); + + DBG("Name %s Frequency %d Security type %s Pmf %u", + name, freq, sec_type, ieee80211w); + + if (g_strcmp0(sec_type, "none") != 0 && + g_strcmp0(sec_type, "sae") != 0) { + DBG("Unsupported security"); + return __connman_error_invalid_arguments(msg); + } + + mesh_ifname = connman_mesh_get_interface_name(); + + if (!connman_mesh_is_interface_created()) { + DBG("Mesh interface doesn't exists"); + return __connman_error_invalid_command(msg); + } + + str = g_string_sized_new((strlen(name) * 2) + 24); + + for (i = 0; name[i]; i++) + g_string_append_printf(str, "%02x", name[i]); + + g_string_append_printf(str, "_mesh"); + + if (g_strcmp0(sec_type, "none") == 0) + g_string_append_printf(str, "_none"); + else if (g_strcmp0(sec_type, "sae") == 0) + g_string_append_printf(str, "_sae"); + + group = g_string_free(str, FALSE); + + identifier = connman_inet_ifaddr(mesh_ifname); + address = connman_inet_ifname2addr(mesh_ifname); + + connman_mesh = connman_mesh_create(identifier, group); + connman_mesh_set_name(connman_mesh, name); + connman_mesh_set_address(connman_mesh, address); + connman_mesh_set_security(connman_mesh, sec_type); + connman_mesh_set_frequency(connman_mesh, freq); + connman_mesh_set_index(connman_mesh, connman_inet_ifindex(mesh_ifname)); + connman_mesh_set_peer_type(connman_mesh, + CONNMAN_MESH_PEER_TYPE_CREATED); + connman_mesh_set_ieee80211w(connman_mesh, ieee80211w); + + connman_mesh_register(connman_mesh); + g_free(group); + g_free(identifier); + g_free(address); + DBG("Successfully Created Mesh Network"); + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + + } else if (g_str_equal(cmd, "AbortScan")) { + DBG("Abort Scan method"); + err = __connman_device_abort_scan(technology->type); + if (err != 0) { + DBG("Failed to abort scan"); + return __connman_error_failed(msg, -err); + } + + DBG("Successfully requested to abort scan"); + dbus_message_ref(msg); + technology->mesh_dbus_msg = msg; + + } else if (g_str_equal(cmd, "MeshSpecificScan")) { + const char *name = NULL; + unsigned int freq = 0; + dbus_message_iter_recurse(&value, &dict); + while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { + DBusMessageIter entry, value2; + const char *key; + int type; + + dbus_message_iter_recurse(&dict, &entry); + + if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&entry, &key); + dbus_message_iter_next(&entry); + + if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_recurse(&entry, &value2); + + type = dbus_message_iter_get_arg_type(&value2); + + if (g_str_equal(key, "Name")) { + if (type != DBUS_TYPE_STRING) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&value2, &name); + } else if (g_str_equal(key, "Frequency")) { + if (type != DBUS_TYPE_UINT16) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&value2, &freq); + } + dbus_message_iter_next(&dict); + } + + DBG("MeshID %s Frequency %d sender %s", name, freq, + dbus_message_get_sender(msg)); + + dbus_message_ref(msg); + technology->scan_pending = + g_slist_prepend(technology->scan_pending, msg); + + err = __connman_device_request_mesh_specific_scan(technology->type, + name, freq); + if (err < 0) + reply_scan_pending(technology, err); + else + DBG("Successfully requested to scan specific Mesh Network"); + + } else if (g_str_equal(cmd, "SetMeshGate")) { + unsigned int hwmp_rootmode = 0; + bool gate_announce = false; + unsigned int stp = 0; + int err; + dbus_message_iter_recurse(&value, &dict); + while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { + DBusMessageIter entry, value2; + const char *key; + int type; + + dbus_message_iter_recurse(&dict, &entry); + + if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&entry, &key); + dbus_message_iter_next(&entry); + + if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_recurse(&entry, &value2); + + type = dbus_message_iter_get_arg_type(&value2); + + if (g_str_equal(key, "GateAnnounce")) { + if (type != DBUS_TYPE_BOOLEAN) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&value2, &gate_announce); + } else if (g_str_equal(key, "HWMPRootMode")) { + if (type != DBUS_TYPE_UINT16) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&value2, &hwmp_rootmode); + } else if (g_str_equal(key, "STP")) { + if (type != DBUS_TYPE_UINT16) + return __connman_error_invalid_arguments(msg); + + dbus_message_iter_get_basic(&value2, &stp); + } + dbus_message_iter_next(&dict); + } + + DBG("GateAnnounce %d HWMPRootMode %d STP %d sender %s", + gate_announce, hwmp_rootmode, stp, dbus_message_get_sender(msg)); + + err = __connman_mesh_set_stp_gate_announce(gate_announce, + hwmp_rootmode, + stp); + + if (err < 0) + return __connman_error_failed(msg, -err); + + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + } else + return __connman_error_invalid_command(msg); return NULL; } +#endif static const GDBusMethodTable technology_methods[] = { { GDBUS_DEPRECATED_METHOD("GetProperties", @@ -1102,6 +1951,21 @@ static const GDBusMethodTable technology_methods[] = { GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL, set_property) }, { GDBUS_ASYNC_METHOD("Scan", NULL, NULL, scan) }, +#if defined TIZEN_EXT + { GDBUS_ASYNC_METHOD("SpecificScan", GDBUS_ARGS({ "specificscan", "a{sv}" }), + NULL, specific_scan) }, + { GDBUS_METHOD("GetScanState", NULL, GDBUS_ARGS({ "scan_state", "a{sv}" }), + get_scan_state) }, + { GDBUS_METHOD("Get5GhzSupported", NULL, GDBUS_ARGS({ "supported", "a{sv}" }), + get_5ghz_supported) }, + { GDBUS_METHOD("GetMaxScanSsid", NULL, GDBUS_ARGS({ "maxscanssid", "a{sv}" }), + get_max_scan_ssid) }, +#endif +#if defined TIZEN_EXT_WIFI_MESH + { GDBUS_ASYNC_METHOD("MeshCommands", + GDBUS_ARGS({ "name", "s" }, { "value", "v" }), + NULL, mesh_commands) }, +#endif { }, }; @@ -1202,7 +2066,12 @@ static struct connman_technology *technology_get(enum connman_service_type type) technology = technology_find(type); if (technology) { +#if defined TIZEN_EXT_WIFI_MESH + if (type != CONNMAN_SERVICE_TYPE_P2P && + type != CONNMAN_SERVICE_TYPE_MESH) +#else if (type != CONNMAN_SERVICE_TYPE_P2P) +#endif __sync_fetch_and_add(&technology->refcount, 1); return technology; } @@ -1232,6 +2101,16 @@ static struct connman_technology *technology_get(enum connman_service_type type) technology->path = g_strdup_printf("%s/technology/%s", CONNMAN_PATH, str); +#if defined TIZEN_EXT_WIFI_MESH + if (type == CONNMAN_SERVICE_TYPE_MESH) { + struct connman_technology *wifi; + + wifi = technology_find(CONNMAN_SERVICE_TYPE_WIFI); + if (wifi) + technology->enabled = wifi->enabled; + } +#endif + technology_load(technology); technology_list = g_slist_prepend(technology_list, technology); technology->driver_list = tech_drivers; @@ -1310,6 +2189,13 @@ exist: return -ENOMEM; } +#if defined TIZEN_EXT_WIFI_MESH + if (driver->type == CONNMAN_SERVICE_TYPE_MESH) { + if (!technology_get(CONNMAN_SERVICE_TYPE_MESH)) + return -ENOMEM; + } +#endif + return 0; } @@ -1347,6 +2233,13 @@ void connman_technology_driver_unregister(struct connman_technology_driver *driv if (technology) technology_put(technology); } +#if defined TIZEN_EXT_WIFI_MESH + if (driver->type == CONNMAN_SERVICE_TYPE_MESH) { + technology = technology_find(CONNMAN_SERVICE_TYPE_MESH); + if (technology) + technology_put(technology); + } +#endif } void __connman_technology_add_interface(enum connman_service_type type, @@ -1369,6 +2262,9 @@ void __connman_technology_add_interface(enum connman_service_type type, case CONNMAN_SERVICE_TYPE_VPN: case CONNMAN_SERVICE_TYPE_GADGET: case CONNMAN_SERVICE_TYPE_P2P: +#if defined TIZEN_EXT_WIFI_MESH + case CONNMAN_SERVICE_TYPE_MESH: +#endif break; } @@ -1420,6 +2316,9 @@ void __connman_technology_remove_interface(enum connman_service_type type, case CONNMAN_SERVICE_TYPE_VPN: case CONNMAN_SERVICE_TYPE_GADGET: case CONNMAN_SERVICE_TYPE_P2P: +#if defined TIZEN_EXT_WIFI_MESH + case CONNMAN_SERVICE_TYPE_MESH: +#endif break; } @@ -1535,11 +2434,13 @@ int __connman_technology_enabled(enum connman_service_type type) get_name(type), technology->rfkill_driven, technology->enabled); +#if !defined TIZEN_EXT if (technology->rfkill_driven) { if (technology->tethering_persistent) enable_tethering(technology); return 0; } +#endif return technology_enabled(technology); } @@ -1553,9 +2454,11 @@ int __connman_technology_disabled(enum connman_service_type type) if (!technology) return -ENXIO; +#if !defined TIZEN_EXT if (technology->rfkill_driven) return 0; +#endif for (list = technology->device_list; list; list = list->next) { struct connman_device *device = list->data; @@ -1614,6 +2517,15 @@ int __connman_technology_set_offlinemode(bool offlinemode) return err; } +#if defined TIZEN_EXT_WIFI_MESH +static gboolean __add_ethernet_to_bridge(gpointer data) +{ + DBG(""); + __connman_mesh_add_ethernet_to_bridge(); + return FALSE; +} +#endif + void __connman_technology_set_connected(enum connman_service_type type, bool connected) { @@ -1628,6 +2540,11 @@ void __connman_technology_set_connected(enum connman_service_type type, technology->connected = connected; +#if defined TIZEN_EXT_WIFI_MESH + if (technology->type == CONNMAN_SERVICE_TYPE_ETHERNET && connected) + g_idle_add(__add_ethernet_to_bridge, NULL); +#endif + val = connected; connman_dbus_property_changed_basic(technology->path, CONNMAN_TECHNOLOGY_INTERFACE, "Connected", @@ -1734,6 +2651,10 @@ int __connman_technology_add_rfkill(unsigned int index, g_hash_table_insert(rfkill_list, GINT_TO_POINTER(index), rfkill); done: +#if defined TIZEN_EXT + /* Fix Svace Issue [WGID: 1348]. */ + g_free(rfkill); +#endif technology = technology_get(type); /* If there is no driver for this type, ignore it. */ if (!technology) @@ -1741,10 +2662,12 @@ done: technology->rfkill_driven = true; +#if !defined TIZEN_EXT /* If hardblocked, there is no need to handle softblocked state */ if (technology_apply_rfkill_change(technology, softblock, hardblock, true)) return 0; +#endif if (global_offlinemode) return 0; diff --git a/src/tethering.c b/src/tethering.c index e04756ff..e04756ff 100644..100755 --- a/src/tethering.c +++ b/src/tethering.c diff --git a/src/timeserver.c b/src/timeserver.c index 9832c2a5..c6103466 100644..100755 --- a/src/timeserver.c +++ b/src/timeserver.c @@ -100,6 +100,15 @@ static void resolv_result(GResolvResultStatus status, char **results, { int i; +#if defined TIZEN_EXT + gchar *server = NULL; + + server = g_strdup((gchar *)user_data); + ts_list = g_slist_append(ts_list, server); + + DBG("added server %s", server); +#endif + DBG("status %d", status); if (status == G_RESOLV_RESULT_STATUS_SUCCESS) { @@ -178,8 +187,13 @@ static void sync_next(void) } DBG("Resolving timeserver %s", ts_current); +#if defined TIZEN_EXT + resolv_id = g_resolv_lookup_hostname(resolv, ts_current, + resolv_result, ts_current); +#else resolv_id = g_resolv_lookup_hostname(resolv, ts_current, resolv_result, NULL); +#endif return; } diff --git a/src/timezone.c b/src/timezone.c index 8e912670..8e912670 100644..100755 --- a/src/timezone.c +++ b/src/timezone.c diff --git a/src/util.c b/src/util.c index 03b14cdc..03b14cdc 100644..100755 --- a/src/util.c +++ b/src/util.c diff --git a/src/utsname.c b/src/utsname.c index 1dd5e0f2..1dd5e0f2 100644..100755 --- a/src/utsname.c +++ b/src/utsname.c diff --git a/src/wispr.c b/src/wispr.c index 473c0e03..57abdf1e 100644 --- a/src/wispr.c +++ b/src/wispr.c @@ -688,6 +688,9 @@ static bool wispr_portal_web_result(GWebResult *result, gpointer user_data) const char *str = NULL; guint16 status; gsize length; +#if defined TIZEN_MAINTAIN_ONLINE + static int retried = 0; +#endif DBG(""); @@ -719,6 +722,9 @@ static bool wispr_portal_web_result(GWebResult *result, gpointer user_data) wp_context->status_url, wp_context); break; case 200: +#if defined TIZEN_MAINTAIN_ONLINE + retried = 0; +#endif if (wp_context->wispr_msg.message_type >= 0) break; @@ -756,6 +762,19 @@ static bool wispr_portal_web_result(GWebResult *result, gpointer user_data) case 404: if (__connman_service_online_check_failed(wp_context->service, wp_context->type) == 0) { +#if defined TIZEN_MAINTAIN_ONLINE + if (wp_context->type == CONNMAN_IPCONFIG_TYPE_IPV4) { + if (retried == 0) { + connman_agent_report_error(wp_context->service, + __connman_service_get_path(wp_context->service), + "internet-unreachable", + NULL, NULL, NULL); + + retried = 1; + } + break; + } +#endif wispr_portal_error(wp_context); free_connman_wispr_portal_context(wp_context); return false; @@ -849,6 +868,9 @@ static int wispr_portal_detect(struct connman_wispr_portal_context *wp_context) case CONNMAN_SERVICE_TYPE_GPS: case CONNMAN_SERVICE_TYPE_VPN: case CONNMAN_SERVICE_TYPE_P2P: +#if defined TIZEN_EXT_WIFI_MESH + case CONNMAN_SERVICE_TYPE_MESH: +#endif return -EOPNOTSUPP; } @@ -879,7 +901,9 @@ static int wispr_portal_detect(struct connman_wispr_portal_context *wp_context) goto done; } +#if !defined TIZEN_EXT if (getenv("CONNMAN_WEB_DEBUG")) +#endif g_web_set_debug(wp_context->web, web_debug, "WEB"); if (wp_context->type == CONNMAN_IPCONFIG_TYPE_IPV4) { @@ -925,6 +949,11 @@ int __connman_wispr_start(struct connman_service *service, DBG("service %p", service); +#if defined TIZEN_EXT + if (connman_service_get_type(service) == CONNMAN_SERVICE_TYPE_CELLULAR) + return -EPERM; +#endif + if (!wispr_portal_list) return -EINVAL; diff --git a/src/wpad.c b/src/wpad.c index 54084ee8..f50e4dd0 100644..100755 --- a/src/wpad.c +++ b/src/wpad.c @@ -161,7 +161,9 @@ int __connman_wpad_start(struct connman_service *service) return -ENOMEM; } +#if !defined TIZEN_EXT if (getenv("CONNMAN_RESOLV_DEBUG")) +#endif g_resolv_set_debug(wpad->resolv, resolv_debug, "RESOLV"); for (i = 0; nameservers[i]; i++) diff --git a/test/set-timezone b/test/set-timezone deleted file mode 100755 index dfc1c981..00000000 --- a/test/set-timezone +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/python - -import sys -import dbus - -if (len(sys.argv) != 2): - print "Usage: %s <timezone>" % (sys.argv[0]) - sys.exit(1) - -bus = dbus.SystemBus() - -clock = dbus.Interface(bus.get_object('net.connman', '/'), - 'net.connman.Clock') - -print "Setting timezone to %s" % (sys.argv[1]) - -try: - clock.SetProperty("Timezone", dbus.String(sys.argv[1], variant_level=1), - signature=dbus.Signature('sv')) -except dbus.exceptions.DBusException, e_msg: - print e_msg diff --git a/tools/dbus-test.c b/tools/dbus-test.c index ece5d193..ece5d193 100644..100755 --- a/tools/dbus-test.c +++ b/tools/dbus-test.c diff --git a/tools/dhcp-server-test.c b/tools/dhcp-server-test.c index 59f5f34d..59f5f34d 100644..100755 --- a/tools/dhcp-server-test.c +++ b/tools/dhcp-server-test.c diff --git a/tools/dhcp-test.c b/tools/dhcp-test.c index a6c3e993..a6c3e993 100644..100755 --- a/tools/dhcp-test.c +++ b/tools/dhcp-test.c diff --git a/tools/dnsproxy-test.c b/tools/dnsproxy-test.c index 371e2e23..371e2e23 100644..100755 --- a/tools/dnsproxy-test.c +++ b/tools/dnsproxy-test.c diff --git a/tools/iptables-test.c b/tools/iptables-test.c index e9b7cb22..e9b7cb22 100644..100755 --- a/tools/iptables-test.c +++ b/tools/iptables-test.c diff --git a/tools/iptables-unit.c b/tools/iptables-unit.c index b91591f2..b91591f2 100644..100755 --- a/tools/iptables-unit.c +++ b/tools/iptables-unit.c diff --git a/tools/manager-api.c b/tools/manager-api.c index e082962d..e082962d 100644..100755 --- a/tools/manager-api.c +++ b/tools/manager-api.c diff --git a/tools/netlink-test.c b/tools/netlink-test.c index 221e3490..221e3490 100644..100755 --- a/tools/netlink-test.c +++ b/tools/netlink-test.c diff --git a/tools/polkit-test.c b/tools/polkit-test.c index ea1d24ae..ea1d24ae 100644..100755 --- a/tools/polkit-test.c +++ b/tools/polkit-test.c diff --git a/tools/private-network-test.c b/tools/private-network-test.c index 2828bb30..2828bb30 100644..100755 --- a/tools/private-network-test.c +++ b/tools/private-network-test.c diff --git a/tools/resolv-test.c b/tools/resolv-test.c index 1aad2841..1aad2841 100644..100755 --- a/tools/resolv-test.c +++ b/tools/resolv-test.c diff --git a/tools/session-api.c b/tools/session-api.c index e869d190..e869d190 100644..100755 --- a/tools/session-api.c +++ b/tools/session-api.c diff --git a/tools/session-test.c b/tools/session-test.c index 4319e5a4..4319e5a4 100644..100755 --- a/tools/session-test.c +++ b/tools/session-test.c diff --git a/tools/session-test.h b/tools/session-test.h index 2c068bd7..2c068bd7 100644..100755 --- a/tools/session-test.h +++ b/tools/session-test.h diff --git a/tools/session-utils.c b/tools/session-utils.c index 47f0de1f..47f0de1f 100644..100755 --- a/tools/session-utils.c +++ b/tools/session-utils.c diff --git a/tools/stats-tool.c b/tools/stats-tool.c index 5695048f..5695048f 100644..100755 --- a/tools/stats-tool.c +++ b/tools/stats-tool.c diff --git a/tools/supplicant-dbus.c b/tools/supplicant-dbus.c index d409da2d..d409da2d 100644..100755 --- a/tools/supplicant-dbus.c +++ b/tools/supplicant-dbus.c diff --git a/tools/supplicant-dbus.h b/tools/supplicant-dbus.h index 4452894b..4452894b 100644..100755 --- a/tools/supplicant-dbus.h +++ b/tools/supplicant-dbus.h diff --git a/tools/supplicant-test.c b/tools/supplicant-test.c index a6408076..a6408076 100644..100755 --- a/tools/supplicant-test.c +++ b/tools/supplicant-test.c diff --git a/tools/supplicant.c b/tools/supplicant.c index e2e6fea5..e2e6fea5 100644..100755 --- a/tools/supplicant.c +++ b/tools/supplicant.c diff --git a/tools/supplicant.h b/tools/supplicant.h index 556dc7d9..556dc7d9 100644..100755 --- a/tools/supplicant.h +++ b/tools/supplicant.h diff --git a/tools/tap-test.c b/tools/tap-test.c index cb3ee622..cb3ee622 100644..100755 --- a/tools/tap-test.c +++ b/tools/tap-test.c diff --git a/tools/web-test.c b/tools/web-test.c index 55c58af5..55c58af5 100644..100755 --- a/tools/web-test.c +++ b/tools/web-test.c diff --git a/tools/wispr.c b/tools/wispr.c index e56dfc16..e56dfc16 100644..100755 --- a/tools/wispr.c +++ b/tools/wispr.c diff --git a/tools/wpad-test.c b/tools/wpad-test.c index 2ecbcdae..2ecbcdae 100644..100755 --- a/tools/wpad-test.c +++ b/tools/wpad-test.c diff --git a/unit/test-ippool.c b/unit/test-ippool.c index a6cae652..a6cae652 100644..100755 --- a/unit/test-ippool.c +++ b/unit/test-ippool.c diff --git a/vpn/connman-task.te b/vpn/connman-task.te index dd777107..dd777107 100644..100755 --- a/vpn/connman-task.te +++ b/vpn/connman-task.te diff --git a/vpn/connman-vpn.service.in b/vpn/connman-vpn.service.in index e98fb714..a8f2948f 100644..100755 --- a/vpn/connman-vpn.service.in +++ b/vpn/connman-vpn.service.in @@ -1,12 +1,18 @@ [Unit] Description=ConnMan VPN service +Requires=dbus.socket +After=dbus.socket [Service] Type=dbus +User=network_fw +Group=network_fw BusName=net.connman.vpn -ExecStart=@sbindir@/connman-vpnd -n +SmackProcessLabel=System +ExecStart=@bindir@/connman-vpnd -n StandardOutput=null -CapabilityBoundingSet=CAP_KILL CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW +Capabilities=cap_net_admin,cap_net_bind_service,cap_net_broadcast,cap_net_raw,cap_dac_override=i +SecureBits=keep-caps ProtectHome=read-only ProtectSystem=full diff --git a/vpn/main.c b/vpn/main.c index ee88aacd..c18fee4f 100644..100755 --- a/vpn/main.c +++ b/vpn/main.c @@ -45,6 +45,7 @@ #define CONFIGMAINFILE CONFIGDIR "/connman-vpn.conf" #define DEFAULT_INPUT_REQUEST_TIMEOUT 300 * 1000 +#define DEFAULT_BROWSER_LAUNCH_TIMEOUT 300 * 1000 static GMainLoop *main_loop = NULL; @@ -52,8 +53,10 @@ static unsigned int __terminated = 0; static struct { unsigned int timeout_inputreq; + unsigned int timeout_browserlaunch; } connman_vpn_settings = { .timeout_inputreq = DEFAULT_INPUT_REQUEST_TIMEOUT, + .timeout_browserlaunch = DEFAULT_BROWSER_LAUNCH_TIMEOUT, }; static GKeyFile *load_config(const char *file) @@ -224,6 +227,21 @@ static GOptionEntry options[] = { { NULL }, }; +bool connman_setting_get_bool(const char *key) +{ + return false; +} + +char **connman_setting_get_string_list(const char *key) +{ + return NULL; +} + +unsigned int *connman_setting_get_uint_list(const char *key) +{ + return NULL; +} + /* * This function will be called from generic src/agent.c code so we have * to use connman_ prefix instead of vpn_ one. @@ -233,6 +251,16 @@ unsigned int connman_timeout_input_request(void) return connman_vpn_settings.timeout_inputreq; } +unsigned int connman_timeout_browser_launch(void) +{ + return connman_vpn_settings.timeout_browserlaunch; +} + +const char *connman_option_get_string(const char *key) +{ + return NULL; +} + int main(int argc, char *argv[]) { GOptionContext *context; diff --git a/vpn/net.connman.vpn.service.in b/vpn/net.connman.vpn.service.in index e473ea9e..c1640cb3 100644..100755 --- a/vpn/net.connman.vpn.service.in +++ b/vpn/net.connman.vpn.service.in @@ -1,5 +1,4 @@ [D-BUS Service] Name=net.connman.vpn -Exec=@sbindir@/connman-vpnd -n -User=root +Exec=/bin/false SystemdService=connman-vpn.service diff --git a/vpn/plugins/ipsec.c b/vpn/plugins/ipsec.c new file mode 100644 index 00000000..36502dde --- /dev/null +++ b/vpn/plugins/ipsec.c @@ -0,0 +1,925 @@ +/* + * + * ConnMan VPN daemon + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <stdio.h> +#include <sys/stat.h> +#include <net/if.h> + +#include <glib.h> +#include <gio/gio.h> + +#define CONNMAN_API_SUBJECT_TO_CHANGE +#include <connman/plugin.h> +#include <connman/log.h> +#include <connman/task.h> +#include <connman/dbus.h> +#include <connman/ipconfig.h> + +#include "../vpn-provider.h" + +#include "vpn.h" +#include "ipsec.h" +#include "vici-client.h" + +#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) + +typedef enum { + CERT_TYPE_NONE, + CERT_TYPE_DER, + CERT_TYPE_PEM, + CERT_TYPE_PKCS12, + CERT_TYPE_MAX, +} cert_type_e; + +static DBusConnection *connection; +static VICIClient *vici_client; +static GFileMonitor* monitor; + +struct ipsec_private_data { + struct vpn_provider *provider; + vpn_provider_connect_cb_t connect_cb; + void *connect_user_data; +}; + +struct ipsec_event_data { + vpn_event_callback event_cb; + void *event_user_data; +}; + +struct { + const char *cm_opt; + const char *vici_key; + const char *subsection; + vici_add_element add_elem; +} ipsec_conn_options[] = { + {"IPsec.Version", "version", NULL, vici_add_kv}, + {"IPsec.LeftAddrs", "local_addrs", NULL, vici_add_kvl}, + {"IPsec.RightAddrs", "remote_addrs", NULL, vici_add_kvl}, + + {"IPsec.LocalAuth", "auth", "local", vici_add_kv}, + {"IPsec.LocalID", "id", "local", vici_add_kv}, + {"IPsec.LocalXauthID", "xauth_id", "local", vici_add_kv}, + {"IPsec.LocalXauthAuth", "auth", "local-xauth", vici_add_kv}, + {"IPsec.LocalXauthXauthID", "xauth_id", "local-xauth", vici_add_kv}, + {"IPsec.RemoteAuth", "auth", "remote", vici_add_kv}, + {"IPsec.RemoteID", "id", "remote", vici_add_kv}, + {"IPsec.RemoteXauthID", "xauth_id", "remote", vici_add_kv}, + {"IPsec.RemoteXauthAuth", "auth", "remote-xauth", vici_add_kv}, + {"IPsec.RemoteXauthXauthID", "xauth_id", "remote-xauth", vici_add_kv}, + {"IPsec.ChildrenLocalTS", "local_ts", "children", vici_add_kvl}, + {"IPsec.ChildrenRemoteTS", "remote_ts", "children", vici_add_kvl}, +}; + +struct { + const char *cm_opt; + const char *vici_type; +} ipsec_shared_options[] = { + {"IPsec.IKEData", "data"}, + {"IPsec.IKEOwners", "owners"}, + {"IPsec.XauthData", "data"}, + {"IPsec.XauthOwners", "owners"}, +}; + +struct { + const char *cm_opt; + const char *vici_type; + const char *vici_flag; +} ipsec_cert_options[] = { + {"IPsec.CertType", "type", NULL}, + {"IPsec.CertFlag", "flag", NULL}, + {"IPsec.CertData", "data", NULL}, + {"IPsec.CertPass", "data", NULL}, +}; + +struct { + const char *cm_opt; + const char *vici_type; +} ipsec_pkey_options[] = { + {"IPsec.PKeyType", "type"}, + {"IPsec.PKeyData", "data"}, +}; + +static const char *ikev1_esp_proposals [] ={ + "aes256-sha256", + "aes128-sha256", + "aes256-sha1", + "aes128-sha1", + "aes256-md5", + "aes128-md5", + "3des-sha1", + "3des-md5", + NULL, +}; + +static const char *ikev1_proposals [] ={ + "aes256-sha256-modp1024", + "aes128-sha256-modp1024", + "aes256-sha1-modp1024", + "aes128-sha1-modp1024", + "aes256-md5-modp1024", + "aes128-md5-modp1024", + "3des-sha1-modp1024", + "3des-md5-modp1024", + NULL, +}; + +static const char *ikev2_esp_proposals = "aes256-aes128-sha256-sha1"; + +static const char *ikev2_proposals = "aes256-aes128-sha512-sha384-sha256-sha1-modp2048-modp1536-modp1024"; + +static struct ipsec_event_data event_data; + +static void free_private_data(struct ipsec_private_data *data) +{ + g_free(data); +} + +static int ipsec_notify(DBusMessage *msg, struct vpn_provider *provider) +{ + return 0; +} + +static void ipsec_set_event_cb(vpn_event_callback event_cb, struct vpn_provider *provider) +{ + DBG("set event cb!"); + event_data.event_cb = event_cb; + event_data.event_user_data = provider; + return; +} + +static int ipsec_is_same_auth(const char* req, const char* target) +{ + if (req == NULL || target == NULL) + return 0; + return (g_strcmp0(req, target) == 0); +} + +static int vici_load_cert(const char* type, const char* flag, const char* data) +{ + VICISection *sect; + int ret = 0; + + sect = vici_create_section(NULL); + if (!sect) + return -ENOMEM; + + vici_add_kv(sect, "type", type, NULL); + vici_add_kv(sect, "flag", flag, NULL); + vici_add_kv(sect, "data", data, NULL); + + ret = vici_send_request(vici_client, VICI_CMD_LOAD_CERT, sect); + if (ret < 0) + connman_error("vici_send_request failed"); + + vici_destroy_section(sect); + + return ret; +} + +static void ipsec_add_default_child_sa_data(struct vpn_provider *provider, VICISection *child) +{ + const char *version = vpn_provider_get_string(provider, "IPsec.Version"); + if (g_strcmp0(version, "1") == 0) { + int i = 0; + GSList *list; + + for (list = NULL; ikev1_esp_proposals[i] != NULL; i++) + list = g_slist_append(list, g_strdup(ikev1_esp_proposals[i])); + vici_add_list(child, "esp_proposals", list, "net"); + g_slist_free_full(list, g_free); + list = NULL; + } else { + vici_add_kvl(child, "esp_proposals", ikev2_esp_proposals, "net"); + } + return; +} + +static void ipsec_add_default_conn_data(struct vpn_provider *provider, VICISection *conn) +{ + const char *version = vpn_provider_get_string(provider, "IPsec.Version"); + const char *remote_addr = vpn_provider_get_string(provider, "Host"); + + vici_add_kvl(conn, "remote_addrs", remote_addr, NULL); + if (g_strcmp0(version, "1") == 0) { + int i = 0; + GSList *list; + + for (list = NULL; ikev1_proposals[i] != NULL; i++) + list = g_slist_append(list, g_strdup(ikev1_proposals[i])); + vici_add_list(conn, "proposals", list, NULL); + g_slist_free_full(list, g_free); + list = NULL; + + if (g_strcmp0(vpn_provider_get_string(provider, "IPsec.LocalAuth"), "psk") == 0) + vici_add_kv(conn, "aggressive", "yes", NULL); + } else { + vici_add_kvl(conn, "proposals", ikev2_proposals, NULL); + } + + vici_add_kvl(conn, "vips", "0.0.0.0", NULL); + return; +} + +static char *load_file_from_path(const char *path) +{ + struct stat st; + FILE *fp = NULL; + int fd = 0; + size_t file_size = 0; + char *file_buff = NULL; + + if (!path) { + connman_error("File path is NULL\n"); + return NULL; + } + + fp = fopen(path, "rb"); + if (!fp) { + connman_error("fopen %s is failed\n", path); + return NULL; + } + + fd = fileno(fp); + if (fd == -1) { + connman_error("fp is not a valid stream"); + fclose(fp); + return NULL; + } + + if (fstat(fd, &st) != 0) { + connman_error("fstat failed"); + fclose(fp); + return NULL; + } + + file_size = st.st_size; + file_buff = g_try_malloc0(sizeof(char)*st.st_size); + if (file_buff == NULL) { + connman_error("g_try_malloc0 failed\n"); + fclose(fp); + return NULL; + } + + if (fread(file_buff, 1, file_size, fp) != file_size) { + connman_error("file size not matched\n"); + g_free(file_buff); + file_buff = NULL; + } + + fclose(fp); + return file_buff; +} + +static char * get_local_cert_str(struct vpn_provider *provider) +{ + const char *path; + + if (!provider) + return NULL; + + path = vpn_provider_get_string(provider, "IPsec.LocalCerts"); + + return load_file_from_path(path); +} + +static int ipsec_load_conn(struct vpn_provider *provider, struct ipsec_private_data *data) +{ + const char *key; + const char *value; + const char *subsection; + char *local_cert_str; + VICISection *conn; + VICISection *children; + int i; + int ret = 0; + + if (!provider || !data) { + connman_error("invalid provider or data"); + return -EINVAL; + } + + value = vpn_provider_get_string(provider, "Name"); + DBG("Name: %s", value); + conn = vici_create_section(value); + children = vici_create_section("children"); + add_subsection("children", children, conn); + + for (i = 0; i < (int)ARRAY_SIZE(ipsec_conn_options); i++) { + value = vpn_provider_get_string(provider, ipsec_conn_options[i].cm_opt); + if (!value) + continue; + + key = ipsec_conn_options[i].vici_key; + subsection = ipsec_conn_options[i].subsection; + ipsec_conn_options[i].add_elem(conn, key, value, subsection); + } + + local_cert_str = get_local_cert_str(provider); + if (local_cert_str) { + /* TODO :remove this after debug */ + DBG("There's local certification to add local section"); + vici_add_kvl(conn, "certs", local_cert_str, "local"); + g_free(local_cert_str); + } + + ipsec_add_default_conn_data(provider, conn); + ipsec_add_default_child_sa_data(provider, children); + + ret = vici_send_request(vici_client, VICI_CMD_LOAD_CONN, conn); + if (ret < 0) + connman_error("vici_send_request failed"); + + vici_destroy_section(conn); + + return ret; +} + +static int ipsec_load_shared_psk(struct vpn_provider *provider) +{ + const char *data; + const char *owner; + VICISection *sect; + int ret = 0; + + if (!provider) { + connman_error("invalid provider"); + return -EINVAL; + } + + data = vpn_provider_get_string(provider, "IPsec.IKEData"); + owner = vpn_provider_get_string(provider, "IPsec.IKEOwners"); + DBG("IKEData: %s, IKEOwners: %s", data, owner); + + if (!data) + return 0; + + sect = vici_create_section(NULL); + if (!sect) { + return -ENOMEM; + } + + vici_add_kv(sect, "type", VICI_SHARED_TYPE_PSK, NULL); + vici_add_kv(sect, "data", data, NULL); + vici_add_kvl(sect, "owners", owner, NULL); + + ret = vici_send_request(vici_client, VICI_CMD_LOAD_SHARED, sect); + if (ret < 0) + connman_error("vici_send_request failed"); + + vici_destroy_section(sect); + + return ret; +} + +static int ipsec_load_shared_xauth(struct vpn_provider *provider) +{ + const char *data; + const char *owner; + VICISection *sect; + int ret = 0; + + if (!provider) { + connman_error("invalid provider"); + return -EINVAL; + } + + data = vpn_provider_get_string(provider, "IPsec.XauthData"); + owner = vpn_provider_get_string(provider, "IPsec.XauthOwners"); + DBG("XauthData: %s, XauthOwners: %s", data, owner); + + if (!data) + return 0; + + sect = vici_create_section(NULL); + + vici_add_kv(sect, "type", VICI_SHARED_TYPE_XAUTH, NULL); + vici_add_kv(sect, "data", data, NULL); + vici_add_kvl(sect, "owners", owner, NULL); + + ret = vici_send_request(vici_client, VICI_CMD_LOAD_SHARED, sect); + if (ret < 0) + connman_error("vici_send_request failed"); + + vici_destroy_section(sect); + + return ret; +} + +static int ipsec_load_key(struct vpn_provider *provider) +{ + const char *type; + const char *path; + char *data; + VICISection *sect; + int ret = 0; + + if (!provider) { + connman_error("invalid provider"); + return -EINVAL; + } + + type = vpn_provider_get_string(provider, "IPsec.PKeyType"); + path = vpn_provider_get_string(provider, "IPsec.PKeyData"); + DBG("PKeyType: %s, PKeyData: %s", type, path); + + if (!type || !path) + return 0; + + data = load_file_from_path(path); + if (!data) + return 0; + + sect = vici_create_section(NULL); + if (!sect) { + g_free(data); + return -ENOMEM; + } + + vici_add_kv(sect, "type", type, NULL); + vici_add_kv(sect, "data", data, NULL); + + ret = vici_send_request(vici_client, VICI_CMD_LOAD_KEY, sect); + if (ret < 0) + connman_error("vici_send_request failed"); + + vici_destroy_section(sect); + g_free(data); + + return ret; +} + +static int ipsec_initiate(struct vpn_provider *provider) +{ + VICISection *sect; + int ret = 0; + + sect = vici_create_section(NULL); + if (!sect) + return -ENOMEM; + + vici_add_kv(sect, "child", "net", NULL); + ret = vici_send_request(vici_client, VICI_CMD_INITIATE, sect); + if (ret < 0) + connman_error("vici_send_request failed"); + + vici_destroy_section(sect); + + return ret; +} + +static int ipsec_load_cert(struct vpn_provider *provider) +{ + const char *type; + const char *flag; + char *data; + const char *local_auth_type; + const char *remote_auth_type; + int ret = 0; + + if (!provider) { + connman_error("invalid provider"); + return -EINVAL; + } + + local_auth_type = vpn_provider_get_string(provider, "IPsec.LocalAuth"); + remote_auth_type = vpn_provider_get_string(provider, "IPsec.RemoteAuth"); + if (!ipsec_is_same_auth(local_auth_type, "pubkey") && + !ipsec_is_same_auth(remote_auth_type, "pubkey")) { + DBG("invalid auth type"); + return 0; + } + + type = vpn_provider_get_string(provider, "IPsec.CertType"); + flag = vpn_provider_get_string(provider, "IPsec.CertFlag"); + data = load_file_from_path(vpn_provider_get_string(provider, "IPsec.CertData")); + DBG("CertType: %s, CertFalg: %s,CertData: %s", type, flag, data); + if (!type || ! flag || !data) { + connman_error("invalid certification information"); + g_free(data); + return -EINVAL; + } + + ret = vici_load_cert(type, flag, data); + if (ret < 0) + connman_error("failed to load cert"); + + g_free(data); + + return ret; +} + +static int ipsec_terminate(struct vpn_provider *provider) +{ + VICISection *sect; + int ret = 0; + + sect = vici_create_section(NULL); + if (!sect) + return -ENOMEM; + + vici_add_kv(sect, "child", "net", NULL); + vici_add_kv(sect, "ike", vpn_provider_get_string(provider, "Name"), NULL); + vici_add_kv(sect, "timeout", "-1", NULL); + ret = vici_send_request(vici_client, VICI_CMD_TERMINATE, sect); + if (ret < 0) + connman_error("vici_send_request failed"); + + vici_destroy_section(sect); + + return ret; +} + +static void request_reply_cb(int err, void *user_data) +{ + struct ipsec_private_data *data; + + data = (struct ipsec_private_data *)user_data; + DBG("request reply cb"); + + if(err != 0) { + if (event_data.event_cb) + event_data.event_cb(event_data.event_user_data, VPN_STATE_FAILURE); + /* TODO: Does close socket needed? */ + } else { + DBG("Series of requests are succeeded"); + /* TODO: Not sure about below */ + if (event_data.event_cb) + event_data.event_cb(event_data.event_user_data, VPN_STATE_CONNECT); + } + + free_private_data(data); +} + +static void ipsec_vici_event_cb(VICIClientEvent event, void *user_data) +{ + struct vpn_provider *provider; + + provider = (struct vpn_provider *)user_data; + if (!provider) { + DBG("Invalid user data"); + return; + } + + if(event == VICI_EVENT_CHILD_UP) { + if (event_data.event_cb) + event_data.event_cb(event_data.event_user_data, VPN_STATE_READY); + } else if (event == VICI_EVENT_CHILD_DOWN) { + if (event_data.event_cb) + event_data.event_cb(event_data.event_user_data, VPN_STATE_DISCONNECT); + } else { + DBG("Unknown event"); + } + + return; +} + +static struct ipsec_private_data* create_ipsec_private_data(struct vpn_provider *provider, + vpn_provider_connect_cb_t cb, void* user_data) +{ + struct ipsec_private_data *data; + data = g_try_new0(struct ipsec_private_data, 1); + if (!data) { + connman_error("out of memory"); + return NULL; + } + + data->provider = provider; + data->connect_cb = cb; + data->connect_user_data = user_data; + return data; +} + +static void vici_connect(struct ipsec_private_data *data) +{ + struct vpn_provider *provider = NULL; + vpn_provider_connect_cb_t cb = NULL; + int err = 0; + + if (!data) + IPSEC_ERROR_CHECK_GOTO(-1, done, "Invalid data parameter"); + + provider = data->provider; + cb = data->connect_cb; + if (!provider || !cb) + IPSEC_ERROR_CHECK_GOTO(-1, done, "Invalid provider or callback"); + + DBG("data %p, provider %p", data, provider); + + /* + * Initialize vici client + */ + err = vici_initialize(&vici_client); + IPSEC_ERROR_CHECK_GOTO(err, done, "failed to initialize vici_client"); + + /* TODO :remove this after debug */ + DBG("success to initialize vici socket"); + + vici_set_request_reply_cb(vici_client, (vici_request_reply_cb)request_reply_cb, data); + /* + * Sets child-updown event + */ + err = vici_set_event_cb(vici_client, (vici_event_cb)ipsec_vici_event_cb, provider); + IPSEC_ERROR_CHECK_GOTO(err, done, "register event failed"); + + /* TODO :remove this after debug */ + DBG("success to vici_set_event_cb"); + /* + * Send the load-conn command + */ + err = ipsec_load_conn(provider, data); + IPSEC_ERROR_CHECK_GOTO(err, done, "load-conn failed"); + + /* TODO :remove this after debug */ + DBG("success to ipsec_load_conn"); + + /* + * Send the load-shared command for PSK + */ + err = ipsec_load_shared_psk(provider); + IPSEC_ERROR_CHECK_GOTO(err, done, "load-shared failed"); + + /* TODO :remove this after debug */ + DBG("success to ipsec_load_shared_psk"); + + /* + * Send the load-shared command for XAUTH + */ + err = ipsec_load_shared_xauth(provider); + IPSEC_ERROR_CHECK_GOTO(err, done, "load-shared failed"); + + /* TODO :remove this after debug */ + DBG("success to ipsec_load_shared_xauth"); + /* + * Send the load-cert command + */ + err = ipsec_load_cert(provider); + IPSEC_ERROR_CHECK_GOTO(err, done, "load-cert failed"); + + /* TODO :remove this after debug */ + DBG("success to ipsec_load_cert"); + + /* + * Send the load-key command + */ + err = ipsec_load_key(provider); + IPSEC_ERROR_CHECK_GOTO(err, done, "load-key failed"); + + /* TODO :remove this after debug */ + DBG("success to ipsec_load_cert"); + /* + * Send the initiate command + */ + err = ipsec_initiate(provider); + IPSEC_ERROR_CHECK_GOTO(err, done, "initiate failed"); + + /* TODO :remove this after debug */ + DBG("success to ipsec_initiate"); + +done: + /* refer to connect_cb on vpn-provider.c for cb */ + if(cb) + cb(provider, data->connect_user_data, -err); + /* TODO: Does close socket needed? when err is not zero */ + + return; +} + +static void monitor_changed(GFileMonitor *monitor, GFile *file, GFile *other_file, + GFileMonitorEvent event_type, gpointer user_data) +{ + DBG("file %s", g_file_get_path(file)); + if (event_type == G_FILE_MONITOR_EVENT_CREATED) { + if (g_file_test(VICI_DEFAULT_URI, G_FILE_TEST_EXISTS)) { + DBG("file created: %s", VICI_DEFAULT_URI); + struct ipsec_private_data *data = user_data; + vici_connect(data); + g_object_unref(monitor); + } + } +} + +static void monitor_vici_socket(struct ipsec_private_data *data) +{ + GError *error = NULL; + GFile* file; + + file = g_file_new_for_path(VICI_DEFAULT_URI); + monitor = g_file_monitor_file(file, G_FILE_MONITOR_SEND_MOVED, NULL, &error); + if (error) { + connman_error("g_file_monitor_directory failed: %s / %d", error->message, error->code); + g_error_free(error); + if(event_data.event_cb) + event_data.event_cb(event_data.event_user_data, VPN_STATE_FAILURE); + return; + } + /* TODO :remove this after debug */ + DBG("starting to monitor vici socket"); + g_signal_connect(monitor, "changed", G_CALLBACK(monitor_changed), data); + g_object_unref(file); +} + +static void check_vici_socket(struct ipsec_private_data *data) +{ + DBG("data %p", data); + if (g_file_test(VICI_DEFAULT_URI, G_FILE_TEST_EXISTS)) { + DBG("file exists: %s", VICI_DEFAULT_URI); + vici_connect(data); + } else { + monitor_vici_socket(data); + } +} + +static void ipsec_died(struct connman_task *task, int exit_code, void *user_data) +{ + DBG("task %p exit_code %d", task, exit_code); + unlink(VICI_DEFAULT_URI); + vpn_died(task, exit_code, user_data); +} + +static int ipsec_connect(struct vpn_provider *provider, + struct connman_task *task, const char *if_name, + vpn_provider_connect_cb_t cb, const char *dbus_sender, + void *user_data) +{ + struct ipsec_private_data *data; + int err = 0; + + data = create_ipsec_private_data(provider, cb, user_data); + if (!data) { + connman_error("create ipsec private data failed"); + return -ENOMEM; + } + /* + * Start charon daemon using ipsec script of strongSwan. + */ + err = connman_task_run(task, ipsec_died, provider, NULL, NULL, NULL); + if (err < 0) { + connman_error("charon start failed"); + if (cb) + cb(provider, user_data, err); + + g_free(data); + return err; + } + + check_vici_socket(data); +// g_usleep(G_USEC_PER_SEC); + + return err; +} + +static int ipsec_error_code(struct vpn_provider *provider, int exit_code) +{ + return 0; +} + +static int ipsec_save(struct vpn_provider *provider, GKeyFile *keyfile) +{ + int i; + const char *option; + + DBG(""); + /* + * Save IKE connection configurations + */ + for (i = 0; i < (int)ARRAY_SIZE(ipsec_conn_options); i++) { + option = vpn_provider_get_string(provider, ipsec_conn_options[i].cm_opt); + if (option) + g_key_file_set_string(keyfile, + vpn_provider_get_save_group(provider), + ipsec_conn_options[i].cm_opt, + option); + } + + /* + * Save shared IKE PSK, EAP or XAUTH secret + */ + for (i = 0; i < (int)ARRAY_SIZE(ipsec_shared_options); i++) { + option = vpn_provider_get_string(provider, ipsec_shared_options[i].cm_opt); + if (option) + g_key_file_set_string(keyfile, + vpn_provider_get_save_group(provider), + ipsec_shared_options[i].cm_opt, + option); + } + + /* + * Save certification + */ + for (i = 0; i < (int)ARRAY_SIZE(ipsec_cert_options); i++) { + option = vpn_provider_get_string(provider, ipsec_cert_options[i].cm_opt); + if (option) + g_key_file_set_string(keyfile, + vpn_provider_get_save_group(provider), + ipsec_cert_options[i].cm_opt, + option); + } + + /* + * Save private key + */ + for (i = 0; i < (int)ARRAY_SIZE(ipsec_pkey_options); i++) { + option = vpn_provider_get_string(provider, ipsec_pkey_options[i].cm_opt); + if (option) + g_key_file_set_string(keyfile, + vpn_provider_get_save_group(provider), + ipsec_pkey_options[i].cm_opt, + option); + } + + /* + * Save local certification + */ + option = vpn_provider_get_string(provider, "IPsec.LocalCerts"); + if (option) + g_key_file_set_string(keyfile, + vpn_provider_get_save_group(provider), + "IPsec.LocalCerts", + option); + option = vpn_provider_get_string(provider, "IPsec.LocalCertPass"); + if (option) + g_key_file_set_string(keyfile, + vpn_provider_get_save_group(provider), + "IPsec.LocalCertPass", + option); + /* + * Save CA certification directory + */ + option = vpn_provider_get_string(provider, "IPsec.CACertsDir"); + if (option) + g_key_file_set_string(keyfile, + vpn_provider_get_save_group(provider), + "IPsec.CACertsDir", + option); + + return 0; +} + +static void ipsec_disconnect(struct vpn_provider *provider) +{ + int err = 0; + /* + * Send the terminate command + */ + err = ipsec_terminate(provider); + IPSEC_ERROR_CHECK_RETURN(err, "terminate failed"); + + err = vici_deinitialize(vici_client); + IPSEC_ERROR_CHECK_RETURN(err, "failed to deinitialize vici_client"); + + return; +} + +static struct vpn_driver vpn_driver = { + .flags = VPN_FLAG_NO_TUN, + .notify = ipsec_notify, + .set_event_cb = ipsec_set_event_cb, + .connect = ipsec_connect, + .error_code = ipsec_error_code, + .save = ipsec_save, + .disconnect = ipsec_disconnect, +}; + +static int ipsec_init(void) +{ + connection = connman_dbus_get_connection(); + + event_data.event_cb = NULL; + event_data.event_user_data = NULL; + + return vpn_register("ipsec", &vpn_driver, IPSEC); +} + +static void ipsec_exit(void) +{ + vpn_unregister("ipsec"); + + dbus_connection_unref(connection); +} + +CONNMAN_PLUGIN_DEFINE(ipsec, "IPSec plugin", VERSION, + CONNMAN_PLUGIN_PRIORITY_DEFAULT, ipsec_init, ipsec_exit) diff --git a/vpn/plugins/ipsec.h b/vpn/plugins/ipsec.h new file mode 100644 index 00000000..14b9596f --- /dev/null +++ b/vpn/plugins/ipsec.h @@ -0,0 +1,51 @@ +/* + * + * ConnMan VPN daemon + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __CONNMAN_VPND_PLUGIN_IPSEC_H +#define __CONNMAN_VPND_PLUGIN_IPSEC_H + +#define IPSEC_AUTH_PSK "PSK" +#define IPSEC_AUTH_RSA "RSA" +#define IPSEC_AUTH_XAUTH "XAUTH" + +#define VICI_SHARED_TYPE_PSK "IKE" +#define VICI_SHARED_TYPE_XAUTH "xauth" + +#define IPSEC_ERROR_CHECK_GOTO(err, target, fmt, arg...) do { \ + if (err < 0) { \ + connman_error(fmt, ## arg); \ + goto target; \ + } \ +} while (0) + +#define IPSEC_ERROR_CHECK_RETURN(err, fmt, arg...) do { \ + if (err < 0) { \ + connman_error(fmt, ## arg); \ + return; \ + } \ +} while (0) + +#define IPSEC_ERROR_CHECK_RETURN_VAL(err, ret, fmt, arg...) do { \ + if (err < 0) { \ + connman_error(fmt, ## arg); \ + return ret; \ + } \ +} while (0) + +#endif /* __CONNMAN_VPND_PLUGIN_IPSEC_H */ diff --git a/vpn/plugins/l2tp.c b/vpn/plugins/l2tp.c index 5d83eb88..5d83eb88 100644..100755 --- a/vpn/plugins/l2tp.c +++ b/vpn/plugins/l2tp.c diff --git a/vpn/plugins/openconnect.c b/vpn/plugins/openconnect.c index 8e74479f..8e74479f 100644..100755 --- a/vpn/plugins/openconnect.c +++ b/vpn/plugins/openconnect.c diff --git a/vpn/plugins/openvpn.c b/vpn/plugins/openvpn.c index f38c0c36..6b090e45 100644..100755 --- a/vpn/plugins/openvpn.c +++ b/vpn/plugins/openvpn.c @@ -421,8 +421,10 @@ static int ov_connect(struct vpn_provider *provider, connman_task_add_argument(task, "--persist-tun", NULL); +#if !defined TIZEN_EXT connman_task_add_argument(task, "--route-noexec", NULL); connman_task_add_argument(task, "--ifconfig-noexec", NULL); +#endif /* * Disable client restarts because we can't handle this at the diff --git a/vpn/plugins/pptp.c b/vpn/plugins/pptp.c index 3dc93b03..3dc93b03 100644..100755 --- a/vpn/plugins/pptp.c +++ b/vpn/plugins/pptp.c diff --git a/vpn/plugins/vici-client.c b/vpn/plugins/vici-client.c new file mode 100644 index 00000000..67e365a5 --- /dev/null +++ b/vpn/plugins/vici-client.c @@ -0,0 +1,1290 @@ +/* + * + * ConnMan VPN daemon + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <unistd.h> +#include <errno.h> + +#include <sys/poll.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/stat.h> +#include <arpa/inet.h> + +#include <glib.h> + +#include <connman/log.h> +#include "ipsec.h" +#include "vici-client.h" + +#define SOCK_FD_MIN 3 +#define VICI_REQUEST_TIMEOUT 5000 + +enum vici_element { + VICI_END = 0, + VICI_SECTION_START = 1, + VICI_SECTION_END = 2, + VICI_KEY_VALUE = 3, + VICI_LIST_START = 4, + VICI_LIST_ITEM = 5, + VICI_LIST_END = 6, +}; + +enum vici_packet_type { + VICI_CMD_REQUEST = 0, + VICI_CMD_RESPONSE = 1, + VICI_CMD_UNKNOWN = 2, + VICI_EVENT_REGISTER = 3, + VICI_EVENT_UNREGISTER = 4, + VICI_EVENT_CONFIRM = 5, + VICI_EVENT_UNKNOWN = 6, + VICI_EVENT = 7, +}; + +static const char *vici_cmd_str[] = { + "load-conn", + "load-shared", + "load-cert", + "load-authority", + "unload-authority", + "load-key", + "initiate", + "terminate", + "child-updown", + NULL, +}; + +struct request { + unsigned int allocated; + unsigned int used; + unsigned int hdr_len; + char *sndbuf; + int cmd; + int err; + /* process reply */ + unsigned int rcv_pkt_size; + char *rcvbuf; + /* davici_cb cb; */ + void *user; +}; + +struct _VICIClient { + /* io data */ + int client_sock_fd; + int client_watch; + unsigned int rcv_pkt_size; + char *rcvbuf; + GSList *request_list; + vici_request_reply_cb reply_cb; + vici_event_cb event_cb; + void *reply_user_data; + void *event_user_data; +}; + +struct _VICISection { + char *name; + GHashTable *kvs; + GHashTable *kvls; + GHashTable *subsection; +}; + +static void remove_list(gpointer data) +{ + if (data == NULL) + return; + + g_slist_free_full((GSList *)data, g_free); +} + +void vici_destroy_section(VICISection* section) +{ + g_free(section->name); + g_hash_table_destroy(section->kvs); + g_hash_table_destroy(section->kvls); + g_hash_table_destroy(section->subsection); + g_free(section); +} + +static void free_section(gpointer data) +{ + VICISection* section = (VICISection*)data; + vici_destroy_section(section); +} + +VICISection* vici_create_section(const char* name) +{ + VICISection* section; + + section = g_try_new0(VICISection, 1); + if (!section) { + connman_error("Failed to create section"); + return NULL; + } + + if (name) + section->name = g_strdup(name); + section->kvs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + section->kvls = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, remove_list); + section->subsection = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_section); + return section; +} + +int add_subsection(const char* name, VICISection* child, VICISection* section) +{ + if (section == NULL || name == NULL || child == NULL) { + connman_error("invalid parameter"); + return -1; + } + + g_hash_table_insert(section->subsection, g_strdup(name), child); + return 0; +} + +static int add_kvl_to_section(const char* key, const char* value, VICISection* section) +{ + GSList *list = NULL; + if (section == NULL || key == NULL || value == NULL) { + connman_error("invalid parameter"); + return -1; + } + + list = g_hash_table_lookup(section->kvls, key); + if (list == NULL) + list = g_slist_alloc(); + + list = g_slist_prepend(list, g_strdup(value)); + g_hash_table_replace(section->kvls, g_strdup(key), list); + return 0; +} + +static int add_kv_to_section(const char* key, const char* value, VICISection* section) +{ + if (section == NULL || key == NULL || value == NULL) { + connman_error("invalid parameter"); + return -1; + } + + g_hash_table_insert(section->kvs, g_strdup(key), g_strdup(value)); + return 0; +} + +static VICISection* get_subsection(VICISection* section, const char* name) +{ + VICISection* sub = g_hash_table_lookup(section->subsection, name); + if (sub == NULL) { + sub = vici_create_section(name); + add_subsection(name, sub, section); + } + return sub; +} + +int vici_add_kv(VICISection* section, const char* key, + const char* value, const char* subsection) +{ + VICISection* target = section; + DBG("key: %s, value: %s, subsection: %s", key, value, subsection); + + if (section == NULL || key == NULL) { + connman_error("invalid parameter"); + return -1; + } + + if (subsection) + target = get_subsection(section, subsection); + + add_kv_to_section(key, value, target); + return 0; +} + +int vici_add_kvl(VICISection* section, const char* key, + const char* value, const char* subsection) +{ + VICISection* target = section; + + DBG("key: %s, value: %s, subsection: %s", key, value, subsection); + if (section == NULL || key == NULL) { + connman_error("invalid parameter"); + return -1; + } + + if (subsection) + target = get_subsection(section, subsection); + + if (g_strcmp0(subsection, "children") == 0) + target = get_subsection(target, "net"); + + add_kvl_to_section(key, value, target); + return 0; +} + +static void add_list_to_section(char *key, GSList *list, VICISection *section) +{ + if (section == NULL || key == NULL || list == NULL) + return; + + g_hash_table_insert(section->kvls, g_strdup(key), g_slist_copy_deep(list, (GCopyFunc)g_strdup, NULL)); + return; +} + +int vici_add_list(VICISection* section, char *key, GSList *list, const char* subsection) +{ + VICISection* target = section; + + DBG("key: %s, subsection: %s", key, subsection); + if (section == NULL || key == NULL) { + connman_error("invalid parameter"); + return -1; + } + + if (subsection) + target = get_subsection(section, subsection); + + if (g_strcmp0(subsection, "children") == 0) + target = get_subsection(target, "net"); + + add_list_to_section(key, list, target); + return 0; +} + +static char *load_cert_from_path(const char *path) +{ + struct stat st; + FILE *fp = NULL; + int fd = 0; + size_t file_size = 0; + char *file_buff = NULL; + + fp = fopen(path, "rb"); + if (fp == NULL) { + connman_error("fopen failed"); + return NULL; + } + + fd = fileno(fp); + if (fd == -1) { + connman_error("fp is not a valid stream"); + fclose(fp); + return NULL; + } + + if (fstat(fd, &st) != 0) { + connman_error("fstat failed"); + fclose(fp); + return NULL; + } + + file_size = st.st_size; + file_buff = g_try_malloc0(sizeof(char)*st.st_size); + if (file_buff == NULL) { + connman_error("g_try_malloc0 failed\n"); + fclose(fp); + return NULL; + } + + if (fread(file_buff, 1, file_size, fp) != file_size) { + connman_error("file size not matched\n"); + g_free(file_buff); + file_buff = NULL; + } + + fclose(fp); + return file_buff; +} + +int vici_add_cert_kv(VICISection *section, const char *key, + const char *value, const char *subsection) +{ + char *cert = NULL; + int ret = 0; + + if (value == NULL) { + DBG("value is null"); + return 0; + } + + cert = load_cert_from_path(value); + if (!cert) + return -1; + + ret = vici_add_kv(section, key, (const char *)cert, subsection); + g_free(cert); + return ret; +} + +int vici_add_cert_kvl(VICISection *section, const char *key, + const char *value, const char *subsection) +{ + char *cert = NULL; + int ret = 0; + + cert = load_cert_from_path(value); + if (!cert) + return -1; + + ret = vici_add_kvl(section, key, (const char *)cert, subsection); + g_free(cert); + return ret; +} + +static void *add_element(struct request *r, enum vici_element type, + unsigned int size) +{ + unsigned int newlen; + void *ret, *new; + + if (r->used + size + 1 > r->allocated) { + newlen = r->allocated; + while (newlen < r->used + size + 1) { + newlen *= 2; + } + new = realloc(r->sndbuf, newlen); + if (!new) { + r->err = -errno; + return NULL; + } + r->sndbuf = new; + r->allocated = newlen; + } + r->sndbuf[r->used++] = type; + ret = r->sndbuf + r->used; + r->used += size; + return ret; +} + +static void section_start(struct request *r, const char *name) +{ + uint8_t nlen; + char *pos; + + nlen = strlen(name); + pos = add_element(r, VICI_SECTION_START, 1 + nlen); + if (pos) { + pos[0] = nlen; + memcpy(pos + 1, name, nlen); + } +} + +static void section_end(struct request *r) +{ + add_element(r, VICI_SECTION_END, 0); +} + +static void key_value(struct request *r, const char *name, + const void *buf, unsigned int buflen) +{ + uint8_t nlen; + uint16_t vlen; + char *pos; + + nlen = strlen(name); + pos = add_element(r, VICI_KEY_VALUE, 1 + nlen + sizeof(vlen) + buflen); + if (pos) { + pos[0] = nlen; + memcpy(pos + 1, name, nlen); + vlen = htons(buflen); + memcpy(pos + 1 + nlen, &vlen, sizeof(vlen)); + memcpy(pos + 1 + nlen + sizeof(vlen), buf, buflen); + } +} + + +static void list_start(struct request *r, const char *name) +{ + uint8_t nlen; + char *pos; + + nlen = strlen(name); + pos = add_element(r, VICI_LIST_START, 1 + nlen); + if (pos) { + pos[0] = nlen; + memcpy(pos + 1, name, nlen); + } +} + +static void list_item(struct request *r, const void *buf, + unsigned int buflen) +{ + uint16_t vlen; + char *pos; + + pos = add_element(r, VICI_LIST_ITEM, sizeof(vlen) + buflen); + if (pos) { + vlen = htons(buflen); + memcpy(pos, &vlen, sizeof(vlen)); + memcpy(pos + sizeof(vlen), buf, buflen); + } +} + +static void list_end(struct request *r) +{ + add_element(r, VICI_LIST_END, 0); +} + +static void destroy_vici_request(gpointer data) +{ + struct request *req = (struct request *)data; + if(!req) + return; + + g_free(req->sndbuf); + g_free(req); +} + +static int create_vici_request(enum vici_packet_type type, VICIClientCmd cmd, + struct request **rp) +{ + struct request *req = NULL; + + if (cmd >= VICI_CMD_MAX || !rp) + return -EINVAL; + + req = g_try_new0(struct request, 1); + if (!req) { + connman_error("g_try_new0 failed"); + return -ENOMEM; + } + + req->used = 2; + req->used += strlen(vici_cmd_str[cmd]); + req->allocated = MIN(32, req->used); + req->sndbuf = g_try_new0(char, req->allocated); + if (!req->sndbuf) { + connman_error("g_try_new0 failed"); + g_free(req); + return -ENOMEM; + } + + req->sndbuf[0] = type; + req->sndbuf[1] = req->used - 2; /* except for type and name length */ + memcpy(req->sndbuf + 2, vici_cmd_str[cmd], req->used - 2); + req->hdr_len = req->used; + req->cmd = cmd; + + *rp = req; + + return 0; +} + +static void write_section_kvs(VICISection *section, struct request *req) +{ + GHashTableIter iter; + gpointer key, value; + + if (section == NULL || req == NULL) + return; + + g_hash_table_iter_init (&iter, section->kvs); + while (g_hash_table_iter_next (&iter, &key, &value)) { + if (!key || !value) + continue; + key_value(req, (const char*)key, (const void *)value, strlen((char *)value)); + } + + return; +} + +static void write_list_item(gpointer data, gpointer user_data) +{ + struct request *req = NULL; + char *value = NULL; + + if (!data || !user_data) + return; + + value = (char *)data; + req = (struct request *)user_data; + list_item(req, value, strlen(value)); + + return; +} + +static void write_section_kvls(VICISection *section, struct request *req) +{ + GHashTableIter iter; + gpointer key, value; + + if (section == NULL || req == NULL) + return; + + g_hash_table_iter_init (&iter, section->kvls); + while (g_hash_table_iter_next (&iter, &key, &value)) { + if (!key || !value) + continue; + + list_start(req, key); + g_slist_foreach((GSList *)value, (GFunc)write_list_item, (gpointer)req); + list_end(req); + } + + return; +} + +static void write_section(struct request *req, VICISection *section) +{ + GHashTableIter iter; + gpointer key, value; + + if (req == NULL || section == NULL) + return; + + if (section->name) + section_start(req, section->name); + + write_section_kvs(section, req); + write_section_kvls(section, req); + + g_hash_table_iter_init(&iter, section->subsection); + while (g_hash_table_iter_next (&iter, &key, &value)) { + if (!key || !value) + continue; + write_section(req, (VICISection *)value); + } + + if (section->name) + section_end(req); + return; +} + +static int check_socket(int sock) +{ + struct pollfd p_fd; + int res = 0; + + p_fd.fd = sock; + p_fd.events = POLLIN | POLLOUT | POLLERR | POLLHUP | POLLNVAL; + res = poll((struct pollfd *) &p_fd, 1, 1); + + if (res < 0) { + connman_error("Polling error from socket\n"); + return -1; + } else if (res == 0) { + connman_error( "poll timeout. socket is busy\n"); + return 1; + } else { + + if (p_fd.revents & POLLERR) { + connman_error("Error! POLLERR from socket[%d]\n", sock); + return -1; + } else if (p_fd.revents & POLLHUP) { + connman_error("Error! POLLHUP from socket[%d]\n", sock); + return -1; + } else if (p_fd.revents & POLLNVAL) { + connman_error("Error! POLLNVAL from socket[%d]\n", sock); + return -1; + } else if (p_fd.revents & POLLIN) { + return 0; + } else if (p_fd.revents & POLLOUT) { + return 0; + } + } + + connman_error("Unknown poll event [%d]\n", p_fd.revents); + return -1; +} + +static int write_socket(int sock, char *data, int data_len) +{ + int wbytes = 0; + int left_len = data_len; + char *ptr = data; + int res = 0; + + if (sock < SOCK_FD_MIN || !data || data_len < 0) + return -1; + + res = check_socket(sock); + if (res < 0) + return -1; + else if (res > 0) + return -2; + + errno = 0; + while (left_len) { + wbytes = write(sock, ptr, left_len); + if (wbytes <= 0) { + connman_error("Failed to write data into socket[%d].\n", sock); + break; + }else if (wbytes < left_len) { + left_len -= wbytes; + ptr += wbytes; + } else if (wbytes == left_len) { + left_len = 0; + } else { + connman_error("Unknown error occurred.\n"); + break; + } + } + + if (left_len) + return -1; + else + return 0; +} + +int send_vici_command(struct request *req, VICIClient *vici_client) +{ + unsigned int size = 0; + int sock_fd = 0; + int res = 0; + + if (req == NULL || vici_client == NULL) { + connman_error("request is NULL\n"); + return -EINVAL; + } + sock_fd = vici_client->client_sock_fd; + + size = htonl(req->used); + res = write_socket(sock_fd, (char *)&size, sizeof(size)); + if (res != 0) { + connman_error("failed to send size with network byte order\n"); + return -EIO; + } + + res = write_socket(sock_fd, req->sndbuf, req->used); + if (res != 0) { + connman_error("failed to send pkt\n"); + return -EIO; + } + + if(req->cmd != VICI_CMD_REGISTER_CHILD_UPDOWN) + vici_client->request_list = g_slist_append(vici_client->request_list, req); + + return res; +} + +static void print_vici_element(int elem_type, char *value, int sections) +{ + int i = 0; + + + switch (elem_type) { + case VICI_SECTION_START: + for (i = 0; i < sections - 1; i++) + DBG("\t"); + DBG("%s = {\n", value); + break; + case VICI_SECTION_END: + for (i = 0; i < sections; i++) + DBG("\t"); + DBG("}\n"); + break; + case VICI_KEY_VALUE: + for (i = 0; i < sections; i++) + DBG("\t"); + DBG("%s\n", value); + break; + case VICI_LIST_START: + for (i = 0; i < sections; i++) + DBG("\t"); + DBG("%s = [", value); + break; + case VICI_LIST_ITEM: + DBG("%s, ", value); + break; + case VICI_LIST_END: + DBG("]\n"); + break; + default: + break; + } + return; +} + +static void debug_vici_message(char *buf, unsigned int size) +{ + char temp[255]; + unsigned int pos = 0; + int len = 0; + int sections = 0; + int type = -1; + + if (buf == NULL || size == 0) + return; + + pos = 1; + while (pos < size) { + + type = buf[pos]; + pos++; + switch (type) { + case VICI_SECTION_START: + { + len = buf[pos]; + pos++; + g_strlcpy(temp, (const gchar *)&buf[pos], len + 1); + pos += len; + sections++; + } + break; + case VICI_SECTION_END: + { + sections--; + } + break; + case VICI_KEY_VALUE: + { + int key_len = 0; + int value_len = 0; + + key_len = buf[pos]; + pos++; + g_strlcpy(temp, (const gchar *)&buf[pos], key_len + 1); + temp[key_len] = '='; + pos += (key_len + 1); + value_len = buf[pos]; + pos++; + g_strlcpy(temp + key_len + 1, (const gchar *)&buf[pos], value_len + 1); + pos += value_len; + } + break; + case VICI_LIST_START: + { + len = buf[pos]; + pos++; + g_strlcpy(temp, (const gchar *)&buf[pos], len + 1); + pos += len; + } + break; + case VICI_LIST_ITEM: + { + pos++; + len = buf[pos]; + pos++; + g_strlcpy(temp, (const gchar *)&buf[pos], len + 1); + pos += len; + } + break; + case VICI_LIST_END: + break; + default: + break; + } + print_vici_element(type, temp, sections); + } + return; +} + +static unsigned int extract_key_value(char *buf, unsigned int pos, char **key, char **value) +{ + int key_len = 0; + int value_len = 0; + + key_len = buf[pos]; + pos++; + *key = g_strndup((const gchar *)&buf[pos], key_len); + pos+=(key_len + 1); + value_len = buf[pos]; + pos++; + *value = g_strndup((const gchar *)&buf[pos], value_len); + pos+=value_len; + return pos; +} + +static gboolean extract_request_result(char *buf, unsigned int size, char **err) +{ + gboolean success = FALSE; + unsigned int pos = 0; + int type = -1; + + pos = 1; + while (pos < size) { + + type = buf[pos];//3 + pos++; + if (type == VICI_KEY_VALUE) { + char *key = NULL; + char *value = NULL; + pos = extract_key_value(buf, pos, &key, &value); + DBG("pos : %d size : %d\n", pos, size); + + /* TODO :remove this after debug */ + DBG("key : %s value : %s\n", key, value); + if (g_strcmp0(key, "success") == 0) + (g_strcmp0(value, "yes") == 0)?(success = TRUE):(success = FALSE); + + if (g_strcmp0(key, "errmsg")) + *err = g_strdup(value); + g_free(key); + g_free(value); + } + } + return success; +} + +static int handle_vici_result(gboolean success, int cmd, char * err) +{ + int ret = 0; + if (success) + return 0; + + g_free(err); + + switch (cmd) { + case VICI_CMD_LOAD_CONN: + ret = EINVAL; + break; + case VICI_CMD_LOAD_SHARED: + ret = EINVAL; + break; + case VICI_CMD_LOAD_CERT: + ret = EINVAL; + break; + case VICI_CMD_LOAD_AUTH: + ret = 0; + break; + case VICI_CMD_LOAD_KEY: + ret = EINVAL; + break; + case VICI_CMD_INITIATE: + ret = ECONNABORTED; + break; + case VICI_CMD_TERMINATE: + ret = EINVAL; + break; + default: + break; + } + + DBG(" %s failed with %d!\n", vici_cmd_str[cmd], ret); + return ret; +} + +static int process_vici_response(struct request * req) +{ + char *err = NULL; + gboolean success = FALSE; + int ret = 0; + + if (!req) + return -1; + + if (!req->rcvbuf || req->rcvbuf[0] != VICI_CMD_RESPONSE) + return -1; + + //TODO: remove below when there's no further problem. + debug_vici_message(req->rcvbuf, req->rcv_pkt_size); + + success = extract_request_result(req->rcvbuf, req->rcv_pkt_size, &err); + ret = handle_vici_result(success, req->cmd, err); + + return ret; +} + +int vici_send_request(VICIClient *vici_client, VICIClientCmd cmd, VICISection *root) +{ + struct request *req = NULL; + int ret; + + DBG("%s", vici_cmd_str[cmd]); + ret = create_vici_request(VICI_CMD_REQUEST, cmd, &req); + if (ret < 0) { + connman_error("error on create_request\n"); + return ret; + } + + write_section(req, root); + //TODO: remove below when there's no further problem. + debug_vici_message(req->sndbuf + req->hdr_len - 1, req->used - req->hdr_len + 1); + + ret = send_vici_command(req, vici_client); + if (ret < 0) { + destroy_vici_request(req); + connman_error("error on send_command\n"); + } + + return ret; +} + + +int vici_set_event_cb(VICIClient *vici_client, vici_event_cb cb, gpointer user_data) +{ + struct request *req = NULL; + int ret; + + DBG("%s",vici_cmd_str[VICI_EVENT_CHILD_UP]); + ret = create_vici_request(VICI_EVENT_REGISTER, VICI_CMD_REGISTER_CHILD_UPDOWN, &req); + if (ret < 0) { + connman_error("error on create_request\n"); + return ret; + } + + ret = send_vici_command(req, vici_client); + if (ret < 0) { + connman_error("error on send_command\n"); + } + + destroy_vici_request(req); + vici_client->event_cb = cb; + vici_client->event_user_data = user_data; + + return ret; + +} + +static int get_socket_from_source(GIOChannel *source, GIOCondition condition) +{ + int sock = -1; + /* check socket */ + sock = g_io_channel_unix_get_fd(source); + if (sock < SOCK_FD_MIN) + return -1; + + if ((condition & G_IO_ERR) || (condition & G_IO_HUP) || (condition & G_IO_NVAL)) { + connman_error("G_IO_ERR/G_IO_HUP/G_IO_NVAL received sock [%d] condition [%d]\n", sock, condition); + //TODO: handle the breaking socket + return -1; + } + return sock; +} + +static int read_socket(int sock, char *data, unsigned int data_len) +{ + int rbytes = 0; + int total_rbytes = 0; + + if (sock < SOCK_FD_MIN || !data || data_len <= 0) + return -1; + + while (data_len > 0) { + errno = 0; + rbytes = read(sock, data, data_len); + if (rbytes <= 0) + return -1; + + total_rbytes += rbytes; + data += rbytes; + data_len -= rbytes; + } + + return total_rbytes; +} + +static int recv_vici_pkt(int sock, struct _VICIClient *vici_client) +{ + if(!vici_client) + return -1; + + if (vici_client->rcv_pkt_size == 0) { + unsigned int pkt_size = 0; + if (read_socket(sock, (char *)&pkt_size, sizeof(pkt_size)) < 0) + return -1; + + vici_client->rcv_pkt_size = ntohl(pkt_size); + /* TODO :REMOVE THIS AFTER DEBUG */ + DBG("rcv_pkt_size [%d] will be recved\n", vici_client->rcv_pkt_size); + } else { + + DBG("rcv_pkt_size [%d] is recved\n", vici_client->rcv_pkt_size); + char *buf = NULL; + buf = g_try_malloc0(vici_client->rcv_pkt_size); + if (buf == NULL) + return -1; + + if (read_socket(sock, buf, vici_client->rcv_pkt_size) < 0) { + g_free(buf); + return -1; + } + vici_client->rcvbuf = buf; + } + + return 0; +} + +static struct request *pop_vici_request(VICIClient *vici_client) +{ + GSList *list = NULL; + + if (!vici_client) + return NULL; + + list = vici_client->request_list; + if(!list) + return NULL; + + return list->data; +} + +static void process_vici_reply(VICIClient *vici_client) +{ + struct request *req; + int ret = 0; + + if (!vici_client) + return; + + /* get first request */ + req = pop_vici_request(vici_client); + if (!req) + return; + + req->rcvbuf = vici_client->rcvbuf; + req->rcv_pkt_size = vici_client->rcv_pkt_size; + + ret = process_vici_response(req); + vici_client->request_list = g_slist_remove(vici_client->request_list, req); + destroy_vici_request(req); + + /* TODO :remove this after debug */ + DBG("left request reply : %d", g_slist_length(vici_client->request_list)); + + if (ret != 0 || g_slist_length(vici_client->request_list) == 0) + vici_client->reply_cb(ret, vici_client->reply_user_data); + +} + +static int extract_event_name(char *buf, unsigned int size, char *temp) +{ + int pos = 1; + int name_len = 0; + name_len = buf[pos]; + pos++; + DBG("event len: %d", name_len); + while(pos < size && pos - 2 < name_len) { + temp[pos - 2] = buf[pos]; + pos++; + } + temp[pos] = '\0'; + DBG("event name: %s", temp); + return pos; +} + +static char *vici_get_value(char *buf, unsigned int pos, unsigned int size, char *search_key) +{ + int type = -1; + + pos = 1; + while (pos < size) { + + type = buf[pos];//3 + pos++; + if (type == VICI_KEY_VALUE) { + char *key = NULL; + char *value = NULL; + pos = extract_key_value(buf, pos, &key, &value); + if (g_strcmp0(search_key, key) == 0) { + g_free(key); + return value; + } + + g_free(key); + g_free(value); + } + } + return NULL; +} + +static void process_child_updown(VICIClient *vici_client,char *buf, unsigned int size) +{ + char *state = NULL; + + state = vici_get_value(buf, 0, size, "state"); + if (g_strcmp0(state, "ESTABLISHED") == 0) { + DBG("ESTABLISHED"); + vici_client->event_cb(VICI_EVENT_CHILD_UP, vici_client->event_user_data); + } else if (g_strcmp0(state, "DELETING") == 0) { + DBG("DELETING"); + vici_client->event_cb(VICI_EVENT_CHILD_DOWN, vici_client->event_user_data); + } else { + DBG("Unknown event"); + } + g_free(state); + return; +} + +static void process_vici_event(VICIClient *vici_client) +{ + char *buf = NULL; + unsigned int size = 0; + unsigned int pos = 0; + char temp[256] = {0,}; + if (!vici_client || !(vici_client->rcvbuf) || vici_client->rcv_pkt_size == 0) + return; + + buf = vici_client->rcvbuf; + size = vici_client->rcv_pkt_size; + + pos = extract_event_name(buf, size, temp); + /* TODO: remove below after debug */ + /* add parser */ + if (g_strcmp0(temp, "child-updown") == 0) + process_child_updown(vici_client, buf + pos -1, size - pos); +} + +static void process_vici_packet(VICIClient *vici_client, char *buf) +{ + + if (!vici_client || !buf) + return; + + if (buf[0] == VICI_CMD_RESPONSE) { + DBG("VICI_CMD_RESPONSE\n"); + process_vici_reply(vici_client); + } else if (buf[0] == VICI_EVENT_CONFIRM) { + DBG("VICI_EVENT_CONFIRM\n"); + } else if (buf[0] == VICI_EVENT) { + DBG("VICI_EVENT"); + process_vici_event(vici_client); + } else { + DBG("Not handled [%u]", buf[0]); + } + return; +} + +static gboolean process_vici_msg(GIOChannel *source, + GIOCondition condition, + gpointer user_data) +{ + VICIClient *vici_client = NULL; + int sock = 0; + + vici_client = (VICIClient *)user_data; + if (!vici_client) + return FALSE; + + sock = get_socket_from_source(source, condition); + if (sock < 0) + return FALSE; + + + if(recv_vici_pkt(sock, vici_client) < 0) + return FALSE; + + if (!vici_client->rcvbuf) { + return TRUE; + } + + process_vici_packet(vici_client, vici_client->rcvbuf); + g_free(vici_client->rcvbuf); + vici_client->rcvbuf = NULL; + vici_client->rcv_pkt_size = 0; + + return TRUE; +} + +static int str_to_socket_addr(const char *uri, struct sockaddr_un *addr) +{ + memset(addr, 0, sizeof(*addr)); + addr->sun_family = AF_UNIX; + strncpy(addr->sun_path, uri, sizeof(addr->sun_path)); + + addr->sun_path[sizeof(addr->sun_path)-1] = '\0'; + + return offsetof(struct sockaddr_un, sun_path) + strlen(addr->sun_path); +} + +static int connect_socket(const char *uri) +{ + struct sockaddr_un addr; + int len, fd; + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + connman_error("socket() failed"); + return -errno; + } + + len = str_to_socket_addr(uri, &addr); + if (len == -1) { + connman_error("str_to_socket_addr failed"); + close(fd); + return -1; + } + + if (connect(fd, (struct sockaddr*)&addr, len) < 0) { + connman_error("connect failed. errno %d/%s", errno, strerror(errno)); + close(fd); + return -errno; + } + + return fd; +} + +static int initialize_vici_source(VICIClient *vici_client) +{ + GIOChannel *vici_channel; + if (!vici_client) { + return -ENOMEM; + } + + vici_client->client_sock_fd = connect_socket(VICI_DEFAULT_URI); + if (vici_client->client_sock_fd < 0) { + connman_error("connect_socket failed"); + return -EIO; + } + + vici_channel = g_io_channel_unix_new(vici_client->client_sock_fd); + if (!vici_channel) { + connman_error("g_io_channel_unix_new failed"); + close(vici_client->client_sock_fd); + return -ENOMEM; + } + + vici_client->client_watch = g_io_add_watch_full(vici_channel, + G_PRIORITY_LOW, + G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, + (GIOFunc)process_vici_msg, + (gpointer)vici_client, + NULL); + g_io_channel_unref(vici_channel); + return 0; +} + +int vici_initialize(VICIClient **vici_client) +{ + int ret = 0; + + *vici_client = g_try_new0(VICIClient, 1); + if (!*vici_client) { + connman_error("out of memory"); + return -ENOMEM; + } + + ret = initialize_vici_source(*vici_client); + if (ret != 0) { + g_free(*vici_client); + return ret; + } + + DBG("connected"); + return 0; +} + +void vici_set_request_reply_cb(VICIClient *vici_client, vici_request_reply_cb reply_cb, gpointer user_data) +{ + vici_client->reply_cb = reply_cb; + vici_client->reply_user_data = user_data; +} + +int vici_deinitialize(VICIClient *vici_client) +{ + if (vici_client->client_watch > 0) { + g_source_remove(vici_client->client_watch); + vici_client->client_watch = 0; + } + + close(vici_client->client_sock_fd); + g_slist_free_full(vici_client->request_list, destroy_vici_request); + g_free(vici_client->rcvbuf); + g_free(vici_client); + + return 0; +} diff --git a/vpn/plugins/vici-client.h b/vpn/plugins/vici-client.h new file mode 100644 index 00000000..a33a8e46 --- /dev/null +++ b/vpn/plugins/vici-client.h @@ -0,0 +1,84 @@ +/* + * + * ConnMan VPN daemon + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __VICI_CLIENT_H +#define __VICI_CLIENT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* strongswan VICI plugin client part*/ +struct _VICIClient; +typedef struct _VICIClient VICIClient; + +struct _VICISection; +typedef struct _VICISection VICISection; + +typedef enum { + VICI_CMD_LOAD_CONN, + VICI_CMD_LOAD_SHARED, + VICI_CMD_LOAD_CERT, + VICI_CMD_LOAD_AUTH, + VICI_CMD_UNLOAD_AUTH, + VICI_CMD_LOAD_KEY, + VICI_CMD_INITIATE, + VICI_CMD_TERMINATE, + VICI_CMD_REGISTER_CHILD_UPDOWN, + VICI_CMD_MAX, +} VICIClientCmd; + +typedef enum { + VICI_EVENT_CHILD_UP, + VICI_EVENT_CHILD_DOWN, + VICI_EVENT_MAX, +} VICIClientEvent; +#define VICI_DEFAULT_URI "/var/run/charon.vici" + +typedef int (*vici_add_element)(VICISection *sect, const char *key, + const char *value, const char *subsection); + +typedef void (*vici_request_reply_cb)(int err, void *user_data); +typedef void (*vici_event_cb)(VICIClientEvent event, void *user_data); + +VICISection* vici_create_section(const char *name); +int add_subsection(const char* name, VICISection* child, VICISection* section); +void vici_destroy_section(VICISection *sect); +int vici_add_kv(VICISection *sect, const char *key, + const char *value, const char *subsection); +int vici_add_kvl(VICISection *sect, const char *key, + const char *value, const char *subsection); +int vici_add_list(VICISection* section, char *key, + GSList *list, const char* subsection); +int vici_add_cert_kv(VICISection *section, const char *key, + const char *value, const char *subsection); +int vici_add_cert_kvl(VICISection *section, const char *key, + const char *value, const char *subsection); + +int vici_initialize(VICIClient **vici_client); +int vici_deinitialize(VICIClient *vici_client); +void vici_set_request_reply_cb(VICIClient *vici_client, vici_request_reply_cb reply_cb, gpointer user_data); +int vici_send_request(VICIClient *vici_client, VICIClientCmd cmd, VICISection *root); +int vici_set_event_cb(VICIClient *vici_client, vici_event_cb cb, gpointer user_data); + +#ifdef __cplusplus +} +#endif + +#endif /* __VICI_CLIENT_H */ diff --git a/vpn/plugins/vpn.c b/vpn/plugins/vpn.c index acede747..d9c6dbbb 100644..100755 --- a/vpn/plugins/vpn.c +++ b/vpn/plugins/vpn.c @@ -343,6 +343,56 @@ static DBusMessage *vpn_notify(struct connman_task *task, return NULL; } +#if defined TIZEN_EXT +static void vpn_event(struct vpn_provider *provider, int state) +{ + struct vpn_driver_data *vpn_driver_data; + const char *name; + + name = vpn_provider_get_driver_name(provider); + if (!name) { + DBG("Cannot find VPN driver for provider %p", provider); + vpn_provider_set_state(provider, VPN_PROVIDER_STATE_FAILURE); + return; + } + + vpn_driver_data = g_hash_table_lookup(driver_hash, name); + if (!vpn_driver_data) { + DBG("Cannot find VPN driver data for name %s", name); + vpn_provider_set_state(provider, VPN_PROVIDER_STATE_FAILURE); + return; + } + + DBG("provider %p driver %s state %d", provider, name, state); + + switch (state) { + case VPN_STATE_CONNECT: + vpn_provider_set_state(provider, + VPN_PROVIDER_STATE_CONNECT); + break; + case VPN_STATE_READY: + vpn_provider_set_state(provider, + VPN_PROVIDER_STATE_READY); + break; + + case VPN_STATE_UNKNOWN: + case VPN_STATE_IDLE: + case VPN_STATE_DISCONNECT: + case VPN_STATE_FAILURE: + vpn_provider_set_state(provider, + VPN_PROVIDER_STATE_DISCONNECT); + break; + + case VPN_STATE_AUTH_FAILURE: + vpn_provider_indicate_error(provider, + VPN_PROVIDER_ERROR_AUTH_FAILED); + break; + } + + return; +} +#endif + static int vpn_create_tun(struct vpn_provider *provider, int flags) { struct vpn_data *data = vpn_provider_get_data(provider); @@ -495,6 +545,12 @@ static int vpn_connect(struct vpn_provider *provider, goto exist_err; } + +#if defined TIZEN_EXT + if(vpn_driver_data->vpn_driver->set_event_cb) + vpn_driver_data->vpn_driver->set_event_cb(vpn_event, provider); +#endif + ret = vpn_driver_data->vpn_driver->connect(provider, data->task, data->if_name, cb, dbus_sender, user_data); diff --git a/vpn/plugins/vpn.h b/vpn/plugins/vpn.h index 265fd82f..318a10c5 100644..100755 --- a/vpn/plugins/vpn.h +++ b/vpn/plugins/vpn.h @@ -40,9 +40,16 @@ enum vpn_state { VPN_STATE_AUTH_FAILURE = 6, }; +#if defined TIZEN_EXT +typedef void (*vpn_event_callback)(struct vpn_provider *provider, int state); +#endif + struct vpn_driver { int flags; int (*notify) (DBusMessage *msg, struct vpn_provider *provider); +#if defined TIZEN_EXT + void (*set_event_cb) (vpn_event_callback event_cb, struct vpn_provider *provider); +#endif int (*connect) (struct vpn_provider *provider, struct connman_task *task, const char *if_name, vpn_provider_connect_cb_t cb, const char *dbus_sender, diff --git a/vpn/plugins/vpnc.c b/vpn/plugins/vpnc.c index af9dbe76..af9dbe76 100644..100755 --- a/vpn/plugins/vpnc.c +++ b/vpn/plugins/vpnc.c diff --git a/vpn/vpn-agent.c b/vpn/vpn-agent.c index b0b582b7..b0b582b7 100644..100755 --- a/vpn/vpn-agent.c +++ b/vpn/vpn-agent.c diff --git a/vpn/vpn-agent.h b/vpn/vpn-agent.h index c7328d7f..c7328d7f 100644..100755 --- a/vpn/vpn-agent.h +++ b/vpn/vpn-agent.h diff --git a/vpn/vpn-config.c b/vpn/vpn-config.c index c88a99ab..5f0e749a 100644..100755 --- a/vpn/vpn-config.c +++ b/vpn/vpn-config.c @@ -203,7 +203,11 @@ static int load_provider(GKeyFile *keyfile, const char *group, struct vpn_config *config, enum what action) { struct vpn_config_provider *config_provider; +#if !defined TIZEN_EXT const char *ident, *host, *domain; +#else + const char *ident, *host, *domain, *name; +#endif int err; /* Strip off "provider_" prefix */ @@ -229,8 +233,14 @@ static int load_provider(GKeyFile *keyfile, const char *group, host = get_string(config_provider, "Host"); domain = get_string(config_provider, "Domain"); +#if !defined TIZEN_EXT if (host && domain) { char *id = __vpn_provider_create_identifier(host, domain); +#else + name = get_string(config_provider, "Name"); + if (host && domain && name) { + char *id = __vpn_provider_create_identifier(host, domain, name); +#endif struct vpn_provider *provider; provider = __vpn_provider_lookup(id); @@ -252,7 +262,11 @@ static int load_provider(GKeyFile *keyfile, const char *group, DBG("provider identifier %s", id); } else { +#if !defined TIZEN_EXT DBG("invalid values host %s domain %s", host, domain); +#else + DBG("invalid values host %s domain %s name %s", host, domain, name); +#endif err = -EINVAL; goto err; } diff --git a/vpn/vpn-dbus.conf b/vpn/vpn-dbus.conf index 0f0c8da4..8ebfc6b6 100644..100755 --- a/vpn/vpn-dbus.conf +++ b/vpn/vpn-dbus.conf @@ -1,15 +1,22 @@ <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> <busconfig> - <policy user="root"> - <allow own="net.connman.vpn"/> - <allow send_destination="net.connman.vpn"/> - <allow send_interface="net.connman.vpn.Agent"/> - </policy> - <policy at_console="true"> - <allow send_destination="net.connman.vpn"/> - </policy> - <policy context="default"> - <deny send_destination="net.connman.vpn"/> - </policy> + <policy user="root"> + <allow own="net.connman.vpn"/> + <allow send_destination="net.connman.vpn"/> + <allow send_interface="net.connman.vpn.Agent"/> + </policy> + <policy user="network_fw"> + <allow own="net.connman.vpn"/> + <allow send_destination="net.connman.vpn"/> + <allow send_interface="net.connman.vpn.Agent"/> + </policy> + <policy at_console="true"> + <allow send_destination="net.connman.vpn"/> + </policy> + <policy context="default"> + <deny own="net.connman.vpn"/> + <deny send_destination="net.connman.vpn"/> + <deny send_interface="net.connman.vpn.Agent"/> + </policy> </busconfig> diff --git a/vpn/vpn-ipconfig.c b/vpn/vpn-ipconfig.c index c096fa37..c096fa37 100644..100755 --- a/vpn/vpn-ipconfig.c +++ b/vpn/vpn-ipconfig.c diff --git a/vpn/vpn-manager.c b/vpn/vpn-manager.c index 021d625f..021d625f 100644..100755 --- a/vpn/vpn-manager.c +++ b/vpn/vpn-manager.c diff --git a/vpn/vpn-polkit.conf b/vpn/vpn-polkit.conf index a1dc6177..237d21be 100644..100755 --- a/vpn/vpn-polkit.conf +++ b/vpn/vpn-polkit.conf @@ -5,6 +5,10 @@ <allow own="net.connman.vpn"/> <allow send_interface="net.connman.vpn.Agent"/> </policy> + <policy user="network_fw"> + <allow own="net.connman.vpn"/> + <allow send_interface="net.connman.vpn.Agent"/> + </policy> <policy context="default"> <allow send_destination="net.connman.vpn"/> </policy> diff --git a/vpn/vpn-polkit.policy b/vpn/vpn-polkit.policy index 0c427220..0c427220 100644..100755 --- a/vpn/vpn-polkit.policy +++ b/vpn/vpn-polkit.policy diff --git a/vpn/vpn-provider.c b/vpn/vpn-provider.c index dd54ac08..bb1a103a 100644..100755 --- a/vpn/vpn-provider.c +++ b/vpn/vpn-provider.c @@ -1804,6 +1804,7 @@ static void provider_create_all_from_type(const char *provider_type) g_strfreev(providers); } +#if !defined TIZEN_EXT char *__vpn_provider_create_identifier(const char *host, const char *domain) { char *ident; @@ -1816,6 +1817,20 @@ char *__vpn_provider_create_identifier(const char *host, const char *domain) return ident; } +#else +char *__vpn_provider_create_identifier(const char *host, const char *domain, const char *name) +{ + char *ident; + + ident = g_strdup_printf("%s_%s_%s", host, domain, name); + if (!ident) + return NULL; + + provider_dbus_ident(ident); + + return ident; +} +#endif int __vpn_provider_create(DBusMessage *msg) { @@ -1869,7 +1884,11 @@ int __vpn_provider_create(DBusMessage *msg) if (!type || !name) return -EOPNOTSUPP; +#if !defined TIZEN_EXT ident = __vpn_provider_create_identifier(host, domain); +#else + ident = __vpn_provider_create_identifier(host, domain, name); +#endif DBG("ident %s", ident); provider = __vpn_provider_lookup(ident); @@ -2058,7 +2077,11 @@ int __vpn_provider_create_from_config(GHashTable *settings, goto fail; } +#if !defined TIZEN_EXT ident = __vpn_provider_create_identifier(host, domain); +#else + ident = __vpn_provider_create_identifier(host, domain, name); +#endif DBG("ident %s", ident); provider = __vpn_provider_lookup(ident); diff --git a/vpn/vpn-provider.h b/vpn/vpn-provider.h index 96452c11..96452c11 100644..100755 --- a/vpn/vpn-provider.h +++ b/vpn/vpn-provider.h diff --git a/vpn/vpn-rtnl.c b/vpn/vpn-rtnl.c index 6ddfd832..6ddfd832 100644..100755 --- a/vpn/vpn-rtnl.c +++ b/vpn/vpn-rtnl.c diff --git a/vpn/vpn-rtnl.h b/vpn/vpn-rtnl.h index aa640a66..aa640a66 100644..100755 --- a/vpn/vpn-rtnl.h +++ b/vpn/vpn-rtnl.h diff --git a/vpn/vpn.h b/vpn/vpn.h index 8bf86bd1..26b13d70 100644..100755 --- a/vpn/vpn.h +++ b/vpn/vpn.h @@ -71,8 +71,11 @@ int __vpn_ipconfig_init(void); void __vpn_ipconfig_cleanup(void); #include "vpn-provider.h" - +#if !defined TIZEN_EXT char *__vpn_provider_create_identifier(const char *host, const char *domain); +#else +char *__vpn_provider_create_identifier(const char *host, const char *domain, const char *name); +#endif bool __vpn_provider_check_routes(struct vpn_provider *provider); int __vpn_provider_append_user_route(struct vpn_provider *provider, int family, const char *network, diff --git a/vpn/vpn.ver b/vpn/vpn.ver index b8877064..b8877064 100644..100755 --- a/vpn/vpn.ver +++ b/vpn/vpn.ver |