2 * netifd - network interface daemon
3 * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
4 * Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
5 * Copyright (C) 2013 Steven Barth <steven@midlink.org>
6 * Copyright (C) 2014 Gioacchino Mazzurco <gio@eigenlab.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2
10 * as published by the Free Software Foundation
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
19 #include <sys/socket.h>
20 #include <sys/ioctl.h>
22 #include <sys/syscall.h>
25 #include <net/if_arp.h>
27 #include <arpa/inet.h>
28 #include <netinet/in.h>
30 #include <linux/rtnetlink.h>
31 #include <linux/sockios.h>
33 #include <linux/if_link.h>
34 #include <linux/if_vlan.h>
35 #include <linux/if_bridge.h>
36 #include <linux/if_tunnel.h>
37 #include <linux/ip6_tunnel.h>
38 #include <linux/ethtool.h>
39 #include <linux/fib_rules.h>
40 #include <linux/version.h>
42 #ifndef RTN_FAILED_POLICY
43 #define RTN_FAILED_POLICY 12
51 #include <netlink/msg.h>
52 #include <netlink/attr.h>
53 #include <netlink/socket.h>
54 #include <libubox/uloop.h>
61 struct uloop_fd uloop;
66 static int sock_ioctl = -1;
67 static struct nl_sock *sock_rtnl = NULL;
69 static int cb_rtnl_event(struct nl_msg *msg, void *arg);
70 static void handle_hotplug_event(struct uloop_fd *u, unsigned int events);
72 static char dev_buf[256];
75 handler_nl_event(struct uloop_fd *u, unsigned int events)
77 struct event_socket *ev = container_of(u, struct event_socket, uloop);
79 socklen_t errlen = sizeof(err);
82 nl_recvmsgs_default(ev->sock);
86 if (getsockopt(u->fd, SOL_SOCKET, SO_ERROR, (void *)&err, &errlen))
91 // Increase rx buffer size on netlink socket
93 if (nl_socket_set_buffer_size(ev->sock, ev->bufsize, 0))
96 // Request full dump since some info got dropped
97 struct rtgenmsg msg = { .rtgen_family = AF_UNSPEC };
98 nl_send_simple(ev->sock, RTM_GETLINK, NLM_F_DUMP, &msg, sizeof(msg));
108 uloop_fd_delete(&ev->uloop);
112 static struct nl_sock *
113 create_socket(int protocol, int groups)
115 struct nl_sock *sock;
117 sock = nl_socket_alloc();
122 nl_join_groups(sock, groups);
124 if (nl_connect(sock, protocol))
131 create_raw_event_socket(struct event_socket *ev, int protocol, int groups,
132 uloop_fd_handler cb, int flags)
134 ev->sock = create_socket(protocol, groups);
138 ev->uloop.fd = nl_socket_get_fd(ev->sock);
140 if (uloop_fd_add(&ev->uloop, ULOOP_READ|flags))
147 create_event_socket(struct event_socket *ev, int protocol,
148 int (*cb)(struct nl_msg *msg, void *arg))
150 if (!create_raw_event_socket(ev, protocol, 0, handler_nl_event, ULOOP_ERROR_CB))
153 // Install the valid custom callback handler
154 nl_socket_modify_cb(ev->sock, NL_CB_VALID, NL_CB_CUSTOM, cb, NULL);
156 // Disable sequence number checking on event sockets
157 nl_socket_disable_seq_check(ev->sock);
159 // Increase rx buffer size to 65K on event sockets
161 if (nl_socket_set_buffer_size(ev->sock, ev->bufsize, 0))
168 system_rtn_aton(const char *src, unsigned int *dst)
173 if (!strcmp(src, "local"))
175 else if (!strcmp(src, "nat"))
177 else if (!strcmp(src, "broadcast"))
179 else if (!strcmp(src, "anycast"))
181 else if (!strcmp(src, "multicast"))
183 else if (!strcmp(src, "prohibit"))
185 else if (!strcmp(src, "unreachable"))
187 else if (!strcmp(src, "blackhole"))
189 else if (!strcmp(src, "xresolve"))
191 else if (!strcmp(src, "unicast"))
193 else if (!strcmp(src, "throw"))
195 else if (!strcmp(src, "failed_policy"))
196 n = RTN_FAILED_POLICY;
198 n = strtoul(src, &e, 0);
199 if (!e || *e || e == src || n > 255)
208 system_tos_aton(const char *src, unsigned *dst)
212 *dst = strtoul(src, &e, 16);
213 if (e == src || *e || *dst > 255)
219 int system_init(void)
221 static struct event_socket rtnl_event;
222 static struct event_socket hotplug_event;
224 sock_ioctl = socket(AF_LOCAL, SOCK_DGRAM, 0);
225 system_fd_set_cloexec(sock_ioctl);
227 // Prepare socket for routing / address control
228 sock_rtnl = create_socket(NETLINK_ROUTE, 0);
232 if (!create_event_socket(&rtnl_event, NETLINK_ROUTE, cb_rtnl_event))
235 if (!create_raw_event_socket(&hotplug_event, NETLINK_KOBJECT_UEVENT, 1,
236 handle_hotplug_event, 0))
239 // Receive network link events form kernel
240 nl_socket_add_membership(rtnl_event.sock, RTNLGRP_LINK);
245 static void system_set_sysctl(const char *path, const char *val)
249 fd = open(path, O_WRONLY);
253 if (write(fd, val, strlen(val))) {}
257 static void system_set_dev_sysctl(const char *path, const char *device, const char *val)
259 snprintf(dev_buf, sizeof(dev_buf), path, device);
260 system_set_sysctl(dev_buf, val);
263 static void system_set_disable_ipv6(struct device *dev, const char *val)
265 system_set_dev_sysctl("/proc/sys/net/ipv6/conf/%s/disable_ipv6", dev->ifname, val);
268 static void system_set_rpfilter(struct device *dev, const char *val)
270 system_set_dev_sysctl("/proc/sys/net/ipv4/conf/%s/rp_filter", dev->ifname, val);
273 static void system_set_acceptlocal(struct device *dev, const char *val)
275 system_set_dev_sysctl("/proc/sys/net/ipv4/conf/%s/accept_local", dev->ifname, val);
278 static void system_set_igmpversion(struct device *dev, const char *val)
280 system_set_dev_sysctl("/proc/sys/net/ipv4/conf/%s/force_igmp_version", dev->ifname, val);
283 static int system_get_sysctl(const char *path, char *buf, const size_t buf_sz)
285 int fd = -1, ret = -1;
287 fd = open(path, O_RDONLY);
291 ssize_t len = read(fd, buf, buf_sz - 1);
305 system_get_dev_sysctl(const char *path, const char *device, char *buf, const size_t buf_sz)
307 snprintf(dev_buf, sizeof(dev_buf), path, device);
308 return system_get_sysctl(dev_buf, buf, buf_sz);
311 static int system_get_disable_ipv6(struct device *dev, char *buf, const size_t buf_sz)
313 return system_get_dev_sysctl("/proc/sys/net/ipv6/conf/%s/disable_ipv6",
314 dev->ifname, buf, buf_sz);
317 static int system_get_rpfilter(struct device *dev, char *buf, const size_t buf_sz)
319 return system_get_dev_sysctl("/proc/sys/net/ipv4/conf/%s/rp_filter",
320 dev->ifname, buf, buf_sz);
323 static int system_get_acceptlocal(struct device *dev, char *buf, const size_t buf_sz)
325 return system_get_dev_sysctl("/proc/sys/net/ipv4/conf/%s/accept_local",
326 dev->ifname, buf, buf_sz);
329 static int system_get_igmpversion(struct device *dev, char *buf, const size_t buf_sz)
331 return system_get_dev_sysctl("/proc/sys/net/ipv4/conf/%s/force_igmp_version",
332 dev->ifname, buf, buf_sz);
335 // Evaluate netlink messages
336 static int cb_rtnl_event(struct nl_msg *msg, void *arg)
338 struct nlmsghdr *nh = nlmsg_hdr(msg);
339 struct ifinfomsg *ifi = NLMSG_DATA(nh);
340 struct nlattr *nla[__IFLA_MAX];
344 if (nh->nlmsg_type != RTM_NEWLINK)
347 nlmsg_parse(nh, sizeof(*ifi), nla, __IFLA_MAX - 1, NULL);
348 if (!nla[IFLA_IFNAME])
351 struct device *dev = device_get(nla_data(nla[IFLA_IFNAME]), false);
352 if (!dev || dev->type->keep_link_status)
355 if (!system_get_dev_sysctl("/sys/class/net/%s/carrier", dev->ifname, buf, sizeof(buf)))
356 link_state = strtoul(buf, NULL, 0);
358 device_set_link(dev, link_state ? true : false);
365 handle_hotplug_msg(char *data, int size)
367 const char *subsystem = NULL, *interface = NULL;
368 char *cur, *end, *sep;
373 if (!strncmp(data, "add@", 4))
375 else if (!strncmp(data, "remove@", 7))
380 skip = strlen(data) + 1;
383 for (cur = data + skip; cur < end; cur += skip) {
384 skip = strlen(cur) + 1;
386 sep = strchr(cur, '=');
391 if (!strcmp(cur, "INTERFACE"))
393 else if (!strcmp(cur, "SUBSYSTEM")) {
395 if (strcmp(subsystem, "net") != 0)
398 if (subsystem && interface)
404 dev = device_get(interface, false);
408 if (dev->type != &simple_device_type)
411 if (add && system_if_force_external(dev->ifname))
414 device_set_present(dev, add);
418 handle_hotplug_event(struct uloop_fd *u, unsigned int events)
420 struct event_socket *ev = container_of(u, struct event_socket, uloop);
421 struct sockaddr_nl nla;
422 unsigned char *buf = NULL;
425 while ((size = nl_recv(ev->sock, &nla, &buf, NULL)) > 0) {
427 handle_hotplug_msg((char *) buf, size);
433 static int system_rtnl_call(struct nl_msg *msg)
437 ret = nl_send_auto_complete(sock_rtnl, msg);
443 return nl_wait_for_ack(sock_rtnl);
446 int system_bridge_delbr(struct device *bridge)
448 return ioctl(sock_ioctl, SIOCBRDELBR, bridge->ifname);
451 static int system_bridge_if(const char *bridge, struct device *dev, int cmd, void *data)
455 memset(&ifr, 0, sizeof(ifr));
457 ifr.ifr_ifindex = dev->ifindex;
460 strncpy(ifr.ifr_name, bridge, sizeof(ifr.ifr_name));
461 return ioctl(sock_ioctl, cmd, &ifr);
464 static bool system_is_bridge(const char *name, char *buf, int buflen)
468 snprintf(buf, buflen, "/sys/devices/virtual/net/%s/bridge", name);
469 if (stat(buf, &st) < 0)
475 static char *system_get_bridge(const char *name, char *buf, int buflen)
481 snprintf(buf, buflen, "/sys/devices/virtual/net/*/brif/%s/bridge", name);
482 if (glob(buf, GLOB_NOSORT, NULL, &gl) < 0)
486 len = readlink(gl.gl_pathv[0], buf, buflen);
494 path = strrchr(buf, '/');
501 static void system_bridge_set_wireless(const char *bridge, const char *dev)
503 snprintf(dev_buf, sizeof(dev_buf),
504 "/sys/devices/virtual/net/%s/brif/%s/multicast_to_unicast",
506 system_set_sysctl(dev_buf, "1");
509 int system_bridge_addif(struct device *bridge, struct device *dev)
514 oldbr = system_get_bridge(dev->ifname, dev_buf, sizeof(dev_buf));
515 if (!oldbr || strcmp(oldbr, bridge->ifname) != 0)
516 ret = system_bridge_if(bridge->ifname, dev, SIOCBRADDIF, NULL);
519 system_bridge_set_wireless(bridge->ifname, dev->ifname);
524 int system_bridge_delif(struct device *bridge, struct device *dev)
526 return system_bridge_if(bridge->ifname, dev, SIOCBRDELIF, NULL);
529 int system_if_resolve(struct device *dev)
532 strncpy(ifr.ifr_name, dev->ifname, sizeof(ifr.ifr_name));
533 if (!ioctl(sock_ioctl, SIOCGIFINDEX, &ifr))
534 return ifr.ifr_ifindex;
539 static int system_if_flags(const char *ifname, unsigned add, unsigned rem)
543 memset(&ifr, 0, sizeof(ifr));
544 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
545 ioctl(sock_ioctl, SIOCGIFFLAGS, &ifr);
546 ifr.ifr_flags |= add;
547 ifr.ifr_flags &= ~rem;
548 return ioctl(sock_ioctl, SIOCSIFFLAGS, &ifr);
560 static bool check_ifaddr(struct nlmsghdr *hdr, int ifindex)
562 struct ifaddrmsg *ifa = NLMSG_DATA(hdr);
564 return ifa->ifa_index == ifindex;
567 static bool check_route(struct nlmsghdr *hdr, int ifindex)
569 struct rtmsg *r = NLMSG_DATA(hdr);
570 struct nlattr *tb[__RTA_MAX];
572 if (r->rtm_protocol == RTPROT_KERNEL &&
573 r->rtm_family == AF_INET6)
576 nlmsg_parse(hdr, sizeof(struct rtmsg), tb, __RTA_MAX - 1, NULL);
580 return *(int *)RTA_DATA(tb[RTA_OIF]) == ifindex;
583 static bool check_rule(struct nlmsghdr *hdr, int ifindex)
588 static int cb_clear_event(struct nl_msg *msg, void *arg)
590 struct clear_data *clr = arg;
591 struct nlmsghdr *hdr = nlmsg_hdr(msg);
592 bool (*cb)(struct nlmsghdr *, int ifindex);
598 if (hdr->nlmsg_type != RTM_NEWADDR)
605 if (hdr->nlmsg_type != RTM_NEWROUTE)
612 if (hdr->nlmsg_type != RTM_NEWRULE)
621 if (!cb(hdr, clr->dev ? clr->dev->ifindex : 0))
624 if (type == RTM_DELRULE)
625 D(SYSTEM, "Remove a rule\n");
627 D(SYSTEM, "Remove %s from device %s\n",
628 type == RTM_DELADDR ? "an address" : "a route",
630 memcpy(nlmsg_hdr(clr->msg), hdr, hdr->nlmsg_len);
631 hdr = nlmsg_hdr(clr->msg);
632 hdr->nlmsg_type = type;
633 hdr->nlmsg_flags = NLM_F_REQUEST;
635 nl_socket_disable_auto_ack(sock_rtnl);
636 nl_send_auto_complete(sock_rtnl, clr->msg);
637 nl_socket_enable_auto_ack(sock_rtnl);
643 cb_finish_event(struct nl_msg *msg, void *arg)
651 error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
654 *pending = err->error;
659 system_if_clear_entries(struct device *dev, int type, int af)
661 struct clear_data clr;
662 struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
665 .rtm_flags = RTM_F_CLONED,
667 int flags = NLM_F_DUMP;
676 clr.size = sizeof(struct rtgenmsg);
679 clr.size = sizeof(struct rtmsg);
688 clr.msg = nlmsg_alloc_simple(type, flags);
692 nlmsg_append(clr.msg, &rtm, clr.size, 0);
693 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_clear_event, &clr);
694 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_finish_event, &pending);
695 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &pending);
697 nl_send_auto_complete(sock_rtnl, clr.msg);
699 nl_recvmsgs(sock_rtnl, cb);
707 * Clear bridge (membership) state and bring down device
709 void system_if_clear_state(struct device *dev)
711 static char buf[256];
714 device_set_ifindex(dev, system_if_resolve(dev));
715 if (dev->external || !dev->ifindex)
718 system_if_flags(dev->ifname, 0, IFF_UP);
720 if (system_is_bridge(dev->ifname, buf, sizeof(buf))) {
721 D(SYSTEM, "Delete existing bridge named '%s'\n", dev->ifname);
722 system_bridge_delbr(dev);
726 bridge = system_get_bridge(dev->ifname, buf, sizeof(buf));
728 D(SYSTEM, "Remove device '%s' from bridge '%s'\n", dev->ifname, bridge);
729 system_bridge_if(bridge, dev, SIOCBRDELIF, NULL);
732 system_if_clear_entries(dev, RTM_GETROUTE, AF_INET);
733 system_if_clear_entries(dev, RTM_GETADDR, AF_INET);
734 system_if_clear_entries(dev, RTM_GETROUTE, AF_INET6);
735 system_if_clear_entries(dev, RTM_GETADDR, AF_INET6);
736 system_set_disable_ipv6(dev, "0");
739 static inline unsigned long
740 sec_to_jiffies(int val)
742 return (unsigned long) val * 100;
745 int system_bridge_addbr(struct device *bridge, struct bridge_config *cfg)
747 unsigned long args[4] = {};
749 if (ioctl(sock_ioctl, SIOCBRADDBR, bridge->ifname) < 0)
752 args[0] = BRCTL_SET_BRIDGE_STP_STATE;
753 args[1] = !!cfg->stp;
754 system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
756 args[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
757 args[1] = sec_to_jiffies(cfg->forward_delay);
758 system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
760 system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_snooping",
761 bridge->ifname, cfg->igmp_snoop ? "1" : "0");
763 system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_querier",
764 bridge->ifname, cfg->igmp_snoop ? "1" : "0");
766 args[0] = BRCTL_SET_BRIDGE_PRIORITY;
767 args[1] = cfg->priority;
768 system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
770 if (cfg->flags & BRIDGE_OPT_AGEING_TIME) {
771 args[0] = BRCTL_SET_AGEING_TIME;
772 args[1] = sec_to_jiffies(cfg->ageing_time);
773 system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
776 if (cfg->flags & BRIDGE_OPT_HELLO_TIME) {
777 args[0] = BRCTL_SET_BRIDGE_HELLO_TIME;
778 args[1] = sec_to_jiffies(cfg->hello_time);
779 system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
782 if (cfg->flags & BRIDGE_OPT_MAX_AGE) {
783 args[0] = BRCTL_SET_BRIDGE_MAX_AGE;
784 args[1] = sec_to_jiffies(cfg->max_age);
785 system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
791 int system_macvlan_add(struct device *macvlan, struct device *dev, struct macvlan_config *cfg)
794 struct nlattr *linkinfo, *data;
795 struct ifinfomsg iim = { .ifi_family = AF_UNSPEC, };
797 static const struct {
799 enum macvlan_mode val;
801 { "private", MACVLAN_MODE_PRIVATE },
802 { "vepa", MACVLAN_MODE_VEPA },
803 { "bridge", MACVLAN_MODE_BRIDGE },
804 { "passthru", MACVLAN_MODE_PASSTHRU },
807 msg = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
812 nlmsg_append(msg, &iim, sizeof(iim), 0);
814 if (cfg->flags & MACVLAN_OPT_MACADDR)
815 nla_put(msg, IFLA_ADDRESS, sizeof(cfg->macaddr), cfg->macaddr);
816 nla_put_string(msg, IFLA_IFNAME, macvlan->ifname);
817 nla_put_u32(msg, IFLA_LINK, dev->ifindex);
819 if (!(linkinfo = nla_nest_start(msg, IFLA_LINKINFO)))
820 goto nla_put_failure;
822 nla_put_string(msg, IFLA_INFO_KIND, "macvlan");
824 if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
825 goto nla_put_failure;
828 for (i = 0; i < ARRAY_SIZE(modes); i++) {
829 if (strcmp(cfg->mode, modes[i].name) != 0)
832 nla_put_u32(msg, IFLA_MACVLAN_MODE, modes[i].val);
837 nla_nest_end(msg, data);
838 nla_nest_end(msg, linkinfo);
840 rv = system_rtnl_call(msg);
842 D(SYSTEM, "Error adding macvlan '%s' over '%s': %d\n", macvlan->ifname, dev->ifname, rv);
851 static int system_link_del(const char *ifname)
854 struct ifinfomsg iim = {
855 .ifi_family = AF_UNSPEC,
859 msg = nlmsg_alloc_simple(RTM_DELLINK, NLM_F_REQUEST);
864 nlmsg_append(msg, &iim, sizeof(iim), 0);
865 nla_put_string(msg, IFLA_IFNAME, ifname);
866 return system_rtnl_call(msg);
869 int system_macvlan_del(struct device *macvlan)
871 return system_link_del(macvlan->ifname);
874 static int system_vlan(struct device *dev, int id)
876 struct vlan_ioctl_args ifr = {
877 .cmd = SET_VLAN_NAME_TYPE_CMD,
878 .u.name_type = VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD,
881 ioctl(sock_ioctl, SIOCSIFVLAN, &ifr);
884 ifr.cmd = DEL_VLAN_CMD;
887 ifr.cmd = ADD_VLAN_CMD;
890 strncpy(ifr.device1, dev->ifname, sizeof(ifr.device1));
891 return ioctl(sock_ioctl, SIOCSIFVLAN, &ifr);
894 int system_vlan_add(struct device *dev, int id)
896 return system_vlan(dev, id);
899 int system_vlan_del(struct device *dev)
901 return system_vlan(dev, -1);
904 int system_vlandev_add(struct device *vlandev, struct device *dev, struct vlandev_config *cfg)
907 struct nlattr *linkinfo, *data;
908 struct ifinfomsg iim = { .ifi_family = AF_UNSPEC };
911 msg = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
916 nlmsg_append(msg, &iim, sizeof(iim), 0);
917 nla_put_string(msg, IFLA_IFNAME, vlandev->ifname);
918 nla_put_u32(msg, IFLA_LINK, dev->ifindex);
920 if (!(linkinfo = nla_nest_start(msg, IFLA_LINKINFO)))
921 goto nla_put_failure;
923 nla_put_string(msg, IFLA_INFO_KIND, "vlan");
925 if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
926 goto nla_put_failure;
928 nla_put_u16(msg, IFLA_VLAN_ID, cfg->vid);
930 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
931 nla_put_u16(msg, IFLA_VLAN_PROTOCOL, htons(cfg->proto));
933 if(cfg->proto == VLAN_PROTO_8021AD)
934 netifd_log_message(L_WARNING, "%s Your kernel is older than linux 3.10.0, 802.1ad is not supported defaulting to 802.1q", vlandev->type->name);
937 nla_nest_end(msg, data);
938 nla_nest_end(msg, linkinfo);
940 rv = system_rtnl_call(msg);
942 D(SYSTEM, "Error adding vlandev '%s' over '%s': %d\n", vlandev->ifname, dev->ifname, rv);
951 int system_vlandev_del(struct device *vlandev)
953 return system_link_del(vlandev->ifname);
957 system_if_get_settings(struct device *dev, struct device_settings *s)
962 memset(&ifr, 0, sizeof(ifr));
963 strncpy(ifr.ifr_name, dev->ifname, sizeof(ifr.ifr_name));
965 if (ioctl(sock_ioctl, SIOCGIFMTU, &ifr) == 0) {
966 s->mtu = ifr.ifr_mtu;
967 s->flags |= DEV_OPT_MTU;
970 if (ioctl(sock_ioctl, SIOCGIFTXQLEN, &ifr) == 0) {
971 s->txqueuelen = ifr.ifr_qlen;
972 s->flags |= DEV_OPT_TXQUEUELEN;
975 if (ioctl(sock_ioctl, SIOCGIFHWADDR, &ifr) == 0) {
976 memcpy(s->macaddr, &ifr.ifr_hwaddr.sa_data, sizeof(s->macaddr));
977 s->flags |= DEV_OPT_MACADDR;
980 if (!system_get_disable_ipv6(dev, buf, sizeof(buf))) {
981 s->ipv6 = !strtoul(buf, NULL, 0);
982 s->flags |= DEV_OPT_IPV6;
985 if (ioctl(sock_ioctl, SIOCGIFFLAGS, &ifr) == 0) {
986 s->promisc = ifr.ifr_flags & IFF_PROMISC;
987 s->flags |= DEV_OPT_PROMISC;
990 if (!system_get_rpfilter(dev, buf, sizeof(buf))) {
991 s->rpfilter = strtoul(buf, NULL, 0);
992 s->flags |= DEV_OPT_RPFILTER;
995 if (!system_get_acceptlocal(dev, buf, sizeof(buf))) {
996 s->acceptlocal = strtoul(buf, NULL, 0);
997 s->flags |= DEV_OPT_ACCEPTLOCAL;
1000 if (!system_get_igmpversion(dev, buf, sizeof(buf))) {
1001 s->igmpversion = strtoul(buf, NULL, 0);
1002 s->flags |= DEV_OPT_IGMPVERSION;
1007 system_if_apply_settings(struct device *dev, struct device_settings *s, unsigned int apply_mask)
1014 memset(&ifr, 0, sizeof(ifr));
1015 strncpy(ifr.ifr_name, dev->ifname, sizeof(ifr.ifr_name));
1016 if (s->flags & DEV_OPT_MTU & apply_mask) {
1017 ifr.ifr_mtu = s->mtu;
1018 if (ioctl(sock_ioctl, SIOCSIFMTU, &ifr) < 0)
1019 s->flags &= ~DEV_OPT_MTU;
1021 if (s->flags & DEV_OPT_TXQUEUELEN & apply_mask) {
1022 ifr.ifr_qlen = s->txqueuelen;
1023 if (ioctl(sock_ioctl, SIOCSIFTXQLEN, &ifr) < 0)
1024 s->flags &= ~DEV_OPT_TXQUEUELEN;
1026 if ((s->flags & DEV_OPT_MACADDR & apply_mask) && !dev->external) {
1027 ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
1028 memcpy(&ifr.ifr_hwaddr.sa_data, s->macaddr, sizeof(s->macaddr));
1029 if (ioctl(sock_ioctl, SIOCSIFHWADDR, &ifr) < 0)
1030 s->flags &= ~DEV_OPT_MACADDR;
1032 if (s->flags & DEV_OPT_IPV6 & apply_mask)
1033 system_set_disable_ipv6(dev, s->ipv6 ? "0" : "1");
1034 if (s->flags & DEV_OPT_PROMISC & apply_mask) {
1035 if (system_if_flags(dev->ifname, s->promisc ? IFF_PROMISC : 0,
1036 !s->promisc ? IFF_PROMISC : 0) < 0)
1037 s->flags &= ~DEV_OPT_PROMISC;
1039 if (s->flags & DEV_OPT_RPFILTER & apply_mask) {
1042 snprintf(buf, sizeof(buf), "%d", s->rpfilter);
1043 system_set_rpfilter(dev, buf);
1045 if (s->flags & DEV_OPT_ACCEPTLOCAL & apply_mask)
1046 system_set_acceptlocal(dev, s->acceptlocal ? "1" : "0");
1047 if (s->flags & DEV_OPT_IGMPVERSION & apply_mask) {
1050 snprintf(buf, sizeof(buf), "%d", s->igmpversion);
1051 system_set_igmpversion(dev, buf);
1055 int system_if_up(struct device *dev)
1057 system_if_get_settings(dev, &dev->orig_settings);
1058 /* Only keep orig settings based on what needs to be set */
1059 dev->orig_settings.flags &= dev->settings.flags;
1060 system_if_apply_settings(dev, &dev->settings, dev->settings.flags);
1061 return system_if_flags(dev->ifname, IFF_UP, 0);
1064 int system_if_down(struct device *dev)
1066 int ret = system_if_flags(dev->ifname, 0, IFF_UP);
1067 system_if_apply_settings(dev, &dev->orig_settings, dev->orig_settings.flags);
1071 struct if_check_data {
1077 #ifndef IFF_LOWER_UP
1078 #define IFF_LOWER_UP 0x10000
1081 static int cb_if_check_valid(struct nl_msg *msg, void *arg)
1083 struct nlmsghdr *nh = nlmsg_hdr(msg);
1084 struct ifinfomsg *ifi = NLMSG_DATA(nh);
1085 struct if_check_data *chk = (struct if_check_data *)arg;
1087 if (nh->nlmsg_type != RTM_NEWLINK)
1090 device_set_present(chk->dev, ifi->ifi_index > 0 ? true : false);
1091 device_set_link(chk->dev, ifi->ifi_flags & IFF_LOWER_UP ? true : false);
1096 static int cb_if_check_ack(struct nl_msg *msg, void *arg)
1098 struct if_check_data *chk = (struct if_check_data *)arg;
1103 static int cb_if_check_error(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
1105 struct if_check_data *chk = (struct if_check_data *)arg;
1107 device_set_present(chk->dev, false);
1108 device_set_link(chk->dev, false);
1109 chk->pending = err->error;
1114 int system_if_check(struct device *dev)
1116 struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
1118 struct ifinfomsg ifi = {
1119 .ifi_family = AF_UNSPEC,
1122 struct if_check_data chk = {
1128 msg = nlmsg_alloc_simple(RTM_GETLINK, 0);
1129 if (!msg || nlmsg_append(msg, &ifi, sizeof(ifi), 0) ||
1130 nla_put_string(msg, IFLA_IFNAME, dev->ifname))
1133 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_if_check_valid, &chk);
1134 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, cb_if_check_ack, &chk);
1135 nl_cb_err(cb, NL_CB_CUSTOM, cb_if_check_error, &chk);
1137 nl_send_auto_complete(sock_rtnl, msg);
1138 while (chk.pending > 0)
1139 nl_recvmsgs(sock_rtnl, cb);
1150 system_if_get_parent(struct device *dev)
1152 char buf[64], *devname;
1153 int ifindex, iflink, len;
1156 snprintf(buf, sizeof(buf), "/sys/class/net/%s/iflink", dev->ifname);
1157 f = fopen(buf, "r");
1161 len = fread(buf, 1, sizeof(buf) - 1, f);
1168 iflink = strtoul(buf, NULL, 0);
1169 ifindex = system_if_resolve(dev);
1170 if (!iflink || iflink == ifindex)
1173 devname = if_indextoname(iflink, buf);
1177 return device_get(devname, true);
1181 read_string_file(int dir_fd, const char *file, char *buf, int len)
1187 fd = openat(dir_fd, file, O_RDONLY);
1192 len = read(fd, buf, len - 1);
1196 } else if (len > 0) {
1199 c = strchr(buf, '\n');
1212 read_uint64_file(int dir_fd, const char *file, uint64_t *val)
1217 ret = read_string_file(dir_fd, file, buf, sizeof(buf));
1219 *val = strtoull(buf, NULL, 0);
1224 /* Assume advertised flags == supported flags */
1225 static const struct {
1228 } ethtool_link_modes[] = {
1229 { ADVERTISED_10baseT_Half, "10H" },
1230 { ADVERTISED_10baseT_Full, "10F" },
1231 { ADVERTISED_100baseT_Half, "100H" },
1232 { ADVERTISED_100baseT_Full, "100F" },
1233 { ADVERTISED_1000baseT_Half, "1000H" },
1234 { ADVERTISED_1000baseT_Full, "1000F" },
1237 static void system_add_link_modes(struct blob_buf *b, __u32 mask)
1240 for (i = 0; i < ARRAY_SIZE(ethtool_link_modes); i++) {
1241 if (mask & ethtool_link_modes[i].mask)
1242 blobmsg_add_string(b, NULL, ethtool_link_modes[i].name);
1247 system_if_force_external(const char *ifname)
1252 snprintf(buf, sizeof(buf), "/sys/class/net/%s/phy80211", ifname);
1253 return stat(buf, &s) == 0;
1257 system_if_dump_info(struct device *dev, struct blob_buf *b)
1259 struct ethtool_cmd ecmd;
1265 snprintf(buf, sizeof(buf), "/sys/class/net/%s", dev->ifname);
1266 dir_fd = open(buf, O_DIRECTORY);
1268 memset(&ecmd, 0, sizeof(ecmd));
1269 memset(&ifr, 0, sizeof(ifr));
1270 strcpy(ifr.ifr_name, dev->ifname);
1271 ifr.ifr_data = (caddr_t) &ecmd;
1272 ecmd.cmd = ETHTOOL_GSET;
1274 if (ioctl(sock_ioctl, SIOCETHTOOL, &ifr) == 0) {
1275 c = blobmsg_open_array(b, "link-advertising");
1276 system_add_link_modes(b, ecmd.advertising);
1277 blobmsg_close_array(b, c);
1279 c = blobmsg_open_array(b, "link-supported");
1280 system_add_link_modes(b, ecmd.supported);
1281 blobmsg_close_array(b, c);
1283 s = blobmsg_alloc_string_buffer(b, "speed", 8);
1284 snprintf(s, 8, "%d%c", ethtool_cmd_speed(&ecmd),
1285 ecmd.duplex == DUPLEX_HALF ? 'H' : 'F');
1286 blobmsg_add_string_buffer(b);
1294 system_if_dump_stats(struct device *dev, struct blob_buf *b)
1296 const char *const counters[] = {
1297 "collisions", "rx_frame_errors", "tx_compressed",
1298 "multicast", "rx_length_errors", "tx_dropped",
1299 "rx_bytes", "rx_missed_errors", "tx_errors",
1300 "rx_compressed", "rx_over_errors", "tx_fifo_errors",
1301 "rx_crc_errors", "rx_packets", "tx_heartbeat_errors",
1302 "rx_dropped", "tx_aborted_errors", "tx_packets",
1303 "rx_errors", "tx_bytes", "tx_window_errors",
1304 "rx_fifo_errors", "tx_carrier_errors",
1311 snprintf(buf, sizeof(buf), "/sys/class/net/%s/statistics", dev->ifname);
1312 stats_dir = open(buf, O_DIRECTORY);
1316 for (i = 0; i < ARRAY_SIZE(counters); i++)
1317 if (read_uint64_file(stats_dir, counters[i], &val))
1318 blobmsg_add_u64(b, counters[i], val);
1324 static int system_addr(struct device *dev, struct device_addr *addr, int cmd)
1326 bool v4 = ((addr->flags & DEVADDR_FAMILY) == DEVADDR_INET4);
1327 int alen = v4 ? 4 : 16;
1328 unsigned int flags = 0;
1329 struct ifaddrmsg ifa = {
1330 .ifa_family = (alen == 4) ? AF_INET : AF_INET6,
1331 .ifa_prefixlen = addr->mask,
1332 .ifa_index = dev->ifindex,
1336 if (cmd == RTM_NEWADDR)
1337 flags |= NLM_F_CREATE | NLM_F_REPLACE;
1339 msg = nlmsg_alloc_simple(cmd, flags);
1343 nlmsg_append(msg, &ifa, sizeof(ifa), 0);
1344 nla_put(msg, IFA_LOCAL, alen, &addr->addr);
1346 if (addr->broadcast)
1347 nla_put_u32(msg, IFA_BROADCAST, addr->broadcast);
1348 if (addr->point_to_point)
1349 nla_put_u32(msg, IFA_ADDRESS, addr->point_to_point);
1351 time_t now = system_get_rtime();
1352 struct ifa_cacheinfo cinfo = {0xffffffffU, 0xffffffffU, 0, 0};
1354 if (addr->preferred_until) {
1355 int64_t preferred = addr->preferred_until - now;
1358 else if (preferred > UINT32_MAX)
1359 preferred = UINT32_MAX;
1361 cinfo.ifa_prefered = preferred;
1364 if (addr->valid_until) {
1365 int64_t valid = addr->valid_until - now;
1368 else if (valid > UINT32_MAX)
1371 cinfo.ifa_valid = valid;
1374 nla_put(msg, IFA_CACHEINFO, sizeof(cinfo), &cinfo);
1377 return system_rtnl_call(msg);
1380 int system_add_address(struct device *dev, struct device_addr *addr)
1382 return system_addr(dev, addr, RTM_NEWADDR);
1385 int system_del_address(struct device *dev, struct device_addr *addr)
1387 return system_addr(dev, addr, RTM_DELADDR);
1390 static int system_rt(struct device *dev, struct device_route *route, int cmd)
1392 int alen = ((route->flags & DEVADDR_FAMILY) == DEVADDR_INET4) ? 4 : 16;
1394 unsigned int flags = 0;
1397 have_gw = !!route->nexthop.in.s_addr;
1399 have_gw = route->nexthop.in6.s6_addr32[0] ||
1400 route->nexthop.in6.s6_addr32[1] ||
1401 route->nexthop.in6.s6_addr32[2] ||
1402 route->nexthop.in6.s6_addr32[3];
1404 unsigned int table = (route->flags & (DEVROUTE_TABLE | DEVROUTE_SRCTABLE))
1405 ? route->table : RT_TABLE_MAIN;
1407 struct rtmsg rtm = {
1408 .rtm_family = (alen == 4) ? AF_INET : AF_INET6,
1409 .rtm_dst_len = route->mask,
1410 .rtm_src_len = route->sourcemask,
1411 .rtm_table = (table < 256) ? table : RT_TABLE_UNSPEC,
1412 .rtm_protocol = (route->flags & DEVADDR_KERNEL) ? RTPROT_KERNEL : RTPROT_STATIC,
1413 .rtm_scope = RT_SCOPE_NOWHERE,
1414 .rtm_type = (cmd == RTM_DELROUTE) ? 0: RTN_UNICAST,
1415 .rtm_flags = (route->flags & DEVROUTE_ONLINK) ? RTNH_F_ONLINK : 0,
1419 if (cmd == RTM_NEWROUTE) {
1420 flags |= NLM_F_CREATE | NLM_F_REPLACE;
1422 if (!dev) { // Add null-route
1423 rtm.rtm_scope = RT_SCOPE_UNIVERSE;
1424 rtm.rtm_type = RTN_UNREACHABLE;
1427 rtm.rtm_scope = (have_gw) ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK;
1430 if (route->flags & DEVROUTE_TYPE) {
1431 rtm.rtm_type = route->type;
1432 if (!(route->flags & (DEVROUTE_TABLE | DEVROUTE_SRCTABLE))) {
1433 if (rtm.rtm_type == RTN_LOCAL || rtm.rtm_type == RTN_BROADCAST ||
1434 rtm.rtm_type == RTN_NAT || rtm.rtm_type == RTN_ANYCAST)
1435 rtm.rtm_table = RT_TABLE_LOCAL;
1438 if (rtm.rtm_type == RTN_LOCAL || rtm.rtm_type == RTN_NAT) {
1439 rtm.rtm_scope = RT_SCOPE_HOST;
1440 } else if (rtm.rtm_type == RTN_BROADCAST || rtm.rtm_type == RTN_MULTICAST ||
1441 rtm.rtm_type == RTN_ANYCAST) {
1442 rtm.rtm_scope = RT_SCOPE_LINK;
1443 } else if (rtm.rtm_type == RTN_BLACKHOLE || rtm.rtm_type == RTN_UNREACHABLE ||
1444 rtm.rtm_type == RTN_PROHIBIT || rtm.rtm_type == RTN_FAILED_POLICY) {
1445 rtm.rtm_scope = RT_SCOPE_UNIVERSE;
1450 msg = nlmsg_alloc_simple(cmd, flags);
1454 nlmsg_append(msg, &rtm, sizeof(rtm), 0);
1457 nla_put(msg, RTA_DST, alen, &route->addr);
1459 if (route->sourcemask) {
1460 if (rtm.rtm_family == AF_INET)
1461 nla_put(msg, RTA_PREFSRC, alen, &route->source);
1463 nla_put(msg, RTA_SRC, alen, &route->source);
1466 if (route->metric > 0)
1467 nla_put_u32(msg, RTA_PRIORITY, route->metric);
1470 nla_put(msg, RTA_GATEWAY, alen, &route->nexthop);
1473 nla_put_u32(msg, RTA_OIF, dev->ifindex);
1476 nla_put_u32(msg, RTA_TABLE, table);
1478 if (route->flags & DEVROUTE_MTU) {
1479 struct nlattr *metrics;
1481 if (!(metrics = nla_nest_start(msg, RTA_METRICS)))
1482 goto nla_put_failure;
1484 nla_put_u32(msg, RTAX_MTU, route->mtu);
1486 nla_nest_end(msg, metrics);
1489 return system_rtnl_call(msg);
1496 int system_add_route(struct device *dev, struct device_route *route)
1498 return system_rt(dev, route, RTM_NEWROUTE);
1501 int system_del_route(struct device *dev, struct device_route *route)
1503 return system_rt(dev, route, RTM_DELROUTE);
1506 int system_flush_routes(void)
1508 const char *names[] = {
1509 "/proc/sys/net/ipv4/route/flush",
1510 "/proc/sys/net/ipv6/route/flush"
1514 for (i = 0; i < ARRAY_SIZE(names); i++) {
1515 fd = open(names[i], O_WRONLY);
1519 if (write(fd, "-1", 2)) {}
1525 bool system_resolve_rt_type(const char *type, unsigned int *id)
1527 return system_rtn_aton(type, id);
1530 bool system_resolve_rt_table(const char *name, unsigned int *id)
1534 unsigned int n, table = RT_TABLE_UNSPEC;
1536 /* first try to parse table as number */
1537 if ((n = strtoul(name, &e, 0)) > 0 && !*e)
1540 /* handle well known aliases */
1541 else if (!strcmp(name, "default"))
1542 table = RT_TABLE_DEFAULT;
1543 else if (!strcmp(name, "main"))
1544 table = RT_TABLE_MAIN;
1545 else if (!strcmp(name, "local"))
1546 table = RT_TABLE_LOCAL;
1548 /* try to look up name in /etc/iproute2/rt_tables */
1549 else if ((f = fopen("/etc/iproute2/rt_tables", "r")) != NULL)
1551 while (fgets(buf, sizeof(buf) - 1, f) != NULL)
1553 if ((e = strtok(buf, " \t\n")) == NULL || *e == '#')
1556 n = strtoul(e, NULL, 10);
1557 e = strtok(NULL, " \t\n");
1559 if (e && !strcmp(e, name))
1569 if (table == RT_TABLE_UNSPEC)
1576 bool system_is_default_rt_table(unsigned int id)
1578 return (id == RT_TABLE_MAIN);
1581 bool system_resolve_rpfilter(const char *filter, unsigned int *id)
1586 if (!strcmp(filter, "strict"))
1588 else if (!strcmp(filter, "loose"))
1591 n = strtoul(filter, &e, 0);
1592 if (*e || e == filter || n > 2)
1600 bool system_resolve_igmpversion(const unsigned int version, unsigned int *id)
1602 if (!version || version > 3)
1612 static int system_iprule(struct iprule *rule, int cmd)
1614 int alen = ((rule->flags & IPRULE_FAMILY) == IPRULE_INET4) ? 4 : 16;
1617 struct rtmsg rtm = {
1618 .rtm_family = (alen == 4) ? AF_INET : AF_INET6,
1619 .rtm_protocol = RTPROT_STATIC,
1620 .rtm_scope = RT_SCOPE_UNIVERSE,
1621 .rtm_table = RT_TABLE_UNSPEC,
1622 .rtm_type = RTN_UNSPEC,
1626 if (cmd == RTM_NEWRULE) {
1627 rtm.rtm_type = RTN_UNICAST;
1628 rtm.rtm_flags |= NLM_F_REPLACE | NLM_F_EXCL;
1632 rtm.rtm_flags |= FIB_RULE_INVERT;
1634 if (rule->flags & IPRULE_SRC)
1635 rtm.rtm_src_len = rule->src_mask;
1637 if (rule->flags & IPRULE_DEST)
1638 rtm.rtm_dst_len = rule->dest_mask;
1640 if (rule->flags & IPRULE_TOS)
1641 rtm.rtm_tos = rule->tos;
1643 if (rule->flags & IPRULE_LOOKUP) {
1644 if (rule->lookup < 256)
1645 rtm.rtm_table = rule->lookup;
1648 if (rule->flags & IPRULE_ACTION)
1649 rtm.rtm_type = rule->action;
1650 else if (rule->flags & IPRULE_GOTO)
1651 rtm.rtm_type = FR_ACT_GOTO;
1652 else if (!(rule->flags & (IPRULE_LOOKUP | IPRULE_ACTION | IPRULE_GOTO)))
1653 rtm.rtm_type = FR_ACT_NOP;
1655 msg = nlmsg_alloc_simple(cmd, NLM_F_REQUEST);
1660 nlmsg_append(msg, &rtm, sizeof(rtm), 0);
1662 if (rule->flags & IPRULE_IN)
1663 nla_put(msg, FRA_IFNAME, strlen(rule->in_dev) + 1, rule->in_dev);
1665 if (rule->flags & IPRULE_OUT)
1666 nla_put(msg, FRA_OIFNAME, strlen(rule->out_dev) + 1, rule->out_dev);
1668 if (rule->flags & IPRULE_SRC)
1669 nla_put(msg, FRA_SRC, alen, &rule->src_addr);
1671 if (rule->flags & IPRULE_DEST)
1672 nla_put(msg, FRA_DST, alen, &rule->dest_addr);
1674 if (rule->flags & IPRULE_PRIORITY)
1675 nla_put_u32(msg, FRA_PRIORITY, rule->priority);
1676 else if (cmd == RTM_NEWRULE)
1677 nla_put_u32(msg, FRA_PRIORITY, rule->order);
1679 if (rule->flags & IPRULE_FWMARK)
1680 nla_put_u32(msg, FRA_FWMARK, rule->fwmark);
1682 if (rule->flags & IPRULE_FWMASK)
1683 nla_put_u32(msg, FRA_FWMASK, rule->fwmask);
1685 if (rule->flags & IPRULE_LOOKUP) {
1686 if (rule->lookup >= 256)
1687 nla_put_u32(msg, FRA_TABLE, rule->lookup);
1690 if (rule->flags & IPRULE_GOTO)
1691 nla_put_u32(msg, FRA_GOTO, rule->gotoid);
1693 return system_rtnl_call(msg);
1696 int system_add_iprule(struct iprule *rule)
1698 return system_iprule(rule, RTM_NEWRULE);
1701 int system_del_iprule(struct iprule *rule)
1703 return system_iprule(rule, RTM_DELRULE);
1706 int system_flush_iprules(void)
1711 system_if_clear_entries(NULL, RTM_GETRULE, AF_INET);
1712 system_if_clear_entries(NULL, RTM_GETRULE, AF_INET6);
1714 memset(&rule, 0, sizeof(rule));
1717 rule.flags = IPRULE_INET4 | IPRULE_PRIORITY | IPRULE_LOOKUP;
1720 rule.lookup = RT_TABLE_LOCAL;
1721 rv |= system_iprule(&rule, RTM_NEWRULE);
1723 rule.priority = 32766;
1724 rule.lookup = RT_TABLE_MAIN;
1725 rv |= system_iprule(&rule, RTM_NEWRULE);
1727 rule.priority = 32767;
1728 rule.lookup = RT_TABLE_DEFAULT;
1729 rv |= system_iprule(&rule, RTM_NEWRULE);
1732 rule.flags = IPRULE_INET6 | IPRULE_PRIORITY | IPRULE_LOOKUP;
1735 rule.lookup = RT_TABLE_LOCAL;
1736 rv |= system_iprule(&rule, RTM_NEWRULE);
1738 rule.priority = 32766;
1739 rule.lookup = RT_TABLE_MAIN;
1740 rv |= system_iprule(&rule, RTM_NEWRULE);
1745 bool system_resolve_iprule_action(const char *action, unsigned int *id)
1747 return system_rtn_aton(action, id);
1750 time_t system_get_rtime(void)
1755 if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, &ts) == 0)
1758 if (gettimeofday(&tv, NULL) == 0)
1765 #define IP_DF 0x4000
1768 static int tunnel_ioctl(const char *name, int cmd, void *p)
1772 memset(&ifr, 0, sizeof(ifr));
1773 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1774 ifr.ifr_ifru.ifru_data = p;
1775 return ioctl(sock_ioctl, cmd, &ifr);
1778 #ifdef IFLA_IPTUN_MAX
1779 #define IP6_FLOWINFO_TCLASS htonl(0x0FF00000)
1780 static int system_add_gre_tunnel(const char *name, const char *kind,
1781 const unsigned int link, struct blob_attr **tb, bool v6)
1784 struct ifinfomsg ifi = { .ifi_family = AF_UNSPEC, };
1785 struct blob_attr *cur;
1786 uint32_t ikey = 0, okey = 0, flags = 0, flowinfo = 0;
1787 uint16_t iflags = 0, oflags = 0;
1789 int ret = 0, ttl = 64;
1791 nlm = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_CREATE);
1795 nlmsg_append(nlm, &ifi, sizeof(ifi), 0);
1796 nla_put_string(nlm, IFLA_IFNAME, name);
1798 struct nlattr *linkinfo = nla_nest_start(nlm, IFLA_LINKINFO);
1804 nla_put_string(nlm, IFLA_INFO_KIND, kind);
1805 struct nlattr *infodata = nla_nest_start(nlm, IFLA_INFO_DATA);
1812 nla_put_u32(nlm, IFLA_GRE_LINK, link);
1814 if ((cur = tb[TUNNEL_ATTR_TTL]))
1815 ttl = blobmsg_get_u32(cur);
1817 nla_put_u8(nlm, IFLA_GRE_TTL, ttl);
1819 if ((cur = tb[TUNNEL_ATTR_TOS])) {
1820 char *str = blobmsg_get_string(cur);
1821 if (strcmp(str, "inherit")) {
1824 if (!system_tos_aton(str, &uval)) {
1830 flowinfo |= htonl(uval << 20) & IP6_FLOWINFO_TCLASS;
1835 flags |= IP6_TNL_F_USE_ORIG_TCLASS;
1841 if ((cur = tb[TUNNEL_ATTR_INFO]) && (blobmsg_type(cur) == BLOBMSG_TYPE_STRING)) {
1842 uint8_t icsum, ocsum, iseqno, oseqno;
1843 if (sscanf(blobmsg_get_string(cur), "%u,%u,%hhu,%hhu,%hhu,%hhu",
1844 &ikey, &okey, &icsum, &ocsum, &iseqno, &oseqno) < 6) {
1869 struct in6_addr in6buf;
1870 if ((cur = tb[TUNNEL_ATTR_LOCAL])) {
1871 if (inet_pton(AF_INET6, blobmsg_data(cur), &in6buf) < 1) {
1875 nla_put(nlm, IFLA_GRE_LOCAL, sizeof(in6buf), &in6buf);
1878 if ((cur = tb[TUNNEL_ATTR_REMOTE])) {
1879 if (inet_pton(AF_INET6, blobmsg_data(cur), &in6buf) < 1) {
1883 nla_put(nlm, IFLA_GRE_REMOTE, sizeof(in6buf), &in6buf);
1885 nla_put_u8(nlm, IFLA_GRE_ENCAP_LIMIT, 4);
1888 nla_put_u32(nlm, IFLA_GRE_FLOWINFO, flowinfo);
1891 nla_put_u32(nlm, IFLA_GRE_FLAGS, flags);
1893 struct in_addr inbuf;
1896 if ((cur = tb[TUNNEL_ATTR_LOCAL])) {
1897 if (inet_pton(AF_INET, blobmsg_data(cur), &inbuf) < 1) {
1901 nla_put(nlm, IFLA_GRE_LOCAL, sizeof(inbuf), &inbuf);
1904 if ((cur = tb[TUNNEL_ATTR_REMOTE])) {
1905 if (inet_pton(AF_INET, blobmsg_data(cur), &inbuf) < 1) {
1909 nla_put(nlm, IFLA_GRE_REMOTE, sizeof(inbuf), &inbuf);
1911 if (IN_MULTICAST(ntohl(inbuf.s_addr))) {
1913 okey = inbuf.s_addr;
1918 ikey = inbuf.s_addr;
1924 if ((cur = tb[TUNNEL_ATTR_DF]))
1925 set_df = blobmsg_get_bool(cur);
1927 /* ttl !=0 and nopmtudisc are incompatible */
1928 if (ttl && !set_df) {
1933 nla_put_u8(nlm, IFLA_GRE_PMTUDISC, set_df ? 1 : 0);
1935 nla_put_u8(nlm, IFLA_GRE_TOS, tos);
1939 nla_put_u16(nlm, IFLA_GRE_OFLAGS, oflags);
1942 nla_put_u16(nlm, IFLA_GRE_IFLAGS, iflags);
1945 nla_put_u32(nlm, IFLA_GRE_OKEY, okey);
1948 nla_put_u32(nlm, IFLA_GRE_IKEY, ikey);
1950 nla_nest_end(nlm, infodata);
1951 nla_nest_end(nlm, linkinfo);
1953 return system_rtnl_call(nlm);
1961 static int system_add_proto_tunnel(const char *name, const uint8_t proto, const unsigned int link, struct blob_attr **tb)
1963 struct blob_attr *cur;
1965 struct ip_tunnel_parm p = {
1974 if ((cur = tb[TUNNEL_ATTR_LOCAL]) &&
1975 inet_pton(AF_INET, blobmsg_data(cur), &p.iph.saddr) < 1)
1978 if ((cur = tb[TUNNEL_ATTR_REMOTE]) &&
1979 inet_pton(AF_INET, blobmsg_data(cur), &p.iph.daddr) < 1)
1982 if ((cur = tb[TUNNEL_ATTR_DF]))
1983 set_df = blobmsg_get_bool(cur);
1985 if ((cur = tb[TUNNEL_ATTR_TTL]))
1986 p.iph.ttl = blobmsg_get_u32(cur);
1988 if ((cur = tb[TUNNEL_ATTR_TOS])) {
1989 char *str = blobmsg_get_string(cur);
1990 if (strcmp(str, "inherit")) {
1993 if (!system_tos_aton(str, &uval))
2001 p.iph.frag_off = set_df ? htons(IP_DF) : 0;
2002 /* ttl !=0 and nopmtudisc are incompatible */
2003 if (p.iph.ttl && p.iph.frag_off == 0)
2006 strncpy(p.name, name, sizeof(p.name));
2008 switch (p.iph.protocol) {
2010 return tunnel_ioctl("tunl0", SIOCADDTUNNEL, &p);
2012 return tunnel_ioctl("sit0", SIOCADDTUNNEL, &p);
2019 static int __system_del_ip_tunnel(const char *name, struct blob_attr **tb)
2021 struct blob_attr *cur;
2024 if (!(cur = tb[TUNNEL_ATTR_TYPE]))
2026 str = blobmsg_data(cur);
2028 if (!strcmp(str, "greip") || !strcmp(str, "gretapip") ||
2029 !strcmp(str, "greip6") || !strcmp(str, "gretapip6"))
2030 return system_link_del(name);
2032 return tunnel_ioctl(name, SIOCDELTUNNEL, NULL);
2035 int system_del_ip_tunnel(const char *name, struct blob_attr *attr)
2037 struct blob_attr *tb[__TUNNEL_ATTR_MAX];
2039 blobmsg_parse(tunnel_attr_list.params, __TUNNEL_ATTR_MAX, tb,
2040 blob_data(attr), blob_len(attr));
2042 return __system_del_ip_tunnel(name, tb);
2045 int system_update_ipv6_mtu(struct device *dev, int mtu)
2049 snprintf(buf, sizeof(buf), "/proc/sys/net/ipv6/conf/%s/mtu",
2052 int fd = open(buf, O_RDWR);
2053 ssize_t len = read(fd, buf, sizeof(buf) - 1);
2060 if (!mtu || ret <= mtu)
2063 lseek(fd, 0, SEEK_SET);
2064 if (write(fd, buf, snprintf(buf, sizeof(buf), "%i", mtu)) <= 0)
2072 int system_add_ip_tunnel(const char *name, struct blob_attr *attr)
2074 struct blob_attr *tb[__TUNNEL_ATTR_MAX];
2075 struct blob_attr *cur;
2078 blobmsg_parse(tunnel_attr_list.params, __TUNNEL_ATTR_MAX, tb,
2079 blob_data(attr), blob_len(attr));
2081 __system_del_ip_tunnel(name, tb);
2083 if (!(cur = tb[TUNNEL_ATTR_TYPE]))
2085 str = blobmsg_data(cur);
2087 unsigned int ttl = 0;
2088 if ((cur = tb[TUNNEL_ATTR_TTL])) {
2089 ttl = blobmsg_get_u32(cur);
2094 unsigned int link = 0;
2095 if ((cur = tb[TUNNEL_ATTR_LINK])) {
2096 struct interface *iface = vlist_find(&interfaces, blobmsg_data(cur), iface, node);
2100 if (iface->l3_dev.dev)
2101 link = iface->l3_dev.dev->ifindex;
2104 if (!strcmp(str, "sit")) {
2105 if (system_add_proto_tunnel(name, IPPROTO_IPV6, link, tb) < 0)
2109 if ((cur = tb[TUNNEL_ATTR_6RD_PREFIX])) {
2111 struct ip_tunnel_6rd p6;
2113 memset(&p6, 0, sizeof(p6));
2115 if (!parse_ip_and_netmask(AF_INET6, blobmsg_data(cur),
2116 &p6.prefix, &mask) || mask > 128)
2118 p6.prefixlen = mask;
2120 if ((cur = tb[TUNNEL_ATTR_6RD_RELAY_PREFIX])) {
2121 if (!parse_ip_and_netmask(AF_INET, blobmsg_data(cur),
2122 &p6.relay_prefix, &mask) || mask > 32)
2124 p6.relay_prefixlen = mask;
2127 if (tunnel_ioctl(name, SIOCADD6RD, &p6) < 0) {
2128 __system_del_ip_tunnel(name, tb);
2133 #ifdef IFLA_IPTUN_MAX
2134 } else if (!strcmp(str, "ipip6")) {
2135 struct nl_msg *nlm = nlmsg_alloc_simple(RTM_NEWLINK,
2136 NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_CREATE);
2137 struct ifinfomsg ifi = { .ifi_family = AF_UNSPEC };
2143 nlmsg_append(nlm, &ifi, sizeof(ifi), 0);
2144 nla_put_string(nlm, IFLA_IFNAME, name);
2147 nla_put_u32(nlm, IFLA_LINK, link);
2149 struct nlattr *linkinfo = nla_nest_start(nlm, IFLA_LINKINFO);
2154 nla_put_string(nlm, IFLA_INFO_KIND, "ip6tnl");
2155 struct nlattr *infodata = nla_nest_start(nlm, IFLA_INFO_DATA);
2162 nla_put_u32(nlm, IFLA_IPTUN_LINK, link);
2164 nla_put_u8(nlm, IFLA_IPTUN_PROTO, IPPROTO_IPIP);
2165 nla_put_u8(nlm, IFLA_IPTUN_TTL, (ttl) ? ttl : 64);
2166 nla_put_u8(nlm, IFLA_IPTUN_ENCAP_LIMIT, 4);
2168 struct in6_addr in6buf;
2169 if ((cur = tb[TUNNEL_ATTR_LOCAL])) {
2170 if (inet_pton(AF_INET6, blobmsg_data(cur), &in6buf) < 1) {
2174 nla_put(nlm, IFLA_IPTUN_LOCAL, sizeof(in6buf), &in6buf);
2177 if ((cur = tb[TUNNEL_ATTR_REMOTE])) {
2178 if (inet_pton(AF_INET6, blobmsg_data(cur), &in6buf) < 1) {
2182 nla_put(nlm, IFLA_IPTUN_REMOTE, sizeof(in6buf), &in6buf);
2185 #ifdef IFLA_IPTUN_FMR_MAX
2186 if ((cur = tb[TUNNEL_ATTR_FMRS])) {
2187 struct nlattr *fmrs = nla_nest_start(nlm, IFLA_IPTUN_FMRS);
2189 struct blob_attr *fmr;
2190 unsigned rem, fmrcnt = 0;
2191 blobmsg_for_each_attr(fmr, cur, rem) {
2192 if (blobmsg_type(fmr) != BLOBMSG_TYPE_STRING)
2195 unsigned ip4len, ip6len, ealen, offset = 6;
2199 if (sscanf(blobmsg_get_string(fmr), "%47[^/]/%u,%15[^/]/%u,%u,%u",
2200 ip6buf, &ip6len, ip4buf, &ip4len, &ealen, &offset) < 5) {
2205 struct in6_addr ip6prefix;
2206 struct in_addr ip4prefix;
2207 if (inet_pton(AF_INET6, ip6buf, &ip6prefix) != 1 ||
2208 inet_pton(AF_INET, ip4buf, &ip4prefix) != 1) {
2213 struct nlattr *rule = nla_nest_start(nlm, ++fmrcnt);
2215 nla_put(nlm, IFLA_IPTUN_FMR_IP6_PREFIX, sizeof(ip6prefix), &ip6prefix);
2216 nla_put(nlm, IFLA_IPTUN_FMR_IP4_PREFIX, sizeof(ip4prefix), &ip4prefix);
2217 nla_put_u8(nlm, IFLA_IPTUN_FMR_IP6_PREFIX_LEN, ip6len);
2218 nla_put_u8(nlm, IFLA_IPTUN_FMR_IP4_PREFIX_LEN, ip4len);
2219 nla_put_u8(nlm, IFLA_IPTUN_FMR_EA_LEN, ealen);
2220 nla_put_u8(nlm, IFLA_IPTUN_FMR_OFFSET, offset);
2222 nla_nest_end(nlm, rule);
2225 nla_nest_end(nlm, fmrs);
2229 nla_nest_end(nlm, infodata);
2230 nla_nest_end(nlm, linkinfo);
2232 return system_rtnl_call(nlm);
2236 } else if (!strcmp(str, "greip")) {
2237 return system_add_gre_tunnel(name, "gre", link, tb, false);
2238 } else if (!strcmp(str, "gretapip")) {
2239 return system_add_gre_tunnel(name, "gretap", link, tb, false);
2240 } else if (!strcmp(str, "greip6")) {
2241 return system_add_gre_tunnel(name, "ip6gre", link, tb, true);
2242 } else if (!strcmp(str, "gretapip6")) {
2243 return system_add_gre_tunnel(name, "ip6gretap", link, tb, true);
2245 } else if (!strcmp(str, "ipip")) {
2246 return system_add_proto_tunnel(name, IPPROTO_IPIP, link, tb);