/* * tun_add_eid_to_iface() * * Add an EID to the TUN/TAP interface */ int tun_add_eid_to_iface( lisp_addr_t eid_address, char *dev_name) { struct rtattr *rta = NULL; struct ifaddrmsg *ifa = NULL; struct nlmsghdr *nlh = NULL; char sndbuf[4096]; int retval = 0; int sockfd = 0; int ifindex = 0; int addr_size = 0; int prefix_length = 0; ifindex = if_nametoindex (dev_name); sockfd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); if (sockfd < 0) { lispd_log_msg(LISP_LOG_ERR, "tun_add_eid_to_iface: Failed to connect to netlink socket"); return(BAD); } if (eid_address.afi == AF_INET){ addr_size = sizeof(struct in_addr); prefix_length = 32; }else { addr_size = sizeof(struct in6_addr); prefix_length = 128; } /* * Build the command */ memset(sndbuf, 0, 4096); nlh = (struct nlmsghdr *)sndbuf; nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg) + sizeof(struct rtattr) + addr_size); nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE; nlh->nlmsg_type = RTM_NEWADDR; ifa = (struct ifaddrmsg *)(sndbuf + sizeof(struct nlmsghdr)); ifa->ifa_prefixlen = prefix_length; ifa->ifa_family = eid_address.afi; ifa->ifa_index = ifindex; ifa->ifa_scope = RT_SCOPE_UNIVERSE; ifa->ifa_flags = 0; // Bring it up rta = (struct rtattr *)(sndbuf + sizeof(struct nlmsghdr) + sizeof(struct ifaddrmsg)); rta->rta_type = IFA_LOCAL; rta->rta_len = sizeof(struct rtattr) + addr_size; memcopy_lisp_addr((void *)((char *)rta + sizeof(struct rtattr)),&eid_address); retval = send(sockfd, sndbuf, nlh->nlmsg_len, 0); if (retval < 0) { lispd_log_msg(LISP_LOG_ERR, "tun_add_eid_to_iface: send() failed %s", strerror(errno)); close(sockfd); return(BAD); } lispd_log_msg(LISP_LOG_DEBUG_1, "added %s EID to TUN interface.",get_char_from_lisp_addr_t(eid_address)); close(sockfd); return(GOOD); }
void add_ip_header ( char *position, char *original_packet_position, int ip_payload_length, lisp_addr_t *src_addr, lisp_addr_t *dst_addr) { struct iphdr *iph = NULL; struct iphdr *inner_iph = NULL; struct ip6_hdr *ip6h = NULL; struct ip6_hdr *inner_ip6h = NULL; uint8_t tos = 0; uint8_t ttl = 0; inner_iph = (struct iphdr *) original_packet_position; /* We SHOULD copy ttl and tos fields from the inner packet to the encapsulated one */ if (inner_iph->version == 4 ) { tos = inner_iph->tos; ttl = inner_iph->ttl; } else { inner_ip6h = (struct ip6_hdr *) original_packet_position; ttl = inner_ip6h->ip6_hops; /* ttl = Hops limit in IPv6 */ //tos = (inner_ip6h->ip6_flow & 0x0ff00000) >> 20; /* 4 bits version, 8 bits Traffic Class, 20 bits flow-ID */ tos = IPV6_GET_TC(*inner_ip6h); /* tos = Traffic class field in IPv6 */ } /* * Construct and add the outer ip header */ switch (dst_addr->afi){ case AF_INET: iph = (struct iphdr *) position; iph->version = 4; //iph->ihl = sizeof ( struct iphdr ) >>2; iph->ihl = 5; /* Minimal IPv4 header */ /*XXX Beware, hardcoded. Supposing no IP options */ iph->tos = tos; iph->tot_len = htons(ip_payload_length); iph->frag_off = htons(IP_DF); /* Do not fragment flag. See 5.4.1 in LISP RFC (6830) */ iph->ttl = ttl; iph->protocol = IPPROTO_UDP; iph->check = 0; //Computed by the NIC (checksum offloading) iph->daddr = dst_addr->address.ip.s_addr; iph->saddr = src_addr->address.ip.s_addr; break; case AF_INET6: ip6h = ( struct ip6_hdr *) position; IPV6_SET_VERSION(ip6h, 6); IPV6_SET_TC(ip6h,tos); IPV6_SET_FLOW_LABEL(ip6h,0); ip6h->ip6_plen = htons(ip_payload_length); ip6h->ip6_nxt = IPPROTO_UDP; ip6h->ip6_hops = ttl; memcopy_lisp_addr(&(ip6h->ip6_dst),dst_addr); memcopy_lisp_addr(&(ip6h->ip6_src),src_addr); break; default: break; } }