Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 
0003 /*
0004  * DECnet       An implementation of the DECnet protocol suite for the LINUX
0005  *              operating system.  DECnet is implemented using the  BSD Socket
0006  *              interface as the means of communication with the user level.
0007  *
0008  *              DECnet Routing Forwarding Information Base (Rules)
0009  *
0010  * Author:      Steve Whitehouse <SteveW@ACM.org>
0011  *              Mostly copied from Alexey Kuznetsov's ipv4/fib_rules.c
0012  *
0013  *
0014  * Changes:
0015  *              Steve Whitehouse <steve@chygwyn.com>
0016  *              Updated for Thomas Graf's generic rules
0017  *
0018  */
0019 #include <linux/net.h>
0020 #include <linux/init.h>
0021 #include <linux/netlink.h>
0022 #include <linux/rtnetlink.h>
0023 #include <linux/netdevice.h>
0024 #include <linux/spinlock.h>
0025 #include <linux/list.h>
0026 #include <linux/rcupdate.h>
0027 #include <linux/export.h>
0028 #include <net/neighbour.h>
0029 #include <net/dst.h>
0030 #include <net/flow.h>
0031 #include <net/fib_rules.h>
0032 #include <net/dn.h>
0033 #include <net/dn_fib.h>
0034 #include <net/dn_neigh.h>
0035 #include <net/dn_dev.h>
0036 #include <net/dn_route.h>
0037 
0038 static struct fib_rules_ops *dn_fib_rules_ops;
0039 
0040 struct dn_fib_rule
0041 {
0042     struct fib_rule     common;
0043     unsigned char       dst_len;
0044     unsigned char       src_len;
0045     __le16          src;
0046     __le16          srcmask;
0047     __le16          dst;
0048     __le16          dstmask;
0049     __le16          srcmap;
0050     u8          flags;
0051 };
0052 
0053 
0054 int dn_fib_lookup(struct flowidn *flp, struct dn_fib_res *res)
0055 {
0056     struct fib_lookup_arg arg = {
0057         .result = res,
0058     };
0059     int err;
0060 
0061     err = fib_rules_lookup(dn_fib_rules_ops,
0062                    flowidn_to_flowi(flp), 0, &arg);
0063     res->r = arg.rule;
0064 
0065     return err;
0066 }
0067 
0068 static int dn_fib_rule_action(struct fib_rule *rule, struct flowi *flp,
0069                   int flags, struct fib_lookup_arg *arg)
0070 {
0071     struct flowidn *fld = &flp->u.dn;
0072     int err = -EAGAIN;
0073     struct dn_fib_table *tbl;
0074 
0075     switch(rule->action) {
0076     case FR_ACT_TO_TBL:
0077         break;
0078 
0079     case FR_ACT_UNREACHABLE:
0080         err = -ENETUNREACH;
0081         goto errout;
0082 
0083     case FR_ACT_PROHIBIT:
0084         err = -EACCES;
0085         goto errout;
0086 
0087     case FR_ACT_BLACKHOLE:
0088     default:
0089         err = -EINVAL;
0090         goto errout;
0091     }
0092 
0093     tbl = dn_fib_get_table(rule->table, 0);
0094     if (tbl == NULL)
0095         goto errout;
0096 
0097     err = tbl->lookup(tbl, fld, (struct dn_fib_res *)arg->result);
0098     if (err > 0)
0099         err = -EAGAIN;
0100 errout:
0101     return err;
0102 }
0103 
0104 static int dn_fib_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
0105 {
0106     struct dn_fib_rule *r = (struct dn_fib_rule *)rule;
0107     struct flowidn *fld = &fl->u.dn;
0108     __le16 daddr = fld->daddr;
0109     __le16 saddr = fld->saddr;
0110 
0111     if (((saddr ^ r->src) & r->srcmask) ||
0112         ((daddr ^ r->dst) & r->dstmask))
0113         return 0;
0114 
0115     return 1;
0116 }
0117 
0118 static int dn_fib_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
0119                  struct fib_rule_hdr *frh,
0120                  struct nlattr **tb,
0121                  struct netlink_ext_ack *extack)
0122 {
0123     int err = -EINVAL;
0124     struct dn_fib_rule *r = (struct dn_fib_rule *)rule;
0125 
0126     if (frh->tos) {
0127         NL_SET_ERR_MSG(extack, "Invalid tos value");
0128         goto  errout;
0129     }
0130 
0131     if (rule->table == RT_TABLE_UNSPEC) {
0132         if (rule->action == FR_ACT_TO_TBL) {
0133             struct dn_fib_table *table;
0134 
0135             table = dn_fib_empty_table();
0136             if (table == NULL) {
0137                 err = -ENOBUFS;
0138                 goto errout;
0139             }
0140 
0141             rule->table = table->n;
0142         }
0143     }
0144 
0145     if (frh->src_len)
0146         r->src = nla_get_le16(tb[FRA_SRC]);
0147 
0148     if (frh->dst_len)
0149         r->dst = nla_get_le16(tb[FRA_DST]);
0150 
0151     r->src_len = frh->src_len;
0152     r->srcmask = dnet_make_mask(r->src_len);
0153     r->dst_len = frh->dst_len;
0154     r->dstmask = dnet_make_mask(r->dst_len);
0155     err = 0;
0156 errout:
0157     return err;
0158 }
0159 
0160 static int dn_fib_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
0161                    struct nlattr **tb)
0162 {
0163     struct dn_fib_rule *r = (struct dn_fib_rule *)rule;
0164 
0165     if (frh->src_len && (r->src_len != frh->src_len))
0166         return 0;
0167 
0168     if (frh->dst_len && (r->dst_len != frh->dst_len))
0169         return 0;
0170 
0171     if (frh->src_len && (r->src != nla_get_le16(tb[FRA_SRC])))
0172         return 0;
0173 
0174     if (frh->dst_len && (r->dst != nla_get_le16(tb[FRA_DST])))
0175         return 0;
0176 
0177     return 1;
0178 }
0179 
0180 unsigned int dnet_addr_type(__le16 addr)
0181 {
0182     struct flowidn fld = { .daddr = addr };
0183     struct dn_fib_res res;
0184     unsigned int ret = RTN_UNICAST;
0185     struct dn_fib_table *tb = dn_fib_get_table(RT_TABLE_LOCAL, 0);
0186 
0187     res.r = NULL;
0188 
0189     if (tb) {
0190         if (!tb->lookup(tb, &fld, &res)) {
0191             ret = res.type;
0192             dn_fib_res_put(&res);
0193         }
0194     }
0195     return ret;
0196 }
0197 
0198 static int dn_fib_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
0199                 struct fib_rule_hdr *frh)
0200 {
0201     struct dn_fib_rule *r = (struct dn_fib_rule *)rule;
0202 
0203     frh->dst_len = r->dst_len;
0204     frh->src_len = r->src_len;
0205     frh->tos = 0;
0206 
0207     if ((r->dst_len &&
0208          nla_put_le16(skb, FRA_DST, r->dst)) ||
0209         (r->src_len &&
0210          nla_put_le16(skb, FRA_SRC, r->src)))
0211         goto nla_put_failure;
0212     return 0;
0213 
0214 nla_put_failure:
0215     return -ENOBUFS;
0216 }
0217 
0218 static void dn_fib_rule_flush_cache(struct fib_rules_ops *ops)
0219 {
0220     dn_rt_cache_flush(-1);
0221 }
0222 
0223 static const struct fib_rules_ops __net_initconst dn_fib_rules_ops_template = {
0224     .family     = AF_DECnet,
0225     .rule_size  = sizeof(struct dn_fib_rule),
0226     .addr_size  = sizeof(u16),
0227     .action     = dn_fib_rule_action,
0228     .match      = dn_fib_rule_match,
0229     .configure  = dn_fib_rule_configure,
0230     .compare    = dn_fib_rule_compare,
0231     .fill       = dn_fib_rule_fill,
0232     .flush_cache    = dn_fib_rule_flush_cache,
0233     .nlgroup    = RTNLGRP_DECnet_RULE,
0234     .owner      = THIS_MODULE,
0235     .fro_net    = &init_net,
0236 };
0237 
0238 void __init dn_fib_rules_init(void)
0239 {
0240     dn_fib_rules_ops =
0241         fib_rules_register(&dn_fib_rules_ops_template, &init_net);
0242     BUG_ON(IS_ERR(dn_fib_rules_ops));
0243     BUG_ON(fib_default_rule_add(dn_fib_rules_ops, 0x7fff,
0244                         RT_TABLE_MAIN, 0));
0245 }
0246 
0247 void __exit dn_fib_rules_cleanup(void)
0248 {
0249     rtnl_lock();
0250     fib_rules_unregister(dn_fib_rules_ops);
0251     rtnl_unlock();
0252     rcu_barrier();
0253 }