Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * DECnet       An implementation of the DECnet protocol suite for the LINUX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *              operating system.  DECnet is implemented using the  BSD Socket
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  *              interface as the means of communication with the user level.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  *              DECnet Routing Forwarding Information Base (Glue/Info List)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  * Author:      Steve Whitehouse <SteveW@ACM.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  * Changes:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13)  *              Alexey Kuznetsov : SMP locking changes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14)  *              Steve Whitehouse : Rewrote it... Well to be more correct, I
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15)  *                                 copied most of it from the ipv4 fib code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16)  *              Steve Whitehouse : Updated it in style and fixed a few bugs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17)  *                                 which were fixed in the ipv4 code since
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18)  *                                 this code was copied from it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) #include <linux/net.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) #include <linux/socket.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) #include <linux/sockios.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) #include <linux/skbuff.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) #include <linux/netlink.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) #include <linux/rtnetlink.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) #include <linux/proc_fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) #include <linux/netdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) #include <linux/timer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) #include <linux/atomic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) #include <net/neighbour.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) #include <net/dst.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) #include <net/flow.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) #include <net/fib_rules.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) #include <net/dn.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) #include <net/dn_route.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) #include <net/dn_fib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) #include <net/dn_neigh.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) #include <net/dn_dev.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) #include <net/rtnh.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) #define RT_MIN_TABLE 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) #define for_fib_info() { struct dn_fib_info *fi;\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 	for(fi = dn_fib_info_list; fi; fi = fi->fib_next)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) #define endfor_fib_info() }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) #define for_nexthops(fi) { int nhsel; const struct dn_fib_nh *nh;\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	for(nhsel = 0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) #define change_nexthops(fi) { int nhsel; struct dn_fib_nh *nh;\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 	for(nhsel = 0, nh = (struct dn_fib_nh *)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nh++, nhsel++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) #define endfor_nexthops(fi) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) static DEFINE_SPINLOCK(dn_fib_multipath_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) static struct dn_fib_info *dn_fib_info_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) static DEFINE_SPINLOCK(dn_fib_info_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) static struct
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 	int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 	u8 scope;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) } dn_fib_props[RTN_MAX+1] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	[RTN_UNSPEC] =      { .error = 0,       .scope = RT_SCOPE_NOWHERE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	[RTN_UNICAST] =     { .error = 0,       .scope = RT_SCOPE_UNIVERSE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 	[RTN_LOCAL] =       { .error = 0,       .scope = RT_SCOPE_HOST },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	[RTN_BROADCAST] =   { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 	[RTN_ANYCAST] =     { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	[RTN_MULTICAST] =   { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 	[RTN_BLACKHOLE] =   { .error = -EINVAL, .scope = RT_SCOPE_UNIVERSE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	[RTN_UNREACHABLE] = { .error = -EHOSTUNREACH, .scope = RT_SCOPE_UNIVERSE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 	[RTN_PROHIBIT] =    { .error = -EACCES, .scope = RT_SCOPE_UNIVERSE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 	[RTN_THROW] =       { .error = -EAGAIN, .scope = RT_SCOPE_UNIVERSE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 	[RTN_NAT] =         { .error = 0,       .scope = RT_SCOPE_NOWHERE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	[RTN_XRESOLVE] =    { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) static int dn_fib_sync_down(__le16 local, struct net_device *dev, int force);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) static int dn_fib_sync_up(struct net_device *dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) void dn_fib_free_info(struct dn_fib_info *fi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	if (fi->fib_dead == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 		printk(KERN_DEBUG "DECnet: BUG! Attempt to free alive dn_fib_info\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	change_nexthops(fi) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 		if (nh->nh_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 			dev_put(nh->nh_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 		nh->nh_dev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	} endfor_nexthops(fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	kfree(fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) void dn_fib_release_info(struct dn_fib_info *fi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	spin_lock(&dn_fib_info_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	if (fi && --fi->fib_treeref == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 		if (fi->fib_next)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 			fi->fib_next->fib_prev = fi->fib_prev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 		if (fi->fib_prev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 			fi->fib_prev->fib_next = fi->fib_next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 		if (fi == dn_fib_info_list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 			dn_fib_info_list = fi->fib_next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 		fi->fib_dead = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 		dn_fib_info_put(fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	spin_unlock(&dn_fib_info_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) static inline int dn_fib_nh_comp(const struct dn_fib_info *fi, const struct dn_fib_info *ofi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 	const struct dn_fib_nh *onh = ofi->fib_nh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 	for_nexthops(fi) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 		if (nh->nh_oif != onh->nh_oif ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 			nh->nh_gw != onh->nh_gw ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 			nh->nh_scope != onh->nh_scope ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 			nh->nh_weight != onh->nh_weight ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 			((nh->nh_flags^onh->nh_flags)&~RTNH_F_DEAD))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 				return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 		onh++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	} endfor_nexthops(fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) static inline struct dn_fib_info *dn_fib_find_info(const struct dn_fib_info *nfi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 	for_fib_info() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 		if (fi->fib_nhs != nfi->fib_nhs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 		if (nfi->fib_protocol == fi->fib_protocol &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 			nfi->fib_prefsrc == fi->fib_prefsrc &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 			nfi->fib_priority == fi->fib_priority &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 			memcmp(nfi->fib_metrics, fi->fib_metrics, sizeof(fi->fib_metrics)) == 0 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 			((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 			(nfi->fib_nhs == 0 || dn_fib_nh_comp(fi, nfi) == 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 				return fi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 	} endfor_fib_info();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) static int dn_fib_count_nhs(const struct nlattr *attr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 	struct rtnexthop *nhp = nla_data(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	int nhs = 0, nhlen = nla_len(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 	while (rtnh_ok(nhp, nhlen)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 		nhs++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 		nhp = rtnh_next(nhp, &nhlen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 	/* leftover implies invalid nexthop configuration, discard it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	return nhlen > 0 ? 0 : nhs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct nlattr *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 			  const struct rtmsg *r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	struct rtnexthop *nhp = nla_data(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	int nhlen = nla_len(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 	change_nexthops(fi) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 		int attrlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 		if (!rtnh_ok(nhp, nhlen))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 		nh->nh_flags  = (r->rtm_flags&~0xFF) | nhp->rtnh_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 		nh->nh_oif    = nhp->rtnh_ifindex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 		nh->nh_weight = nhp->rtnh_hops + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 		attrlen = rtnh_attrlen(nhp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 		if (attrlen > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 			struct nlattr *gw_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 			gw_attr = nla_find((struct nlattr *) (nhp + 1), attrlen, RTA_GATEWAY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 			nh->nh_gw = gw_attr ? nla_get_le16(gw_attr) : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 		nhp = rtnh_next(nhp, &nhlen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 	} endfor_nexthops(fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) static int dn_fib_check_nh(const struct rtmsg *r, struct dn_fib_info *fi, struct dn_fib_nh *nh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 	if (nh->nh_gw) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 		struct flowidn fld;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 		struct dn_fib_res res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 		if (nh->nh_flags&RTNH_F_ONLINK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 			struct net_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 			if (r->rtm_scope >= RT_SCOPE_LINK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 				return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 			if (dnet_addr_type(nh->nh_gw) != RTN_UNICAST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 				return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 			if ((dev = __dev_get_by_index(&init_net, nh->nh_oif)) == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 				return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 			if (!(dev->flags&IFF_UP))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 				return -ENETDOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 			nh->nh_dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 			dev_hold(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 			nh->nh_scope = RT_SCOPE_LINK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 			return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 		memset(&fld, 0, sizeof(fld));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 		fld.daddr = nh->nh_gw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 		fld.flowidn_oif = nh->nh_oif;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 		fld.flowidn_scope = r->rtm_scope + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 		if (fld.flowidn_scope < RT_SCOPE_LINK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 			fld.flowidn_scope = RT_SCOPE_LINK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 		if ((err = dn_fib_lookup(&fld, &res)) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 			return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 		err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 		if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 			goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 		nh->nh_scope = res.scope;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 		nh->nh_oif = DN_FIB_RES_OIF(res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 		nh->nh_dev = DN_FIB_RES_DEV(res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 		if (nh->nh_dev == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 			goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 		dev_hold(nh->nh_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 		err = -ENETDOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 		if (!(nh->nh_dev->flags & IFF_UP))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 			goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 		err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 		dn_fib_res_put(&res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 		struct net_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 		if (nh->nh_flags&(RTNH_F_PERVASIVE|RTNH_F_ONLINK))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 		dev = __dev_get_by_index(&init_net, nh->nh_oif);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 		if (dev == NULL || dev->dn_ptr == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 			return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 		if (!(dev->flags&IFF_UP))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 			return -ENETDOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 		nh->nh_dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 		dev_hold(nh->nh_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 		nh->nh_scope = RT_SCOPE_HOST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct nlattr *attrs[],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 				       const struct nlmsghdr *nlh, int *errp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 	struct dn_fib_info *fi = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 	struct dn_fib_info *ofi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 	int nhs = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 	if (r->rtm_type > RTN_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 		goto err_inval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 	if (dn_fib_props[r->rtm_type].scope > r->rtm_scope)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 		goto err_inval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 	if (attrs[RTA_MULTIPATH] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 	    (nhs = dn_fib_count_nhs(attrs[RTA_MULTIPATH])) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 		goto err_inval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 	fi = kzalloc(struct_size(fi, fib_nh, nhs), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 	err = -ENOBUFS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 	if (fi == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 		goto failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 	fi->fib_protocol = r->rtm_protocol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 	fi->fib_nhs = nhs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 	fi->fib_flags = r->rtm_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 	if (attrs[RTA_PRIORITY])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 		fi->fib_priority = nla_get_u32(attrs[RTA_PRIORITY]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 	if (attrs[RTA_METRICS]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 		struct nlattr *attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 		int rem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 		nla_for_each_nested(attr, attrs[RTA_METRICS], rem) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 			int type = nla_type(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 			if (type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 				if (type > RTAX_MAX || type == RTAX_CC_ALGO ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 				    nla_len(attr) < 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 					goto err_inval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 				fi->fib_metrics[type-1] = nla_get_u32(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 	if (attrs[RTA_PREFSRC])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 		fi->fib_prefsrc = nla_get_le16(attrs[RTA_PREFSRC]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 	if (attrs[RTA_MULTIPATH]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 		if ((err = dn_fib_get_nhs(fi, attrs[RTA_MULTIPATH], r)) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 			goto failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 		if (attrs[RTA_OIF] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 		    fi->fib_nh->nh_oif != nla_get_u32(attrs[RTA_OIF]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 			goto err_inval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 		if (attrs[RTA_GATEWAY] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 		    fi->fib_nh->nh_gw != nla_get_le16(attrs[RTA_GATEWAY]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 			goto err_inval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 		struct dn_fib_nh *nh = fi->fib_nh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 		if (attrs[RTA_OIF])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 			nh->nh_oif = nla_get_u32(attrs[RTA_OIF]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 		if (attrs[RTA_GATEWAY])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 			nh->nh_gw = nla_get_le16(attrs[RTA_GATEWAY]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 		nh->nh_flags = r->rtm_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 		nh->nh_weight = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 	if (r->rtm_type == RTN_NAT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 		if (!attrs[RTA_GATEWAY] || nhs != 1 || attrs[RTA_OIF])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 			goto err_inval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 		fi->fib_nh->nh_gw = nla_get_le16(attrs[RTA_GATEWAY]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 		goto link_it;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 	if (dn_fib_props[r->rtm_type].error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 		if (attrs[RTA_GATEWAY] || attrs[RTA_OIF] || attrs[RTA_MULTIPATH])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 			goto err_inval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 		goto link_it;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 	if (r->rtm_scope > RT_SCOPE_HOST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 		goto err_inval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 	if (r->rtm_scope == RT_SCOPE_HOST) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 		struct dn_fib_nh *nh = fi->fib_nh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 		/* Local address is added */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 		if (nhs != 1 || nh->nh_gw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 			goto err_inval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 		nh->nh_scope = RT_SCOPE_NOWHERE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 		nh->nh_dev = dev_get_by_index(&init_net, fi->fib_nh->nh_oif);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 		err = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 		if (nh->nh_dev == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 			goto failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 		change_nexthops(fi) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 			if ((err = dn_fib_check_nh(r, fi, nh)) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 				goto failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 		} endfor_nexthops(fi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 	if (fi->fib_prefsrc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 		if (r->rtm_type != RTN_LOCAL || !attrs[RTA_DST] ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 		    fi->fib_prefsrc != nla_get_le16(attrs[RTA_DST]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 			if (dnet_addr_type(fi->fib_prefsrc) != RTN_LOCAL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 				goto err_inval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) link_it:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 	if ((ofi = dn_fib_find_info(fi)) != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 		fi->fib_dead = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 		dn_fib_free_info(fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 		ofi->fib_treeref++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 		return ofi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 	fi->fib_treeref++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 	refcount_set(&fi->fib_clntref, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 	spin_lock(&dn_fib_info_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 	fi->fib_next = dn_fib_info_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 	fi->fib_prev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 	if (dn_fib_info_list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) 		dn_fib_info_list->fib_prev = fi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 	dn_fib_info_list = fi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 	spin_unlock(&dn_fib_info_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 	return fi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) err_inval:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 	err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) failure:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 	*errp = err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 	if (fi) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 		fi->fib_dead = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 		dn_fib_free_info(fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 	return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) int dn_fib_semantic_match(int type, struct dn_fib_info *fi, const struct flowidn *fld, struct dn_fib_res *res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 	int err = dn_fib_props[type].error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 	if (err == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 		if (fi->fib_flags & RTNH_F_DEAD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 			return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) 		res->fi = fi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) 		switch (type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 		case RTN_NAT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) 			DN_FIB_RES_RESET(*res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) 			refcount_inc(&fi->fib_clntref);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 			return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) 		case RTN_UNICAST:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 		case RTN_LOCAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) 			for_nexthops(fi) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) 				if (nh->nh_flags & RTNH_F_DEAD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) 					continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) 				if (!fld->flowidn_oif ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 				    fld->flowidn_oif == nh->nh_oif)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) 					break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) 			if (nhsel < fi->fib_nhs) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) 				res->nh_sel = nhsel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) 				refcount_inc(&fi->fib_clntref);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) 				return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) 			endfor_nexthops(fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) 			res->fi = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) 			return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) 		default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) 			net_err_ratelimited("DECnet: impossible routing event : dn_fib_semantic_match type=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) 					    type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 			res->fi = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) 	return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) void dn_fib_select_multipath(const struct flowidn *fld, struct dn_fib_res *res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) 	struct dn_fib_info *fi = res->fi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) 	int w;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) 	spin_lock_bh(&dn_fib_multipath_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) 	if (fi->fib_power <= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) 		int power = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) 		change_nexthops(fi) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) 			if (!(nh->nh_flags&RTNH_F_DEAD)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) 				power += nh->nh_weight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) 				nh->nh_power = nh->nh_weight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) 		} endfor_nexthops(fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) 		fi->fib_power = power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 		if (power < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 			spin_unlock_bh(&dn_fib_multipath_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 			res->nh_sel = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 			return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) 	w = jiffies % fi->fib_power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) 	change_nexthops(fi) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) 		if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) 			if ((w -= nh->nh_power) <= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) 				nh->nh_power--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) 				fi->fib_power--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 				res->nh_sel = nhsel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) 				spin_unlock_bh(&dn_fib_multipath_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) 				return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) 	} endfor_nexthops(fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) 	res->nh_sel = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) 	spin_unlock_bh(&dn_fib_multipath_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) static inline u32 rtm_get_table(struct nlattr *attrs[], u8 table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) 	if (attrs[RTA_TABLE])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) 		table = nla_get_u32(attrs[RTA_TABLE]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) 	return table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) 			       struct netlink_ext_ack *extack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) 	struct net *net = sock_net(skb->sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) 	struct dn_fib_table *tb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) 	struct rtmsg *r = nlmsg_data(nlh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) 	struct nlattr *attrs[RTA_MAX+1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) 	if (!netlink_capable(skb, CAP_NET_ADMIN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) 		return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) 	if (!net_eq(net, &init_net))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) 	err = nlmsg_parse_deprecated(nlh, sizeof(*r), attrs, RTA_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) 				     rtm_dn_policy, extack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) 	if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) 	tb = dn_fib_get_table(rtm_get_table(attrs, r->rtm_table), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) 	if (!tb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) 		return -ESRCH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) 	return tb->delete(tb, r, attrs, nlh, &NETLINK_CB(skb));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) 			       struct netlink_ext_ack *extack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) 	struct net *net = sock_net(skb->sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) 	struct dn_fib_table *tb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) 	struct rtmsg *r = nlmsg_data(nlh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) 	struct nlattr *attrs[RTA_MAX+1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) 	if (!netlink_capable(skb, CAP_NET_ADMIN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) 		return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) 	if (!net_eq(net, &init_net))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) 	err = nlmsg_parse_deprecated(nlh, sizeof(*r), attrs, RTA_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) 				     rtm_dn_policy, extack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) 	if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) 	tb = dn_fib_get_table(rtm_get_table(attrs, r->rtm_table), 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) 	if (!tb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) 		return -ENOBUFS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) 	return tb->insert(tb, r, attrs, nlh, &NETLINK_CB(skb));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifaddr *ifa)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) 	struct dn_fib_table *tb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) 	struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) 		struct nlmsghdr nlh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) 		struct rtmsg rtm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) 	} req;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) 	struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) 		struct nlattr hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) 		__le16 dst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) 	} dst_attr = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) 		.dst = dst,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) 	};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) 	struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) 		struct nlattr hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) 		__le16 prefsrc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) 	} prefsrc_attr = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) 		.prefsrc = ifa->ifa_local,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) 	};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) 	struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) 		struct nlattr hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) 		u32 oif;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) 	} oif_attr = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) 		.oif = ifa->ifa_dev->dev->ifindex,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) 	};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) 	struct nlattr *attrs[RTA_MAX+1] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) 		[RTA_DST] = (struct nlattr *) &dst_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) 		[RTA_PREFSRC] = (struct nlattr * ) &prefsrc_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) 		[RTA_OIF] = (struct nlattr *) &oif_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) 	};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) 	memset(&req.rtm, 0, sizeof(req.rtm));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) 	if (type == RTN_UNICAST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) 		tb = dn_fib_get_table(RT_MIN_TABLE, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) 		tb = dn_fib_get_table(RT_TABLE_LOCAL, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) 	if (tb == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) 	req.nlh.nlmsg_len = sizeof(req);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) 	req.nlh.nlmsg_type = cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) 	req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_APPEND;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) 	req.nlh.nlmsg_pid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) 	req.nlh.nlmsg_seq = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) 	req.rtm.rtm_dst_len = dst_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) 	req.rtm.rtm_table = tb->n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) 	req.rtm.rtm_protocol = RTPROT_KERNEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) 	req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) 	req.rtm.rtm_type = type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) 	if (cmd == RTM_NEWROUTE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) 		tb->insert(tb, &req.rtm, attrs, &req.nlh, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) 		tb->delete(tb, &req.rtm, attrs, &req.nlh, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) static void dn_fib_add_ifaddr(struct dn_ifaddr *ifa)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) 	fib_magic(RTM_NEWROUTE, RTN_LOCAL, ifa->ifa_local, 16, ifa);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) #if 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) 	if (!(dev->flags&IFF_UP))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) 	/* In the future, we will want to add default routes here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) static void dn_fib_del_ifaddr(struct dn_ifaddr *ifa)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) 	int found_it = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) 	struct net_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) 	struct dn_dev *dn_db;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) 	struct dn_ifaddr *ifa2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) 	ASSERT_RTNL();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) 	/* Scan device list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) 	rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) 	for_each_netdev_rcu(&init_net, dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) 		dn_db = rcu_dereference(dev->dn_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) 		if (dn_db == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) 		for (ifa2 = rcu_dereference(dn_db->ifa_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) 		     ifa2 != NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) 		     ifa2 = rcu_dereference(ifa2->ifa_next)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) 			if (ifa2->ifa_local == ifa->ifa_local) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) 				found_it = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) 				break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) 	rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) 	if (found_it == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) 		fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 16, ifa);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) 		if (dnet_addr_type(ifa->ifa_local) != RTN_LOCAL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) 			if (dn_fib_sync_down(ifa->ifa_local, NULL, 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) 				dn_fib_flush();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) static void dn_fib_disable_addr(struct net_device *dev, int force)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) 	if (dn_fib_sync_down(0, dev, force))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) 		dn_fib_flush();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) 	dn_rt_cache_flush(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) 	neigh_ifdown(&dn_neigh_table, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) static int dn_fib_dnaddr_event(struct notifier_block *this, unsigned long event, void *ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) 	struct dn_ifaddr *ifa = (struct dn_ifaddr *)ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) 	switch (event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) 	case NETDEV_UP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) 		dn_fib_add_ifaddr(ifa);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) 		dn_fib_sync_up(ifa->ifa_dev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) 		dn_rt_cache_flush(-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) 	case NETDEV_DOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) 		dn_fib_del_ifaddr(ifa);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) 		if (ifa->ifa_dev && ifa->ifa_dev->ifa_list == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) 			dn_fib_disable_addr(ifa->ifa_dev->dev, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) 		} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) 			dn_rt_cache_flush(-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) 	return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) static int dn_fib_sync_down(__le16 local, struct net_device *dev, int force)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) 	int scope = RT_SCOPE_NOWHERE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) 	if (force)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) 		scope = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) 	for_fib_info() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) 		 * This makes no sense for DECnet.... we will almost
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) 		 * certainly have more than one local address the same
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) 		 * over all our interfaces. It needs thinking about
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) 		 * some more.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) 		if (local && fi->fib_prefsrc == local) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) 			fi->fib_flags |= RTNH_F_DEAD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) 			ret++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) 		} else if (dev && fi->fib_nhs) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) 			int dead = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) 			change_nexthops(fi) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) 				if (nh->nh_flags&RTNH_F_DEAD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) 					dead++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) 				else if (nh->nh_dev == dev &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) 						nh->nh_scope != scope) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) 					spin_lock_bh(&dn_fib_multipath_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) 					nh->nh_flags |= RTNH_F_DEAD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) 					fi->fib_power -= nh->nh_power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) 					nh->nh_power = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) 					spin_unlock_bh(&dn_fib_multipath_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) 					dead++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) 				}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) 			} endfor_nexthops(fi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) 			if (dead == fi->fib_nhs) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) 				fi->fib_flags |= RTNH_F_DEAD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) 				ret++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) 	} endfor_fib_info();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) static int dn_fib_sync_up(struct net_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) 	if (!(dev->flags&IFF_UP))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) 	for_fib_info() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) 		int alive = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) 		change_nexthops(fi) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) 			if (!(nh->nh_flags&RTNH_F_DEAD)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) 				alive++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) 				continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) 			if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) 				continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) 			if (nh->nh_dev != dev || dev->dn_ptr == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) 				continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) 			alive++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) 			spin_lock_bh(&dn_fib_multipath_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) 			nh->nh_power = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) 			nh->nh_flags &= ~RTNH_F_DEAD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) 			spin_unlock_bh(&dn_fib_multipath_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) 		} endfor_nexthops(fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) 		if (alive > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) 			fi->fib_flags &= ~RTNH_F_DEAD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) 			ret++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) 	} endfor_fib_info();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) static struct notifier_block dn_fib_dnaddr_notifier = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) 	.notifier_call = dn_fib_dnaddr_event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) void __exit dn_fib_cleanup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) 	dn_fib_table_cleanup();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) 	dn_fib_rules_cleanup();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) 	unregister_dnaddr_notifier(&dn_fib_dnaddr_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) void __init dn_fib_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) 	dn_fib_table_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) 	dn_fib_rules_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) 	register_dnaddr_notifier(&dn_fib_dnaddr_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) 	rtnl_register_module(THIS_MODULE, PF_DECnet, RTM_NEWROUTE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) 			     dn_fib_rtm_newroute, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) 	rtnl_register_module(THIS_MODULE, PF_DECnet, RTM_DELROUTE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) 			     dn_fib_rtm_delroute, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) }