cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dn_fib.c (19088B)


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