X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Futils%2Futil.c;h=9e1b46a7d78a4e5925078541f603dae05450ae67;hb=a259e3e99a5382699c19fc50288bf46eb03f18a4;hp=bec7fc2049d23bc95055eb3c8d2872e26a4341d1;hpb=7d35a6f5689bf387949ad441cf7dfc5bb42a9884;p=platform%2Fcore%2Fconnectivity%2Fnet-config.git diff --git a/src/utils/util.c b/src/utils/util.c index bec7fc2..9e1b46a 100755 --- a/src/utils/util.c +++ b/src/utils/util.c @@ -34,6 +34,9 @@ #include #include #include +#include +#include +#include #include "log.h" #include "util.h" @@ -49,6 +52,23 @@ #define HEADED_PLUGIN_FILEPATH "/usr/lib/net-config-plugin-headed.so" #define TELEPHONY_PLUGIN_FILEPATH "/usr/lib/net-config-plugin-telephony.so" +typedef struct { + uint8_t family; + uint8_t bytelen; + int16_t bitlen; + uint32_t flags; + uint32_t data[8]; +} netconfig_inet_prefix_s; + +typedef struct { + int fd; + struct sockaddr_nl local; + struct sockaddr_nl peer; + uint32_t seq; + uint32_t dump; +} netconfig_rtnl_s; +netconfig_rtnl_s rth = { .fd = -1 }; + static gboolean netconfig_device_picker_test = FALSE; static int mdnsd_ref_count = 0; typedef struct { @@ -63,6 +83,9 @@ static void *handle_telephony; static struct netconfig_headed_plugin_t *headed_plugin; static struct netconfig_telephony_plugin_t *telephony_plugin; +static bool is_feature_checked[NETCONFIG_SUPPORTED_FEATURE_MAX] = {0, }; +static bool feature_supported[NETCONFIG_SUPPORTED_FEATURE_MAX] = {0, }; + gboolean netconfig_check_passphrase(const gchar *service, const char *passphrase) { gsize length; @@ -317,7 +340,7 @@ void netconfig_wifi_device_picker_service_stop(void) gboolean netconfig_is_wifi_direct_on(void) { - if (!netconfig_check_feature_supported(WIFI_DIRECT_FEATURE)) + if (!netconfig_check_feature_supported(NETCONFIG_SUPPORTED_FEATURE_WIFI_DIRECT)) return FALSE; int wifi_direct_state = 0; @@ -330,7 +353,7 @@ gboolean netconfig_is_wifi_direct_on(void) gboolean netconfig_is_wifi_tethering_on(void) { - if (netconfig_check_feature_supported(TETHERING_FEATURE)) { + if (netconfig_check_feature_supported(NETCONFIG_SUPPORTED_FEATURE_TETHERING)) { int wifi_tethering_state = 0; netconfig_vconf_get_int(VCONFKEY_MOBILE_HOTSPOT_MODE, &wifi_tethering_state); @@ -579,6 +602,7 @@ int netconfig_execute_file_no_wait(const char *file_path, char *const args[]) struct sigaction act; int state = 0; + char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, }; act.sa_handler = no_wait_signal_handler; sigemptyset(&act.sa_mask); @@ -601,7 +625,8 @@ int netconfig_execute_file_no_wait(const char *file_path, char *const args[]) errno = 0; if (execvp(file_path, args) == -1) { - ERR("Fail to execute command (%s)", strerror(errno)); + ERR("Fail to execute command (%s)", + strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER)); return -1; } } else if (pid > 0) { @@ -609,7 +634,8 @@ int netconfig_execute_file_no_wait(const char *file_path, char *const args[]) return rv; } - DBG("failed to fork(%s)", strerror(errno)); + DBG("failed to fork(%s)", + strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER)); return -EIO; } @@ -756,36 +782,190 @@ int netconfig_del_route_ipv4(gchar *ip_addr, gchar *subnet, gchar *interface, gi return 1; } -int netconfig_add_route_ipv6(gchar *ip_addr, gchar *interface, gchar *gateway, unsigned char prefix_len) +static int __netconfig_rtnl_talk(netconfig_rtnl_s *rtnl, struct nlmsghdr *n, pid_t peer, + unsigned groups, struct nlmsghdr *answer) { - struct in6_rtmsg rt; - int fd = 0; - int err = 0; + struct nlmsghdr *h; + struct sockaddr_nl nladdr; + struct iovec iov = { + .iov_base = (void*)n, + .iov_len = n->nlmsg_len + }; + struct msghdr msg = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + int status; + unsigned seq; + char buf[16384]; char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, }; - memset(&rt, 0, sizeof(rt)); + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + nladdr.nl_pid = peer; + nladdr.nl_groups = groups; - rt.rtmsg_dst_len = prefix_len; + n->nlmsg_seq = seq = ++rtnl->seq; - rt.rtmsg_flags = RTF_UP | RTF_HOST; + if (answer == NULL) + n->nlmsg_flags |= NLM_F_ACK; - errno = 0; - if (inet_pton(AF_INET6, ip_addr, &rt.rtmsg_dst) < 0) { - strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER); - DBG("inet_pton failed : %s", error_buf); + status = sendmsg(rtnl->fd, &msg, 0); + if (status < 0) { + DBG("failed to send message to kernel, status: %d", status); return -1; } - if (gateway != NULL) { - rt.rtmsg_flags |= RTF_GATEWAY; - if (inet_pton(AF_INET6, gateway, &rt.rtmsg_gateway) < 0) { + memset(buf, 0, sizeof(buf)); + + iov.iov_base = buf; + + while (1) { + iov.iov_len = sizeof(buf); + status = recvmsg(rtnl->fd, &msg, 0); + DBG("status: %d", status); + + if (status < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER); - DBG("inet_pton failed : %s", error_buf); + DBG("netlink receive error %s (%d)", error_buf, errno); + return -1; + } + if (status == 0) { + DBG("EOF on netlink"); + return -1; + } + if (msg.msg_namelen != sizeof(nladdr)) { + DBG("sender address length == %d", msg.msg_namelen); + return -1; + } + for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { + int len = h->nlmsg_len; + int l = len - sizeof(*h); + + if (l < 0 || len > status) { + if (msg.msg_flags & MSG_TRUNC) { + DBG("truncated message"); + return -1; + } + DBG("malformed message: len=%d", len); + return -1; + } + + if (nladdr.nl_pid != peer || + h->nlmsg_pid != rtnl->local.nl_pid || + h->nlmsg_seq != seq) { + /** Don't forget to skip that message. */ + status -= NLMSG_ALIGN(len); + h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); + continue; + } + + if (h->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); + if (l < sizeof(struct nlmsgerr)) { + DBG("Error truncated message"); + } else { + if (!err->error) { + if (answer) + memcpy(answer, h, h->nlmsg_len); + return 0; + } + + errno = -err->error; + strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER); + DBG("RTNETLINK answers: %s", error_buf); + } + return -1; + } + if (answer) { + memcpy(answer, h, h->nlmsg_len); + return 0; + } + + DBG("Unexpected reply"); + + status -= NLMSG_ALIGN(len); + h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); + } + if (msg.msg_flags & MSG_TRUNC) { + DBG("Message truncated"); + continue; + } + if (status) { + DBG("Remnant of size %d", status); + return -1; + } + } +} + +static int __netconfig_get_prefix(netconfig_inet_prefix_s *dst, char *arg, int family) +{ + if (family != AF_UNSPEC && family != AF_INET6) { + DBG("Error: invalid address family."); + return -1; + } + + memset(dst, 0, sizeof(*dst)); + + if (strchr(arg, ':')) { + dst->family = AF_INET6; + if (inet_pton(AF_INET6, arg, dst->data) <= 0) { + DBG("Error: invalid ipv6 address."); return -1; } + dst->bytelen = 16; + dst->bitlen = 128; } - rt.rtmsg_metric = 1; + return 0; +} + +static int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, + int alen) +{ + int len = RTA_LENGTH(alen); + struct rtattr *rta; + + if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { + DBG("Error message exceeded bound of %d", maxlen); + return -1; + } + rta = NLMSG_TAIL(n); + rta->rta_type = type; + rta->rta_len = len; + memcpy(RTA_DATA(rta), data, alen); + n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); + + return 0; +} + +static int __netconfig_iproute_modify(int cmd, unsigned flags, char *interface, char *ip_addr) +{ + struct { + struct nlmsghdr n; + struct rtmsg r; + char buf[1024]; + } req; + + struct ifreq ifr; + int fd, idx, ret; + char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, }; + + memset(&req, 0, sizeof(req)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST|flags; + req.n.nlmsg_type = cmd; + req.r.rtm_family = AF_INET6; + + if (cmd != RTM_DELROUTE) { + req.r.rtm_protocol = RTPROT_BOOT; + req.r.rtm_type = RTN_UNICAST; + } fd = socket(AF_INET6, SOCK_DGRAM, 0); if (fd < 0) { @@ -794,85 +974,151 @@ int netconfig_add_route_ipv6(gchar *ip_addr, gchar *interface, gchar *gateway, u return -1; } - rt.rtmsg_ifindex = 0; + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name)-1); + ioctl(fd, SIOCGIFINDEX, &ifr); + idx = ifr.ifr_ifindex; + close(fd); - if (interface) { - struct ifreq ifr; - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name)-1); - ioctl(fd, SIOCGIFINDEX, &ifr); - rt.rtmsg_ifindex = ifr.ifr_ifindex; + if (ifr.ifr_ifindex == 0) { + DBG("Cannot find device %s", interface); + return -1; } - if ((err = ioctl(fd, SIOCADDRT, &rt)) < 0) { - strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER); - DBG("Failed to add route: %s", error_buf); - close(fd); + netconfig_inet_prefix_s dst; + + ret = __netconfig_get_prefix(&dst, ip_addr, req.r.rtm_family); + if (ret < 0) return -1; + + req.r.rtm_dst_len = dst.bitlen; + if (dst.bytelen) { + ret = addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen); + if (ret < 0) + return -1; } - close(fd); + ret = addattr_l(&req.n, sizeof(req), RTA_OIF, &idx, sizeof(uint32_t)); + if (ret < 0) + return -1; - return 1; + if (__netconfig_rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) { + DBG("__netconfig_rtnl_talk failed"); + return -1; + } + + return 0; } -int netconfig_del_route_ipv6(gchar *ip_addr, gchar *interface, gchar *gateway, unsigned char prefix_len) +static void __netconfig_rtnl_close() { - struct in6_rtmsg rt; - int fd = 0; - int err = 0; + if (rth.fd >= 0) { + close(rth.fd); + rth.fd = -1; + } +} - memset(&rt, 0, sizeof(rt)); +static int __netconfig_rtnl_open(netconfig_rtnl_s *rth, unsigned subscriptions, + int protocol) +{ + socklen_t addr_len; + int sndbuf = 32768; + int rcvbuf = 1024 * 1024; + char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, }; - rt.rtmsg_dst_len = prefix_len; + memset(rth, 0, sizeof(*rth)); - rt.rtmsg_flags = RTF_UP | RTF_HOST; + rth->fd = socket(AF_NETLINK, SOCK_RAW, protocol); + if (rth->fd < 0) { + strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER); + DBG("Failed to open netlink socket: %s", error_buf); + return -1; + } - if (inet_pton(AF_INET6, ip_addr, &rt.rtmsg_dst) < 0) { - err = -errno; - return err; + if (setsockopt(rth->fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) < 0) { + strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER); + DBG("Failed to set option(SO_SNDBUF) on socket [Error: %s]", error_buf); + return -1; } - if (gateway != NULL) { - rt.rtmsg_flags |= RTF_GATEWAY; - if (inet_pton(AF_INET6, gateway, &rt.rtmsg_gateway) < 0) { - err = -errno; - return err; - } + if (setsockopt(rth->fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) < 0) { + strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER); + DBG("Failed to set option(SO_RCVBUF) on socket [Error: %s]", error_buf); + return -1; } - rt.rtmsg_metric = 1; + memset(&rth->local, 0, sizeof(rth->local)); + rth->local.nl_family = AF_NETLINK; + rth->local.nl_groups = subscriptions; - fd = socket(AF_INET6, SOCK_DGRAM, 0); - if (fd < 0) + if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) { + strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER); + DBG("Failed to bind netlink socket [Error: %s]", error_buf); return -1; + } + + addr_len = sizeof(rth->local); + if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) { + strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER); + DBG("Failed to getsockname [Error: %s]", error_buf); + return -1; + } + if (addr_len != sizeof(rth->local)) { + DBG("Wrong address length %d", addr_len); + return -1; + } + if (rth->local.nl_family != AF_NETLINK) { + DBG("Wrong address family %d", rth->local.nl_family); + return -1; + } + rth->seq = time(NULL); + + return 0; +} - rt.rtmsg_ifindex = 0; +int netconfig_add_route_ipv6(gchar *interface, gchar *gateway) +{ + int ret = __netconfig_rtnl_open(&rth, 0, NETLINK_ROUTE); + if (ret < 0) { + DBG("Failed to open rtnl socket"); + return -1; + } - if (interface) { - struct ifreq ifr; - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name)-1); - ioctl(fd, SIOCGIFINDEX, &ifr); - rt.rtmsg_ifindex = ifr.ifr_ifindex; + ret = __netconfig_iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_EXCL, interface, gateway); + if (ret < 0) { + DBG("Failed to modify ipv6 route."); + __netconfig_rtnl_close(); + return -1; } - if ((err = ioctl(fd, SIOCDELRT, &rt)) < 0) { - DBG("Failed to del route: %d\n", err); - close(fd); + __netconfig_rtnl_close(); + return 0; +} + +int netconfig_del_route_ipv6(gchar *interface, gchar *gateway) +{ + int ret = __netconfig_rtnl_open(&rth, 0, NETLINK_ROUTE); + if (ret < 0) { + DBG("Failed to open rtnl socket"); return -1; } - close(fd); + ret = __netconfig_iproute_modify(RTM_DELROUTE, NLM_F_CREATE|NLM_F_EXCL, interface, gateway); + if (ret < 0) { + DBG("Failed to delete ipv6 route."); + __netconfig_rtnl_close(); + return -1; + } - return 1; + __netconfig_rtnl_close(); + return 0; } gboolean handle_launch_direct(Wifi *wifi, GDBusMethodInvocation *context) { - if (!netconfig_check_feature_supported(WIFI_DIRECT_FEATURE)) { + if (!netconfig_check_feature_supported(NETCONFIG_SUPPORTED_FEATURE_WIFI_DIRECT)) { wifi_complete_launch_direct(wifi, context); - return FALSE; + return TRUE; } int ret = 0; @@ -886,7 +1132,7 @@ gboolean handle_launch_direct(Wifi *wifi, GDBusMethodInvocation *context) if (ret < 0) { ERR("Failed to launch Wi-Fi direct daemon"); netconfig_error_wifi_direct_failed(context); - return FALSE; + return TRUE; } wifi_complete_launch_direct(wifi, context); @@ -1274,22 +1520,6 @@ tizen_profile_t _get_tizen_profile() return profile; } -bool netconfig_check_feature_supported(const char *feature) -{ - bool is_supported = false; - - if (!system_info_get_platform_bool(feature, &is_supported)) { - if (is_supported != TRUE) - DBG("%s is not supported", feature); - else - DBG("%s is supported", feature); - } else { - ERR("Error - Feature getting from System Info"); - } - - return is_supported; -} - void netconfig_plugin_init() { handle_headed = dlopen(HEADED_PLUGIN_FILEPATH, RTLD_NOW); @@ -1342,3 +1572,31 @@ gboolean netconfig_get_telephony_plugin_flag() return netconfig_plugin_telephony_enabled; } +bool netconfig_check_feature_supported(netconfig_supported_feature_e feature) +{ + const char *key = NULL; + + if (!is_feature_checked[feature]) { + switch (feature) { + case NETCONFIG_SUPPORTED_FEATURE_ETHERNET: + key = ETHERNET_FEATURE; + break; + case NETCONFIG_SUPPORTED_FEATURE_TETHERING: + key = TETHERING_FEATURE; + break; + case NETCONFIG_SUPPORTED_FEATURE_WIFI_DIRECT: + key = WIFI_DIRECT_FEATURE; + break; + default: + ERR("Uknown feature"); + return false; + } + + if (system_info_get_platform_bool(key, &feature_supported[feature]) < 0) { + ERR("Get feature is failed"); + return false; + } + is_feature_checked[feature] = true; + } + return feature_supported[feature]; +}