Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * DECnet       An implementation of the DECnet protocol suite for the LINUX
0004  *              operating system.  DECnet is implemented using the  BSD Socket
0005  *              interface as the means of communication with the user level.
0006  *
0007  *              DECnet Routing Forwarding Information Base (Glue/Info List)
0008  *
0009  * Author:      Steve Whitehouse <SteveW@ACM.org>
0010  *
0011  *
0012  * Changes:
0013  *              Alexey Kuznetsov : SMP locking changes
0014  *              Steve Whitehouse : Rewrote it... Well to be more correct, I
0015  *                                 copied most of it from the ipv4 fib code.
0016  *              Steve Whitehouse : Updated it in style and fixed a few bugs
0017  *                                 which were fixed in the ipv4 code since
0018  *                                 this code was copied from it.
0019  *
0020  */
0021 #include <linux/string.h>
0022 #include <linux/net.h>
0023 #include <linux/socket.h>
0024 #include <linux/slab.h>
0025 #include <linux/sockios.h>
0026 #include <linux/init.h>
0027 #include <linux/skbuff.h>
0028 #include <linux/netlink.h>
0029 #include <linux/rtnetlink.h>
0030 #include <linux/proc_fs.h>
0031 #include <linux/netdevice.h>
0032 #include <linux/timer.h>
0033 #include <linux/spinlock.h>
0034 #include <linux/atomic.h>
0035 #include <linux/uaccess.h>
0036 #include <net/neighbour.h>
0037 #include <net/dst.h>
0038 #include <net/flow.h>
0039 #include <net/fib_rules.h>
0040 #include <net/dn.h>
0041 #include <net/dn_route.h>
0042 #include <net/dn_fib.h>
0043 #include <net/dn_neigh.h>
0044 #include <net/dn_dev.h>
0045 #include <net/rtnh.h>
0046 
0047 #define RT_MIN_TABLE 1
0048 
0049 #define for_fib_info() { struct dn_fib_info *fi;\
0050     for(fi = dn_fib_info_list; fi; fi = fi->fib_next)
0051 #define endfor_fib_info() }
0052 
0053 #define for_nexthops(fi) { int nhsel; const struct dn_fib_nh *nh;\
0054     for(nhsel = 0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++)
0055 
0056 #define change_nexthops(fi) { int nhsel; struct dn_fib_nh *nh;\
0057     for(nhsel = 0, nh = (struct dn_fib_nh *)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nh++, nhsel++)
0058 
0059 #define endfor_nexthops(fi) }
0060 
0061 static DEFINE_SPINLOCK(dn_fib_multipath_lock);
0062 static struct dn_fib_info *dn_fib_info_list;
0063 static DEFINE_SPINLOCK(dn_fib_info_lock);
0064 
0065 static struct
0066 {
0067     int error;
0068     u8 scope;
0069 } dn_fib_props[RTN_MAX+1] = {
0070     [RTN_UNSPEC] =      { .error = 0,       .scope = RT_SCOPE_NOWHERE },
0071     [RTN_UNICAST] =     { .error = 0,       .scope = RT_SCOPE_UNIVERSE },
0072     [RTN_LOCAL] =       { .error = 0,       .scope = RT_SCOPE_HOST },
0073     [RTN_BROADCAST] =   { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
0074     [RTN_ANYCAST] =     { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
0075     [RTN_MULTICAST] =   { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
0076     [RTN_BLACKHOLE] =   { .error = -EINVAL, .scope = RT_SCOPE_UNIVERSE },
0077     [RTN_UNREACHABLE] = { .error = -EHOSTUNREACH, .scope = RT_SCOPE_UNIVERSE },
0078     [RTN_PROHIBIT] =    { .error = -EACCES, .scope = RT_SCOPE_UNIVERSE },
0079     [RTN_THROW] =       { .error = -EAGAIN, .scope = RT_SCOPE_UNIVERSE },
0080     [RTN_NAT] =         { .error = 0,       .scope = RT_SCOPE_NOWHERE },
0081     [RTN_XRESOLVE] =    { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
0082 };
0083 
0084 static int dn_fib_sync_down(__le16 local, struct net_device *dev, int force);
0085 static int dn_fib_sync_up(struct net_device *dev);
0086 
0087 void dn_fib_free_info(struct dn_fib_info *fi)
0088 {
0089     if (fi->fib_dead == 0) {
0090         printk(KERN_DEBUG "DECnet: BUG! Attempt to free alive dn_fib_info\n");
0091         return;
0092     }
0093 
0094     change_nexthops(fi) {
0095         dev_put(nh->nh_dev);
0096         nh->nh_dev = NULL;
0097     } endfor_nexthops(fi);
0098     kfree(fi);
0099 }
0100 
0101 void dn_fib_release_info(struct dn_fib_info *fi)
0102 {
0103     spin_lock(&dn_fib_info_lock);
0104     if (fi && refcount_dec_and_test(&fi->fib_treeref)) {
0105         if (fi->fib_next)
0106             fi->fib_next->fib_prev = fi->fib_prev;
0107         if (fi->fib_prev)
0108             fi->fib_prev->fib_next = fi->fib_next;
0109         if (fi == dn_fib_info_list)
0110             dn_fib_info_list = fi->fib_next;
0111         fi->fib_dead = 1;
0112         dn_fib_info_put(fi);
0113     }
0114     spin_unlock(&dn_fib_info_lock);
0115 }
0116 
0117 static inline int dn_fib_nh_comp(const struct dn_fib_info *fi, const struct dn_fib_info *ofi)
0118 {
0119     const struct dn_fib_nh *onh = ofi->fib_nh;
0120 
0121     for_nexthops(fi) {
0122         if (nh->nh_oif != onh->nh_oif ||
0123             nh->nh_gw != onh->nh_gw ||
0124             nh->nh_scope != onh->nh_scope ||
0125             nh->nh_weight != onh->nh_weight ||
0126             ((nh->nh_flags^onh->nh_flags)&~RTNH_F_DEAD))
0127                 return -1;
0128         onh++;
0129     } endfor_nexthops(fi);
0130     return 0;
0131 }
0132 
0133 static inline struct dn_fib_info *dn_fib_find_info(const struct dn_fib_info *nfi)
0134 {
0135     for_fib_info() {
0136         if (fi->fib_nhs != nfi->fib_nhs)
0137             continue;
0138         if (nfi->fib_protocol == fi->fib_protocol &&
0139             nfi->fib_prefsrc == fi->fib_prefsrc &&
0140             nfi->fib_priority == fi->fib_priority &&
0141             memcmp(nfi->fib_metrics, fi->fib_metrics, sizeof(fi->fib_metrics)) == 0 &&
0142             ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 &&
0143             (nfi->fib_nhs == 0 || dn_fib_nh_comp(fi, nfi) == 0))
0144                 return fi;
0145     } endfor_fib_info();
0146     return NULL;
0147 }
0148 
0149 static int dn_fib_count_nhs(const struct nlattr *attr)
0150 {
0151     struct rtnexthop *nhp = nla_data(attr);
0152     int nhs = 0, nhlen = nla_len(attr);
0153 
0154     while (rtnh_ok(nhp, nhlen)) {
0155         nhs++;
0156         nhp = rtnh_next(nhp, &nhlen);
0157     }
0158 
0159     /* leftover implies invalid nexthop configuration, discard it */
0160     return nhlen > 0 ? 0 : nhs;
0161 }
0162 
0163 static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct nlattr *attr,
0164               const struct rtmsg *r)
0165 {
0166     struct rtnexthop *nhp = nla_data(attr);
0167     int nhlen = nla_len(attr);
0168 
0169     change_nexthops(fi) {
0170         int attrlen;
0171 
0172         if (!rtnh_ok(nhp, nhlen))
0173             return -EINVAL;
0174 
0175         nh->nh_flags  = (r->rtm_flags&~0xFF) | nhp->rtnh_flags;
0176         nh->nh_oif    = nhp->rtnh_ifindex;
0177         nh->nh_weight = nhp->rtnh_hops + 1;
0178 
0179         attrlen = rtnh_attrlen(nhp);
0180         if (attrlen > 0) {
0181             struct nlattr *gw_attr;
0182 
0183             gw_attr = nla_find((struct nlattr *) (nhp + 1), attrlen, RTA_GATEWAY);
0184             nh->nh_gw = gw_attr ? nla_get_le16(gw_attr) : 0;
0185         }
0186 
0187         nhp = rtnh_next(nhp, &nhlen);
0188     } endfor_nexthops(fi);
0189 
0190     return 0;
0191 }
0192 
0193 
0194 static int dn_fib_check_nh(const struct rtmsg *r, struct dn_fib_info *fi, struct dn_fib_nh *nh)
0195 {
0196     int err;
0197 
0198     if (nh->nh_gw) {
0199         struct flowidn fld;
0200         struct dn_fib_res res;
0201 
0202         if (nh->nh_flags&RTNH_F_ONLINK) {
0203             struct net_device *dev;
0204 
0205             if (r->rtm_scope >= RT_SCOPE_LINK)
0206                 return -EINVAL;
0207             if (dnet_addr_type(nh->nh_gw) != RTN_UNICAST)
0208                 return -EINVAL;
0209             if ((dev = __dev_get_by_index(&init_net, nh->nh_oif)) == NULL)
0210                 return -ENODEV;
0211             if (!(dev->flags&IFF_UP))
0212                 return -ENETDOWN;
0213             nh->nh_dev = dev;
0214             dev_hold(dev);
0215             nh->nh_scope = RT_SCOPE_LINK;
0216             return 0;
0217         }
0218 
0219         memset(&fld, 0, sizeof(fld));
0220         fld.daddr = nh->nh_gw;
0221         fld.flowidn_oif = nh->nh_oif;
0222         fld.flowidn_scope = r->rtm_scope + 1;
0223 
0224         if (fld.flowidn_scope < RT_SCOPE_LINK)
0225             fld.flowidn_scope = RT_SCOPE_LINK;
0226 
0227         if ((err = dn_fib_lookup(&fld, &res)) != 0)
0228             return err;
0229 
0230         err = -EINVAL;
0231         if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
0232             goto out;
0233         nh->nh_scope = res.scope;
0234         nh->nh_oif = DN_FIB_RES_OIF(res);
0235         nh->nh_dev = DN_FIB_RES_DEV(res);
0236         if (nh->nh_dev == NULL)
0237             goto out;
0238         dev_hold(nh->nh_dev);
0239         err = -ENETDOWN;
0240         if (!(nh->nh_dev->flags & IFF_UP))
0241             goto out;
0242         err = 0;
0243 out:
0244         dn_fib_res_put(&res);
0245         return err;
0246     } else {
0247         struct net_device *dev;
0248 
0249         if (nh->nh_flags&(RTNH_F_PERVASIVE|RTNH_F_ONLINK))
0250             return -EINVAL;
0251 
0252         dev = __dev_get_by_index(&init_net, nh->nh_oif);
0253         if (dev == NULL || dev->dn_ptr == NULL)
0254             return -ENODEV;
0255         if (!(dev->flags&IFF_UP))
0256             return -ENETDOWN;
0257         nh->nh_dev = dev;
0258         dev_hold(nh->nh_dev);
0259         nh->nh_scope = RT_SCOPE_HOST;
0260     }
0261 
0262     return 0;
0263 }
0264 
0265 
0266 struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct nlattr *attrs[],
0267                        const struct nlmsghdr *nlh, int *errp)
0268 {
0269     int err;
0270     struct dn_fib_info *fi = NULL;
0271     struct dn_fib_info *ofi;
0272     int nhs = 1;
0273 
0274     if (r->rtm_type > RTN_MAX)
0275         goto err_inval;
0276 
0277     if (dn_fib_props[r->rtm_type].scope > r->rtm_scope)
0278         goto err_inval;
0279 
0280     if (attrs[RTA_MULTIPATH] &&
0281         (nhs = dn_fib_count_nhs(attrs[RTA_MULTIPATH])) == 0)
0282         goto err_inval;
0283 
0284     fi = kzalloc(struct_size(fi, fib_nh, nhs), GFP_KERNEL);
0285     err = -ENOBUFS;
0286     if (fi == NULL)
0287         goto failure;
0288 
0289     fi->fib_protocol = r->rtm_protocol;
0290     fi->fib_nhs = nhs;
0291     fi->fib_flags = r->rtm_flags;
0292 
0293     if (attrs[RTA_PRIORITY])
0294         fi->fib_priority = nla_get_u32(attrs[RTA_PRIORITY]);
0295 
0296     if (attrs[RTA_METRICS]) {
0297         struct nlattr *attr;
0298         int rem;
0299 
0300         nla_for_each_nested(attr, attrs[RTA_METRICS], rem) {
0301             int type = nla_type(attr);
0302 
0303             if (type) {
0304                 if (type > RTAX_MAX || type == RTAX_CC_ALGO ||
0305                     nla_len(attr) < 4)
0306                     goto err_inval;
0307 
0308                 fi->fib_metrics[type-1] = nla_get_u32(attr);
0309             }
0310         }
0311     }
0312 
0313     if (attrs[RTA_PREFSRC])
0314         fi->fib_prefsrc = nla_get_le16(attrs[RTA_PREFSRC]);
0315 
0316     if (attrs[RTA_MULTIPATH]) {
0317         if ((err = dn_fib_get_nhs(fi, attrs[RTA_MULTIPATH], r)) != 0)
0318             goto failure;
0319 
0320         if (attrs[RTA_OIF] &&
0321             fi->fib_nh->nh_oif != nla_get_u32(attrs[RTA_OIF]))
0322             goto err_inval;
0323 
0324         if (attrs[RTA_GATEWAY] &&
0325             fi->fib_nh->nh_gw != nla_get_le16(attrs[RTA_GATEWAY]))
0326             goto err_inval;
0327     } else {
0328         struct dn_fib_nh *nh = fi->fib_nh;
0329 
0330         if (attrs[RTA_OIF])
0331             nh->nh_oif = nla_get_u32(attrs[RTA_OIF]);
0332 
0333         if (attrs[RTA_GATEWAY])
0334             nh->nh_gw = nla_get_le16(attrs[RTA_GATEWAY]);
0335 
0336         nh->nh_flags = r->rtm_flags;
0337         nh->nh_weight = 1;
0338     }
0339 
0340     if (r->rtm_type == RTN_NAT) {
0341         if (!attrs[RTA_GATEWAY] || nhs != 1 || attrs[RTA_OIF])
0342             goto err_inval;
0343 
0344         fi->fib_nh->nh_gw = nla_get_le16(attrs[RTA_GATEWAY]);
0345         goto link_it;
0346     }
0347 
0348     if (dn_fib_props[r->rtm_type].error) {
0349         if (attrs[RTA_GATEWAY] || attrs[RTA_OIF] || attrs[RTA_MULTIPATH])
0350             goto err_inval;
0351 
0352         goto link_it;
0353     }
0354 
0355     if (r->rtm_scope > RT_SCOPE_HOST)
0356         goto err_inval;
0357 
0358     if (r->rtm_scope == RT_SCOPE_HOST) {
0359         struct dn_fib_nh *nh = fi->fib_nh;
0360 
0361         /* Local address is added */
0362         if (nhs != 1 || nh->nh_gw)
0363             goto err_inval;
0364         nh->nh_scope = RT_SCOPE_NOWHERE;
0365         nh->nh_dev = dev_get_by_index(&init_net, fi->fib_nh->nh_oif);
0366         err = -ENODEV;
0367         if (nh->nh_dev == NULL)
0368             goto failure;
0369     } else {
0370         change_nexthops(fi) {
0371             if ((err = dn_fib_check_nh(r, fi, nh)) != 0)
0372                 goto failure;
0373         } endfor_nexthops(fi)
0374     }
0375 
0376     if (fi->fib_prefsrc) {
0377         if (r->rtm_type != RTN_LOCAL || !attrs[RTA_DST] ||
0378             fi->fib_prefsrc != nla_get_le16(attrs[RTA_DST]))
0379             if (dnet_addr_type(fi->fib_prefsrc) != RTN_LOCAL)
0380                 goto err_inval;
0381     }
0382 
0383 link_it:
0384     if ((ofi = dn_fib_find_info(fi)) != NULL) {
0385         fi->fib_dead = 1;
0386         dn_fib_free_info(fi);
0387         refcount_inc(&ofi->fib_treeref);
0388         return ofi;
0389     }
0390 
0391     refcount_set(&fi->fib_treeref, 1);
0392     refcount_set(&fi->fib_clntref, 1);
0393     spin_lock(&dn_fib_info_lock);
0394     fi->fib_next = dn_fib_info_list;
0395     fi->fib_prev = NULL;
0396     if (dn_fib_info_list)
0397         dn_fib_info_list->fib_prev = fi;
0398     dn_fib_info_list = fi;
0399     spin_unlock(&dn_fib_info_lock);
0400     return fi;
0401 
0402 err_inval:
0403     err = -EINVAL;
0404 
0405 failure:
0406     *errp = err;
0407     if (fi) {
0408         fi->fib_dead = 1;
0409         dn_fib_free_info(fi);
0410     }
0411 
0412     return NULL;
0413 }
0414 
0415 int dn_fib_semantic_match(int type, struct dn_fib_info *fi, const struct flowidn *fld, struct dn_fib_res *res)
0416 {
0417     int err = dn_fib_props[type].error;
0418 
0419     if (err == 0) {
0420         if (fi->fib_flags & RTNH_F_DEAD)
0421             return 1;
0422 
0423         res->fi = fi;
0424 
0425         switch (type) {
0426         case RTN_NAT:
0427             DN_FIB_RES_RESET(*res);
0428             refcount_inc(&fi->fib_clntref);
0429             return 0;
0430         case RTN_UNICAST:
0431         case RTN_LOCAL:
0432             for_nexthops(fi) {
0433                 if (nh->nh_flags & RTNH_F_DEAD)
0434                     continue;
0435                 if (!fld->flowidn_oif ||
0436                     fld->flowidn_oif == nh->nh_oif)
0437                     break;
0438             }
0439             if (nhsel < fi->fib_nhs) {
0440                 res->nh_sel = nhsel;
0441                 refcount_inc(&fi->fib_clntref);
0442                 return 0;
0443             }
0444             endfor_nexthops(fi);
0445             res->fi = NULL;
0446             return 1;
0447         default:
0448             net_err_ratelimited("DECnet: impossible routing event : dn_fib_semantic_match type=%d\n",
0449                         type);
0450             res->fi = NULL;
0451             return -EINVAL;
0452         }
0453     }
0454     return err;
0455 }
0456 
0457 void dn_fib_select_multipath(const struct flowidn *fld, struct dn_fib_res *res)
0458 {
0459     struct dn_fib_info *fi = res->fi;
0460     int w;
0461 
0462     spin_lock_bh(&dn_fib_multipath_lock);
0463     if (fi->fib_power <= 0) {
0464         int power = 0;
0465         change_nexthops(fi) {
0466             if (!(nh->nh_flags&RTNH_F_DEAD)) {
0467                 power += nh->nh_weight;
0468                 nh->nh_power = nh->nh_weight;
0469             }
0470         } endfor_nexthops(fi);
0471         fi->fib_power = power;
0472         if (power < 0) {
0473             spin_unlock_bh(&dn_fib_multipath_lock);
0474             res->nh_sel = 0;
0475             return;
0476         }
0477     }
0478 
0479     w = jiffies % fi->fib_power;
0480 
0481     change_nexthops(fi) {
0482         if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) {
0483             if ((w -= nh->nh_power) <= 0) {
0484                 nh->nh_power--;
0485                 fi->fib_power--;
0486                 res->nh_sel = nhsel;
0487                 spin_unlock_bh(&dn_fib_multipath_lock);
0488                 return;
0489             }
0490         }
0491     } endfor_nexthops(fi);
0492     res->nh_sel = 0;
0493     spin_unlock_bh(&dn_fib_multipath_lock);
0494 }
0495 
0496 static inline u32 rtm_get_table(struct nlattr *attrs[], u8 table)
0497 {
0498     if (attrs[RTA_TABLE])
0499         table = nla_get_u32(attrs[RTA_TABLE]);
0500 
0501     return table;
0502 }
0503 
0504 static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
0505                    struct netlink_ext_ack *extack)
0506 {
0507     struct net *net = sock_net(skb->sk);
0508     struct dn_fib_table *tb;
0509     struct rtmsg *r = nlmsg_data(nlh);
0510     struct nlattr *attrs[RTA_MAX+1];
0511     int err;
0512 
0513     if (!netlink_capable(skb, CAP_NET_ADMIN))
0514         return -EPERM;
0515 
0516     if (!net_eq(net, &init_net))
0517         return -EINVAL;
0518 
0519     err = nlmsg_parse_deprecated(nlh, sizeof(*r), attrs, RTA_MAX,
0520                      rtm_dn_policy, extack);
0521     if (err < 0)
0522         return err;
0523 
0524     tb = dn_fib_get_table(rtm_get_table(attrs, r->rtm_table), 0);
0525     if (!tb)
0526         return -ESRCH;
0527 
0528     return tb->delete(tb, r, attrs, nlh, &NETLINK_CB(skb));
0529 }
0530 
0531 static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
0532                    struct netlink_ext_ack *extack)
0533 {
0534     struct net *net = sock_net(skb->sk);
0535     struct dn_fib_table *tb;
0536     struct rtmsg *r = nlmsg_data(nlh);
0537     struct nlattr *attrs[RTA_MAX+1];
0538     int err;
0539 
0540     if (!netlink_capable(skb, CAP_NET_ADMIN))
0541         return -EPERM;
0542 
0543     if (!net_eq(net, &init_net))
0544         return -EINVAL;
0545 
0546     err = nlmsg_parse_deprecated(nlh, sizeof(*r), attrs, RTA_MAX,
0547                      rtm_dn_policy, extack);
0548     if (err < 0)
0549         return err;
0550 
0551     tb = dn_fib_get_table(rtm_get_table(attrs, r->rtm_table), 1);
0552     if (!tb)
0553         return -ENOBUFS;
0554 
0555     return tb->insert(tb, r, attrs, nlh, &NETLINK_CB(skb));
0556 }
0557 
0558 static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifaddr *ifa)
0559 {
0560     struct dn_fib_table *tb;
0561     struct {
0562         struct nlmsghdr nlh;
0563         struct rtmsg rtm;
0564     } req;
0565     struct {
0566         struct nlattr hdr;
0567         __le16 dst;
0568     } dst_attr = {
0569         .dst = dst,
0570     };
0571     struct {
0572         struct nlattr hdr;
0573         __le16 prefsrc;
0574     } prefsrc_attr = {
0575         .prefsrc = ifa->ifa_local,
0576     };
0577     struct {
0578         struct nlattr hdr;
0579         u32 oif;
0580     } oif_attr = {
0581         .oif = ifa->ifa_dev->dev->ifindex,
0582     };
0583     struct nlattr *attrs[RTA_MAX+1] = {
0584         [RTA_DST] = (struct nlattr *) &dst_attr,
0585         [RTA_PREFSRC] = (struct nlattr * ) &prefsrc_attr,
0586         [RTA_OIF] = (struct nlattr *) &oif_attr,
0587     };
0588 
0589     memset(&req.rtm, 0, sizeof(req.rtm));
0590 
0591     if (type == RTN_UNICAST)
0592         tb = dn_fib_get_table(RT_MIN_TABLE, 1);
0593     else
0594         tb = dn_fib_get_table(RT_TABLE_LOCAL, 1);
0595 
0596     if (tb == NULL)
0597         return;
0598 
0599     req.nlh.nlmsg_len = sizeof(req);
0600     req.nlh.nlmsg_type = cmd;
0601     req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_APPEND;
0602     req.nlh.nlmsg_pid = 0;
0603     req.nlh.nlmsg_seq = 0;
0604 
0605     req.rtm.rtm_dst_len = dst_len;
0606     req.rtm.rtm_table = tb->n;
0607     req.rtm.rtm_protocol = RTPROT_KERNEL;
0608     req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST);
0609     req.rtm.rtm_type = type;
0610 
0611     if (cmd == RTM_NEWROUTE)
0612         tb->insert(tb, &req.rtm, attrs, &req.nlh, NULL);
0613     else
0614         tb->delete(tb, &req.rtm, attrs, &req.nlh, NULL);
0615 }
0616 
0617 static void dn_fib_add_ifaddr(struct dn_ifaddr *ifa)
0618 {
0619 
0620     fib_magic(RTM_NEWROUTE, RTN_LOCAL, ifa->ifa_local, 16, ifa);
0621 
0622 #if 0
0623     if (!(dev->flags&IFF_UP))
0624         return;
0625     /* In the future, we will want to add default routes here */
0626 
0627 #endif
0628 }
0629 
0630 static void dn_fib_del_ifaddr(struct dn_ifaddr *ifa)
0631 {
0632     int found_it = 0;
0633     struct net_device *dev;
0634     struct dn_dev *dn_db;
0635     struct dn_ifaddr *ifa2;
0636 
0637     ASSERT_RTNL();
0638 
0639     /* Scan device list */
0640     rcu_read_lock();
0641     for_each_netdev_rcu(&init_net, dev) {
0642         dn_db = rcu_dereference(dev->dn_ptr);
0643         if (dn_db == NULL)
0644             continue;
0645         for (ifa2 = rcu_dereference(dn_db->ifa_list);
0646              ifa2 != NULL;
0647              ifa2 = rcu_dereference(ifa2->ifa_next)) {
0648             if (ifa2->ifa_local == ifa->ifa_local) {
0649                 found_it = 1;
0650                 break;
0651             }
0652         }
0653     }
0654     rcu_read_unlock();
0655 
0656     if (found_it == 0) {
0657         fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 16, ifa);
0658 
0659         if (dnet_addr_type(ifa->ifa_local) != RTN_LOCAL) {
0660             if (dn_fib_sync_down(ifa->ifa_local, NULL, 0))
0661                 dn_fib_flush();
0662         }
0663     }
0664 }
0665 
0666 static void dn_fib_disable_addr(struct net_device *dev, int force)
0667 {
0668     if (dn_fib_sync_down(0, dev, force))
0669         dn_fib_flush();
0670     dn_rt_cache_flush(0);
0671     neigh_ifdown(&dn_neigh_table, dev);
0672 }
0673 
0674 static int dn_fib_dnaddr_event(struct notifier_block *this, unsigned long event, void *ptr)
0675 {
0676     struct dn_ifaddr *ifa = (struct dn_ifaddr *)ptr;
0677 
0678     switch (event) {
0679     case NETDEV_UP:
0680         dn_fib_add_ifaddr(ifa);
0681         dn_fib_sync_up(ifa->ifa_dev->dev);
0682         dn_rt_cache_flush(-1);
0683         break;
0684     case NETDEV_DOWN:
0685         dn_fib_del_ifaddr(ifa);
0686         if (ifa->ifa_dev && ifa->ifa_dev->ifa_list == NULL) {
0687             dn_fib_disable_addr(ifa->ifa_dev->dev, 1);
0688         } else {
0689             dn_rt_cache_flush(-1);
0690         }
0691         break;
0692     }
0693     return NOTIFY_DONE;
0694 }
0695 
0696 static int dn_fib_sync_down(__le16 local, struct net_device *dev, int force)
0697 {
0698     int ret = 0;
0699     int scope = RT_SCOPE_NOWHERE;
0700 
0701     if (force)
0702         scope = -1;
0703 
0704     for_fib_info() {
0705         /*
0706          * This makes no sense for DECnet.... we will almost
0707          * certainly have more than one local address the same
0708          * over all our interfaces. It needs thinking about
0709          * some more.
0710          */
0711         if (local && fi->fib_prefsrc == local) {
0712             fi->fib_flags |= RTNH_F_DEAD;
0713             ret++;
0714         } else if (dev && fi->fib_nhs) {
0715             int dead = 0;
0716 
0717             change_nexthops(fi) {
0718                 if (nh->nh_flags&RTNH_F_DEAD)
0719                     dead++;
0720                 else if (nh->nh_dev == dev &&
0721                         nh->nh_scope != scope) {
0722                     spin_lock_bh(&dn_fib_multipath_lock);
0723                     nh->nh_flags |= RTNH_F_DEAD;
0724                     fi->fib_power -= nh->nh_power;
0725                     nh->nh_power = 0;
0726                     spin_unlock_bh(&dn_fib_multipath_lock);
0727                     dead++;
0728                 }
0729             } endfor_nexthops(fi)
0730             if (dead == fi->fib_nhs) {
0731                 fi->fib_flags |= RTNH_F_DEAD;
0732                 ret++;
0733             }
0734         }
0735     } endfor_fib_info();
0736     return ret;
0737 }
0738 
0739 
0740 static int dn_fib_sync_up(struct net_device *dev)
0741 {
0742     int ret = 0;
0743 
0744     if (!(dev->flags&IFF_UP))
0745         return 0;
0746 
0747     for_fib_info() {
0748         int alive = 0;
0749 
0750         change_nexthops(fi) {
0751             if (!(nh->nh_flags&RTNH_F_DEAD)) {
0752                 alive++;
0753                 continue;
0754             }
0755             if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
0756                 continue;
0757             if (nh->nh_dev != dev || dev->dn_ptr == NULL)
0758                 continue;
0759             alive++;
0760             spin_lock_bh(&dn_fib_multipath_lock);
0761             nh->nh_power = 0;
0762             nh->nh_flags &= ~RTNH_F_DEAD;
0763             spin_unlock_bh(&dn_fib_multipath_lock);
0764         } endfor_nexthops(fi);
0765 
0766         if (alive > 0) {
0767             fi->fib_flags &= ~RTNH_F_DEAD;
0768             ret++;
0769         }
0770     } endfor_fib_info();
0771     return ret;
0772 }
0773 
0774 static struct notifier_block dn_fib_dnaddr_notifier = {
0775     .notifier_call = dn_fib_dnaddr_event,
0776 };
0777 
0778 void __exit dn_fib_cleanup(void)
0779 {
0780     dn_fib_table_cleanup();
0781     dn_fib_rules_cleanup();
0782 
0783     unregister_dnaddr_notifier(&dn_fib_dnaddr_notifier);
0784 }
0785 
0786 
0787 void __init dn_fib_init(void)
0788 {
0789     dn_fib_table_init();
0790     dn_fib_rules_init();
0791 
0792     register_dnaddr_notifier(&dn_fib_dnaddr_notifier);
0793 
0794     rtnl_register_module(THIS_MODULE, PF_DECnet, RTM_NEWROUTE,
0795                  dn_fib_rtm_newroute, NULL, 0);
0796     rtnl_register_module(THIS_MODULE, PF_DECnet, RTM_DELROUTE,
0797                  dn_fib_rtm_delroute, NULL, 0);
0798 }