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 int system_get_sysctl(const char *path, char *buf, const size_t buf_sz)
270 int fd = -1, ret = -1;
272 fd = open(path, O_RDONLY);
276 ssize_t len = read(fd, buf, buf_sz - 1);
290 system_get_dev_sysctl(const char *path, const char *device, char *buf, const size_t buf_sz)
292 snprintf(dev_buf, sizeof(dev_buf), path, device);
293 return system_get_sysctl(dev_buf, buf, buf_sz);
296 static int system_get_disable_ipv6(struct device *dev, char *buf, const size_t buf_sz)
298 return system_get_dev_sysctl("/proc/sys/net/ipv6/conf/%s/disable_ipv6",
299 dev->ifname, buf, buf_sz);
303 #define IFF_LOWER_UP 0x10000
306 // Evaluate netlink messages
307 static int cb_rtnl_event(struct nl_msg *msg, void *arg)
309 struct nlmsghdr *nh = nlmsg_hdr(msg);
310 struct ifinfomsg *ifi = NLMSG_DATA(nh);
311 struct nlattr *nla[__IFLA_MAX];
313 if (nh->nlmsg_type != RTM_NEWLINK)
316 nlmsg_parse(nh, sizeof(*ifi), nla, __IFLA_MAX - 1, NULL);
317 if (!nla[IFLA_IFNAME])
320 struct device *dev = device_get(nla_data(nla[IFLA_IFNAME]), false);
324 device_set_ifindex(dev, ifi->ifi_index);
325 device_set_link(dev, ifi->ifi_flags & IFF_LOWER_UP ? true : false);
332 handle_hotplug_msg(char *data, int size)
334 const char *subsystem = NULL, *interface = NULL;
335 char *cur, *end, *sep;
340 if (!strncmp(data, "add@", 4))
342 else if (!strncmp(data, "remove@", 7))
347 skip = strlen(data) + 1;
350 for (cur = data + skip; cur < end; cur += skip) {
351 skip = strlen(cur) + 1;
353 sep = strchr(cur, '=');
358 if (!strcmp(cur, "INTERFACE"))
360 else if (!strcmp(cur, "SUBSYSTEM")) {
362 if (strcmp(subsystem, "net") != 0)
365 if (subsystem && interface)
371 dev = device_get(interface, false);
375 if (dev->type != &simple_device_type)
378 if (add && system_if_force_external(dev->ifname))
381 device_set_present(dev, add);
385 handle_hotplug_event(struct uloop_fd *u, unsigned int events)
387 struct event_socket *ev = container_of(u, struct event_socket, uloop);
388 struct sockaddr_nl nla;
389 unsigned char *buf = NULL;
392 while ((size = nl_recv(ev->sock, &nla, &buf, NULL)) > 0) {
394 handle_hotplug_msg((char *) buf, size);
400 static int system_rtnl_call(struct nl_msg *msg)
404 ret = nl_send_auto_complete(sock_rtnl, msg);
410 return nl_wait_for_ack(sock_rtnl);
413 int system_bridge_delbr(struct device *bridge)
415 return ioctl(sock_ioctl, SIOCBRDELBR, bridge->ifname);
418 static int system_bridge_if(const char *bridge, struct device *dev, int cmd, void *data)
422 memset(&ifr, 0, sizeof(ifr));
424 ifr.ifr_ifindex = dev->ifindex;
427 strncpy(ifr.ifr_name, bridge, sizeof(ifr.ifr_name));
428 return ioctl(sock_ioctl, cmd, &ifr);
431 static bool system_is_bridge(const char *name, char *buf, int buflen)
435 snprintf(buf, buflen, "/sys/devices/virtual/net/%s/bridge", name);
436 if (stat(buf, &st) < 0)
442 static char *system_get_bridge(const char *name, char *buf, int buflen)
448 snprintf(buf, buflen, "/sys/devices/virtual/net/*/brif/%s/bridge", name);
449 if (glob(buf, GLOB_NOSORT, NULL, &gl) < 0)
452 if (gl.gl_pathc == 0)
455 len = readlink(gl.gl_pathv[0], buf, buflen);
460 path = strrchr(buf, '/');
467 static void system_bridge_set_wireless(const char *bridge, const char *dev)
469 snprintf(dev_buf, sizeof(dev_buf),
470 "/sys/devices/virtual/net/%s/brif/%s/multicast_to_unicast",
472 system_set_sysctl(dev_buf, "1");
475 int system_bridge_addif(struct device *bridge, struct device *dev)
480 oldbr = system_get_bridge(dev->ifname, dev_buf, sizeof(dev_buf));
481 if (!oldbr || strcmp(oldbr, bridge->ifname) != 0)
482 ret = system_bridge_if(bridge->ifname, dev, SIOCBRADDIF, NULL);
485 system_bridge_set_wireless(bridge->ifname, dev->ifname);
490 int system_bridge_delif(struct device *bridge, struct device *dev)
492 return system_bridge_if(bridge->ifname, dev, SIOCBRDELIF, NULL);
495 static int system_if_resolve(struct device *dev)
498 strncpy(ifr.ifr_name, dev->ifname, sizeof(ifr.ifr_name));
499 if (!ioctl(sock_ioctl, SIOCGIFINDEX, &ifr))
500 return ifr.ifr_ifindex;
505 static int system_if_flags(const char *ifname, unsigned add, unsigned rem)
509 memset(&ifr, 0, sizeof(ifr));
510 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
511 ioctl(sock_ioctl, SIOCGIFFLAGS, &ifr);
512 ifr.ifr_flags |= add;
513 ifr.ifr_flags &= ~rem;
514 return ioctl(sock_ioctl, SIOCSIFFLAGS, &ifr);
526 static bool check_ifaddr(struct nlmsghdr *hdr, int ifindex)
528 struct ifaddrmsg *ifa = NLMSG_DATA(hdr);
530 return ifa->ifa_index == ifindex;
533 static bool check_route(struct nlmsghdr *hdr, int ifindex)
535 struct rtmsg *r = NLMSG_DATA(hdr);
536 struct nlattr *tb[__RTA_MAX];
538 if (r->rtm_protocol == RTPROT_KERNEL &&
539 r->rtm_family == AF_INET6)
542 nlmsg_parse(hdr, sizeof(struct rtmsg), tb, __RTA_MAX - 1, NULL);
546 return *(int *)RTA_DATA(tb[RTA_OIF]) == ifindex;
549 static bool check_rule(struct nlmsghdr *hdr, int ifindex)
554 static int cb_clear_event(struct nl_msg *msg, void *arg)
556 struct clear_data *clr = arg;
557 struct nlmsghdr *hdr = nlmsg_hdr(msg);
558 bool (*cb)(struct nlmsghdr *, int ifindex);
564 if (hdr->nlmsg_type != RTM_NEWADDR)
571 if (hdr->nlmsg_type != RTM_NEWROUTE)
578 if (hdr->nlmsg_type != RTM_NEWRULE)
587 if (!cb(hdr, clr->dev ? clr->dev->ifindex : 0))
590 if (type == RTM_DELRULE)
591 D(SYSTEM, "Remove a rule\n");
593 D(SYSTEM, "Remove %s from device %s\n",
594 type == RTM_DELADDR ? "an address" : "a route",
596 memcpy(nlmsg_hdr(clr->msg), hdr, hdr->nlmsg_len);
597 hdr = nlmsg_hdr(clr->msg);
598 hdr->nlmsg_type = type;
599 hdr->nlmsg_flags = NLM_F_REQUEST;
601 nl_socket_disable_auto_ack(sock_rtnl);
602 nl_send_auto_complete(sock_rtnl, clr->msg);
603 nl_socket_enable_auto_ack(sock_rtnl);
609 cb_finish_event(struct nl_msg *msg, void *arg)
617 error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
620 *pending = err->error;
625 system_if_clear_entries(struct device *dev, int type, int af)
627 struct clear_data clr;
628 struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
631 .rtm_flags = RTM_F_CLONED,
633 int flags = NLM_F_DUMP;
642 clr.size = sizeof(struct rtgenmsg);
645 clr.size = sizeof(struct rtmsg);
654 clr.msg = nlmsg_alloc_simple(type, flags);
658 nlmsg_append(clr.msg, &rtm, clr.size, 0);
659 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_clear_event, &clr);
660 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_finish_event, &pending);
661 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &pending);
663 nl_send_auto_complete(sock_rtnl, clr.msg);
665 nl_recvmsgs(sock_rtnl, cb);
673 * Clear bridge (membership) state and bring down device
675 void system_if_clear_state(struct device *dev)
677 static char buf[256];
680 device_set_ifindex(dev, system_if_resolve(dev));
681 if (dev->external || !dev->ifindex)
684 system_if_flags(dev->ifname, 0, IFF_UP);
686 if (system_is_bridge(dev->ifname, buf, sizeof(buf))) {
687 D(SYSTEM, "Delete existing bridge named '%s'\n", dev->ifname);
688 system_bridge_delbr(dev);
692 bridge = system_get_bridge(dev->ifname, buf, sizeof(buf));
694 D(SYSTEM, "Remove device '%s' from bridge '%s'\n", dev->ifname, bridge);
695 system_bridge_if(bridge, dev, SIOCBRDELIF, NULL);
698 system_if_clear_entries(dev, RTM_GETROUTE, AF_INET);
699 system_if_clear_entries(dev, RTM_GETADDR, AF_INET);
700 system_if_clear_entries(dev, RTM_GETROUTE, AF_INET6);
701 system_if_clear_entries(dev, RTM_GETADDR, AF_INET6);
702 system_set_disable_ipv6(dev, "0");
705 static inline unsigned long
706 sec_to_jiffies(int val)
708 return (unsigned long) val * 100;
711 int system_bridge_addbr(struct device *bridge, struct bridge_config *cfg)
713 unsigned long args[4] = {};
715 if (ioctl(sock_ioctl, SIOCBRADDBR, bridge->ifname) < 0)
718 args[0] = BRCTL_SET_BRIDGE_STP_STATE;
719 args[1] = !!cfg->stp;
720 system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
722 args[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
723 args[1] = sec_to_jiffies(cfg->forward_delay);
724 system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
726 system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_snooping",
727 bridge->ifname, cfg->igmp_snoop ? "1" : "0");
729 system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_querier",
730 bridge->ifname, cfg->igmp_snoop ? "1" : "0");
732 args[0] = BRCTL_SET_BRIDGE_PRIORITY;
733 args[1] = cfg->priority;
734 system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
736 if (cfg->flags & BRIDGE_OPT_AGEING_TIME) {
737 args[0] = BRCTL_SET_AGEING_TIME;
738 args[1] = sec_to_jiffies(cfg->ageing_time);
739 system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
742 if (cfg->flags & BRIDGE_OPT_HELLO_TIME) {
743 args[0] = BRCTL_SET_BRIDGE_HELLO_TIME;
744 args[1] = sec_to_jiffies(cfg->hello_time);
745 system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
748 if (cfg->flags & BRIDGE_OPT_MAX_AGE) {
749 args[0] = BRCTL_SET_BRIDGE_MAX_AGE;
750 args[1] = sec_to_jiffies(cfg->max_age);
751 system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
757 int system_macvlan_add(struct device *macvlan, struct device *dev, struct macvlan_config *cfg)
760 struct nlattr *linkinfo, *data;
761 struct ifinfomsg iim = { .ifi_family = AF_UNSPEC, };
762 int ifindex = system_if_resolve(dev);
764 static const struct {
766 enum macvlan_mode val;
768 { "private", MACVLAN_MODE_PRIVATE },
769 { "vepa", MACVLAN_MODE_VEPA },
770 { "bridge", MACVLAN_MODE_BRIDGE },
771 { "passthru", MACVLAN_MODE_PASSTHRU },
777 msg = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
782 nlmsg_append(msg, &iim, sizeof(iim), 0);
784 if (cfg->flags & MACVLAN_OPT_MACADDR)
785 nla_put(msg, IFLA_ADDRESS, sizeof(cfg->macaddr), cfg->macaddr);
786 nla_put_string(msg, IFLA_IFNAME, macvlan->ifname);
787 nla_put_u32(msg, IFLA_LINK, ifindex);
789 if (!(linkinfo = nla_nest_start(msg, IFLA_LINKINFO)))
790 goto nla_put_failure;
792 nla_put_string(msg, IFLA_INFO_KIND, "macvlan");
794 if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
795 goto nla_put_failure;
798 for (i = 0; i < ARRAY_SIZE(modes); i++) {
799 if (strcmp(cfg->mode, modes[i].name) != 0)
802 nla_put_u32(msg, IFLA_MACVLAN_MODE, modes[i].val);
807 nla_nest_end(msg, data);
808 nla_nest_end(msg, linkinfo);
810 rv = system_rtnl_call(msg);
812 D(SYSTEM, "Error adding macvlan '%s' over '%s': %d\n", macvlan->ifname, dev->ifname, rv);
821 static int system_link_del(const char *ifname)
824 struct ifinfomsg iim = {
825 .ifi_family = AF_UNSPEC,
829 msg = nlmsg_alloc_simple(RTM_DELLINK, NLM_F_REQUEST);
834 nlmsg_append(msg, &iim, sizeof(iim), 0);
835 nla_put_string(msg, IFLA_IFNAME, ifname);
836 return system_rtnl_call(msg);
839 int system_macvlan_del(struct device *macvlan)
841 return system_link_del(macvlan->ifname);
844 static int system_vlan(struct device *dev, int id)
846 struct vlan_ioctl_args ifr = {
847 .cmd = SET_VLAN_NAME_TYPE_CMD,
848 .u.name_type = VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD,
851 ioctl(sock_ioctl, SIOCSIFVLAN, &ifr);
854 ifr.cmd = DEL_VLAN_CMD;
857 ifr.cmd = ADD_VLAN_CMD;
860 strncpy(ifr.device1, dev->ifname, sizeof(ifr.device1));
861 return ioctl(sock_ioctl, SIOCSIFVLAN, &ifr);
864 int system_vlan_add(struct device *dev, int id)
866 return system_vlan(dev, id);
869 int system_vlan_del(struct device *dev)
871 return system_vlan(dev, -1);
874 int system_vlandev_add(struct device *vlandev, struct device *dev, struct vlandev_config *cfg)
877 struct nlattr *linkinfo, *data;
878 struct ifinfomsg iim = { .ifi_family = AF_UNSPEC };
879 int ifindex = system_if_resolve(dev);
885 msg = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
890 nlmsg_append(msg, &iim, sizeof(iim), 0);
891 nla_put_string(msg, IFLA_IFNAME, vlandev->ifname);
892 nla_put_u32(msg, IFLA_LINK, ifindex);
894 if (!(linkinfo = nla_nest_start(msg, IFLA_LINKINFO)))
895 goto nla_put_failure;
897 nla_put_string(msg, IFLA_INFO_KIND, "vlan");
899 if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
900 goto nla_put_failure;
902 nla_put_u16(msg, IFLA_VLAN_ID, cfg->vid);
904 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
905 nla_put_u16(msg, IFLA_VLAN_PROTOCOL, htons(cfg->proto));
907 if(cfg->proto == VLAN_PROTO_8021AD)
908 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);
911 nla_nest_end(msg, data);
912 nla_nest_end(msg, linkinfo);
914 rv = system_rtnl_call(msg);
916 D(SYSTEM, "Error adding vlandev '%s' over '%s': %d\n", vlandev->ifname, dev->ifname, rv);
925 int system_vlandev_del(struct device *vlandev)
927 return system_link_del(vlandev->ifname);
931 system_if_get_settings(struct device *dev, struct device_settings *s)
936 memset(&ifr, 0, sizeof(ifr));
937 strncpy(ifr.ifr_name, dev->ifname, sizeof(ifr.ifr_name));
939 if (ioctl(sock_ioctl, SIOCGIFMTU, &ifr) == 0) {
940 s->mtu = ifr.ifr_mtu;
941 s->flags |= DEV_OPT_MTU;
944 if (ioctl(sock_ioctl, SIOCGIFTXQLEN, &ifr) == 0) {
945 s->txqueuelen = ifr.ifr_qlen;
946 s->flags |= DEV_OPT_TXQUEUELEN;
949 if (ioctl(sock_ioctl, SIOCGIFHWADDR, &ifr) == 0) {
950 memcpy(s->macaddr, &ifr.ifr_hwaddr.sa_data, sizeof(s->macaddr));
951 s->flags |= DEV_OPT_MACADDR;
954 if (!system_get_disable_ipv6(dev, buf, sizeof(buf))) {
955 s->ipv6 = !strtoul(buf, NULL, 0);
956 s->flags |= DEV_OPT_IPV6;
959 if (ioctl(sock_ioctl, SIOCGIFFLAGS, &ifr) == 0) {
960 s->promisc = ifr.ifr_flags & IFF_PROMISC;
961 s->flags |= DEV_OPT_PROMISC;
966 system_if_apply_settings(struct device *dev, struct device_settings *s, unsigned int apply_mask)
973 memset(&ifr, 0, sizeof(ifr));
974 strncpy(ifr.ifr_name, dev->ifname, sizeof(ifr.ifr_name));
975 if (s->flags & DEV_OPT_MTU & apply_mask) {
976 ifr.ifr_mtu = s->mtu;
977 if (ioctl(sock_ioctl, SIOCSIFMTU, &ifr) < 0)
978 s->flags &= ~DEV_OPT_MTU;
980 if (s->flags & DEV_OPT_TXQUEUELEN & apply_mask) {
981 ifr.ifr_qlen = s->txqueuelen;
982 if (ioctl(sock_ioctl, SIOCSIFTXQLEN, &ifr) < 0)
983 s->flags &= ~DEV_OPT_TXQUEUELEN;
985 if ((s->flags & DEV_OPT_MACADDR & apply_mask) && !dev->external) {
986 ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
987 memcpy(&ifr.ifr_hwaddr.sa_data, s->macaddr, sizeof(s->macaddr));
988 if (ioctl(sock_ioctl, SIOCSIFHWADDR, &ifr) < 0)
989 s->flags &= ~DEV_OPT_MACADDR;
991 if (s->flags & DEV_OPT_IPV6 & apply_mask)
992 system_set_disable_ipv6(dev, s->ipv6 ? "0" : "1");
993 if (s->flags & DEV_OPT_PROMISC & apply_mask) {
994 if (system_if_flags(dev->ifname, s->promisc ? IFF_PROMISC : 0,
995 !s->promisc ? IFF_PROMISC : 0) < 0)
996 s->flags &= ~DEV_OPT_PROMISC;
1000 int system_if_up(struct device *dev)
1002 system_if_get_settings(dev, &dev->orig_settings);
1003 system_if_apply_settings(dev, &dev->settings, dev->settings.flags);
1004 device_set_ifindex(dev, system_if_resolve(dev));
1005 return system_if_flags(dev->ifname, IFF_UP, 0);
1008 int system_if_down(struct device *dev)
1010 int ret = system_if_flags(dev->ifname, 0, IFF_UP);
1011 dev->orig_settings.flags &= dev->settings.flags;
1012 system_if_apply_settings(dev, &dev->orig_settings, dev->orig_settings.flags);
1016 struct if_check_data {
1022 static int cb_if_check_valid(struct nl_msg *msg, void *arg)
1024 struct nlmsghdr *nh = nlmsg_hdr(msg);
1025 struct ifinfomsg *ifi = NLMSG_DATA(nh);
1026 struct if_check_data *chk = (struct if_check_data *)arg;
1028 if (nh->nlmsg_type != RTM_NEWLINK)
1031 device_set_present(chk->dev, ifi->ifi_index > 0 ? true : false);
1032 device_set_link(chk->dev, ifi->ifi_flags & IFF_LOWER_UP ? true : false);
1037 static int cb_if_check_ack(struct nl_msg *msg, void *arg)
1039 struct if_check_data *chk = (struct if_check_data *)arg;
1044 static int cb_if_check_error(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
1046 struct if_check_data *chk = (struct if_check_data *)arg;
1048 device_set_present(chk->dev, false);
1049 device_set_link(chk->dev, false);
1050 chk->pending = err->error;
1055 int system_if_check(struct device *dev)
1057 struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
1059 struct ifinfomsg ifi = {
1060 .ifi_family = AF_UNSPEC,
1063 struct if_check_data chk = {
1069 msg = nlmsg_alloc_simple(RTM_GETLINK, 0);
1070 if (!msg || nlmsg_append(msg, &ifi, sizeof(ifi), 0) ||
1071 nla_put_string(msg, IFLA_IFNAME, dev->ifname))
1074 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_if_check_valid, &chk);
1075 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, cb_if_check_ack, &chk);
1076 nl_cb_err(cb, NL_CB_CUSTOM, cb_if_check_error, &chk);
1078 nl_send_auto_complete(sock_rtnl, msg);
1079 while (chk.pending > 0)
1080 nl_recvmsgs(sock_rtnl, cb);
1091 system_if_get_parent(struct device *dev)
1093 char buf[64], *devname;
1094 int ifindex, iflink, len;
1097 snprintf(buf, sizeof(buf), "/sys/class/net/%s/iflink", dev->ifname);
1098 f = fopen(buf, "r");
1102 len = fread(buf, 1, sizeof(buf) - 1, f);
1109 iflink = strtoul(buf, NULL, 0);
1110 ifindex = system_if_resolve(dev);
1111 if (!iflink || iflink == ifindex)
1114 devname = if_indextoname(iflink, buf);
1118 return device_get(devname, true);
1122 read_string_file(int dir_fd, const char *file, char *buf, int len)
1128 fd = openat(dir_fd, file, O_RDONLY);
1133 len = read(fd, buf, len - 1);
1137 } else if (len > 0) {
1140 c = strchr(buf, '\n');
1153 read_uint64_file(int dir_fd, const char *file, uint64_t *val)
1158 ret = read_string_file(dir_fd, file, buf, sizeof(buf));
1160 *val = strtoull(buf, NULL, 0);
1165 /* Assume advertised flags == supported flags */
1166 static const struct {
1169 } ethtool_link_modes[] = {
1170 { ADVERTISED_10baseT_Half, "10H" },
1171 { ADVERTISED_10baseT_Full, "10F" },
1172 { ADVERTISED_100baseT_Half, "100H" },
1173 { ADVERTISED_100baseT_Full, "100F" },
1174 { ADVERTISED_1000baseT_Half, "1000H" },
1175 { ADVERTISED_1000baseT_Full, "1000F" },
1178 static void system_add_link_modes(struct blob_buf *b, __u32 mask)
1181 for (i = 0; i < ARRAY_SIZE(ethtool_link_modes); i++) {
1182 if (mask & ethtool_link_modes[i].mask)
1183 blobmsg_add_string(b, NULL, ethtool_link_modes[i].name);
1188 system_if_force_external(const char *ifname)
1193 snprintf(buf, sizeof(buf), "/sys/class/net/%s/phy80211", ifname);
1194 return stat(buf, &s) == 0;
1198 system_if_dump_info(struct device *dev, struct blob_buf *b)
1200 struct ethtool_cmd ecmd;
1206 snprintf(buf, sizeof(buf), "/sys/class/net/%s", dev->ifname);
1207 dir_fd = open(buf, O_DIRECTORY);
1209 memset(&ecmd, 0, sizeof(ecmd));
1210 memset(&ifr, 0, sizeof(ifr));
1211 strcpy(ifr.ifr_name, dev->ifname);
1212 ifr.ifr_data = (caddr_t) &ecmd;
1213 ecmd.cmd = ETHTOOL_GSET;
1215 if (ioctl(sock_ioctl, SIOCETHTOOL, &ifr) == 0) {
1216 c = blobmsg_open_array(b, "link-advertising");
1217 system_add_link_modes(b, ecmd.advertising);
1218 blobmsg_close_array(b, c);
1220 c = blobmsg_open_array(b, "link-supported");
1221 system_add_link_modes(b, ecmd.supported);
1222 blobmsg_close_array(b, c);
1224 s = blobmsg_alloc_string_buffer(b, "speed", 8);
1225 snprintf(s, 8, "%d%c", ethtool_cmd_speed(&ecmd),
1226 ecmd.duplex == DUPLEX_HALF ? 'H' : 'F');
1227 blobmsg_add_string_buffer(b);
1235 system_if_dump_stats(struct device *dev, struct blob_buf *b)
1237 const char *const counters[] = {
1238 "collisions", "rx_frame_errors", "tx_compressed",
1239 "multicast", "rx_length_errors", "tx_dropped",
1240 "rx_bytes", "rx_missed_errors", "tx_errors",
1241 "rx_compressed", "rx_over_errors", "tx_fifo_errors",
1242 "rx_crc_errors", "rx_packets", "tx_heartbeat_errors",
1243 "rx_dropped", "tx_aborted_errors", "tx_packets",
1244 "rx_errors", "tx_bytes", "tx_window_errors",
1245 "rx_fifo_errors", "tx_carrier_errors",
1252 snprintf(buf, sizeof(buf), "/sys/class/net/%s/statistics", dev->ifname);
1253 stats_dir = open(buf, O_DIRECTORY);
1257 for (i = 0; i < ARRAY_SIZE(counters); i++)
1258 if (read_uint64_file(stats_dir, counters[i], &val))
1259 blobmsg_add_u64(b, counters[i], val);
1265 static int system_addr(struct device *dev, struct device_addr *addr, int cmd)
1267 bool v4 = ((addr->flags & DEVADDR_FAMILY) == DEVADDR_INET4);
1268 int alen = v4 ? 4 : 16;
1269 unsigned int flags = 0;
1270 struct ifaddrmsg ifa = {
1271 .ifa_family = (alen == 4) ? AF_INET : AF_INET6,
1272 .ifa_prefixlen = addr->mask,
1273 .ifa_index = dev->ifindex,
1277 if (cmd == RTM_NEWADDR)
1278 flags |= NLM_F_CREATE | NLM_F_REPLACE;
1280 msg = nlmsg_alloc_simple(cmd, flags);
1284 nlmsg_append(msg, &ifa, sizeof(ifa), 0);
1285 nla_put(msg, IFA_LOCAL, alen, &addr->addr);
1287 if (addr->broadcast)
1288 nla_put_u32(msg, IFA_BROADCAST, addr->broadcast);
1289 if (addr->point_to_point)
1290 nla_put_u32(msg, IFA_ADDRESS, addr->point_to_point);
1292 time_t now = system_get_rtime();
1293 struct ifa_cacheinfo cinfo = {0xffffffffU, 0xffffffffU, 0, 0};
1295 if (addr->preferred_until) {
1296 int64_t preferred = addr->preferred_until - now;
1299 else if (preferred > UINT32_MAX)
1300 preferred = UINT32_MAX;
1302 cinfo.ifa_prefered = preferred;
1305 if (addr->valid_until) {
1306 int64_t valid = addr->valid_until - now;
1309 else if (valid > UINT32_MAX)
1312 cinfo.ifa_valid = valid;
1315 nla_put(msg, IFA_CACHEINFO, sizeof(cinfo), &cinfo);
1318 return system_rtnl_call(msg);
1321 int system_add_address(struct device *dev, struct device_addr *addr)
1323 return system_addr(dev, addr, RTM_NEWADDR);
1326 int system_del_address(struct device *dev, struct device_addr *addr)
1328 return system_addr(dev, addr, RTM_DELADDR);
1331 static int system_rt(struct device *dev, struct device_route *route, int cmd)
1333 int alen = ((route->flags & DEVADDR_FAMILY) == DEVADDR_INET4) ? 4 : 16;
1335 unsigned int flags = 0;
1338 have_gw = !!route->nexthop.in.s_addr;
1340 have_gw = route->nexthop.in6.s6_addr32[0] ||
1341 route->nexthop.in6.s6_addr32[1] ||
1342 route->nexthop.in6.s6_addr32[2] ||
1343 route->nexthop.in6.s6_addr32[3];
1345 unsigned int table = (route->flags & (DEVROUTE_TABLE | DEVROUTE_SRCTABLE))
1346 ? route->table : RT_TABLE_MAIN;
1348 struct rtmsg rtm = {
1349 .rtm_family = (alen == 4) ? AF_INET : AF_INET6,
1350 .rtm_dst_len = route->mask,
1351 .rtm_src_len = route->sourcemask,
1352 .rtm_table = (table < 256) ? table : RT_TABLE_UNSPEC,
1353 .rtm_protocol = (route->flags & DEVADDR_KERNEL) ? RTPROT_KERNEL : RTPROT_STATIC,
1354 .rtm_scope = RT_SCOPE_NOWHERE,
1355 .rtm_type = (cmd == RTM_DELROUTE) ? 0: RTN_UNICAST,
1356 .rtm_flags = (route->flags & DEVROUTE_ONLINK) ? RTNH_F_ONLINK : 0,
1360 if (cmd == RTM_NEWROUTE) {
1361 flags |= NLM_F_CREATE | NLM_F_REPLACE;
1363 if (!dev) { // Add null-route
1364 rtm.rtm_scope = RT_SCOPE_UNIVERSE;
1365 rtm.rtm_type = RTN_UNREACHABLE;
1368 rtm.rtm_scope = (have_gw) ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK;
1371 if (route->flags & DEVROUTE_TYPE) {
1372 rtm.rtm_type = route->type;
1373 if (!(route->flags & (DEVROUTE_TABLE | DEVROUTE_SRCTABLE))) {
1374 if (rtm.rtm_type == RTN_LOCAL || rtm.rtm_type == RTN_BROADCAST ||
1375 rtm.rtm_type == RTN_NAT || rtm.rtm_type == RTN_ANYCAST)
1376 rtm.rtm_table = RT_TABLE_LOCAL;
1379 if (rtm.rtm_type == RTN_LOCAL || rtm.rtm_type == RTN_NAT)
1380 rtm.rtm_scope = RT_SCOPE_HOST;
1381 else if (rtm.rtm_type == RTN_BROADCAST || rtm.rtm_type == RTN_MULTICAST ||
1382 rtm.rtm_type == RTN_ANYCAST)
1383 rtm.rtm_scope = RT_SCOPE_LINK;
1386 msg = nlmsg_alloc_simple(cmd, flags);
1390 nlmsg_append(msg, &rtm, sizeof(rtm), 0);
1393 nla_put(msg, RTA_DST, alen, &route->addr);
1395 if (route->sourcemask)
1396 nla_put(msg, RTA_SRC, alen, &route->source);
1398 if (route->metric > 0)
1399 nla_put_u32(msg, RTA_PRIORITY, route->metric);
1402 nla_put(msg, RTA_GATEWAY, alen, &route->nexthop);
1405 nla_put_u32(msg, RTA_OIF, dev->ifindex);
1408 nla_put_u32(msg, RTA_TABLE, table);
1410 if (route->flags & DEVROUTE_MTU) {
1411 struct nlattr *metrics;
1413 if (!(metrics = nla_nest_start(msg, RTA_METRICS)))
1414 goto nla_put_failure;
1416 nla_put_u32(msg, RTAX_MTU, route->mtu);
1418 nla_nest_end(msg, metrics);
1421 return system_rtnl_call(msg);
1428 int system_add_route(struct device *dev, struct device_route *route)
1430 return system_rt(dev, route, RTM_NEWROUTE);
1433 int system_del_route(struct device *dev, struct device_route *route)
1435 return system_rt(dev, route, RTM_DELROUTE);
1438 int system_flush_routes(void)
1440 const char *names[] = {
1441 "/proc/sys/net/ipv4/route/flush",
1442 "/proc/sys/net/ipv6/route/flush"
1446 for (i = 0; i < ARRAY_SIZE(names); i++) {
1447 fd = open(names[i], O_WRONLY);
1451 if (write(fd, "-1", 2)) {}
1457 bool system_resolve_rt_type(const char *type, unsigned int *id)
1459 return system_rtn_aton(type, id);
1462 bool system_resolve_rt_table(const char *name, unsigned int *id)
1466 unsigned int n, table = RT_TABLE_UNSPEC;
1468 /* first try to parse table as number */
1469 if ((n = strtoul(name, &e, 0)) > 0 && !*e)
1472 /* handle well known aliases */
1473 else if (!strcmp(name, "default"))
1474 table = RT_TABLE_DEFAULT;
1475 else if (!strcmp(name, "main"))
1476 table = RT_TABLE_MAIN;
1477 else if (!strcmp(name, "local"))
1478 table = RT_TABLE_LOCAL;
1480 /* try to look up name in /etc/iproute2/rt_tables */
1481 else if ((f = fopen("/etc/iproute2/rt_tables", "r")) != NULL)
1483 while (fgets(buf, sizeof(buf) - 1, f) != NULL)
1485 if ((e = strtok(buf, " \t\n")) == NULL || *e == '#')
1488 n = strtoul(e, NULL, 10);
1489 e = strtok(NULL, " \t\n");
1491 if (e && !strcmp(e, name))
1501 if (table == RT_TABLE_UNSPEC)
1508 bool system_is_default_rt_table(unsigned int id)
1510 return (id == RT_TABLE_MAIN);
1513 static int system_iprule(struct iprule *rule, int cmd)
1515 int alen = ((rule->flags & IPRULE_FAMILY) == IPRULE_INET4) ? 4 : 16;
1518 struct rtmsg rtm = {
1519 .rtm_family = (alen == 4) ? AF_INET : AF_INET6,
1520 .rtm_protocol = RTPROT_STATIC,
1521 .rtm_scope = RT_SCOPE_UNIVERSE,
1522 .rtm_table = RT_TABLE_UNSPEC,
1523 .rtm_type = RTN_UNSPEC,
1527 if (cmd == RTM_NEWRULE) {
1528 rtm.rtm_type = RTN_UNICAST;
1529 rtm.rtm_flags |= NLM_F_REPLACE | NLM_F_EXCL;
1533 rtm.rtm_flags |= FIB_RULE_INVERT;
1535 if (rule->flags & IPRULE_SRC)
1536 rtm.rtm_src_len = rule->src_mask;
1538 if (rule->flags & IPRULE_DEST)
1539 rtm.rtm_dst_len = rule->dest_mask;
1541 if (rule->flags & IPRULE_TOS)
1542 rtm.rtm_tos = rule->tos;
1544 if (rule->flags & IPRULE_LOOKUP) {
1545 if (rule->lookup < 256)
1546 rtm.rtm_table = rule->lookup;
1549 if (rule->flags & IPRULE_ACTION)
1550 rtm.rtm_type = rule->action;
1551 else if (rule->flags & IPRULE_GOTO)
1552 rtm.rtm_type = FR_ACT_GOTO;
1553 else if (!(rule->flags & (IPRULE_LOOKUP | IPRULE_ACTION | IPRULE_GOTO)))
1554 rtm.rtm_type = FR_ACT_NOP;
1556 msg = nlmsg_alloc_simple(cmd, NLM_F_REQUEST);
1561 nlmsg_append(msg, &rtm, sizeof(rtm), 0);
1563 if (rule->flags & IPRULE_IN)
1564 nla_put(msg, FRA_IFNAME, strlen(rule->in_dev) + 1, rule->in_dev);
1566 if (rule->flags & IPRULE_OUT)
1567 nla_put(msg, FRA_OIFNAME, strlen(rule->out_dev) + 1, rule->out_dev);
1569 if (rule->flags & IPRULE_SRC)
1570 nla_put(msg, FRA_SRC, alen, &rule->src_addr);
1572 if (rule->flags & IPRULE_DEST)
1573 nla_put(msg, FRA_DST, alen, &rule->dest_addr);
1575 if (rule->flags & IPRULE_PRIORITY)
1576 nla_put_u32(msg, FRA_PRIORITY, rule->priority);
1577 else if (cmd == RTM_NEWRULE)
1578 nla_put_u32(msg, FRA_PRIORITY, rule->order);
1580 if (rule->flags & IPRULE_FWMARK)
1581 nla_put_u32(msg, FRA_FWMARK, rule->fwmark);
1583 if (rule->flags & IPRULE_FWMASK)
1584 nla_put_u32(msg, FRA_FWMASK, rule->fwmask);
1586 if (rule->flags & IPRULE_LOOKUP) {
1587 if (rule->lookup >= 256)
1588 nla_put_u32(msg, FRA_TABLE, rule->lookup);
1591 if (rule->flags & IPRULE_GOTO)
1592 nla_put_u32(msg, FRA_GOTO, rule->gotoid);
1594 return system_rtnl_call(msg);
1597 int system_add_iprule(struct iprule *rule)
1599 return system_iprule(rule, RTM_NEWRULE);
1602 int system_del_iprule(struct iprule *rule)
1604 return system_iprule(rule, RTM_DELRULE);
1607 int system_flush_iprules(void)
1612 system_if_clear_entries(NULL, RTM_GETRULE, AF_INET);
1613 system_if_clear_entries(NULL, RTM_GETRULE, AF_INET6);
1615 memset(&rule, 0, sizeof(rule));
1618 rule.flags = IPRULE_INET4 | IPRULE_PRIORITY | IPRULE_LOOKUP;
1621 rule.lookup = RT_TABLE_LOCAL;
1622 rv |= system_iprule(&rule, RTM_NEWRULE);
1624 rule.priority = 32766;
1625 rule.lookup = RT_TABLE_MAIN;
1626 rv |= system_iprule(&rule, RTM_NEWRULE);
1628 rule.priority = 32767;
1629 rule.lookup = RT_TABLE_DEFAULT;
1630 rv |= system_iprule(&rule, RTM_NEWRULE);
1633 rule.flags = IPRULE_INET6 | IPRULE_PRIORITY | IPRULE_LOOKUP;
1636 rule.lookup = RT_TABLE_LOCAL;
1637 rv |= system_iprule(&rule, RTM_NEWRULE);
1639 rule.priority = 32766;
1640 rule.lookup = RT_TABLE_MAIN;
1641 rv |= system_iprule(&rule, RTM_NEWRULE);
1646 bool system_resolve_iprule_action(const char *action, unsigned int *id)
1648 return system_rtn_aton(action, id);
1651 time_t system_get_rtime(void)
1656 if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, &ts) == 0)
1659 if (gettimeofday(&tv, NULL) == 0)
1666 #define IP_DF 0x4000
1669 static int tunnel_ioctl(const char *name, int cmd, void *p)
1673 memset(&ifr, 0, sizeof(ifr));
1674 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1675 ifr.ifr_ifru.ifru_data = p;
1676 return ioctl(sock_ioctl, cmd, &ifr);
1679 #ifdef IFLA_IPTUN_MAX
1680 #define IP6_FLOWINFO_TCLASS htonl(0x0FF00000)
1681 static int system_add_gre_tunnel(const char *name, const char *kind,
1682 const unsigned int link, struct blob_attr **tb, bool v6)
1685 struct ifinfomsg ifi = { .ifi_family = AF_UNSPEC, };
1686 struct blob_attr *cur;
1687 uint32_t ikey = 0, okey = 0, flags = 0, flowinfo = 0;
1688 uint16_t iflags = 0, oflags = 0;
1690 int ret = 0, ttl = 64;
1692 nlm = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_CREATE);
1696 nlmsg_append(nlm, &ifi, sizeof(ifi), 0);
1697 nla_put_string(nlm, IFLA_IFNAME, name);
1699 struct nlattr *linkinfo = nla_nest_start(nlm, IFLA_LINKINFO);
1705 nla_put_string(nlm, IFLA_INFO_KIND, kind);
1706 struct nlattr *infodata = nla_nest_start(nlm, IFLA_INFO_DATA);
1713 nla_put_u32(nlm, IFLA_GRE_LINK, link);
1715 if ((cur = tb[TUNNEL_ATTR_TTL]))
1716 ttl = blobmsg_get_u32(cur);
1718 nla_put_u8(nlm, IFLA_GRE_TTL, ttl);
1720 if ((cur = tb[TUNNEL_ATTR_TOS])) {
1721 char *str = blobmsg_get_string(cur);
1722 if (strcmp(str, "inherit")) {
1725 if (!system_tos_aton(str, &uval)) {
1731 flowinfo |= htonl(uval << 20) & IP6_FLOWINFO_TCLASS;
1736 flags |= IP6_TNL_F_USE_ORIG_TCLASS;
1742 if ((cur = tb[TUNNEL_ATTR_INFO]) && (blobmsg_type(cur) == BLOBMSG_TYPE_STRING)) {
1743 uint8_t icsum, ocsum, iseqno, oseqno;
1744 if (sscanf(blobmsg_get_string(cur), "%u,%u,%hhu,%hhu,%hhu,%hhu",
1745 &ikey, &okey, &icsum, &ocsum, &iseqno, &oseqno) < 6) {
1770 struct in6_addr in6buf;
1771 if ((cur = tb[TUNNEL_ATTR_LOCAL])) {
1772 if (inet_pton(AF_INET6, blobmsg_data(cur), &in6buf) < 1) {
1776 nla_put(nlm, IFLA_GRE_LOCAL, sizeof(in6buf), &in6buf);
1779 if ((cur = tb[TUNNEL_ATTR_REMOTE])) {
1780 if (inet_pton(AF_INET6, blobmsg_data(cur), &in6buf) < 1) {
1784 nla_put(nlm, IFLA_GRE_REMOTE, sizeof(in6buf), &in6buf);
1786 nla_put_u8(nlm, IFLA_GRE_ENCAP_LIMIT, 4);
1789 nla_put_u32(nlm, IFLA_GRE_FLOWINFO, flowinfo);
1792 nla_put_u32(nlm, IFLA_GRE_FLAGS, flags);
1794 struct in_addr inbuf;
1797 if ((cur = tb[TUNNEL_ATTR_LOCAL])) {
1798 if (inet_pton(AF_INET, blobmsg_data(cur), &inbuf) < 1) {
1802 nla_put(nlm, IFLA_GRE_LOCAL, sizeof(inbuf), &inbuf);
1805 if ((cur = tb[TUNNEL_ATTR_REMOTE])) {
1806 if (inet_pton(AF_INET, blobmsg_data(cur), &inbuf) < 1) {
1810 nla_put(nlm, IFLA_GRE_REMOTE, sizeof(inbuf), &inbuf);
1812 if (IN_MULTICAST(ntohl(inbuf.s_addr))) {
1814 okey = inbuf.s_addr;
1819 ikey = inbuf.s_addr;
1825 if ((cur = tb[TUNNEL_ATTR_DF]))
1826 set_df = blobmsg_get_bool(cur);
1828 /* ttl !=0 and nopmtudisc are incompatible */
1829 if (ttl && !set_df) {
1834 nla_put_u8(nlm, IFLA_GRE_PMTUDISC, set_df ? 1 : 0);
1836 nla_put_u8(nlm, IFLA_GRE_TOS, tos);
1840 nla_put_u16(nlm, IFLA_GRE_OFLAGS, oflags);
1843 nla_put_u16(nlm, IFLA_GRE_IFLAGS, iflags);
1846 nla_put_u32(nlm, IFLA_GRE_OKEY, okey);
1849 nla_put_u32(nlm, IFLA_GRE_IKEY, ikey);
1851 nla_nest_end(nlm, infodata);
1852 nla_nest_end(nlm, linkinfo);
1854 return system_rtnl_call(nlm);
1862 static int system_add_proto_tunnel(const char *name, const uint8_t proto, const unsigned int link, struct blob_attr **tb)
1864 struct blob_attr *cur;
1866 struct ip_tunnel_parm p = {
1875 if ((cur = tb[TUNNEL_ATTR_LOCAL]) &&
1876 inet_pton(AF_INET, blobmsg_data(cur), &p.iph.saddr) < 1)
1879 if ((cur = tb[TUNNEL_ATTR_REMOTE]) &&
1880 inet_pton(AF_INET, blobmsg_data(cur), &p.iph.daddr) < 1)
1883 if ((cur = tb[TUNNEL_ATTR_DF]))
1884 set_df = blobmsg_get_bool(cur);
1886 if ((cur = tb[TUNNEL_ATTR_TTL]))
1887 p.iph.ttl = blobmsg_get_u32(cur);
1889 if ((cur = tb[TUNNEL_ATTR_TOS])) {
1890 char *str = blobmsg_get_string(cur);
1891 if (strcmp(str, "inherit")) {
1894 if (!system_tos_aton(str, &uval))
1902 p.iph.frag_off = set_df ? htons(IP_DF) : 0;
1903 /* ttl !=0 and nopmtudisc are incompatible */
1904 if (p.iph.ttl && p.iph.frag_off == 0)
1907 strncpy(p.name, name, sizeof(p.name));
1909 switch (p.iph.protocol) {
1911 return tunnel_ioctl("tunl0", SIOCADDTUNNEL, &p);
1913 return tunnel_ioctl("sit0", SIOCADDTUNNEL, &p);
1920 static int __system_del_ip_tunnel(const char *name, struct blob_attr **tb)
1922 struct blob_attr *cur;
1925 if (!(cur = tb[TUNNEL_ATTR_TYPE]))
1927 str = blobmsg_data(cur);
1929 if (!strcmp(str, "greip") || !strcmp(str, "gretapip") ||
1930 !strcmp(str, "greip6") || !strcmp(str, "gretapip6"))
1931 return system_link_del(name);
1933 return tunnel_ioctl(name, SIOCDELTUNNEL, NULL);
1936 int system_del_ip_tunnel(const char *name, struct blob_attr *attr)
1938 struct blob_attr *tb[__TUNNEL_ATTR_MAX];
1940 blobmsg_parse(tunnel_attr_list.params, __TUNNEL_ATTR_MAX, tb,
1941 blob_data(attr), blob_len(attr));
1943 return __system_del_ip_tunnel(name, tb);
1946 int system_update_ipv6_mtu(struct device *dev, int mtu)
1950 snprintf(buf, sizeof(buf), "/proc/sys/net/ipv6/conf/%s/mtu",
1953 int fd = open(buf, O_RDWR);
1954 ssize_t len = read(fd, buf, sizeof(buf) - 1);
1961 if (!mtu || ret <= mtu)
1964 lseek(fd, 0, SEEK_SET);
1965 if (write(fd, buf, snprintf(buf, sizeof(buf), "%i", mtu)) <= 0)
1973 int system_add_ip_tunnel(const char *name, struct blob_attr *attr)
1975 struct blob_attr *tb[__TUNNEL_ATTR_MAX];
1976 struct blob_attr *cur;
1979 blobmsg_parse(tunnel_attr_list.params, __TUNNEL_ATTR_MAX, tb,
1980 blob_data(attr), blob_len(attr));
1982 __system_del_ip_tunnel(name, tb);
1984 if (!(cur = tb[TUNNEL_ATTR_TYPE]))
1986 str = blobmsg_data(cur);
1988 unsigned int ttl = 0;
1989 if ((cur = tb[TUNNEL_ATTR_TTL])) {
1990 ttl = blobmsg_get_u32(cur);
1995 unsigned int link = 0;
1996 if ((cur = tb[TUNNEL_ATTR_LINK])) {
1997 struct interface *iface = vlist_find(&interfaces, blobmsg_data(cur), iface, node);
2001 if (iface->l3_dev.dev)
2002 link = iface->l3_dev.dev->ifindex;
2005 if (!strcmp(str, "sit")) {
2006 if (system_add_proto_tunnel(name, IPPROTO_IPV6, link, tb) < 0)
2010 if ((cur = tb[TUNNEL_ATTR_6RD_PREFIX])) {
2012 struct ip_tunnel_6rd p6;
2014 memset(&p6, 0, sizeof(p6));
2016 if (!parse_ip_and_netmask(AF_INET6, blobmsg_data(cur),
2017 &p6.prefix, &mask) || mask > 128)
2019 p6.prefixlen = mask;
2021 if ((cur = tb[TUNNEL_ATTR_6RD_RELAY_PREFIX])) {
2022 if (!parse_ip_and_netmask(AF_INET, blobmsg_data(cur),
2023 &p6.relay_prefix, &mask) || mask > 32)
2025 p6.relay_prefixlen = mask;
2028 if (tunnel_ioctl(name, SIOCADD6RD, &p6) < 0) {
2029 __system_del_ip_tunnel(name, tb);
2034 #ifdef IFLA_IPTUN_MAX
2035 } else if (!strcmp(str, "ipip6")) {
2036 struct nl_msg *nlm = nlmsg_alloc_simple(RTM_NEWLINK,
2037 NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_CREATE);
2038 struct ifinfomsg ifi = { .ifi_family = AF_UNSPEC };
2044 nlmsg_append(nlm, &ifi, sizeof(ifi), 0);
2045 nla_put_string(nlm, IFLA_IFNAME, name);
2048 nla_put_u32(nlm, IFLA_LINK, link);
2050 struct nlattr *linkinfo = nla_nest_start(nlm, IFLA_LINKINFO);
2055 nla_put_string(nlm, IFLA_INFO_KIND, "ip6tnl");
2056 struct nlattr *infodata = nla_nest_start(nlm, IFLA_INFO_DATA);
2063 nla_put_u32(nlm, IFLA_IPTUN_LINK, link);
2065 nla_put_u8(nlm, IFLA_IPTUN_PROTO, IPPROTO_IPIP);
2066 nla_put_u8(nlm, IFLA_IPTUN_TTL, (ttl) ? ttl : 64);
2067 nla_put_u8(nlm, IFLA_IPTUN_ENCAP_LIMIT, 4);
2069 struct in6_addr in6buf;
2070 if ((cur = tb[TUNNEL_ATTR_LOCAL])) {
2071 if (inet_pton(AF_INET6, blobmsg_data(cur), &in6buf) < 1) {
2075 nla_put(nlm, IFLA_IPTUN_LOCAL, sizeof(in6buf), &in6buf);
2078 if ((cur = tb[TUNNEL_ATTR_REMOTE])) {
2079 if (inet_pton(AF_INET6, blobmsg_data(cur), &in6buf) < 1) {
2083 nla_put(nlm, IFLA_IPTUN_REMOTE, sizeof(in6buf), &in6buf);
2086 #ifdef IFLA_IPTUN_FMR_MAX
2087 if ((cur = tb[TUNNEL_ATTR_FMRS])) {
2088 struct nlattr *fmrs = nla_nest_start(nlm, IFLA_IPTUN_FMRS);
2090 struct blob_attr *fmr;
2091 unsigned rem, fmrcnt = 0;
2092 blobmsg_for_each_attr(fmr, cur, rem) {
2093 if (blobmsg_type(fmr) != BLOBMSG_TYPE_STRING)
2096 unsigned ip4len, ip6len, ealen, offset = 6;
2100 if (sscanf(blobmsg_get_string(fmr), "%47[^/]/%u,%15[^/]/%u,%u,%u",
2101 ip6buf, &ip6len, ip4buf, &ip4len, &ealen, &offset) < 5) {
2106 struct in6_addr ip6prefix;
2107 struct in_addr ip4prefix;
2108 if (inet_pton(AF_INET6, ip6buf, &ip6prefix) != 1 ||
2109 inet_pton(AF_INET, ip4buf, &ip4prefix) != 1) {
2114 struct nlattr *rule = nla_nest_start(nlm, ++fmrcnt);
2116 nla_put(nlm, IFLA_IPTUN_FMR_IP6_PREFIX, sizeof(ip6prefix), &ip6prefix);
2117 nla_put(nlm, IFLA_IPTUN_FMR_IP4_PREFIX, sizeof(ip4prefix), &ip4prefix);
2118 nla_put_u8(nlm, IFLA_IPTUN_FMR_IP6_PREFIX_LEN, ip6len);
2119 nla_put_u8(nlm, IFLA_IPTUN_FMR_IP4_PREFIX_LEN, ip4len);
2120 nla_put_u8(nlm, IFLA_IPTUN_FMR_EA_LEN, ealen);
2121 nla_put_u8(nlm, IFLA_IPTUN_FMR_OFFSET, offset);
2123 nla_nest_end(nlm, rule);
2126 nla_nest_end(nlm, fmrs);
2130 nla_nest_end(nlm, infodata);
2131 nla_nest_end(nlm, linkinfo);
2133 return system_rtnl_call(nlm);
2137 } else if (!strcmp(str, "greip")) {
2138 return system_add_gre_tunnel(name, "gre", link, tb, false);
2139 } else if (!strcmp(str, "gretapip")) {
2140 return system_add_gre_tunnel(name, "gretap", link, tb, false);
2141 } else if (!strcmp(str, "greip6")) {
2142 return system_add_gre_tunnel(name, "ip6gre", link, tb, true);
2143 } else if (!strcmp(str, "gretapip6")) {
2144 return system_add_gre_tunnel(name, "ip6gretap", link, tb, true);
2146 } else if (!strcmp(str, "ipip")) {
2147 return system_add_proto_tunnel(name, IPPROTO_IPIP, link, tb);