<commit_before>/**
 * @file
 * @brief implementation of the IP router.
 *
 * @date 16.11.09
 * @author <NAME>
 * @author <NAME>
 * @author <NAME>
 */

#include <errno.h>
#include <assert.h>
#include <net/l3/route.h>
#include <linux/in.h>
#include <mem/misc/pool.h>
#include <net/inetdevice.h>
#include <util/bit.h>
#include <util/dlist.h>
#include <util/member.h>
#include <net/skbuff.h>
#include <net/sock.h>

#include <framework/mod/options.h>

/**
 * NOTE: Linux route uses 3 structures for routing:
 *    + Forwarding Information Base (FIB)
 *    - routing cache (256 chains)
 *    + neighbour table (ARP cache)
 */

struct rt_entry_info {
	struct dlist_head lnk;
	struct rt_entry entry;
};

POOL_DEF(rt_entry_info_pool, struct rt_entry_info, OPTION_GET(NUMBER,route_table_size));
static DLIST_DEFINE(rt_entry_info_list);

int rt_add_route(struct net_device *dev, in_addr_t dst,
		in_addr_t mask, in_addr_t gw, int flags) {
	struct rt_entry_info *rt_info;
	bool flag = true;

	if (dev == NULL) {
		return -EINVAL;
	}

	dlist_foreach_entry(rt_info, &rt_entry_info_list, lnk) {
		if ((rt_info->entry.rt_dst == dst) &&
                ((rt_info->entry.rt_mask == mask) || (INADDR_ANY == mask)) &&
    			((rt_info->entry.rt_gateway == gw) || (INADDR_ANY == gw)) &&
    			((rt_info->entry.dev == dev) || (NULL == dev))) {
			flag = false;
			return 0;
		}
	}

	if (flag) {
		rt_info = (struct rt_entry_info *)pool_alloc(&rt_entry_info_pool);
		if (rt_info == NULL) {
			return -ENOMEM;
		}
		rt_info->entry.dev = dev;
		rt_info->entry.rt_dst = dst; /* We assume that host bits are zeroes here */
		rt_info->entry.rt_mask = mask;
		rt_info->entry.rt_gateway = gw;
		rt_info->entry.rt_flags = RTF_UP | flags;
		dlist_add_prev_entry(rt_info, &rt_entry_info_list, lnk);
	}

	return 0;
}

int rt_del_route(struct net_device *dev, in_addr_t dst,
		in_addr_t mask, in_addr_t gw) {
	struct rt_entry_info *rt_info;

	dlist_foreach_entry(rt_info, &rt_entry_info_list, lnk) {
		if ((rt_info->entry.rt_dst == dst) &&
                ((rt_info->entry.rt_mask == mask) || (INADDR_ANY == mask)) &&
    			((rt_info->entry.rt_gateway == gw) || (INADDR_ANY == gw)) &&
    			((rt_info->entry.dev == dev) || (NULL == dev))) {
			dlist_del_init_entry(rt_info, lnk);
			pool_free(&rt_entry_info_pool, rt_info);
			return 0;
		}
	}

	return -ENOENT;
}

int rt_del_route_if(struct net_device *dev) {
	struct rt_entry_info *rt_info;
	int ret = 0;

	dlist_foreach_entry(rt_info, &rt_entry_info_list, lnk) {
		if (rt_info->entry.dev == dev) {
			dlist_del_init_entry(rt_info, lnk);
			pool_free(&rt_entry_info_pool, rt_info);
			ret ++;
		}
	}

	return ret ? 0 : -ENOENT;
}

/* svv: ToDo:
 *      1) this function returns -ENOENT/0, but arp_resolve -1/0
 *         style must be the same
 *      2) Carrier without ARP can't be supported
 */
