Skip to content
Snippets Groups Projects
host_utils.c 8.25 KiB
Newer Older
  • Learn to ignore specific revisions
  • Nevadita's avatar
    Nevadita committed
    /*
     * host_utils.c -- utils for host
     *
     * Author: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
     * Author: Sukru Senli sukru.senli@inteno.se
     * Author: Nevadita Chatterjee nevadita.chatterjee@iopsys.eu
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * version 2 as published by the Free Software Foundation.
     *
     * This program is distributed in the hope that it will be useful, but
     * WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     * General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with this program; If not, see <http://www.gnu.org/licenses/>.
     */
    
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    #ifndef _GNU_SOURCE
    
    Nevadita's avatar
    Nevadita committed
    #define _GNU_SOURCE
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    #endif
    
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <net/if.h>
    #include <sys/ioctl.h>
    #include <netpacket/packet.h>
    #include <net/ethernet.h>
    #include <net/if_arp.h>
    #include <netinet/ether.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <string.h>
    #include <stdbool.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <libubus.h>
    
    Nevadita's avatar
    Nevadita committed
    #include <linux/netlink.h>
    #include <linux/rtnetlink.h>
    
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    #include <netlink/netlink.h>
    #include <netlink/utils.h>
    
    #include <netlink/route/rtnl.h>
    #include <netlink/route/neighbour.h>
    #include <netlink/route/addr.h>
    #include <netlink/route/link.h>
    #include <netlink/genl/ctrl.h>
    #include <netlink/genl/genl.h>
    #include <netlink/attr.h>
    
    #include <uci.h>
    #include <easy/easy.h>
    
    #include "debug.h"
    #include "host_config.h"
    #include "topologyd.h"
    #include "host.h"
    #include "host_utils.h"
    
    #ifndef TLV_TYPE_END_OF_MESSAGE
    #define TLV_TYPE_END_OF_MESSAGE 0x00
    #endif
    
    Nevadita's avatar
    Nevadita committed
    
    struct in_addr src;
    struct in_addr dst;
    struct sockaddr_ll me;
    struct sockaddr_ll he;
    int sock_fd;
    
    typedef struct nl_req_s nl_req_t;
    
    struct nl_req_s {
    	struct nlmsghdr hdr;
    	struct rtgenmsg gen;
    };
    
    int host_get_netlink_ip(uint8_t *mac_addr, char *ipv4_str, char *device)
    {
    	struct rtnl_neigh *neigh;
    	struct nl_object *nobj;
    	struct nl_cache *cache;
    	uint32_t ifindex = 0;
    	struct nl_sock *sk;
    	int i, num;
    	int ret;
    	char *ifname = NULL;
    
    	dbg("Inside %s %d\n", __func__, __LINE__);
    	sk = nl_socket_alloc();
    	if (!sk) {
    		err("Unable to open nl event socket\n");
    		return -1;
    	}
    
    	if (nl_connect(sk, NETLINK_ROUTE) < 0) {
    		nl_socket_free(sk);
    		return -1;
    	}
    
    	ret = rtnl_neigh_alloc_cache(sk, &cache);
    	if (ret) {
    		nl_socket_free(sk);
    		return -1;
    	}
    
    
    	num = nl_cache_nitems(cache);
    	nobj = nl_cache_get_first(cache);
    	neigh = (struct rtnl_neigh *)nobj;
    
    	for (i = 0; i < num; i++) {
    		struct nl_addr *lladdr;
    		struct nl_addr *ipaddr;
    		struct ip_address ip = {0};
    		uint8_t hwaddr[6] = {0};
    		char addr_str[24];
    
    		nl_object_get((struct nl_object *) neigh);
    
    		ifindex = rtnl_neigh_get_ifindex(neigh);
    		lladdr = rtnl_neigh_get_lladdr(neigh);
    		if (lladdr)
    			memcpy(hwaddr, nl_addr_get_binary_addr(lladdr),
    				nl_addr_get_len(lladdr));
    
    		if (hwaddr_is_zero(hwaddr)) {
    			nl_object_put((struct nl_object *) neigh);
    			nobj = nl_cache_get_next(nobj);
    			neigh = (struct rtnl_neigh *)nobj;
    			continue;
    		}
    
    		ipaddr = rtnl_neigh_get_dst(neigh);
    		if (ipaddr) {
    			ip.family = nl_addr_get_family(ipaddr);
    
    			if (ip.family == AF_INET6) {
    				nl_object_put((struct nl_object *) neigh);
    				nobj = nl_cache_get_next(nobj);
    				neigh = (struct rtnl_neigh *)nobj;
    				continue;
    			}
    			if (ip.family == AF_INET) {
    
    Nevadita's avatar
    Nevadita committed
    				memcpy(&ip.addr, nl_addr_get_binary_addr(ipaddr),
    				       nl_addr_get_len(ipaddr));
    			}
    		}
    
    		char *addr_s = nl_addr2str(ipaddr, addr_str, sizeof(addr_str));
    
    		if (addr_s == NULL) {
    			/* error */
    			err("nl_addr2str failed\n");
    
    			nl_object_put((struct nl_object *) neigh);
    
    			nl_cache_free(cache);
    			nl_socket_free(sk);
    
    Nevadita's avatar
    Nevadita committed
    			return -1;
    		}
    
    		ret = memcmp(hwaddr, mac_addr, 6);
    		if (ret == 0) {
    			strncpy(ipv4_str, addr_str, 24);
    			ifname = if_indextoname(ifindex, device);
    
    			if (ifname == NULL) {
    
    				nl_object_put((struct nl_object *) neigh);
    
    				nl_cache_free(cache);
    				nl_socket_free(sk);
    
    Nevadita's avatar
    Nevadita committed
    				return -1;
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    			dbg("intfname = [%s] ipv4addr= [%s] mac=["MACFMT"]\n",
    			    device, ipv4_str, MAC2STR(hwaddr));
    
    
    			nl_object_put((struct nl_object *) neigh);
    
    Nevadita's avatar
    Nevadita committed
    			break;
    		}
    
    		nl_object_put((struct nl_object *) neigh);
    		nobj = nl_cache_get_next(nobj);
    		neigh = (struct rtnl_neigh *)nobj;
    	}
    
    	nl_cache_free(cache);
    	nl_socket_free(sk);
    
    	return 0;
    }
    
    int host_get_netlink_ip6(uint8_t *mac_addr, struct host_node *p)
    {
    	struct rtnl_neigh *neigh;
    	struct nl_object *nobj;
    	struct nl_cache *cache;
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    	//uint32_t ifindex = 0;
    
    	struct nl_sock *sk;
    	int i, num;
    	int ret;
    
    	dbg("Inside %s %d\n", __func__, __LINE__);
    	sk = nl_socket_alloc();
    	if (!sk) {
    		err("Unable to open nl event socket\n");
    		return -1;
    	}
    
    	if (nl_connect(sk, NETLINK_ROUTE) < 0) {
    		nl_socket_free(sk);
    		return -1;
    	}
    
    	ret = rtnl_neigh_alloc_cache(sk, &cache);
    	if (ret) {
    		nl_socket_free(sk);
    		return -1;
    	}
    
    	num = nl_cache_nitems(cache);
    	nobj = nl_cache_get_first(cache);
    	neigh = (struct rtnl_neigh *)nobj;
    	p->ipv6addr_count = 0;
    
    	for (i = 0; i < num; i++) {
    		struct nl_addr *lladdr;
    		struct nl_addr *ipaddr;
    		struct ip_address ip = {0};
    		uint8_t hwaddr[6] = {0};
    		char addr_str[128];
    
    		nl_object_get((struct nl_object *) neigh);
    
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    		//ifindex = rtnl_neigh_get_ifindex(neigh);
    
    		lladdr = rtnl_neigh_get_lladdr(neigh);
    		if (lladdr)
    			memcpy(hwaddr, nl_addr_get_binary_addr(lladdr),
    				nl_addr_get_len(lladdr));
    
    		if (hwaddr_is_zero(hwaddr)) {
    			nl_object_put((struct nl_object *) neigh);
    			nobj = nl_cache_get_next(nobj);
    			neigh = (struct rtnl_neigh *)nobj;
    			continue;
    		}
    
    		ipaddr = rtnl_neigh_get_dst(neigh);
    		if (ipaddr) {
    			ip.family = nl_addr_get_family(ipaddr);
    			if (ip.family == AF_INET6) {
    				memcpy(&ip.addr, nl_addr_get_binary_addr(ipaddr),
    					nl_addr_get_len(ipaddr));
    			} else {
    				nl_object_put((struct nl_object *) neigh);
    				nobj = nl_cache_get_next(nobj);
    				neigh = (struct rtnl_neigh *)nobj;
    				continue;
    			}
    		}
    		char *addr_s = nl_addr2str(ipaddr, addr_str, sizeof(addr_str));
    
    		if (addr_s == NULL) {
    			/* error */
    			err("nl_addr2str failed\n");
    			nl_object_put((struct nl_object *) neigh);
    			nl_cache_free(cache);
    			nl_socket_free(sk);
    			return -1;
    		}
    
    		ret = memcmp(hwaddr, mac_addr, 6);
    		if (ret == 0) {
    
    			if (p->ipv6addr_count >= HOST_MAX_IPV6ADDR) {
    				nl_object_put((struct nl_object *) neigh);
    				break;
    			}
    			memset(p->ipv6addr[p->ipv6addr_count], 0, 128);
    			strncpy(p->ipv6addr[p->ipv6addr_count], addr_str, 127);
    
    			dbg("ipv6addr= [%s] mac=["MACFMT"]\n", p->ipv6addr[p->ipv6addr_count], MAC2STR(hwaddr));
    			p->ipv6addr_count = p->ipv6addr_count + 1;
    		}
    
    		nl_object_put((struct nl_object *) neigh);
    		nobj = nl_cache_get_next(nobj);
    		neigh = (struct rtnl_neigh *)nobj;
    	}
    
    	nl_cache_free(cache);
    	nl_socket_free(sk);
    
    	return 0;
    }
    
    
    void _E1B(uint8_t **packet_ppointer, uint8_t *memory_pointer)
    {
    	*memory_pointer = **packet_ppointer;
    	(*packet_ppointer) += 1;
    }
    
    // Extract/insert 2 bytes
    void _E2B(uint8_t **packet_ppointer, uint16_t *memory_pointer)
    {
    	uint16_t mem = 0;
    	*(((uint8_t *) &mem) + 0) = **packet_ppointer;
    	(*packet_ppointer)++;
    	*(((uint8_t *) &mem) + 1) = **packet_ppointer;
    	(*packet_ppointer)++;
    	*memory_pointer = ntohs(mem);
    }
    
    // Extract/insert N bytes (ignore endianess)
    void _EnB(uint8_t **packet_ppointer,
    		void *memory_pointer,
    		uint32_t n)
    {
    	memcpy(memory_pointer, *packet_ppointer, n);
    	(*packet_ppointer) += n;
    }
    
    // count includes end-of-message tlv
    uint8_t count_tlv_present_instream_unsafe(uint8_t *tlv_stream)
    {
    	uint8_t *p = tlv_stream;
    	uint8_t tlv_type, count = 0;
    	uint16_t tlv_len = 0;
    
    	if (tlv_stream == NULL) {
    		err("tlv Stream is empty\n");
    		return 0;
    	}
    
    	do {
    		_E1B(&p, &tlv_type);
    		_E2B(&p, &tlv_len);
    
    		p = p + tlv_len;
    		count++;
    	} while (tlv_type != TLV_TYPE_END_OF_MESSAGE);
    
    	return count;
    }
    
    uint16_t get_tlv_packet_len(uint8_t *tlv_stream)
    {
    	uint8_t *p;
    	uint8_t type;
    	uint16_t len;
    
    	if (tlv_stream == NULL)
    		return 0;
    
    	p = tlv_stream;
    	_E1B(&p, &type);
    	_E2B(&p, &len);
    
    	// tlv packet does not have length of tlv_type(1 Byte) and
    	// tlv_len(2 Bytes) included
    	return len + 3;
    }
    
    uint8_t get_tlv_packet_type(uint8_t *tlv_stream)
    {
    	uint8_t *p;
    	uint8_t type;
    	uint16_t len;
    
    	if (tlv_stream == NULL)
    		return 0;
    
    	p = tlv_stream;
    	_E1B(&p, &type);
    	_E2B(&p, &len);
    
    	return type;
    }