File: /usr/src/linux/net/decnet/dn_rules.c

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      *
15      */
16     #include <linux/config.h>
17     #include <linux/string.h>
18     #include <linux/net.h>
19     #include <linux/socket.h>
20     #include <linux/sockios.h>
21     #include <linux/init.h>
22     #include <linux/skbuff.h>
23     #include <linux/netlink.h>
24     #include <linux/rtnetlink.h>
25     #include <linux/proc_fs.h>
26     #include <linux/netdevice.h>
27     #include <linux/timer.h>
28     #include <linux/spinlock.h>
29     #include <asm/atomic.h>
30     #include <asm/uaccess.h>
31     #include <net/neighbour.h>
32     #include <net/dst.h>
33     #include <net/dn.h>
34     #include <net/dn_fib.h>
35     #include <net/dn_neigh.h>
36     #include <net/dn_dev.h>
37     
38     struct dn_fib_rule
39     {
40     	struct dn_fib_rule	*r_next;
41     	atomic_t		r_clntref;
42     	u32			r_preference;
43     	unsigned char		r_table;
44     	unsigned char		r_action;
45     	unsigned char		r_dst_len;
46     	unsigned char		r_src_len;
47     	dn_address		r_src;
48     	dn_address		r_srcmask;
49     	dn_address		r_dst;
50     	dn_address		r_dstmask;
51     	u8			r_flags;
52     #ifdef CONFIG_DECNET_ROUTE_FWMARK
53     	u32			r_fwmark;
54     #endif
55     	int			r_ifindex;
56     	char			r_ifname[IFNAMSIZ];
57     	int			r_dead;
58     };
59     
60     static struct dn_fib_rule default_rule = {
61     	r_clntref:		ATOMIC_INIT(2),
62     	r_preference:		0x7fff,
63     	r_table:		DN_DEFAULT_TABLE,
64     	r_action:		RTN_UNICAST
65     };
66     
67     static struct dn_fib_rule *dn_fib_rules = &default_rule;
68     static rwlock_t dn_fib_rules_lock = RW_LOCK_UNLOCKED;
69     
70     
71     int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
72     {
73     	struct rtattr **rta = arg;
74     	struct rtmsg *rtm = NLMSG_DATA(nlh);
75     	struct dn_fib_rule *r, **rp;
76     	int err = -ESRCH;
77     
78     	for(rp=&dn_fib_rules; (r=*rp) != NULL; rp = &r->r_next) {
79     		if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 2) == 0) &&
80     			rtm->rtm_src_len == r->r_src_len &&
81     			rtm->rtm_dst_len == r->r_dst_len &&
82     			(!rta[RTA_DST-1] || memcmp(RTA_DATA(rta[RTA_DST-1]), &r->r_dst, 2) == 0) &&
83     #ifdef CONFIG_DECNET_ROUTE_FWMARK
84     			(!rta[RTA_PROTOINFO-1] || memcmp(RTA_DATA(rta[RTA_PROTOINFO-1]), &r->r_fwmark, 4) == 0) &&
85     #endif
86     			(!rtm->rtm_type || rtm->rtm_type == r->r_action) &&
87     			(!rta[RTA_PRIORITY-1] || memcmp(RTA_DATA(rta[RTA_PRIORITY-1]), &r->r_preference, 4) == 0) &&
88     			(!rta[RTA_IIF-1] || strcmp(RTA_DATA(rta[RTA_IIF-1]), r->r_ifname) == 0) &&
89     			(!rtm->rtm_table || (r && rtm->rtm_table == r->r_table))) {
90     
91     			err = -EPERM;
92     			if (r == &default_rule)
93     				break;
94     
95     			write_lock_bh(&dn_fib_rules_lock);
96     			*rp = r->r_next;
97     			r->r_dead = 1;
98     			write_unlock_bh(&dn_fib_rules_lock);
99     			dn_fib_rule_put(r);
100     			err = 0;
101     			break;
102     		}
103     	}
104     
105     	return err;
106     }
107     
108     void dn_fib_rule_put(struct dn_fib_rule *r)
109     {
110     	if (atomic_dec_and_test(&r->r_clntref)) {
111     		if (r->r_dead)
112     			kfree(r);
113     		else
114     			printk(KERN_DEBUG "Attempt to free alive dn_fib_rule\n");
115     	}
116     }
117     
118     
119     int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
120     {
121     	struct rtattr **rta = arg;
122     	struct rtmsg *rtm = NLMSG_DATA(nlh);
123     	struct dn_fib_rule *r, *new_r, **rp;
124     	unsigned char table_id;
125     
126     	if (rtm->rtm_src_len > 16 || rtm->rtm_dst_len > 16)
127     		return -EINVAL;
128     
129     	if (rta[RTA_IIF-1] && RTA_PAYLOAD(rta[RTA_IIF-1]) > IFNAMSIZ)
130     		return -EINVAL;
131     
132     	if (rtm->rtm_type == RTN_NAT)
133     		return -EINVAL;
134     
135     	table_id = rtm->rtm_table;
136     	if (table_id == RT_TABLE_UNSPEC) {
137     		struct dn_fib_table *tb;
138     		if (rtm->rtm_type == RTN_UNICAST) {
139     			if ((tb = dn_fib_empty_table()) == NULL)
140     				return -ENOBUFS;
141     			table_id = tb->n;
142     		}
143     	}
144     
145     	new_r = kmalloc(sizeof(*new_r), GFP_KERNEL);
146     	if (!new_r)
147     		return -ENOMEM;
148     	memset(new_r, 0, sizeof(*new_r));
149     	if (rta[RTA_SRC-1])
150     		memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 2);
151     	if (rta[RTA_DST-1])
152     		memcpy(&new_r->r_dst, RTA_DATA(rta[RTA_DST-1]), 2);
153     	new_r->r_src_len = rtm->rtm_src_len;
154     	new_r->r_dst_len = rtm->rtm_dst_len;
155     	new_r->r_srcmask = dnet_make_mask(rtm->rtm_src_len);
156     	new_r->r_dstmask = dnet_make_mask(rtm->rtm_dst_len);
157     #ifdef CONFIG_DECNET_ROUTE_FWMARK
158     	if (rta[RTA_PROTOINFO-1])
159     		memcpy(&new_r->r_fwmark, RTA_DATA(rta[RTA_PROTOINFO-1]), 4);
160     #endif
161     	new_r->r_action = rtm->rtm_type;
162     	new_r->r_flags = rtm->rtm_flags;
163     	if (rta[RTA_PRIORITY-1])
164     		memcpy(&new_r->r_preference, RTA_DATA(rta[RTA_PRIORITY-1]), 4);
165     	new_r->r_table = table_id;
166     	if (rta[RTA_IIF-1]) {
167     		struct net_device *dev;
168     		memcpy(new_r->r_ifname, RTA_DATA(rta[RTA_IIF-1]), IFNAMSIZ);
169     		new_r->r_ifname[IFNAMSIZ-1] = 0;
170     		new_r->r_ifindex = -1;
171     		dev = __dev_get_by_name(new_r->r_ifname);
172     		if (dev)
173     			new_r->r_ifindex = dev->ifindex;
174     	}
175     
176     	rp = &dn_fib_rules;
177     	if (!new_r->r_preference) {
178     		r = dn_fib_rules;
179     		if (r && (r = r->r_next) != NULL) {
180     			rp = &dn_fib_rules->r_next;
181     			if (r->r_preference)
182     				new_r->r_preference = r->r_preference - 1;
183     		}
184     	}
185     
186     	while((r=*rp) != NULL) {
187     		if (r->r_preference > new_r->r_preference)
188     			break;
189     		rp = &r->r_next;
190     	}
191     
192     	new_r->r_next = r;
193     	atomic_inc(&new_r->r_clntref);
194     	write_lock_bh(&dn_fib_rules_lock);
195     	*rp = new_r;
196     	write_unlock_bh(&dn_fib_rules_lock);
197     	return 0;
198     }
199     
200     
201     int dn_fib_lookup(struct dn_fib_key *key, struct dn_fib_res *res)
202     {
203     	struct dn_fib_rule *r, *policy;
204     	struct dn_fib_table *tb;
205     	dn_address saddr = key->src;
206     	dn_address daddr = key->dst;
207     	int err;
208     
209     	read_lock(&dn_fib_rules_lock);
210     	for(r = dn_fib_rules; r; r = r->r_next) {
211     		if (((saddr^r->r_src) & r->r_srcmask) ||
212     		    ((daddr^r->r_dst) & r->r_dstmask) ||
213     #ifdef CONFIG_DECNET_ROUTE_FWMARK
214     		    (r->r_fwmark && r->r_fwmark != key->fwmark) ||
215     #endif
216     		    (r->r_ifindex && r->r_ifindex != key->iif))
217     			continue;
218     
219     		switch(r->r_action) {
220     			case RTN_UNICAST:
221     				policy = r;
222     				break;
223     			case RTN_UNREACHABLE:
224     				read_unlock(&dn_fib_rules_lock);
225     				return -ENETUNREACH;
226     			default:
227     			case RTN_BLACKHOLE:
228     				read_unlock(&dn_fib_rules_lock);
229     				return -EINVAL;
230     			case RTN_PROHIBIT:
231     				read_unlock(&dn_fib_rules_lock);
232     				return -EACCES;
233     		}
234     
235     		if ((tb = dn_fib_get_table(r->r_table, 0)) == NULL)
236     			continue;
237     		err = tb->lookup(tb, key, res);
238     		if (err == 0) {
239     			res->r = policy;
240     			if (policy)
241     				atomic_inc(&policy->r_clntref);
242     			read_unlock(&dn_fib_rules_lock);
243     			return 0;
244     		}
245     		if (err < 0 && err != -EAGAIN) {
246     			read_unlock(&dn_fib_rules_lock);
247     			return err;
248     		}
249     	}
250     
251     	read_unlock(&dn_fib_rules_lock);
252     	return -ESRCH;
253     }
254     
255     static void dn_fib_rules_detach(struct net_device *dev)
256     {
257     	struct dn_fib_rule *r;
258     
259     	for(r = dn_fib_rules; r; r = r->r_next) {
260     		if (r->r_ifindex == dev->ifindex) {
261     			write_lock_bh(&dn_fib_rules_lock);
262     			r->r_ifindex = -1;
263     			write_unlock_bh(&dn_fib_rules_lock);
264     		}
265     	}
266     }
267     
268     static void dn_fib_rules_attach(struct net_device *dev)
269     {
270     	struct dn_fib_rule *r;
271     
272     	for(r = dn_fib_rules; r; r = r->r_next) {
273     		if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0) {
274     			write_lock_bh(&dn_fib_rules_lock);
275     			r->r_ifindex = dev->ifindex;
276     			write_unlock_bh(&dn_fib_rules_lock);
277     		}
278     	}
279     }
280     
281     static int dn_fib_rules_event(struct notifier_block *this, unsigned long event, void *ptr)
282     {
283     	struct net_device *dev = ptr;
284     
285     	switch(event) {
286     		case NETDEV_UNREGISTER:
287     			dn_fib_rules_detach(dev);
288     			dn_fib_sync_down(0, dev, 1);
289     		case NETDEV_REGISTER:
290     			dn_fib_rules_attach(dev);
291     			dn_fib_sync_up(dev);
292     	}
293     
294     	return NOTIFY_DONE;
295     }
296     
297     
298     static struct notifier_block dn_fib_rules_notifier = {
299     	notifier_call:		dn_fib_rules_event,
300     };
301     
302     #ifdef CONFIG_RTNETLINK
303     
304     static int dn_fib_fill_rule(struct sk_buff *skb, struct dn_fib_rule *r, struct netlink_callback *cb)
305     {
306     	struct rtmsg *rtm;
307     	struct nlmsghdr *nlh;
308     	unsigned char *b = skb->tail;
309     
310     
311     	nlh = NLMSG_PUT(skb, NETLINK_CREDS(cb->skb)->pid, cb->nlh->nlmsg_seq, RTM_NEWRULE, sizeof(*rtm));
312     	rtm = NLMSG_DATA(nlh);
313     	rtm->rtm_family = AF_DECnet;
314     	rtm->rtm_dst_len = r->r_dst_len;
315     	rtm->rtm_src_len = r->r_src_len;
316     	rtm->rtm_tos = 0;
317     #ifdef CONFIG_DECNET_ROUTE_FWMARK
318     	if (r->r_fwmark)
319     		RTA_PUT(skb, RTA_PROTOINFO, 4, &r->r_fwmark);
320     #endif
321     	rtm->rtm_table = r->r_table;
322     	rtm->rtm_protocol = 0;
323     	rtm->rtm_scope = 0;
324     	rtm->rtm_type = r->r_action;
325     	rtm->rtm_flags = r->r_flags;
326     
327     	if (r->r_dst_len)
328     		RTA_PUT(skb, RTA_DST, 2, &r->r_dst);
329     	if (r->r_src_len)
330     		RTA_PUT(skb, RTA_SRC, 2, &r->r_src);
331     	if (r->r_ifname[0])
332     		RTA_PUT(skb, RTA_IIF, IFNAMSIZ, &r->r_ifname);
333     	if (r->r_preference)
334     		RTA_PUT(skb, RTA_PRIORITY, 4, &r->r_preference);
335     	nlh->nlmsg_len = skb->tail - b;
336     	return skb->len;
337     
338     nlmsg_failure:
339     rtattr_failure:
340     	skb_put(skb, b - skb->tail);
341     	return -1;
342     }
343     
344     int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
345     {
346     	int idx;
347     	int s_idx = cb->args[0];
348     	struct dn_fib_rule *r;
349     
350     	read_lock(&dn_fib_rules_lock);
351     	for(r = dn_fib_rules, idx = 0; r; r = r->r_next, idx++) {
352     		if (idx < s_idx)
353     			continue;
354     		if (dn_fib_fill_rule(skb, r, cb) < 0)
355     			break;
356     	}
357     	read_unlock(&dn_fib_rules_lock);
358     	cb->args[0] = idx;
359     
360     	return skb->len;
361     }
362     
363     #endif /* CONFIG_RTNETLINK */
364     
365     void __init dn_fib_rules_init(void)
366     {
367     	register_netdevice_notifier(&dn_fib_rules_notifier);
368     }
369     
370     void __exit dn_fib_rules_cleanup(void)
371     {
372     	unregister_netdevice_notifier(&dn_fib_rules_notifier);
373     }
374     
375     
376