int ip_route(struct sk_buff *skb, struct net_device *wanna_dev,
		struct rt_entry *suggested_route) {
	in_addr_t daddr;
	struct rt_entry *rte;

	assert(skb != NULL);
	assert(skb->nh.iph != NULL);
	daddr = skb->nh.iph->daddr;

	/* SO_BROADCAST assert. */
	if (daddr == INADDR_BROADCAST) {
		if (wanna_dev == NULL) {
			return -ENODEV;
		}
		skb->dev = wanna_dev;
		return 0;
	}

	/* if loopback set lo device */
	if (ip_is_local(daddr, 0)) {
		assert(inetdev_get_loopback_dev() != NULL);
		skb->dev = inetdev_get_loopback_dev()->dev;
		return 0;
	}

	/* route destination address */
	rte = ((wanna_dev == NULL)
		? (suggested_route == NULL) ? rt_fib_get_best(daddr, NULL) : suggested_route
		: rt_fib_get_best(daddr, wanna_dev));
	if (rte == NULL) {
		return -ENETUNREACH;
	}

	/* set the device for current destination address */
	assert(rte->dev != NULL);
	assert((wanna_dev == NULL) || (wanna_dev == rte->dev));
	skb->dev = rte->dev;

	/* if the packet should be sent using gateway
	 * nothing todo there. all will be done in arp_resolve */
	return 0;
}

