+ ERR("Successfully launched child process");
+ return rv;
+ }
+
+ DBG("failed to fork(%s)",
+ strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER));
+ return -EIO;
+}
+
+int __netconfig_get_interface_index(const char *interface_name)
+{
+ struct ifreq ifr;
+ int sock = 0;
+ int result = 0;
+ char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, };
+
+ if (interface_name == NULL) {
+ DBG("Inteface name is NULL");
+ return -1;
+ }
+
+ errno = 0;
+ sock = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (sock < 0) {
+ strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
+ DBG("Failed to create socket : %s", error_buf);
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, interface_name, sizeof(ifr.ifr_name) - 1);
+ result = ioctl(sock, SIOCGIFINDEX, &ifr);
+ close(sock);
+
+ if (result < 0) {
+ strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
+ DBG("Failed to get ifr index: %s", error_buf);
+ return -1;
+ }
+
+ return ifr.ifr_ifindex;
+}
+
+int netconfig_add_route_ipv4(gchar *ip_addr, gchar *subnet, gchar *interface, gint address_family)
+{
+ struct ifreq ifr;
+ struct rtentry rt;
+ struct sockaddr_in addr_in;
+ int sock;
+ char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, };
+
+ memset(&ifr, 0, sizeof(ifr));
+
+ ifr.ifr_ifindex = __netconfig_get_interface_index(interface);
+
+ if (ifr.ifr_ifindex < 0)
+ return -1;
+
+ strncpy(ifr.ifr_name, interface, IFNAMSIZ-1);
+
+ memset(&rt, 0, sizeof(rt));
+
+ rt.rt_flags = RTF_UP | RTF_HOST;
+ memset(&addr_in, 0, sizeof(struct sockaddr_in));
+ addr_in.sin_family = address_family;
+ addr_in.sin_addr.s_addr = inet_addr(ip_addr);
+ memcpy(&rt.rt_dst, &addr_in, sizeof(rt.rt_dst));
+
+ memset(&addr_in, 0, sizeof(struct sockaddr_in));
+ addr_in.sin_family = address_family;
+ addr_in.sin_addr.s_addr = INADDR_ANY;
+ memcpy(&rt.rt_gateway, &addr_in, sizeof(rt.rt_gateway));
+
+ memset(&addr_in, 0, sizeof(struct sockaddr_in));
+ addr_in.sin_family = AF_INET;
+ addr_in.sin_addr.s_addr = inet_addr(subnet);
+ memcpy(&rt.rt_genmask, &addr_in, sizeof(rt.rt_genmask));
+
+ rt.rt_dev = ifr.ifr_name;
+
+ errno = 0;
+ sock = socket(PF_INET, SOCK_DGRAM, 0);
+
+ if (sock < 0) {
+ strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
+ DBG("Failed to create socket : %s", error_buf);
+ return -1;
+ }
+
+ if (ioctl(sock, SIOCADDRT, &rt) < 0) {
+ strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
+ DBG("Failed to set route address : %s", error_buf);
+ close(sock);
+ return -1;
+ }
+
+ close(sock);
+
+ return 1;
+}
+
+int netconfig_del_route_ipv4(gchar *ip_addr, gchar *subnet, gchar *interface, gint address_family)
+{
+ struct ifreq ifr;
+ struct rtentry rt;
+ struct sockaddr_in addr_in;
+ int sock;
+ char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, };
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_ifindex = __netconfig_get_interface_index(interface);
+
+ if (ifr.ifr_ifindex < 0)
+ return -1;
+
+ strncpy(ifr.ifr_name, interface, IFNAMSIZ-1);
+
+ memset(&rt, 0, sizeof(rt));
+
+ rt.rt_flags = RTF_UP;
+ memset(&addr_in, 0, sizeof(struct sockaddr_in));
+ addr_in.sin_family = address_family;
+ addr_in.sin_addr.s_addr = inet_addr(ip_addr);
+ memcpy(&rt.rt_dst, &addr_in, sizeof(rt.rt_dst));
+
+ memset(&addr_in, 0, sizeof(struct sockaddr_in));
+ addr_in.sin_family = address_family;
+ addr_in.sin_addr.s_addr = inet_addr(subnet);
+ memcpy(&rt.rt_genmask, &addr_in, sizeof(rt.rt_genmask));
+ rt.rt_dev = ifr.ifr_name;
+
+ errno = 0;
+ sock = socket(PF_INET, SOCK_DGRAM, 0);
+
+ if (sock < 0) {
+ strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
+ DBG("Failed to create socket : %s", error_buf);
+ return -1;
+ }
+
+ if (ioctl(sock, SIOCDELRT, &rt) < 0) {
+ strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
+ DBG("Failed to set route address : %s", error_buf);
+ close(sock);
+ return -1;
+ }
+
+ close(sock);
+
+ return 1;
+}
+
+static int __netconfig_rtnl_talk(netconfig_rtnl_s *rtnl, struct nlmsghdr *n, pid_t peer,
+ unsigned groups, struct nlmsghdr *answer)
+{
+ 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(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+ nladdr.nl_pid = peer;
+ nladdr.nl_groups = groups;
+
+ n->nlmsg_seq = seq = ++rtnl->seq;
+
+ if (answer == NULL)
+ n->nlmsg_flags |= NLM_F_ACK;
+
+ status = sendmsg(rtnl->fd, &msg, 0);
+ if (status < 0) {
+ DBG("failed to send message to kernel, status: %d", status);
+ return -1;
+ }
+
+ 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("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;