+ LOG(0, 0, 0, "Malformed answer getting tun ifindex %ld\n", len);
+ exit(1);
+ }
+
+ memcpy(&ifinfo, NLMSG_DATA(resp_nh), sizeof(ifinfo));
+ // got index
+ tunidx = ifinfo.ifi_index;
+ }
+ {
+ struct {
+ // interface setting
+ struct nlmsghdr nh;
+ union {
+ struct ifinfomsg ifinfo;
+ struct ifaddrmsg ifaddr;
+ } ifmsg __attribute__ ((aligned(NLMSG_ALIGNTO)));
+ char rtdata[32]; // 32 should be enough
+ } req;
+ struct {
+ struct rtattr rta;
+ uint32_t u32 __attribute__ ((aligned(RTA_ALIGNTO)));;
+ } u32_attr;
+ struct {
+ struct rtattr rta;
+ struct in_addr addr __attribute__ ((aligned(RTA_ALIGNTO)));;
+ } ipv4_attr;
+ struct {
+ struct rtattr rta;
+ struct in6_addr addr6 __attribute__ ((aligned(RTA_ALIGNTO)));;
+ } ipv6_attr;
+ char *buf_ptr;
+
+ memset(&req, 0, sizeof(req));
+
+ req.nh.nlmsg_type = RTM_SETLINK;
+ req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_MULTI;
+
+ req.ifmsg.ifinfo = ifinfo;
+ req.ifmsg.ifinfo.ifi_flags |= IFF_UP; // set interface up
+ req.ifmsg.ifinfo.ifi_change = IFF_UP; // only change this flag
+
+ buf_ptr = NLMSG_DATA(&req.nh) + sizeof(req.ifmsg.ifinfo);
+
+ u32_attr.rta.rta_len = RTA_LENGTH(sizeof(u32_attr.u32));
+ u32_attr.rta.rta_type = IFLA_TXQLEN;
+ /* Bump up the qlen to deal with bursts from the network */
+ u32_attr.u32 = 1000;
+ memcpy(buf_ptr, &u32_attr, sizeof(u32_attr));
+
+ buf_ptr += RTA_ALIGN(u32_attr.rta.rta_len);
+
+ u32_attr.rta.rta_len = RTA_LENGTH(sizeof(u32_attr.u32));
+ u32_attr.rta.rta_type = IFLA_MTU;
+ /* set MTU to modem MRU */
+ u32_attr.u32 = MRU;
+ memcpy(buf_ptr, &u32_attr, sizeof(u32_attr));
+
+ req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifmsg.ifinfo)
+ + u32_attr.rta.rta_len * 2);
+
+ if (netlink_send(&req.nh) < 0)
+ {
+ LOG(0, 0, 0, "Error setting up tun device interface: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ memset(&req, 0, sizeof(req));
+
+ req.nh.nlmsg_type = RTM_NEWADDR;
+ req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_MULTI;
+
+ req.ifmsg.ifaddr.ifa_family = AF_INET;
+ req.ifmsg.ifaddr.ifa_prefixlen = 32;
+ req.ifmsg.ifaddr.ifa_index = ifinfo.ifi_index;
+
+ ipv4_attr.rta.rta_len = RTA_LENGTH(sizeof(ipv4_attr.addr));
+ ipv4_attr.rta.rta_type = IFA_ADDRESS;
+ ipv4_attr.addr.s_addr = config->bind_address ?
+ config->bind_address : 0x01010101; // 1.1.1.1
+ memcpy(NLMSG_DATA(&req.nh) + sizeof(req.ifmsg.ifaddr), &ipv4_attr, sizeof(ipv4_attr));
+
+ req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifmsg.ifaddr)
+ + ipv4_attr.rta.rta_len);
+
+ if (netlink_send(&req.nh) < 0)
+ {
+ LOG(0, 0, 0, "Error setting up tun device IPv4 address: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ // Only setup IPv6 on the tun device if we have a configured prefix
+ if (config->ipv6_prefix.s6_addr[0]) {
+ memset(&req, 0, sizeof(req));
+
+ req.nh.nlmsg_type = RTM_NEWADDR;
+ req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_MULTI;
+
+ req.ifmsg.ifaddr.ifa_family = AF_INET6;
+ req.ifmsg.ifaddr.ifa_prefixlen = 64;
+ req.ifmsg.ifaddr.ifa_scope = RT_SCOPE_LINK;
+ req.ifmsg.ifaddr.ifa_index = ifinfo.ifi_index;
+
+ ipv6_attr.rta.rta_len = RTA_LENGTH(sizeof(ipv6_attr.addr6));
+ ipv6_attr.rta.rta_type = IFA_LOCAL;
+ // Link local address is FE80::1
+ memset(&ipv6_attr.addr6, 0, sizeof(ipv6_attr.addr6));
+ ipv6_attr.addr6.s6_addr[0] = 0xFE;
+ ipv6_attr.addr6.s6_addr[1] = 0x80;
+ ipv6_attr.addr6.s6_addr[15] = 1;
+ memcpy(NLMSG_DATA(&req.nh) + sizeof(req.ifmsg.ifaddr), &ipv6_attr, sizeof(ipv6_attr));
+
+ req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifmsg.ifaddr)
+ + ipv6_attr.rta.rta_len);
+
+ if (netlink_send(&req.nh) < 0)
+ {
+ LOG(0, 0, 0, "Error setting up tun device IPv6 LL address: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ memset(&req, 0, sizeof(req));
+
+ req.nh.nlmsg_type = RTM_NEWADDR;
+ req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_MULTI;
+
+ req.ifmsg.ifaddr.ifa_family = AF_INET6;
+ req.ifmsg.ifaddr.ifa_prefixlen = 64;
+ req.ifmsg.ifaddr.ifa_scope = RT_SCOPE_UNIVERSE;
+ req.ifmsg.ifaddr.ifa_index = ifinfo.ifi_index;
+
+ ipv6_attr.rta.rta_len = RTA_LENGTH(sizeof(ipv6_attr.addr6));
+ ipv6_attr.rta.rta_type = IFA_LOCAL;
+ // Global address is prefix::1
+ ipv6_attr.addr6 = config->ipv6_prefix;
+ ipv6_attr.addr6.s6_addr[15] = 1;
+ memcpy(NLMSG_DATA(&req.nh) + sizeof(req.ifmsg.ifaddr), &ipv6_attr, sizeof(ipv6_attr));
+
+ req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifmsg.ifaddr)
+ + ipv6_attr.rta.rta_len);
+
+ if (netlink_send(&req.nh) < 0)
+ {
+ LOG(0, 0, 0, "Error setting up tun device IPv6 global address: %s\n", strerror(errno));
+ exit(1);
+ }
+ }
+
+ memset(&req, 0, sizeof(req));
+
+ req.nh.nlmsg_type = NLMSG_DONE;
+ req.nh.nlmsg_len = NLMSG_LENGTH(0);
+
+ if (netlink_send(&req.nh) < 0)
+ {
+ LOG(0, 0, 0, "Error finishing setting up tun device: %s\n", strerror(errno));
+ exit(1);