xref: /openbmc/linux/net/ipv4/fib_rules.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /*
2*1da177e4SLinus Torvalds  * INET		An implementation of the TCP/IP protocol suite for the LINUX
3*1da177e4SLinus Torvalds  *		operating system.  INET is implemented using the  BSD Socket
4*1da177e4SLinus Torvalds  *		interface as the means of communication with the user level.
5*1da177e4SLinus Torvalds  *
6*1da177e4SLinus Torvalds  *		IPv4 Forwarding Information Base: policy rules.
7*1da177e4SLinus Torvalds  *
8*1da177e4SLinus Torvalds  * Version:	$Id: fib_rules.c,v 1.17 2001/10/31 21:55:54 davem Exp $
9*1da177e4SLinus Torvalds  *
10*1da177e4SLinus Torvalds  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
11*1da177e4SLinus Torvalds  *
12*1da177e4SLinus Torvalds  *		This program is free software; you can redistribute it and/or
13*1da177e4SLinus Torvalds  *		modify it under the terms of the GNU General Public License
14*1da177e4SLinus Torvalds  *		as published by the Free Software Foundation; either version
15*1da177e4SLinus Torvalds  *		2 of the License, or (at your option) any later version.
16*1da177e4SLinus Torvalds  *
17*1da177e4SLinus Torvalds  * Fixes:
18*1da177e4SLinus Torvalds  * 		Rani Assaf	:	local_rule cannot be deleted
19*1da177e4SLinus Torvalds  *		Marc Boucher	:	routing by fwmark
20*1da177e4SLinus Torvalds  */
21*1da177e4SLinus Torvalds 
22*1da177e4SLinus Torvalds #include <linux/config.h>
23*1da177e4SLinus Torvalds #include <asm/uaccess.h>
24*1da177e4SLinus Torvalds #include <asm/system.h>
25*1da177e4SLinus Torvalds #include <linux/bitops.h>
26*1da177e4SLinus Torvalds #include <linux/types.h>
27*1da177e4SLinus Torvalds #include <linux/kernel.h>
28*1da177e4SLinus Torvalds #include <linux/sched.h>
29*1da177e4SLinus Torvalds #include <linux/mm.h>
30*1da177e4SLinus Torvalds #include <linux/string.h>
31*1da177e4SLinus Torvalds #include <linux/socket.h>
32*1da177e4SLinus Torvalds #include <linux/sockios.h>
33*1da177e4SLinus Torvalds #include <linux/errno.h>
34*1da177e4SLinus Torvalds #include <linux/in.h>
35*1da177e4SLinus Torvalds #include <linux/inet.h>
36*1da177e4SLinus Torvalds #include <linux/netdevice.h>
37*1da177e4SLinus Torvalds #include <linux/if_arp.h>
38*1da177e4SLinus Torvalds #include <linux/proc_fs.h>
39*1da177e4SLinus Torvalds #include <linux/skbuff.h>
40*1da177e4SLinus Torvalds #include <linux/netlink.h>
41*1da177e4SLinus Torvalds #include <linux/init.h>
42*1da177e4SLinus Torvalds 
43*1da177e4SLinus Torvalds #include <net/ip.h>
44*1da177e4SLinus Torvalds #include <net/protocol.h>
45*1da177e4SLinus Torvalds #include <net/route.h>
46*1da177e4SLinus Torvalds #include <net/tcp.h>
47*1da177e4SLinus Torvalds #include <net/sock.h>
48*1da177e4SLinus Torvalds #include <net/ip_fib.h>
49*1da177e4SLinus Torvalds 
50*1da177e4SLinus Torvalds #define FRprintk(a...)
51*1da177e4SLinus Torvalds 
52*1da177e4SLinus Torvalds struct fib_rule
53*1da177e4SLinus Torvalds {
54*1da177e4SLinus Torvalds 	struct fib_rule *r_next;
55*1da177e4SLinus Torvalds 	atomic_t	r_clntref;
56*1da177e4SLinus Torvalds 	u32		r_preference;
57*1da177e4SLinus Torvalds 	unsigned char	r_table;
58*1da177e4SLinus Torvalds 	unsigned char	r_action;
59*1da177e4SLinus Torvalds 	unsigned char	r_dst_len;
60*1da177e4SLinus Torvalds 	unsigned char	r_src_len;
61*1da177e4SLinus Torvalds 	u32		r_src;
62*1da177e4SLinus Torvalds 	u32		r_srcmask;
63*1da177e4SLinus Torvalds 	u32		r_dst;
64*1da177e4SLinus Torvalds 	u32		r_dstmask;
65*1da177e4SLinus Torvalds 	u32		r_srcmap;
66*1da177e4SLinus Torvalds 	u8		r_flags;
67*1da177e4SLinus Torvalds 	u8		r_tos;
68*1da177e4SLinus Torvalds #ifdef CONFIG_IP_ROUTE_FWMARK
69*1da177e4SLinus Torvalds 	u32		r_fwmark;
70*1da177e4SLinus Torvalds #endif
71*1da177e4SLinus Torvalds 	int		r_ifindex;
72*1da177e4SLinus Torvalds #ifdef CONFIG_NET_CLS_ROUTE
73*1da177e4SLinus Torvalds 	__u32		r_tclassid;
74*1da177e4SLinus Torvalds #endif
75*1da177e4SLinus Torvalds 	char		r_ifname[IFNAMSIZ];
76*1da177e4SLinus Torvalds 	int		r_dead;
77*1da177e4SLinus Torvalds };
78*1da177e4SLinus Torvalds 
79*1da177e4SLinus Torvalds static struct fib_rule default_rule = {
80*1da177e4SLinus Torvalds 	.r_clntref =	ATOMIC_INIT(2),
81*1da177e4SLinus Torvalds 	.r_preference =	0x7FFF,
82*1da177e4SLinus Torvalds 	.r_table =	RT_TABLE_DEFAULT,
83*1da177e4SLinus Torvalds 	.r_action =	RTN_UNICAST,
84*1da177e4SLinus Torvalds };
85*1da177e4SLinus Torvalds 
86*1da177e4SLinus Torvalds static struct fib_rule main_rule = {
87*1da177e4SLinus Torvalds 	.r_next =	&default_rule,
88*1da177e4SLinus Torvalds 	.r_clntref =	ATOMIC_INIT(2),
89*1da177e4SLinus Torvalds 	.r_preference =	0x7FFE,
90*1da177e4SLinus Torvalds 	.r_table =	RT_TABLE_MAIN,
91*1da177e4SLinus Torvalds 	.r_action =	RTN_UNICAST,
92*1da177e4SLinus Torvalds };
93*1da177e4SLinus Torvalds 
94*1da177e4SLinus Torvalds static struct fib_rule local_rule = {
95*1da177e4SLinus Torvalds 	.r_next =	&main_rule,
96*1da177e4SLinus Torvalds 	.r_clntref =	ATOMIC_INIT(2),
97*1da177e4SLinus Torvalds 	.r_table =	RT_TABLE_LOCAL,
98*1da177e4SLinus Torvalds 	.r_action =	RTN_UNICAST,
99*1da177e4SLinus Torvalds };
100*1da177e4SLinus Torvalds 
101*1da177e4SLinus Torvalds static struct fib_rule *fib_rules = &local_rule;
102*1da177e4SLinus Torvalds static DEFINE_RWLOCK(fib_rules_lock);
103*1da177e4SLinus Torvalds 
104*1da177e4SLinus Torvalds int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
105*1da177e4SLinus Torvalds {
106*1da177e4SLinus Torvalds 	struct rtattr **rta = arg;
107*1da177e4SLinus Torvalds 	struct rtmsg *rtm = NLMSG_DATA(nlh);
108*1da177e4SLinus Torvalds 	struct fib_rule *r, **rp;
109*1da177e4SLinus Torvalds 	int err = -ESRCH;
110*1da177e4SLinus Torvalds 
111*1da177e4SLinus Torvalds 	for (rp=&fib_rules; (r=*rp) != NULL; rp=&r->r_next) {
112*1da177e4SLinus Torvalds 		if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 4) == 0) &&
113*1da177e4SLinus Torvalds 		    rtm->rtm_src_len == r->r_src_len &&
114*1da177e4SLinus Torvalds 		    rtm->rtm_dst_len == r->r_dst_len &&
115*1da177e4SLinus Torvalds 		    (!rta[RTA_DST-1] || memcmp(RTA_DATA(rta[RTA_DST-1]), &r->r_dst, 4) == 0) &&
116*1da177e4SLinus Torvalds 		    rtm->rtm_tos == r->r_tos &&
117*1da177e4SLinus Torvalds #ifdef CONFIG_IP_ROUTE_FWMARK
118*1da177e4SLinus Torvalds 		    (!rta[RTA_PROTOINFO-1] || memcmp(RTA_DATA(rta[RTA_PROTOINFO-1]), &r->r_fwmark, 4) == 0) &&
119*1da177e4SLinus Torvalds #endif
120*1da177e4SLinus Torvalds 		    (!rtm->rtm_type || rtm->rtm_type == r->r_action) &&
121*1da177e4SLinus Torvalds 		    (!rta[RTA_PRIORITY-1] || memcmp(RTA_DATA(rta[RTA_PRIORITY-1]), &r->r_preference, 4) == 0) &&
122*1da177e4SLinus Torvalds 		    (!rta[RTA_IIF-1] || rtattr_strcmp(rta[RTA_IIF-1], r->r_ifname) == 0) &&
123*1da177e4SLinus Torvalds 		    (!rtm->rtm_table || (r && rtm->rtm_table == r->r_table))) {
124*1da177e4SLinus Torvalds 			err = -EPERM;
125*1da177e4SLinus Torvalds 			if (r == &local_rule)
126*1da177e4SLinus Torvalds 				break;
127*1da177e4SLinus Torvalds 
128*1da177e4SLinus Torvalds 			write_lock_bh(&fib_rules_lock);
129*1da177e4SLinus Torvalds 			*rp = r->r_next;
130*1da177e4SLinus Torvalds 			r->r_dead = 1;
131*1da177e4SLinus Torvalds 			write_unlock_bh(&fib_rules_lock);
132*1da177e4SLinus Torvalds 			fib_rule_put(r);
133*1da177e4SLinus Torvalds 			err = 0;
134*1da177e4SLinus Torvalds 			break;
135*1da177e4SLinus Torvalds 		}
136*1da177e4SLinus Torvalds 	}
137*1da177e4SLinus Torvalds 	return err;
138*1da177e4SLinus Torvalds }
139*1da177e4SLinus Torvalds 
140*1da177e4SLinus Torvalds /* Allocate new unique table id */
141*1da177e4SLinus Torvalds 
142*1da177e4SLinus Torvalds static struct fib_table *fib_empty_table(void)
143*1da177e4SLinus Torvalds {
144*1da177e4SLinus Torvalds 	int id;
145*1da177e4SLinus Torvalds 
146*1da177e4SLinus Torvalds 	for (id = 1; id <= RT_TABLE_MAX; id++)
147*1da177e4SLinus Torvalds 		if (fib_tables[id] == NULL)
148*1da177e4SLinus Torvalds 			return __fib_new_table(id);
149*1da177e4SLinus Torvalds 	return NULL;
150*1da177e4SLinus Torvalds }
151*1da177e4SLinus Torvalds 
152*1da177e4SLinus Torvalds void fib_rule_put(struct fib_rule *r)
153*1da177e4SLinus Torvalds {
154*1da177e4SLinus Torvalds 	if (atomic_dec_and_test(&r->r_clntref)) {
155*1da177e4SLinus Torvalds 		if (r->r_dead)
156*1da177e4SLinus Torvalds 			kfree(r);
157*1da177e4SLinus Torvalds 		else
158*1da177e4SLinus Torvalds 			printk("Freeing alive rule %p\n", r);
159*1da177e4SLinus Torvalds 	}
160*1da177e4SLinus Torvalds }
161*1da177e4SLinus Torvalds 
162*1da177e4SLinus Torvalds int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
163*1da177e4SLinus Torvalds {
164*1da177e4SLinus Torvalds 	struct rtattr **rta = arg;
165*1da177e4SLinus Torvalds 	struct rtmsg *rtm = NLMSG_DATA(nlh);
166*1da177e4SLinus Torvalds 	struct fib_rule *r, *new_r, **rp;
167*1da177e4SLinus Torvalds 	unsigned char table_id;
168*1da177e4SLinus Torvalds 
169*1da177e4SLinus Torvalds 	if (rtm->rtm_src_len > 32 || rtm->rtm_dst_len > 32 ||
170*1da177e4SLinus Torvalds 	    (rtm->rtm_tos & ~IPTOS_TOS_MASK))
171*1da177e4SLinus Torvalds 		return -EINVAL;
172*1da177e4SLinus Torvalds 
173*1da177e4SLinus Torvalds 	if (rta[RTA_IIF-1] && RTA_PAYLOAD(rta[RTA_IIF-1]) > IFNAMSIZ)
174*1da177e4SLinus Torvalds 		return -EINVAL;
175*1da177e4SLinus Torvalds 
176*1da177e4SLinus Torvalds 	table_id = rtm->rtm_table;
177*1da177e4SLinus Torvalds 	if (table_id == RT_TABLE_UNSPEC) {
178*1da177e4SLinus Torvalds 		struct fib_table *table;
179*1da177e4SLinus Torvalds 		if (rtm->rtm_type == RTN_UNICAST) {
180*1da177e4SLinus Torvalds 			if ((table = fib_empty_table()) == NULL)
181*1da177e4SLinus Torvalds 				return -ENOBUFS;
182*1da177e4SLinus Torvalds 			table_id = table->tb_id;
183*1da177e4SLinus Torvalds 		}
184*1da177e4SLinus Torvalds 	}
185*1da177e4SLinus Torvalds 
186*1da177e4SLinus Torvalds 	new_r = kmalloc(sizeof(*new_r), GFP_KERNEL);
187*1da177e4SLinus Torvalds 	if (!new_r)
188*1da177e4SLinus Torvalds 		return -ENOMEM;
189*1da177e4SLinus Torvalds 	memset(new_r, 0, sizeof(*new_r));
190*1da177e4SLinus Torvalds 	if (rta[RTA_SRC-1])
191*1da177e4SLinus Torvalds 		memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 4);
192*1da177e4SLinus Torvalds 	if (rta[RTA_DST-1])
193*1da177e4SLinus Torvalds 		memcpy(&new_r->r_dst, RTA_DATA(rta[RTA_DST-1]), 4);
194*1da177e4SLinus Torvalds 	if (rta[RTA_GATEWAY-1])
195*1da177e4SLinus Torvalds 		memcpy(&new_r->r_srcmap, RTA_DATA(rta[RTA_GATEWAY-1]), 4);
196*1da177e4SLinus Torvalds 	new_r->r_src_len = rtm->rtm_src_len;
197*1da177e4SLinus Torvalds 	new_r->r_dst_len = rtm->rtm_dst_len;
198*1da177e4SLinus Torvalds 	new_r->r_srcmask = inet_make_mask(rtm->rtm_src_len);
199*1da177e4SLinus Torvalds 	new_r->r_dstmask = inet_make_mask(rtm->rtm_dst_len);
200*1da177e4SLinus Torvalds 	new_r->r_tos = rtm->rtm_tos;
201*1da177e4SLinus Torvalds #ifdef CONFIG_IP_ROUTE_FWMARK
202*1da177e4SLinus Torvalds 	if (rta[RTA_PROTOINFO-1])
203*1da177e4SLinus Torvalds 		memcpy(&new_r->r_fwmark, RTA_DATA(rta[RTA_PROTOINFO-1]), 4);
204*1da177e4SLinus Torvalds #endif
205*1da177e4SLinus Torvalds 	new_r->r_action = rtm->rtm_type;
206*1da177e4SLinus Torvalds 	new_r->r_flags = rtm->rtm_flags;
207*1da177e4SLinus Torvalds 	if (rta[RTA_PRIORITY-1])
208*1da177e4SLinus Torvalds 		memcpy(&new_r->r_preference, RTA_DATA(rta[RTA_PRIORITY-1]), 4);
209*1da177e4SLinus Torvalds 	new_r->r_table = table_id;
210*1da177e4SLinus Torvalds 	if (rta[RTA_IIF-1]) {
211*1da177e4SLinus Torvalds 		struct net_device *dev;
212*1da177e4SLinus Torvalds 		rtattr_strlcpy(new_r->r_ifname, rta[RTA_IIF-1], IFNAMSIZ);
213*1da177e4SLinus Torvalds 		new_r->r_ifindex = -1;
214*1da177e4SLinus Torvalds 		dev = __dev_get_by_name(new_r->r_ifname);
215*1da177e4SLinus Torvalds 		if (dev)
216*1da177e4SLinus Torvalds 			new_r->r_ifindex = dev->ifindex;
217*1da177e4SLinus Torvalds 	}
218*1da177e4SLinus Torvalds #ifdef CONFIG_NET_CLS_ROUTE
219*1da177e4SLinus Torvalds 	if (rta[RTA_FLOW-1])
220*1da177e4SLinus Torvalds 		memcpy(&new_r->r_tclassid, RTA_DATA(rta[RTA_FLOW-1]), 4);
221*1da177e4SLinus Torvalds #endif
222*1da177e4SLinus Torvalds 
223*1da177e4SLinus Torvalds 	rp = &fib_rules;
224*1da177e4SLinus Torvalds 	if (!new_r->r_preference) {
225*1da177e4SLinus Torvalds 		r = fib_rules;
226*1da177e4SLinus Torvalds 		if (r && (r = r->r_next) != NULL) {
227*1da177e4SLinus Torvalds 			rp = &fib_rules->r_next;
228*1da177e4SLinus Torvalds 			if (r->r_preference)
229*1da177e4SLinus Torvalds 				new_r->r_preference = r->r_preference - 1;
230*1da177e4SLinus Torvalds 		}
231*1da177e4SLinus Torvalds 	}
232*1da177e4SLinus Torvalds 
233*1da177e4SLinus Torvalds 	while ( (r = *rp) != NULL ) {
234*1da177e4SLinus Torvalds 		if (r->r_preference > new_r->r_preference)
235*1da177e4SLinus Torvalds 			break;
236*1da177e4SLinus Torvalds 		rp = &r->r_next;
237*1da177e4SLinus Torvalds 	}
238*1da177e4SLinus Torvalds 
239*1da177e4SLinus Torvalds 	new_r->r_next = r;
240*1da177e4SLinus Torvalds 	atomic_inc(&new_r->r_clntref);
241*1da177e4SLinus Torvalds 	write_lock_bh(&fib_rules_lock);
242*1da177e4SLinus Torvalds 	*rp = new_r;
243*1da177e4SLinus Torvalds 	write_unlock_bh(&fib_rules_lock);
244*1da177e4SLinus Torvalds 	return 0;
245*1da177e4SLinus Torvalds }
246*1da177e4SLinus Torvalds 
247*1da177e4SLinus Torvalds #ifdef CONFIG_NET_CLS_ROUTE
248*1da177e4SLinus Torvalds u32 fib_rules_tclass(struct fib_result *res)
249*1da177e4SLinus Torvalds {
250*1da177e4SLinus Torvalds 	if (res->r)
251*1da177e4SLinus Torvalds 		return res->r->r_tclassid;
252*1da177e4SLinus Torvalds 	return 0;
253*1da177e4SLinus Torvalds }
254*1da177e4SLinus Torvalds #endif
255*1da177e4SLinus Torvalds 
256*1da177e4SLinus Torvalds 
257*1da177e4SLinus Torvalds static void fib_rules_detach(struct net_device *dev)
258*1da177e4SLinus Torvalds {
259*1da177e4SLinus Torvalds 	struct fib_rule *r;
260*1da177e4SLinus Torvalds 
261*1da177e4SLinus Torvalds 	for (r=fib_rules; r; r=r->r_next) {
262*1da177e4SLinus Torvalds 		if (r->r_ifindex == dev->ifindex) {
263*1da177e4SLinus Torvalds 			write_lock_bh(&fib_rules_lock);
264*1da177e4SLinus Torvalds 			r->r_ifindex = -1;
265*1da177e4SLinus Torvalds 			write_unlock_bh(&fib_rules_lock);
266*1da177e4SLinus Torvalds 		}
267*1da177e4SLinus Torvalds 	}
268*1da177e4SLinus Torvalds }
269*1da177e4SLinus Torvalds 
270*1da177e4SLinus Torvalds static void fib_rules_attach(struct net_device *dev)
271*1da177e4SLinus Torvalds {
272*1da177e4SLinus Torvalds 	struct fib_rule *r;
273*1da177e4SLinus Torvalds 
274*1da177e4SLinus Torvalds 	for (r=fib_rules; r; r=r->r_next) {
275*1da177e4SLinus Torvalds 		if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0) {
276*1da177e4SLinus Torvalds 			write_lock_bh(&fib_rules_lock);
277*1da177e4SLinus Torvalds 			r->r_ifindex = dev->ifindex;
278*1da177e4SLinus Torvalds 			write_unlock_bh(&fib_rules_lock);
279*1da177e4SLinus Torvalds 		}
280*1da177e4SLinus Torvalds 	}
281*1da177e4SLinus Torvalds }
282*1da177e4SLinus Torvalds 
283*1da177e4SLinus Torvalds int fib_lookup(const struct flowi *flp, struct fib_result *res)
284*1da177e4SLinus Torvalds {
285*1da177e4SLinus Torvalds 	int err;
286*1da177e4SLinus Torvalds 	struct fib_rule *r, *policy;
287*1da177e4SLinus Torvalds 	struct fib_table *tb;
288*1da177e4SLinus Torvalds 
289*1da177e4SLinus Torvalds 	u32 daddr = flp->fl4_dst;
290*1da177e4SLinus Torvalds 	u32 saddr = flp->fl4_src;
291*1da177e4SLinus Torvalds 
292*1da177e4SLinus Torvalds FRprintk("Lookup: %u.%u.%u.%u <- %u.%u.%u.%u ",
293*1da177e4SLinus Torvalds 	NIPQUAD(flp->fl4_dst), NIPQUAD(flp->fl4_src));
294*1da177e4SLinus Torvalds 	read_lock(&fib_rules_lock);
295*1da177e4SLinus Torvalds 	for (r = fib_rules; r; r=r->r_next) {
296*1da177e4SLinus Torvalds 		if (((saddr^r->r_src) & r->r_srcmask) ||
297*1da177e4SLinus Torvalds 		    ((daddr^r->r_dst) & r->r_dstmask) ||
298*1da177e4SLinus Torvalds 		    (r->r_tos && r->r_tos != flp->fl4_tos) ||
299*1da177e4SLinus Torvalds #ifdef CONFIG_IP_ROUTE_FWMARK
300*1da177e4SLinus Torvalds 		    (r->r_fwmark && r->r_fwmark != flp->fl4_fwmark) ||
301*1da177e4SLinus Torvalds #endif
302*1da177e4SLinus Torvalds 		    (r->r_ifindex && r->r_ifindex != flp->iif))
303*1da177e4SLinus Torvalds 			continue;
304*1da177e4SLinus Torvalds 
305*1da177e4SLinus Torvalds FRprintk("tb %d r %d ", r->r_table, r->r_action);
306*1da177e4SLinus Torvalds 		switch (r->r_action) {
307*1da177e4SLinus Torvalds 		case RTN_UNICAST:
308*1da177e4SLinus Torvalds 			policy = r;
309*1da177e4SLinus Torvalds 			break;
310*1da177e4SLinus Torvalds 		case RTN_UNREACHABLE:
311*1da177e4SLinus Torvalds 			read_unlock(&fib_rules_lock);
312*1da177e4SLinus Torvalds 			return -ENETUNREACH;
313*1da177e4SLinus Torvalds 		default:
314*1da177e4SLinus Torvalds 		case RTN_BLACKHOLE:
315*1da177e4SLinus Torvalds 			read_unlock(&fib_rules_lock);
316*1da177e4SLinus Torvalds 			return -EINVAL;
317*1da177e4SLinus Torvalds 		case RTN_PROHIBIT:
318*1da177e4SLinus Torvalds 			read_unlock(&fib_rules_lock);
319*1da177e4SLinus Torvalds 			return -EACCES;
320*1da177e4SLinus Torvalds 		}
321*1da177e4SLinus Torvalds 
322*1da177e4SLinus Torvalds 		if ((tb = fib_get_table(r->r_table)) == NULL)
323*1da177e4SLinus Torvalds 			continue;
324*1da177e4SLinus Torvalds 		err = tb->tb_lookup(tb, flp, res);
325*1da177e4SLinus Torvalds 		if (err == 0) {
326*1da177e4SLinus Torvalds 			res->r = policy;
327*1da177e4SLinus Torvalds 			if (policy)
328*1da177e4SLinus Torvalds 				atomic_inc(&policy->r_clntref);
329*1da177e4SLinus Torvalds 			read_unlock(&fib_rules_lock);
330*1da177e4SLinus Torvalds 			return 0;
331*1da177e4SLinus Torvalds 		}
332*1da177e4SLinus Torvalds 		if (err < 0 && err != -EAGAIN) {
333*1da177e4SLinus Torvalds 			read_unlock(&fib_rules_lock);
334*1da177e4SLinus Torvalds 			return err;
335*1da177e4SLinus Torvalds 		}
336*1da177e4SLinus Torvalds 	}
337*1da177e4SLinus Torvalds FRprintk("FAILURE\n");
338*1da177e4SLinus Torvalds 	read_unlock(&fib_rules_lock);
339*1da177e4SLinus Torvalds 	return -ENETUNREACH;
340*1da177e4SLinus Torvalds }
341*1da177e4SLinus Torvalds 
342*1da177e4SLinus Torvalds void fib_select_default(const struct flowi *flp, struct fib_result *res)
343*1da177e4SLinus Torvalds {
344*1da177e4SLinus Torvalds 	if (res->r && res->r->r_action == RTN_UNICAST &&
345*1da177e4SLinus Torvalds 	    FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) {
346*1da177e4SLinus Torvalds 		struct fib_table *tb;
347*1da177e4SLinus Torvalds 		if ((tb = fib_get_table(res->r->r_table)) != NULL)
348*1da177e4SLinus Torvalds 			tb->tb_select_default(tb, flp, res);
349*1da177e4SLinus Torvalds 	}
350*1da177e4SLinus Torvalds }
351*1da177e4SLinus Torvalds 
352*1da177e4SLinus Torvalds static int fib_rules_event(struct notifier_block *this, unsigned long event, void *ptr)
353*1da177e4SLinus Torvalds {
354*1da177e4SLinus Torvalds 	struct net_device *dev = ptr;
355*1da177e4SLinus Torvalds 
356*1da177e4SLinus Torvalds 	if (event == NETDEV_UNREGISTER)
357*1da177e4SLinus Torvalds 		fib_rules_detach(dev);
358*1da177e4SLinus Torvalds 	else if (event == NETDEV_REGISTER)
359*1da177e4SLinus Torvalds 		fib_rules_attach(dev);
360*1da177e4SLinus Torvalds 	return NOTIFY_DONE;
361*1da177e4SLinus Torvalds }
362*1da177e4SLinus Torvalds 
363*1da177e4SLinus Torvalds 
364*1da177e4SLinus Torvalds static struct notifier_block fib_rules_notifier = {
365*1da177e4SLinus Torvalds 	.notifier_call =fib_rules_event,
366*1da177e4SLinus Torvalds };
367*1da177e4SLinus Torvalds 
368*1da177e4SLinus Torvalds static __inline__ int inet_fill_rule(struct sk_buff *skb,
369*1da177e4SLinus Torvalds 				     struct fib_rule *r,
370*1da177e4SLinus Torvalds 				     struct netlink_callback *cb)
371*1da177e4SLinus Torvalds {
372*1da177e4SLinus Torvalds 	struct rtmsg *rtm;
373*1da177e4SLinus Torvalds 	struct nlmsghdr  *nlh;
374*1da177e4SLinus Torvalds 	unsigned char	 *b = skb->tail;
375*1da177e4SLinus Torvalds 
376*1da177e4SLinus Torvalds 	nlh = NLMSG_PUT(skb, NETLINK_CREDS(cb->skb)->pid, cb->nlh->nlmsg_seq, RTM_NEWRULE, sizeof(*rtm));
377*1da177e4SLinus Torvalds 	rtm = NLMSG_DATA(nlh);
378*1da177e4SLinus Torvalds 	rtm->rtm_family = AF_INET;
379*1da177e4SLinus Torvalds 	rtm->rtm_dst_len = r->r_dst_len;
380*1da177e4SLinus Torvalds 	rtm->rtm_src_len = r->r_src_len;
381*1da177e4SLinus Torvalds 	rtm->rtm_tos = r->r_tos;
382*1da177e4SLinus Torvalds #ifdef CONFIG_IP_ROUTE_FWMARK
383*1da177e4SLinus Torvalds 	if (r->r_fwmark)
384*1da177e4SLinus Torvalds 		RTA_PUT(skb, RTA_PROTOINFO, 4, &r->r_fwmark);
385*1da177e4SLinus Torvalds #endif
386*1da177e4SLinus Torvalds 	rtm->rtm_table = r->r_table;
387*1da177e4SLinus Torvalds 	rtm->rtm_protocol = 0;
388*1da177e4SLinus Torvalds 	rtm->rtm_scope = 0;
389*1da177e4SLinus Torvalds 	rtm->rtm_type = r->r_action;
390*1da177e4SLinus Torvalds 	rtm->rtm_flags = r->r_flags;
391*1da177e4SLinus Torvalds 
392*1da177e4SLinus Torvalds 	if (r->r_dst_len)
393*1da177e4SLinus Torvalds 		RTA_PUT(skb, RTA_DST, 4, &r->r_dst);
394*1da177e4SLinus Torvalds 	if (r->r_src_len)
395*1da177e4SLinus Torvalds 		RTA_PUT(skb, RTA_SRC, 4, &r->r_src);
396*1da177e4SLinus Torvalds 	if (r->r_ifname[0])
397*1da177e4SLinus Torvalds 		RTA_PUT(skb, RTA_IIF, IFNAMSIZ, &r->r_ifname);
398*1da177e4SLinus Torvalds 	if (r->r_preference)
399*1da177e4SLinus Torvalds 		RTA_PUT(skb, RTA_PRIORITY, 4, &r->r_preference);
400*1da177e4SLinus Torvalds 	if (r->r_srcmap)
401*1da177e4SLinus Torvalds 		RTA_PUT(skb, RTA_GATEWAY, 4, &r->r_srcmap);
402*1da177e4SLinus Torvalds #ifdef CONFIG_NET_CLS_ROUTE
403*1da177e4SLinus Torvalds 	if (r->r_tclassid)
404*1da177e4SLinus Torvalds 		RTA_PUT(skb, RTA_FLOW, 4, &r->r_tclassid);
405*1da177e4SLinus Torvalds #endif
406*1da177e4SLinus Torvalds 	nlh->nlmsg_len = skb->tail - b;
407*1da177e4SLinus Torvalds 	return skb->len;
408*1da177e4SLinus Torvalds 
409*1da177e4SLinus Torvalds nlmsg_failure:
410*1da177e4SLinus Torvalds rtattr_failure:
411*1da177e4SLinus Torvalds 	skb_trim(skb, b - skb->data);
412*1da177e4SLinus Torvalds 	return -1;
413*1da177e4SLinus Torvalds }
414*1da177e4SLinus Torvalds 
415*1da177e4SLinus Torvalds int inet_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
416*1da177e4SLinus Torvalds {
417*1da177e4SLinus Torvalds 	int idx;
418*1da177e4SLinus Torvalds 	int s_idx = cb->args[0];
419*1da177e4SLinus Torvalds 	struct fib_rule *r;
420*1da177e4SLinus Torvalds 
421*1da177e4SLinus Torvalds 	read_lock(&fib_rules_lock);
422*1da177e4SLinus Torvalds 	for (r=fib_rules, idx=0; r; r = r->r_next, idx++) {
423*1da177e4SLinus Torvalds 		if (idx < s_idx)
424*1da177e4SLinus Torvalds 			continue;
425*1da177e4SLinus Torvalds 		if (inet_fill_rule(skb, r, cb) < 0)
426*1da177e4SLinus Torvalds 			break;
427*1da177e4SLinus Torvalds 	}
428*1da177e4SLinus Torvalds 	read_unlock(&fib_rules_lock);
429*1da177e4SLinus Torvalds 	cb->args[0] = idx;
430*1da177e4SLinus Torvalds 
431*1da177e4SLinus Torvalds 	return skb->len;
432*1da177e4SLinus Torvalds }
433*1da177e4SLinus Torvalds 
434*1da177e4SLinus Torvalds void __init fib_rules_init(void)
435*1da177e4SLinus Torvalds {
436*1da177e4SLinus Torvalds 	register_netdevice_notifier(&fib_rules_notifier);
437*1da177e4SLinus Torvalds }
438