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)
207 int system_init(void)
209 static struct event_socket rtnl_event;
210 static struct event_socket hotplug_event;
212 sock_ioctl = socket(AF_LOCAL, SOCK_DGRAM, 0);
213 system_fd_set_cloexec(sock_ioctl);
215 // Prepare socket for routing / address control
216 sock_rtnl = create_socket(NETLINK_ROUTE, 0);
220 if (!create_event_socket(&rtnl_event, NETLINK_ROUTE, cb_rtnl_event))
223 if (!create_raw_event_socket(&hotplug_event, NETLINK_KOBJECT_UEVENT, 1,
224 handle_hotplug_event, 0))
227 // Receive network link events form kernel
228 nl_socket_add_membership(rtnl_event.sock, RTNLGRP_LINK);
233 static void system_set_sysctl(const char *path, const char *val)
237 fd = open(path, O_WRONLY);
241 if (write(fd, val, strlen(val))) {}
245 static void system_set_dev_sysctl(const char *path, const char *device, const char *val)
247 snprintf(dev_buf, sizeof(dev_buf), path, device);
248 system_set_sysctl(dev_buf, val);
251 static void system_set_disable_ipv6(struct device *dev, const char *val)
253 system_set_dev_sysctl("/proc/sys/net/ipv6/conf/%s/disable_ipv6", dev->ifname, val);
256 static int system_get_sysctl(const char *path, char *buf, const size_t buf_sz)
258 int fd = -1, ret = -1;
260 fd = open(path, O_RDONLY);
264 ssize_t len = read(fd, buf, buf_sz - 1);
278 system_get_dev_sysctl(const char *path, const char *device, char *buf, const size_t buf_sz)
280 snprintf(dev_buf, sizeof(dev_buf), path, device);
281 return system_get_sysctl(dev_buf, buf, buf_sz);
284 static int system_get_disable_ipv6(struct device *dev, char *buf, const size_t buf_sz)
286 return system_get_dev_sysctl("/proc/sys/net/ipv6/conf/%s/disable_ipv6",
287 dev->ifname, buf, buf_sz);
291 #define IFF_LOWER_UP 0x10000
294 // Evaluate netlink messages
295 static int cb_rtnl_event(struct nl_msg *msg, void *arg)
297 struct nlmsghdr *nh = nlmsg_hdr(msg);
298 struct ifinfomsg *ifi = NLMSG_DATA(nh);
299 struct nlattr *nla[__IFLA_MAX];
301 if (nh->nlmsg_type != RTM_NEWLINK)
304 nlmsg_parse(nh, sizeof(*ifi), nla, __IFLA_MAX - 1, NULL);
305 if (!nla[IFLA_IFNAME])
308 struct device *dev = device_get(nla_data(nla[IFLA_IFNAME]), false);
312 device_set_ifindex(dev, ifi->ifi_index);
313 device_set_link(dev, ifi->ifi_flags & IFF_LOWER_UP ? true : false);
320 handle_hotplug_msg(char *data, int size)
322 const char *subsystem = NULL, *interface = NULL;
323 char *cur, *end, *sep;
328 if (!strncmp(data, "add@", 4))
330 else if (!strncmp(data, "remove@", 7))
335 skip = strlen(data) + 1;
338 for (cur = data + skip; cur < end; cur += skip) {
339 skip = strlen(cur) + 1;
341 sep = strchr(cur, '=');
346 if (!strcmp(cur, "INTERFACE"))
348 else if (!strcmp(cur, "SUBSYSTEM")) {
350 if (strcmp(subsystem, "net") != 0)
353 if (subsystem && interface)
359 dev = device_get(interface, false);
363 if (dev->type != &simple_device_type)
366 if (add && system_if_force_external(dev->ifname))
369 device_set_present(dev, add);
373 handle_hotplug_event(struct uloop_fd *u, unsigned int events)
375 struct event_socket *ev = container_of(u, struct event_socket, uloop);
376 struct sockaddr_nl nla;
377 unsigned char *buf = NULL;
380 while ((size = nl_recv(ev->sock, &nla, &buf, NULL)) > 0) {
382 handle_hotplug_msg((char *) buf, size);
388 static int system_rtnl_call(struct nl_msg *msg)
392 ret = nl_send_auto_complete(sock_rtnl, msg);
398 return nl_wait_for_ack(sock_rtnl);
401 int system_bridge_delbr(struct device *bridge)
403 return ioctl(sock_ioctl, SIOCBRDELBR, bridge->ifname);
406 static int system_bridge_if(const char *bridge, struct device *dev, int cmd, void *data)
410 memset(&ifr, 0, sizeof(ifr));
412 ifr.ifr_ifindex = dev->ifindex;
415 strncpy(ifr.ifr_name, bridge, sizeof(ifr.ifr_name));
416 return ioctl(sock_ioctl, cmd, &ifr);
419 static bool system_is_bridge(const char *name, char *buf, int buflen)
423 snprintf(buf, buflen, "/sys/devices/virtual/net/%s/bridge", name);
424 if (stat(buf, &st) < 0)
430 static char *system_get_bridge(const char *name, char *buf, int buflen)
436 snprintf(buf, buflen, "/sys/devices/virtual/net/*/brif/%s/bridge", name);
437 if (glob(buf, GLOB_NOSORT, NULL, &gl) < 0)
440 if (gl.gl_pathc == 0)
443 len = readlink(gl.gl_pathv[0], buf, buflen);
448 path = strrchr(buf, '/');
455 static void system_bridge_set_wireless(const char *bridge, const char *dev)
457 snprintf(dev_buf, sizeof(dev_buf),
458 "/sys/devices/virtual/net/%s/brif/%s/multicast_to_unicast",
460 system_set_sysctl(dev_buf, "1");
463 int system_bridge_addif(struct device *bridge, struct device *dev)
468 oldbr = system_get_bridge(dev->ifname, dev_buf, sizeof(dev_buf));
469 if (!oldbr || strcmp(oldbr, bridge->ifname) != 0)
470 ret = system_bridge_if(bridge->ifname, dev, SIOCBRADDIF, NULL);
473 system_bridge_set_wireless(bridge->ifname, dev->ifname);
478 int system_bridge_delif(struct device *bridge, struct device *dev)
480 return system_bridge_if(bridge->ifname, dev, SIOCBRDELIF, NULL);
483 static int system_if_resolve(struct device *dev)
486 strncpy(ifr.ifr_name, dev->ifname, sizeof(ifr.ifr_name));
487 if (!ioctl(sock_ioctl, SIOCGIFINDEX, &ifr))
488 return ifr.ifr_ifindex;
493 static int system_if_flags(const char *ifname, unsigned add, unsigned rem)
497 memset(&ifr, 0, sizeof(ifr));
498 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
499 ioctl(sock_ioctl, SIOCGIFFLAGS, &ifr);
500 ifr.ifr_flags |= add;
501 ifr.ifr_flags &= ~rem;
502 return ioctl(sock_ioctl, SIOCSIFFLAGS, &ifr);
514 static bool check_ifaddr(struct nlmsghdr *hdr, int ifindex)
516 struct ifaddrmsg *ifa = NLMSG_DATA(hdr);
518 return ifa->ifa_index == ifindex;
521 static bool check_route(struct nlmsghdr *hdr, int ifindex)
523 struct rtmsg *r = NLMSG_DATA(hdr);
524 struct nlattr *tb[__RTA_MAX];
526 if (r->rtm_protocol == RTPROT_KERNEL &&
527 r->rtm_family == AF_INET6)
530 nlmsg_parse(hdr, sizeof(struct rtmsg), tb, __RTA_MAX - 1, NULL);
534 return *(int *)RTA_DATA(tb[RTA_OIF]) == ifindex;
537 static bool check_rule(struct nlmsghdr *hdr, int ifindex)
542 static int cb_clear_event(struct nl_msg *msg, void *arg)
544 struct clear_data *clr = arg;
545 struct nlmsghdr *hdr = nlmsg_hdr(msg);
546 bool (*cb)(struct nlmsghdr *, int ifindex);
552 if (hdr->nlmsg_type != RTM_NEWADDR)
559 if (hdr->nlmsg_type != RTM_NEWROUTE)
566 if (hdr->nlmsg_type != RTM_NEWRULE)
575 if (!cb(hdr, clr->dev ? clr->dev->ifindex : 0))
578 if (type == RTM_DELRULE)
579 D(SYSTEM, "Remove a rule\n");
581 D(SYSTEM, "Remove %s from device %s\n",
582 type == RTM_DELADDR ? "an address" : "a route",
584 memcpy(nlmsg_hdr(clr->msg), hdr, hdr->nlmsg_len);
585 hdr = nlmsg_hdr(clr->msg);
586 hdr->nlmsg_type = type;
587 hdr->nlmsg_flags = NLM_F_REQUEST;
589 nl_socket_disable_auto_ack(sock_rtnl);
590 nl_send_auto_complete(sock_rtnl, clr->msg);
591 nl_socket_enable_auto_ack(sock_rtnl);
597 cb_finish_event(struct nl_msg *msg, void *arg)
605 error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
608 *pending = err->error;
613 system_if_clear_entries(struct device *dev, int type, int af)
615 struct clear_data clr;
616 struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
619 .rtm_flags = RTM_F_CLONED,
621 int flags = NLM_F_DUMP;
630 clr.size = sizeof(struct rtgenmsg);
633 clr.size = sizeof(struct rtmsg);
642 clr.msg = nlmsg_alloc_simple(type, flags);
646 nlmsg_append(clr.msg, &rtm, clr.size, 0);
647 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_clear_event, &clr);
648 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_finish_event, &pending);
649 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &pending);
651 nl_send_auto_complete(sock_rtnl, clr.msg);
653 nl_recvmsgs(sock_rtnl, cb);
661 * Clear bridge (membership) state and bring down device
663 void system_if_clear_state(struct device *dev)
665 static char buf[256];
668 device_set_ifindex(dev, system_if_resolve(dev));
669 if (dev->external || !dev->ifindex)
672 system_if_flags(dev->ifname, 0, IFF_UP);
674 if (system_is_bridge(dev->ifname, buf, sizeof(buf))) {
675 D(SYSTEM, "Delete existing bridge named '%s'\n", dev->ifname);
676 system_bridge_delbr(dev);
680 bridge = system_get_bridge(dev->ifname, buf, sizeof(buf));
682 D(SYSTEM, "Remove device '%s' from bridge '%s'\n", dev->ifname, bridge);
683 system_bridge_if(bridge, dev, SIOCBRDELIF, NULL);
686 system_if_clear_entries(dev, RTM_GETROUTE, AF_INET);
687 system_if_clear_entries(dev, RTM_GETADDR, AF_INET);
688 system_if_clear_entries(dev, RTM_GETROUTE, AF_INET6);
689 system_if_clear_entries(dev, RTM_GETADDR, AF_INET6);
690 system_set_disable_ipv6(dev, "0");
693 static inline unsigned long
694 sec_to_jiffies(int val)
696 return (unsigned long) val * 100;
699 int system_bridge_addbr(struct device *bridge, struct bridge_config *cfg)
701 unsigned long args[4] = {};
703 if (ioctl(sock_ioctl, SIOCBRADDBR, bridge->ifname) < 0)
706 args[0] = BRCTL_SET_BRIDGE_STP_STATE;
707 args[1] = !!cfg->stp;
708 system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
710 args[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
711 args[1] = sec_to_jiffies(cfg->forward_delay);
712 system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
714 system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/multicast_snooping",
715 bridge->ifname, cfg->igmp_snoop ? "1" : "0");
717 args[0] = BRCTL_SET_BRIDGE_PRIORITY;
718 args[1] = cfg->priority;
719 system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
721 if (cfg->flags & BRIDGE_OPT_AGEING_TIME) {
722 args[0] = BRCTL_SET_AGEING_TIME;
723 args[1] = sec_to_jiffies(cfg->ageing_time);
724 system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
727 if (cfg->flags & BRIDGE_OPT_HELLO_TIME) {
728 args[0] = BRCTL_SET_BRIDGE_HELLO_TIME;
729 args[1] = sec_to_jiffies(cfg->hello_time);
730 system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
733 if (cfg->flags & BRIDGE_OPT_MAX_AGE) {
734 args[0] = BRCTL_SET_BRIDGE_MAX_AGE;
735 args[1] = sec_to_jiffies(cfg->max_age);
736 system_bridge_if(bridge->ifname, NULL, SIOCDEVPRIVATE, &args);
742 int system_macvlan_add(struct device *macvlan, struct device *dev, struct macvlan_config *cfg)
745 struct nlattr *linkinfo, *data;
746 struct ifinfomsg iim = { .ifi_family = AF_UNSPEC, };
747 int ifindex = system_if_resolve(dev);
749 static const struct {
751 enum macvlan_mode val;
753 { "private", MACVLAN_MODE_PRIVATE },
754 { "vepa", MACVLAN_MODE_VEPA },
755 { "bridge", MACVLAN_MODE_BRIDGE },
756 { "passthru", MACVLAN_MODE_PASSTHRU },
762 msg = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
767 nlmsg_append(msg, &iim, sizeof(iim), 0);
769 if (cfg->flags & MACVLAN_OPT_MACADDR)
770 nla_put(msg, IFLA_ADDRESS, sizeof(cfg->macaddr), cfg->macaddr);
771 nla_put_string(msg, IFLA_IFNAME, macvlan->ifname);
772 nla_put_u32(msg, IFLA_LINK, ifindex);
774 if (!(linkinfo = nla_nest_start(msg, IFLA_LINKINFO)))
775 goto nla_put_failure;
777 nla_put_string(msg, IFLA_INFO_KIND, "macvlan");
779 if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
780 goto nla_put_failure;
783 for (i = 0; i < ARRAY_SIZE(modes); i++) {
784 if (strcmp(cfg->mode, modes[i].name) != 0)
787 nla_put_u32(msg, IFLA_MACVLAN_MODE, modes[i].val);
792 nla_nest_end(msg, data);
793 nla_nest_end(msg, linkinfo);
795 rv = system_rtnl_call(msg);
797 D(SYSTEM, "Error adding macvlan '%s' over '%s': %d\n", macvlan->ifname, dev->ifname, rv);
806 static int system_link_del(struct device *dev)
809 struct ifinfomsg iim = {
810 .ifi_family = AF_UNSPEC,
814 msg = nlmsg_alloc_simple(RTM_DELLINK, NLM_F_REQUEST);
819 nlmsg_append(msg, &iim, sizeof(iim), 0);
820 nla_put_string(msg, IFLA_IFNAME, dev->ifname);
821 return system_rtnl_call(msg);
824 int system_macvlan_del(struct device *macvlan)
826 return system_link_del(macvlan);
829 static int system_vlan(struct device *dev, int id)
831 struct vlan_ioctl_args ifr = {
832 .cmd = SET_VLAN_NAME_TYPE_CMD,
833 .u.name_type = VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD,
836 ioctl(sock_ioctl, SIOCSIFVLAN, &ifr);
839 ifr.cmd = DEL_VLAN_CMD;
842 ifr.cmd = ADD_VLAN_CMD;
845 strncpy(ifr.device1, dev->ifname, sizeof(ifr.device1));
846 return ioctl(sock_ioctl, SIOCSIFVLAN, &ifr);
849 int system_vlan_add(struct device *dev, int id)
851 return system_vlan(dev, id);
854 int system_vlan_del(struct device *dev)
856 return system_vlan(dev, -1);
859 int system_vlandev_add(struct device *vlandev, struct device *dev, struct vlandev_config *cfg)
862 struct nlattr *linkinfo, *data;
863 struct ifinfomsg iim = { .ifi_family = AF_UNSPEC };
864 int ifindex = system_if_resolve(dev);
870 msg = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
875 nlmsg_append(msg, &iim, sizeof(iim), 0);
876 nla_put_string(msg, IFLA_IFNAME, vlandev->ifname);
877 nla_put_u32(msg, IFLA_LINK, ifindex);
879 if (!(linkinfo = nla_nest_start(msg, IFLA_LINKINFO)))
880 goto nla_put_failure;
882 nla_put_string(msg, IFLA_INFO_KIND, "vlan");
884 if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
885 goto nla_put_failure;
887 nla_put_u16(msg, IFLA_VLAN_ID, cfg->vid);
889 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
890 nla_put_u16(msg, IFLA_VLAN_PROTOCOL, htons(cfg->proto));
892 if(cfg->proto == VLAN_PROTO_8021AD)
893 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);
896 nla_nest_end(msg, data);
897 nla_nest_end(msg, linkinfo);
899 rv = system_rtnl_call(msg);
901 D(SYSTEM, "Error adding vlandev '%s' over '%s': %d\n", vlandev->ifname, dev->ifname, rv);
910 int system_vlandev_del(struct device *vlandev)
912 return system_link_del(vlandev);
916 system_if_get_settings(struct device *dev, struct device_settings *s)
921 memset(&ifr, 0, sizeof(ifr));
922 strncpy(ifr.ifr_name, dev->ifname, sizeof(ifr.ifr_name));
924 if (ioctl(sock_ioctl, SIOCGIFMTU, &ifr) == 0) {
925 s->mtu = ifr.ifr_mtu;
926 s->flags |= DEV_OPT_MTU;
929 if (ioctl(sock_ioctl, SIOCGIFTXQLEN, &ifr) == 0) {
930 s->txqueuelen = ifr.ifr_qlen;
931 s->flags |= DEV_OPT_TXQUEUELEN;
934 if (ioctl(sock_ioctl, SIOCGIFHWADDR, &ifr) == 0) {
935 memcpy(s->macaddr, &ifr.ifr_hwaddr.sa_data, sizeof(s->macaddr));
936 s->flags |= DEV_OPT_MACADDR;
939 if (!system_get_disable_ipv6(dev, buf, sizeof(buf))) {
940 s->ipv6 = !strtoul(buf, NULL, 0);
941 s->flags |= DEV_OPT_IPV6;
946 system_if_apply_settings(struct device *dev, struct device_settings *s, unsigned int apply_mask)
953 memset(&ifr, 0, sizeof(ifr));
954 strncpy(ifr.ifr_name, dev->ifname, sizeof(ifr.ifr_name));
955 if (s->flags & DEV_OPT_MTU & apply_mask) {
956 ifr.ifr_mtu = s->mtu;
957 if (ioctl(sock_ioctl, SIOCSIFMTU, &ifr) < 0)
958 s->flags &= ~DEV_OPT_MTU;
960 if (s->flags & DEV_OPT_TXQUEUELEN & apply_mask) {
961 ifr.ifr_qlen = s->txqueuelen;
962 if (ioctl(sock_ioctl, SIOCSIFTXQLEN, &ifr) < 0)
963 s->flags &= ~DEV_OPT_TXQUEUELEN;
965 if ((s->flags & DEV_OPT_MACADDR & apply_mask) && !dev->external) {
966 ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
967 memcpy(&ifr.ifr_hwaddr.sa_data, s->macaddr, sizeof(s->macaddr));
968 if (ioctl(sock_ioctl, SIOCSIFHWADDR, &ifr) < 0)
969 s->flags &= ~DEV_OPT_MACADDR;
971 if (s->flags & DEV_OPT_IPV6 & apply_mask)
972 system_set_disable_ipv6(dev, s->ipv6 ? "0" : "1");
975 int system_if_up(struct device *dev)
977 system_if_get_settings(dev, &dev->orig_settings);
978 system_if_apply_settings(dev, &dev->settings, dev->settings.flags);
979 device_set_ifindex(dev, system_if_resolve(dev));
980 return system_if_flags(dev->ifname, IFF_UP, 0);
983 int system_if_down(struct device *dev)
985 int ret = system_if_flags(dev->ifname, 0, IFF_UP);
986 dev->orig_settings.flags &= dev->settings.flags;
987 system_if_apply_settings(dev, &dev->orig_settings, dev->orig_settings.flags);
991 struct if_check_data {
997 static int cb_if_check_valid(struct nl_msg *msg, void *arg)
999 struct nlmsghdr *nh = nlmsg_hdr(msg);
1000 struct ifinfomsg *ifi = NLMSG_DATA(nh);
1001 struct if_check_data *chk = (struct if_check_data *)arg;
1003 if (nh->nlmsg_type != RTM_NEWLINK)
1006 device_set_present(chk->dev, ifi->ifi_index > 0 ? true : false);
1007 device_set_link(chk->dev, ifi->ifi_flags & IFF_LOWER_UP ? true : false);
1012 static int cb_if_check_ack(struct nl_msg *msg, void *arg)
1014 struct if_check_data *chk = (struct if_check_data *)arg;
1019 static int cb_if_check_error(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
1021 struct if_check_data *chk = (struct if_check_data *)arg;
1023 device_set_present(chk->dev, false);
1024 device_set_link(chk->dev, false);
1025 chk->pending = err->error;
1030 int system_if_check(struct device *dev)
1032 struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
1034 struct ifinfomsg ifi = {
1035 .ifi_family = AF_UNSPEC,
1038 struct if_check_data chk = {
1044 msg = nlmsg_alloc_simple(RTM_GETLINK, 0);
1045 if (!msg || nlmsg_append(msg, &ifi, sizeof(ifi), 0) ||
1046 nla_put_string(msg, IFLA_IFNAME, dev->ifname))
1049 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_if_check_valid, &chk);
1050 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, cb_if_check_ack, &chk);
1051 nl_cb_err(cb, NL_CB_CUSTOM, cb_if_check_error, &chk);
1053 nl_send_auto_complete(sock_rtnl, msg);
1054 while (chk.pending > 0)
1055 nl_recvmsgs(sock_rtnl, cb);
1066 system_if_get_parent(struct device *dev)
1068 char buf[64], *devname;
1069 int ifindex, iflink, len;
1072 snprintf(buf, sizeof(buf), "/sys/class/net/%s/iflink", dev->ifname);
1073 f = fopen(buf, "r");
1077 len = fread(buf, 1, sizeof(buf) - 1, f);
1084 iflink = strtoul(buf, NULL, 0);
1085 ifindex = system_if_resolve(dev);
1086 if (!iflink || iflink == ifindex)
1089 devname = if_indextoname(iflink, buf);
1093 return device_get(devname, true);
1097 read_string_file(int dir_fd, const char *file, char *buf, int len)
1103 fd = openat(dir_fd, file, O_RDONLY);
1108 len = read(fd, buf, len - 1);
1112 } else if (len > 0) {
1115 c = strchr(buf, '\n');
1128 read_uint64_file(int dir_fd, const char *file, uint64_t *val)
1133 ret = read_string_file(dir_fd, file, buf, sizeof(buf));
1135 *val = strtoull(buf, NULL, 0);
1140 /* Assume advertised flags == supported flags */
1141 static const struct {
1144 } ethtool_link_modes[] = {
1145 { ADVERTISED_10baseT_Half, "10H" },
1146 { ADVERTISED_10baseT_Full, "10F" },
1147 { ADVERTISED_100baseT_Half, "100H" },
1148 { ADVERTISED_100baseT_Full, "100F" },
1149 { ADVERTISED_1000baseT_Half, "1000H" },
1150 { ADVERTISED_1000baseT_Full, "1000F" },
1153 static void system_add_link_modes(struct blob_buf *b, __u32 mask)
1156 for (i = 0; i < ARRAY_SIZE(ethtool_link_modes); i++) {
1157 if (mask & ethtool_link_modes[i].mask)
1158 blobmsg_add_string(b, NULL, ethtool_link_modes[i].name);
1163 system_if_force_external(const char *ifname)
1168 snprintf(buf, sizeof(buf), "/sys/class/net/%s/phy80211", ifname);
1169 return stat(buf, &s) == 0;
1173 system_if_dump_info(struct device *dev, struct blob_buf *b)
1175 struct ethtool_cmd ecmd;
1181 snprintf(buf, sizeof(buf), "/sys/class/net/%s", dev->ifname);
1182 dir_fd = open(buf, O_DIRECTORY);
1184 memset(&ecmd, 0, sizeof(ecmd));
1185 memset(&ifr, 0, sizeof(ifr));
1186 strcpy(ifr.ifr_name, dev->ifname);
1187 ifr.ifr_data = (caddr_t) &ecmd;
1188 ecmd.cmd = ETHTOOL_GSET;
1190 if (ioctl(sock_ioctl, SIOCETHTOOL, &ifr) == 0) {
1191 c = blobmsg_open_array(b, "link-advertising");
1192 system_add_link_modes(b, ecmd.advertising);
1193 blobmsg_close_array(b, c);
1195 c = blobmsg_open_array(b, "link-supported");
1196 system_add_link_modes(b, ecmd.supported);
1197 blobmsg_close_array(b, c);
1199 s = blobmsg_alloc_string_buffer(b, "speed", 8);
1200 snprintf(s, 8, "%d%c", ethtool_cmd_speed(&ecmd),
1201 ecmd.duplex == DUPLEX_HALF ? 'H' : 'F');
1202 blobmsg_add_string_buffer(b);
1210 system_if_dump_stats(struct device *dev, struct blob_buf *b)
1212 const char *const counters[] = {
1213 "collisions", "rx_frame_errors", "tx_compressed",
1214 "multicast", "rx_length_errors", "tx_dropped",
1215 "rx_bytes", "rx_missed_errors", "tx_errors",
1216 "rx_compressed", "rx_over_errors", "tx_fifo_errors",
1217 "rx_crc_errors", "rx_packets", "tx_heartbeat_errors",
1218 "rx_dropped", "tx_aborted_errors", "tx_packets",
1219 "rx_errors", "tx_bytes", "tx_window_errors",
1220 "rx_fifo_errors", "tx_carrier_errors",
1227 snprintf(buf, sizeof(buf), "/sys/class/net/%s/statistics", dev->ifname);
1228 stats_dir = open(buf, O_DIRECTORY);
1232 for (i = 0; i < ARRAY_SIZE(counters); i++)
1233 if (read_uint64_file(stats_dir, counters[i], &val))
1234 blobmsg_add_u64(b, counters[i], val);
1240 static int system_addr(struct device *dev, struct device_addr *addr, int cmd)
1242 bool v4 = ((addr->flags & DEVADDR_FAMILY) == DEVADDR_INET4);
1243 int alen = v4 ? 4 : 16;
1244 unsigned int flags = 0;
1245 struct ifaddrmsg ifa = {
1246 .ifa_family = (alen == 4) ? AF_INET : AF_INET6,
1247 .ifa_prefixlen = addr->mask,
1248 .ifa_index = dev->ifindex,
1252 if (cmd == RTM_NEWADDR)
1253 flags |= NLM_F_CREATE | NLM_F_REPLACE;
1255 msg = nlmsg_alloc_simple(cmd, flags);
1259 nlmsg_append(msg, &ifa, sizeof(ifa), 0);
1260 nla_put(msg, IFA_LOCAL, alen, &addr->addr);
1262 if (addr->broadcast)
1263 nla_put_u32(msg, IFA_BROADCAST, addr->broadcast);
1264 if (addr->point_to_point)
1265 nla_put_u32(msg, IFA_ADDRESS, addr->point_to_point);
1267 time_t now = system_get_rtime();
1268 struct ifa_cacheinfo cinfo = {0xffffffffU, 0xffffffffU, 0, 0};
1270 if (addr->preferred_until) {
1271 int64_t preferred = addr->preferred_until - now;
1274 else if (preferred > UINT32_MAX)
1275 preferred = UINT32_MAX;
1277 cinfo.ifa_prefered = preferred;
1280 if (addr->valid_until) {
1281 int64_t valid = addr->valid_until - now;
1284 else if (valid > UINT32_MAX)
1287 cinfo.ifa_valid = valid;
1290 nla_put(msg, IFA_CACHEINFO, sizeof(cinfo), &cinfo);
1293 return system_rtnl_call(msg);
1296 int system_add_address(struct device *dev, struct device_addr *addr)
1298 return system_addr(dev, addr, RTM_NEWADDR);
1301 int system_del_address(struct device *dev, struct device_addr *addr)
1303 return system_addr(dev, addr, RTM_DELADDR);
1306 static int system_rt(struct device *dev, struct device_route *route, int cmd)
1308 int alen = ((route->flags & DEVADDR_FAMILY) == DEVADDR_INET4) ? 4 : 16;
1310 unsigned int flags = 0;
1313 have_gw = !!route->nexthop.in.s_addr;
1315 have_gw = route->nexthop.in6.s6_addr32[0] ||
1316 route->nexthop.in6.s6_addr32[1] ||
1317 route->nexthop.in6.s6_addr32[2] ||
1318 route->nexthop.in6.s6_addr32[3];
1320 unsigned int table = (route->flags & (DEVROUTE_TABLE | DEVROUTE_SRCTABLE))
1321 ? route->table : RT_TABLE_MAIN;
1323 struct rtmsg rtm = {
1324 .rtm_family = (alen == 4) ? AF_INET : AF_INET6,
1325 .rtm_dst_len = route->mask,
1326 .rtm_src_len = route->sourcemask,
1327 .rtm_table = (table < 256) ? table : RT_TABLE_UNSPEC,
1328 .rtm_protocol = (route->flags & DEVADDR_KERNEL) ? RTPROT_KERNEL : RTPROT_STATIC,
1329 .rtm_scope = RT_SCOPE_NOWHERE,
1330 .rtm_type = (cmd == RTM_DELROUTE) ? 0: RTN_UNICAST,
1331 .rtm_flags = (route->flags & DEVROUTE_ONLINK) ? RTNH_F_ONLINK : 0,
1335 if (cmd == RTM_NEWROUTE) {
1336 flags |= NLM_F_CREATE | NLM_F_REPLACE;
1338 if (!dev) { // Add null-route
1339 rtm.rtm_scope = RT_SCOPE_UNIVERSE;
1340 rtm.rtm_type = RTN_UNREACHABLE;
1343 rtm.rtm_scope = (have_gw) ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK;
1346 if (route->flags & DEVROUTE_TYPE) {
1347 rtm.rtm_type = route->type;
1348 if (!(route->flags & (DEVROUTE_TABLE | DEVROUTE_SRCTABLE))) {
1349 if (rtm.rtm_type == RTN_LOCAL || rtm.rtm_type == RTN_BROADCAST ||
1350 rtm.rtm_type == RTN_NAT || rtm.rtm_type == RTN_ANYCAST)
1351 rtm.rtm_table = RT_TABLE_LOCAL;
1354 if (rtm.rtm_type == RTN_LOCAL || rtm.rtm_type == RTN_NAT)
1355 rtm.rtm_scope = RT_SCOPE_HOST;
1356 else if (rtm.rtm_type == RTN_BROADCAST || rtm.rtm_type == RTN_MULTICAST ||
1357 rtm.rtm_type == RTN_ANYCAST)
1358 rtm.rtm_scope = RT_SCOPE_LINK;
1361 msg = nlmsg_alloc_simple(cmd, flags);
1365 nlmsg_append(msg, &rtm, sizeof(rtm), 0);
1368 nla_put(msg, RTA_DST, alen, &route->addr);
1370 if (route->sourcemask)
1371 nla_put(msg, RTA_SRC, alen, &route->source);
1373 if (route->metric > 0)
1374 nla_put_u32(msg, RTA_PRIORITY, route->metric);
1377 nla_put(msg, RTA_GATEWAY, alen, &route->nexthop);
1380 nla_put_u32(msg, RTA_OIF, dev->ifindex);
1383 nla_put_u32(msg, RTA_TABLE, table);
1385 if (route->flags & DEVROUTE_MTU) {
1386 struct nlattr *metrics;
1388 if (!(metrics = nla_nest_start(msg, RTA_METRICS)))
1389 goto nla_put_failure;
1391 nla_put_u32(msg, RTAX_MTU, route->mtu);
1393 nla_nest_end(msg, metrics);
1396 return system_rtnl_call(msg);
1403 int system_add_route(struct device *dev, struct device_route *route)
1405 return system_rt(dev, route, RTM_NEWROUTE);
1408 int system_del_route(struct device *dev, struct device_route *route)
1410 return system_rt(dev, route, RTM_DELROUTE);
1413 int system_flush_routes(void)
1415 const char *names[] = {
1416 "/proc/sys/net/ipv4/route/flush",
1417 "/proc/sys/net/ipv6/route/flush"
1421 for (i = 0; i < ARRAY_SIZE(names); i++) {
1422 fd = open(names[i], O_WRONLY);
1426 if (write(fd, "-1", 2)) {}
1432 bool system_resolve_rt_type(const char *type, unsigned int *id)
1434 return system_rtn_aton(type, id);
1437 bool system_resolve_rt_table(const char *name, unsigned int *id)
1441 unsigned int n, table = RT_TABLE_UNSPEC;
1443 /* first try to parse table as number */
1444 if ((n = strtoul(name, &e, 0)) > 0 && !*e)
1447 /* handle well known aliases */
1448 else if (!strcmp(name, "default"))
1449 table = RT_TABLE_DEFAULT;
1450 else if (!strcmp(name, "main"))
1451 table = RT_TABLE_MAIN;
1452 else if (!strcmp(name, "local"))
1453 table = RT_TABLE_LOCAL;
1455 /* try to look up name in /etc/iproute2/rt_tables */
1456 else if ((f = fopen("/etc/iproute2/rt_tables", "r")) != NULL)
1458 while (fgets(buf, sizeof(buf) - 1, f) != NULL)
1460 if ((e = strtok(buf, " \t\n")) == NULL || *e == '#')
1463 n = strtoul(e, NULL, 10);
1464 e = strtok(NULL, " \t\n");
1466 if (e && !strcmp(e, name))
1476 if (table == RT_TABLE_UNSPEC)
1483 bool system_is_default_rt_table(unsigned int id)
1485 return (id == RT_TABLE_MAIN);
1488 static int system_iprule(struct iprule *rule, int cmd)
1490 int alen = ((rule->flags & IPRULE_FAMILY) == IPRULE_INET4) ? 4 : 16;
1493 struct rtmsg rtm = {
1494 .rtm_family = (alen == 4) ? AF_INET : AF_INET6,
1495 .rtm_protocol = RTPROT_STATIC,
1496 .rtm_scope = RT_SCOPE_UNIVERSE,
1497 .rtm_table = RT_TABLE_UNSPEC,
1498 .rtm_type = RTN_UNSPEC,
1502 if (cmd == RTM_NEWRULE) {
1503 rtm.rtm_type = RTN_UNICAST;
1504 rtm.rtm_flags |= NLM_F_REPLACE | NLM_F_EXCL;
1508 rtm.rtm_flags |= FIB_RULE_INVERT;
1510 if (rule->flags & IPRULE_SRC)
1511 rtm.rtm_src_len = rule->src_mask;
1513 if (rule->flags & IPRULE_DEST)
1514 rtm.rtm_dst_len = rule->dest_mask;
1516 if (rule->flags & IPRULE_TOS)
1517 rtm.rtm_tos = rule->tos;
1519 if (rule->flags & IPRULE_LOOKUP) {
1520 if (rule->lookup < 256)
1521 rtm.rtm_table = rule->lookup;
1524 if (rule->flags & IPRULE_ACTION)
1525 rtm.rtm_type = rule->action;
1526 else if (rule->flags & IPRULE_GOTO)
1527 rtm.rtm_type = FR_ACT_GOTO;
1528 else if (!(rule->flags & (IPRULE_LOOKUP | IPRULE_ACTION | IPRULE_GOTO)))
1529 rtm.rtm_type = FR_ACT_NOP;
1531 msg = nlmsg_alloc_simple(cmd, NLM_F_REQUEST);
1536 nlmsg_append(msg, &rtm, sizeof(rtm), 0);
1538 if (rule->flags & IPRULE_IN)
1539 nla_put(msg, FRA_IFNAME, strlen(rule->in_dev) + 1, rule->in_dev);
1541 if (rule->flags & IPRULE_OUT)
1542 nla_put(msg, FRA_OIFNAME, strlen(rule->out_dev) + 1, rule->out_dev);
1544 if (rule->flags & IPRULE_SRC)
1545 nla_put(msg, FRA_SRC, alen, &rule->src_addr);
1547 if (rule->flags & IPRULE_DEST)
1548 nla_put(msg, FRA_DST, alen, &rule->dest_addr);
1550 if (rule->flags & IPRULE_PRIORITY)
1551 nla_put_u32(msg, FRA_PRIORITY, rule->priority);
1552 else if (cmd == RTM_NEWRULE)
1553 nla_put_u32(msg, FRA_PRIORITY, rule->order);
1555 if (rule->flags & IPRULE_FWMARK)
1556 nla_put_u32(msg, FRA_FWMARK, rule->fwmark);
1558 if (rule->flags & IPRULE_FWMASK)
1559 nla_put_u32(msg, FRA_FWMASK, rule->fwmask);
1561 if (rule->flags & IPRULE_LOOKUP) {
1562 if (rule->lookup >= 256)
1563 nla_put_u32(msg, FRA_TABLE, rule->lookup);
1566 if (rule->flags & IPRULE_GOTO)
1567 nla_put_u32(msg, FRA_GOTO, rule->gotoid);
1569 return system_rtnl_call(msg);
1572 int system_add_iprule(struct iprule *rule)
1574 return system_iprule(rule, RTM_NEWRULE);
1577 int system_del_iprule(struct iprule *rule)
1579 return system_iprule(rule, RTM_DELRULE);
1582 int system_flush_iprules(void)
1587 system_if_clear_entries(NULL, RTM_GETRULE, AF_INET);
1588 system_if_clear_entries(NULL, RTM_GETRULE, AF_INET6);
1590 memset(&rule, 0, sizeof(rule));
1593 rule.flags = IPRULE_INET4 | IPRULE_PRIORITY | IPRULE_LOOKUP;
1596 rule.lookup = RT_TABLE_LOCAL;
1597 rv |= system_iprule(&rule, RTM_NEWRULE);
1599 rule.priority = 32766;
1600 rule.lookup = RT_TABLE_MAIN;
1601 rv |= system_iprule(&rule, RTM_NEWRULE);
1603 rule.priority = 32767;
1604 rule.lookup = RT_TABLE_DEFAULT;
1605 rv |= system_iprule(&rule, RTM_NEWRULE);
1608 rule.flags = IPRULE_INET6 | IPRULE_PRIORITY | IPRULE_LOOKUP;
1611 rule.lookup = RT_TABLE_LOCAL;
1612 rv |= system_iprule(&rule, RTM_NEWRULE);
1614 rule.priority = 32766;
1615 rule.lookup = RT_TABLE_MAIN;
1616 rv |= system_iprule(&rule, RTM_NEWRULE);
1621 bool system_resolve_iprule_action(const char *action, unsigned int *id)
1623 return system_rtn_aton(action, id);
1626 time_t system_get_rtime(void)
1631 if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, &ts) == 0)
1634 if (gettimeofday(&tv, NULL) == 0)
1641 #define IP_DF 0x4000
1644 static int tunnel_ioctl(const char *name, int cmd, void *p)
1648 memset(&ifr, 0, sizeof(ifr));
1649 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1650 ifr.ifr_ifru.ifru_data = p;
1651 return ioctl(sock_ioctl, cmd, &ifr);
1654 int system_del_ip_tunnel(const char *name)
1656 return tunnel_ioctl(name, SIOCDELTUNNEL, NULL);
1659 int system_update_ipv6_mtu(struct device *dev, int mtu)
1663 snprintf(buf, sizeof(buf), "/proc/sys/net/ipv6/conf/%s/mtu",
1666 int fd = open(buf, O_RDWR);
1667 ssize_t len = read(fd, buf, sizeof(buf) - 1);
1674 if (!mtu || ret <= mtu)
1677 lseek(fd, 0, SEEK_SET);
1678 if (write(fd, buf, snprintf(buf, sizeof(buf), "%i", mtu)) <= 0)
1686 int system_add_ip_tunnel(const char *name, struct blob_attr *attr)
1688 struct blob_attr *tb[__TUNNEL_ATTR_MAX];
1689 struct blob_attr *cur;
1693 system_del_ip_tunnel(name);
1695 blobmsg_parse(tunnel_attr_list.params, __TUNNEL_ATTR_MAX, tb,
1696 blob_data(attr), blob_len(attr));
1698 if (!(cur = tb[TUNNEL_ATTR_TYPE]))
1700 str = blobmsg_data(cur);
1702 if ((cur = tb[TUNNEL_ATTR_DF]))
1703 set_df = blobmsg_get_bool(cur);
1705 unsigned int ttl = 0;
1706 if ((cur = tb[TUNNEL_ATTR_TTL])) {
1707 ttl = blobmsg_get_u32(cur);
1708 if (ttl > 255 || (!set_df && ttl))
1712 unsigned int link = 0;
1713 if ((cur = tb[TUNNEL_ATTR_LINK])) {
1714 struct interface *iface = vlist_find(&interfaces, blobmsg_data(cur), iface, node);
1718 if (iface->l3_dev.dev)
1719 link = iface->l3_dev.dev->ifindex;
1722 if (!strcmp(str, "sit")) {
1723 struct ip_tunnel_parm p = {
1728 .frag_off = set_df ? htons(IP_DF) : 0,
1729 .protocol = IPPROTO_IPV6,
1734 if ((cur = tb[TUNNEL_ATTR_LOCAL]) &&
1735 inet_pton(AF_INET, blobmsg_data(cur), &p.iph.saddr) < 1)
1738 if ((cur = tb[TUNNEL_ATTR_REMOTE]) &&
1739 inet_pton(AF_INET, blobmsg_data(cur), &p.iph.daddr) < 1)
1742 strncpy(p.name, name, sizeof(p.name));
1743 if (tunnel_ioctl("sit0", SIOCADDTUNNEL, &p) < 0)
1747 if ((cur = tb[TUNNEL_ATTR_6RD_PREFIX])) {
1749 struct ip_tunnel_6rd p6;
1751 memset(&p6, 0, sizeof(p6));
1753 if (!parse_ip_and_netmask(AF_INET6, blobmsg_data(cur),
1754 &p6.prefix, &mask) || mask > 128)
1756 p6.prefixlen = mask;
1758 if ((cur = tb[TUNNEL_ATTR_6RD_RELAY_PREFIX])) {
1759 if (!parse_ip_and_netmask(AF_INET, blobmsg_data(cur),
1760 &p6.relay_prefix, &mask) || mask > 32)
1762 p6.relay_prefixlen = mask;
1765 if (tunnel_ioctl(name, SIOCADD6RD, &p6) < 0) {
1766 system_del_ip_tunnel(name);
1771 } else if (!strcmp(str, "ipip6")) {
1772 struct nl_msg *nlm = nlmsg_alloc_simple(RTM_NEWLINK,
1773 NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_CREATE);
1774 struct ifinfomsg ifi = { .ifi_family = AF_UNSPEC };
1780 nlmsg_append(nlm, &ifi, sizeof(ifi), 0);
1781 nla_put_string(nlm, IFLA_IFNAME, name);
1784 nla_put_u32(nlm, IFLA_LINK, link);
1786 struct nlattr *linkinfo = nla_nest_start(nlm, IFLA_LINKINFO);
1791 nla_put_string(nlm, IFLA_INFO_KIND, "ip6tnl");
1792 struct nlattr *infodata = nla_nest_start(nlm, IFLA_INFO_DATA);
1799 nla_put_u32(nlm, IFLA_IPTUN_LINK, link);
1801 nla_put_u8(nlm, IFLA_IPTUN_PROTO, IPPROTO_IPIP);
1802 nla_put_u8(nlm, IFLA_IPTUN_TTL, (ttl) ? ttl : 64);
1803 nla_put_u8(nlm, IFLA_IPTUN_ENCAP_LIMIT, 4);
1805 struct in6_addr in6buf;
1806 if ((cur = tb[TUNNEL_ATTR_LOCAL])) {
1807 if (inet_pton(AF_INET6, blobmsg_data(cur), &in6buf) < 1) {
1811 nla_put(nlm, IFLA_IPTUN_LOCAL, sizeof(in6buf), &in6buf);
1814 if ((cur = tb[TUNNEL_ATTR_REMOTE])) {
1815 if (inet_pton(AF_INET6, blobmsg_data(cur), &in6buf) < 1) {
1819 nla_put(nlm, IFLA_IPTUN_REMOTE, sizeof(in6buf), &in6buf);
1822 #ifdef IFLA_IPTUN_FMR_MAX
1823 if ((cur = tb[TUNNEL_ATTR_FMRS])) {
1824 struct nlattr *fmrs = nla_nest_start(nlm, IFLA_IPTUN_FMRS);
1826 struct blob_attr *fmr;
1827 unsigned rem, fmrcnt = 0;
1828 blobmsg_for_each_attr(fmr, cur, rem) {
1829 if (blobmsg_type(fmr) != BLOBMSG_TYPE_STRING)
1832 unsigned ip4len, ip6len, ealen, offset = 6;
1836 if (sscanf(blobmsg_get_string(fmr), "%47[^/]/%u,%15[^/]/%u,%u,%u",
1837 ip6buf, &ip6len, ip4buf, &ip4len, &ealen, &offset) < 5) {
1842 struct in6_addr ip6prefix;
1843 struct in_addr ip4prefix;
1844 if (inet_pton(AF_INET6, ip6buf, &ip6prefix) != 1 ||
1845 inet_pton(AF_INET, ip4buf, &ip4prefix) != 1) {
1850 struct nlattr *rule = nla_nest_start(nlm, ++fmrcnt);
1852 nla_put(nlm, IFLA_IPTUN_FMR_IP6_PREFIX, sizeof(ip6prefix), &ip6prefix);
1853 nla_put(nlm, IFLA_IPTUN_FMR_IP4_PREFIX, sizeof(ip4prefix), &ip4prefix);
1854 nla_put_u8(nlm, IFLA_IPTUN_FMR_IP6_PREFIX_LEN, ip6len);
1855 nla_put_u8(nlm, IFLA_IPTUN_FMR_IP4_PREFIX_LEN, ip4len);
1856 nla_put_u8(nlm, IFLA_IPTUN_FMR_EA_LEN, ealen);
1857 nla_put_u8(nlm, IFLA_IPTUN_FMR_OFFSET, offset);
1859 nla_nest_end(nlm, rule);
1862 nla_nest_end(nlm, fmrs);
1866 nla_nest_end(nlm, infodata);
1867 nla_nest_end(nlm, linkinfo);
1869 return system_rtnl_call(nlm);