0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
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 }