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