at v2.6.24-rc1 275 lines 5.9 kB view raw
1 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 (Rules) 8 * 9 * Author: Steve Whitehouse <SteveW@ACM.org> 10 * Mostly copied from Alexey Kuznetsov's ipv4/fib_rules.c 11 * 12 * 13 * Changes: 14 * Steve Whitehouse <steve@chygwyn.com> 15 * Updated for Thomas Graf's generic rules 16 * 17 */ 18#include <linux/net.h> 19#include <linux/init.h> 20#include <linux/netlink.h> 21#include <linux/rtnetlink.h> 22#include <linux/netdevice.h> 23#include <linux/spinlock.h> 24#include <linux/list.h> 25#include <linux/rcupdate.h> 26#include <net/neighbour.h> 27#include <net/dst.h> 28#include <net/flow.h> 29#include <net/fib_rules.h> 30#include <net/dn.h> 31#include <net/dn_fib.h> 32#include <net/dn_neigh.h> 33#include <net/dn_dev.h> 34#include <net/dn_route.h> 35 36static struct fib_rules_ops dn_fib_rules_ops; 37 38struct dn_fib_rule 39{ 40 struct fib_rule common; 41 unsigned char dst_len; 42 unsigned char src_len; 43 __le16 src; 44 __le16 srcmask; 45 __le16 dst; 46 __le16 dstmask; 47 __le16 srcmap; 48 u8 flags; 49}; 50 51static struct dn_fib_rule default_rule = { 52 .common = { 53 .refcnt = ATOMIC_INIT(2), 54 .pref = 0x7fff, 55 .table = RT_TABLE_MAIN, 56 .action = FR_ACT_TO_TBL, 57 }, 58}; 59 60 61int dn_fib_lookup(struct flowi *flp, struct dn_fib_res *res) 62{ 63 struct fib_lookup_arg arg = { 64 .result = res, 65 }; 66 int err; 67 68 err = fib_rules_lookup(&dn_fib_rules_ops, flp, 0, &arg); 69 res->r = arg.rule; 70 71 return err; 72} 73 74static int dn_fib_rule_action(struct fib_rule *rule, struct flowi *flp, 75 int flags, struct fib_lookup_arg *arg) 76{ 77 int err = -EAGAIN; 78 struct dn_fib_table *tbl; 79 80 switch(rule->action) { 81 case FR_ACT_TO_TBL: 82 break; 83 84 case FR_ACT_UNREACHABLE: 85 err = -ENETUNREACH; 86 goto errout; 87 88 case FR_ACT_PROHIBIT: 89 err = -EACCES; 90 goto errout; 91 92 case FR_ACT_BLACKHOLE: 93 default: 94 err = -EINVAL; 95 goto errout; 96 } 97 98 tbl = dn_fib_get_table(rule->table, 0); 99 if (tbl == NULL) 100 goto errout; 101 102 err = tbl->lookup(tbl, flp, (struct dn_fib_res *)arg->result); 103 if (err > 0) 104 err = -EAGAIN; 105errout: 106 return err; 107} 108 109static const struct nla_policy dn_fib_rule_policy[FRA_MAX+1] = { 110 FRA_GENERIC_POLICY, 111}; 112 113static int dn_fib_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) 114{ 115 struct dn_fib_rule *r = (struct dn_fib_rule *)rule; 116 __le16 daddr = fl->fld_dst; 117 __le16 saddr = fl->fld_src; 118 119 if (((saddr ^ r->src) & r->srcmask) || 120 ((daddr ^ r->dst) & r->dstmask)) 121 return 0; 122 123 return 1; 124} 125 126static int dn_fib_rule_configure(struct fib_rule *rule, struct sk_buff *skb, 127 struct nlmsghdr *nlh, struct fib_rule_hdr *frh, 128 struct nlattr **tb) 129{ 130 int err = -EINVAL; 131 struct dn_fib_rule *r = (struct dn_fib_rule *)rule; 132 133 if (frh->tos) 134 goto errout; 135 136 if (rule->table == RT_TABLE_UNSPEC) { 137 if (rule->action == FR_ACT_TO_TBL) { 138 struct dn_fib_table *table; 139 140 table = dn_fib_empty_table(); 141 if (table == NULL) { 142 err = -ENOBUFS; 143 goto errout; 144 } 145 146 rule->table = table->n; 147 } 148 } 149 150 if (frh->src_len) 151 r->src = nla_get_le16(tb[FRA_SRC]); 152 153 if (frh->dst_len) 154 r->dst = nla_get_le16(tb[FRA_DST]); 155 156 r->src_len = frh->src_len; 157 r->srcmask = dnet_make_mask(r->src_len); 158 r->dst_len = frh->dst_len; 159 r->dstmask = dnet_make_mask(r->dst_len); 160 err = 0; 161errout: 162 return err; 163} 164 165static int dn_fib_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, 166 struct nlattr **tb) 167{ 168 struct dn_fib_rule *r = (struct dn_fib_rule *)rule; 169 170 if (frh->src_len && (r->src_len != frh->src_len)) 171 return 0; 172 173 if (frh->dst_len && (r->dst_len != frh->dst_len)) 174 return 0; 175 176 if (frh->src_len && (r->src != nla_get_le16(tb[FRA_SRC]))) 177 return 0; 178 179 if (frh->dst_len && (r->dst != nla_get_le16(tb[FRA_DST]))) 180 return 0; 181 182 return 1; 183} 184 185unsigned dnet_addr_type(__le16 addr) 186{ 187 struct flowi fl = { .nl_u = { .dn_u = { .daddr = addr } } }; 188 struct dn_fib_res res; 189 unsigned ret = RTN_UNICAST; 190 struct dn_fib_table *tb = dn_fib_get_table(RT_TABLE_LOCAL, 0); 191 192 res.r = NULL; 193 194 if (tb) { 195 if (!tb->lookup(tb, &fl, &res)) { 196 ret = res.type; 197 dn_fib_res_put(&res); 198 } 199 } 200 return ret; 201} 202 203static int dn_fib_rule_fill(struct fib_rule *rule, struct sk_buff *skb, 204 struct nlmsghdr *nlh, struct fib_rule_hdr *frh) 205{ 206 struct dn_fib_rule *r = (struct dn_fib_rule *)rule; 207 208 frh->family = AF_DECnet; 209 frh->dst_len = r->dst_len; 210 frh->src_len = r->src_len; 211 frh->tos = 0; 212 213 if (r->dst_len) 214 NLA_PUT_LE16(skb, FRA_DST, r->dst); 215 if (r->src_len) 216 NLA_PUT_LE16(skb, FRA_SRC, r->src); 217 218 return 0; 219 220nla_put_failure: 221 return -ENOBUFS; 222} 223 224static u32 dn_fib_rule_default_pref(void) 225{ 226 struct list_head *pos; 227 struct fib_rule *rule; 228 229 if (!list_empty(&dn_fib_rules_ops.rules_list)) { 230 pos = dn_fib_rules_ops.rules_list.next; 231 if (pos->next != &dn_fib_rules_ops.rules_list) { 232 rule = list_entry(pos->next, struct fib_rule, list); 233 if (rule->pref) 234 return rule->pref - 1; 235 } 236 } 237 238 return 0; 239} 240 241static void dn_fib_rule_flush_cache(void) 242{ 243 dn_rt_cache_flush(-1); 244} 245 246static struct fib_rules_ops dn_fib_rules_ops = { 247 .family = AF_DECnet, 248 .rule_size = sizeof(struct dn_fib_rule), 249 .addr_size = sizeof(u16), 250 .action = dn_fib_rule_action, 251 .match = dn_fib_rule_match, 252 .configure = dn_fib_rule_configure, 253 .compare = dn_fib_rule_compare, 254 .fill = dn_fib_rule_fill, 255 .default_pref = dn_fib_rule_default_pref, 256 .flush_cache = dn_fib_rule_flush_cache, 257 .nlgroup = RTNLGRP_DECnet_RULE, 258 .policy = dn_fib_rule_policy, 259 .rules_list = LIST_HEAD_INIT(dn_fib_rules_ops.rules_list), 260 .owner = THIS_MODULE, 261}; 262 263void __init dn_fib_rules_init(void) 264{ 265 list_add_tail(&default_rule.common.list, 266 &dn_fib_rules_ops.rules_list); 267 fib_rules_register(&dn_fib_rules_ops); 268} 269 270void __exit dn_fib_rules_cleanup(void) 271{ 272 fib_rules_unregister(&dn_fib_rules_ops); 273} 274 275