int rt_fib_route_ip(in_addr_t dst_ip, in_addr_t *next_ip) {
	struct rt_entry *rte;

	if (dst_ip == INADDR_BROADCAST) {
		*next_ip = dst_ip;
		return 0;
	}

	rte = rt_fib_get_best(dst_ip, NULL);
	if (rte == NULL) {
		return -ENETUNREACH;
	}

	*next_ip = rte->rt_gateway == INADDR_ANY ? dst_ip
			: rte->rt_gateway;

	return 0;<commit_msg>net: minor: Clean net/l3/route.c a bit<commit_after>/**
 * @file
 * @brief implementation of the IP router.
 *
 * @date 16.11.09
 * @author <NAME>
 * @author <NAME>
 * @author <NAME>
 */

#include <errno.h>
#include <assert.h>
#include <net/l3/route.h>
#include <linux/in.h>
#include <mem/misc/pool.h>
#include <net/inetdevice.h>
#include <util/bit.h>
#include <util/dlist.h>
#include <util/member.h>
#include <net/skbuff.h>
#include <net/sock.h>

#include <framework/mod/options.h>

/**
 * NOTE: Linux route uses 3 structures for routing:
 *    + Forwarding Information Base (FIB)
 *    - routing cache (256 chains)
 *    + neighbour table (ARP cache)
 */

struct rt_entry_info {
	struct dlist_head lnk;
	struct rt_entry entry;
};

POOL_DEF(rt_entry_info_pool, struct rt_entry_info, OPTION_GET(NUMBER,route_table_size));
static DLIST_DEFINE(rt_entry_info_list);

int rt_add_route(struct net_device *dev, in_addr_t dst,
		in_addr_t mask, in_addr_t gw, int flags) {
	struct rt_entry_info *rt_info;
	bool flag = true;

	if (dev == NULL) {
		return -EINVAL;
	}

	dlist_foreach_entry(rt_info, &rt_entry_info_list, lnk) {
		if ((rt_info->entry.rt_dst == dst) &&
                ((rt_info->entry.rt_mask == mask) || (INADDR_ANY == mask)) &&
    			((rt_info->entry.rt_gateway == gw) || (INADDR_ANY == gw)) &&
    			((rt_info->entry.dev == dev) || (NULL == dev))) {
			flag = false;
			return 0;
		}
	}

	if (flag) {
		rt_info = (struct rt_entry_info *)pool_alloc(&rt_entry_info_pool);
		if (rt_info == NULL) {
			return -ENOMEM;
		}
		rt_info->entry.dev = dev;
		rt_info->entry.rt_dst = dst; /* We assume that host bits are zeroes here */
		rt_info->entry.rt_mask = mask;
		rt_info->entry.rt_gateway = gw;
		rt_info->entry.rt_flags = RTF_UP | flags;
		dlist_add_prev_entry(rt_info, &rt_entry_info_list, lnk);
	}

	return 0;
}

int rt_del_route(struct net_device *dev, in_addr_t dst,
		in_addr_t mask, in_addr_t gw) {
	struct rt_entry_info *rt_info;

	dlist_foreach_entry(rt_info, &rt_entry_info_list, lnk) {
		if ((rt_info->entry.rt_dst == dst) &&
                ((rt_info->entry.rt_mask == mask) || (INADDR_ANY == mask)) &&
    			((rt_info->entry.rt_gateway == gw) || (INADDR_ANY == gw)) &&
    			((rt_info->entry.dev == dev) || (NULL == dev))) {
			dlist_del_init_entry(rt_info, lnk);
			pool_free(&rt_entry_info_pool, rt_info);
			return 0;
		}
	}

	return -ENOENT;
}

int rt_del_route_if(struct net_device *dev) {
	struct rt_entry_info *rt_info;
	int ret = 0;

	dlist_foreach_entry(rt_info, &rt_entry_info_list, lnk) {
		if (rt_info->entry.dev == dev) {
			dlist_del_init_entry(rt_info, lnk);
			pool_free(&rt_entry_info_pool, rt_info);
			ret ++;
		}
	}

	return ret ? 0 : -ENOENT;
}

/* svv: ToDo:
 *      1) this function returns -ENOENT/0, but arp_resolve -1/0
 *         style must be the same
 *      2) Carrier without ARP can't be supported
 */
int ip_route(struct sk_buff *skb, struct net_device *wanna_dev,
		struct rt_entry *suggested_route) {
	in_addr_t daddr;
	struct rt_entry *rte;

	assert(skb != NULL);
	assert(skb->nh.iph != NULL);
	daddr = skb->nh.iph->daddr;

	/* SO_BROADCAST assert. */
	if (daddr == INADDR_BROADCAST) {
		if (wanna_dev == NULL) {
			return -ENODEV;
		}
		skb->dev = wanna_dev;
		return 0;
	}

	/* if loopback set lo device */
	if (ip_is_local(daddr, 0)) {
		assert(inetdev_get_loopback_dev() != NULL);
		skb->dev = inetdev_get_loopback_dev()->dev;
		return 0;
	}

	/* route destination address */
	rte = ((wanna_dev == NULL)
		? (suggested_route == NULL) ? rt_fib_get_best(daddr, NULL) : suggested_route
		: rt_fib_get_best(daddr, wanna_dev));
	if (rte == NULL) {
		return -ENETUNREACH;
	}

	/* set the device for current destination address */
	assert(rte->dev != NULL);
	assert((wanna_dev == NULL) || (wanna_dev == rte->dev));
	skb->dev = rte->dev;

	/* if the packet should be sent using gateway
	 * nothing todo there. all will be done in arp_resolve */
	return 0;
}

int rt_fib_route_ip(in_addr_t dst_ip, in_addr_t *next_ip) {
	struct rt_entry *rte;

	if (dst_ip == INADDR_BROADCAST) {
		*next_ip = dst_ip;
		return 0;
	}

	rte = rt_fib_get_best(dst_ip, NULL);
	if (rte == NULL) {
		return -ENETUNREACH;
	}

	if (rte->rt_gateway == INADDR_ANY) {
		*next_ip = dst_ip;
	} else {
		*next_ip = rte->rt_gateway;
	}

	return 0;
{'fraction_non_alphanumeric': 0.14861995753715498, 'fraction_numerical': 0.006487379098844067, 'mean_word_length': 3.6690528634361232, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 85, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5857112', 'n_tokens_mistral': 3669, 'n_tokens_neox': 3447, 'n_words': 749}