1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/config.h>
19#include <asm/uaccess.h>
20#include <asm/system.h>
21#include <asm/bitops.h>
22#include <linux/types.h>
23#include <linux/kernel.h>
24#include <linux/sched.h>
25#include <linux/mm.h>
26#include <linux/string.h>
27#include <linux/socket.h>
28#include <linux/sockios.h>
29#include <linux/errno.h>
30#include <linux/in.h>
31#include <linux/inet.h>
32#include <linux/netdevice.h>
33#include <linux/if_arp.h>
34#include <linux/proc_fs.h>
35#include <linux/skbuff.h>
36#include <linux/netlink.h>
37#include <linux/init.h>
38
39#include <net/ip.h>
40#include <net/protocol.h>
41#include <net/route.h>
42#include <net/tcp.h>
43#include <net/sock.h>
44#include <net/icmp.h>
45#include <net/arp.h>
46#include <net/ip_fib.h>
47
48#define FFprint(a...) printk(KERN_DEBUG a)
49
50#ifndef CONFIG_IP_MULTIPLE_TABLES
51
52#define RT_TABLE_MIN RT_TABLE_MAIN
53
54struct fib_table *local_table;
55struct fib_table *main_table;
56
57#else
58
59#define RT_TABLE_MIN 1
60
61struct fib_table *fib_tables[RT_TABLE_MAX+1];
62
63struct fib_table *__fib_new_table(int id)
64{
65 struct fib_table *tb;
66
67 tb = fib_hash_init(id);
68 if (!tb)
69 return NULL;
70 fib_tables[id] = tb;
71 return tb;
72}
73
74
75#endif
76
77
78void fib_flush(void)
79{
80 int flushed = 0;
81#ifdef CONFIG_IP_MULTIPLE_TABLES
82 struct fib_table *tb;
83 int id;
84
85 for (id = RT_TABLE_MAX; id>0; id--) {
86 if ((tb = fib_get_table(id))==NULL)
87 continue;
88 flushed += tb->tb_flush(tb);
89 }
90#else
91 flushed += main_table->tb_flush(main_table);
92 flushed += local_table->tb_flush(local_table);
93#endif
94
95 if (flushed)
96 rt_cache_flush(-1);
97}
98
99
100#ifdef CONFIG_PROC_FS
101
102
103
104
105
106
107
108
109static int
110fib_get_procinfo(char *buffer, char **start, off_t offset, int length, int dummy)
111{
112 int first = offset/128;
113 char *ptr = buffer;
114 int count = (length+127)/128;
115 int len;
116
117 *start = buffer + offset%128;
118
119 if (--first < 0) {
120 sprintf(buffer, "%-127s\n", "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU\tWindow\tIRTT");
121 --count;
122 ptr += 128;
123 first = 0;
124 }
125
126
127 if (main_table && count > 0) {
128 int n = main_table->tb_get_info(main_table, ptr, first, count);
129 count -= n;
130 ptr += n*128;
131 }
132
133 len = ptr - *start;
134 if (len >= length)
135 return length;
136 if (len >= 0)
137 return len;
138 return 0;
139}
140
141#endif
142
143
144
145
146
147struct device * ip_dev_find(u32 addr)
148{
149 struct rt_key key;
150 struct fib_result res;
151
152 memset(&key, 0, sizeof(key));
153 key.dst = addr;
154
155 if (!local_table || local_table->tb_lookup(local_table, &key, &res)
156 || res.type != RTN_LOCAL)
157 return NULL;
158
159 return FIB_RES_DEV(res);
160}
161
162unsigned inet_addr_type(u32 addr)
163{
164 struct rt_key key;
165 struct fib_result res;
166
167 if (ZERONET(addr) || BADCLASS(addr))
168 return RTN_BROADCAST;
169 if (MULTICAST(addr))
170 return RTN_MULTICAST;
171
172 memset(&key, 0, sizeof(key));
173 key.dst = addr;
174
175 if (local_table) {
176 if (local_table->tb_lookup(local_table, &key, &res) == 0)
177 return res.type;
178 return RTN_UNICAST;
179 }
180 return RTN_BROADCAST;
181}
182
183
184
185
186
187
188
189
190
191int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
192 struct device *dev, u32 *spec_dst, u32 *itag)
193{
194 struct in_device *in_dev = dev->ip_ptr;
195 struct rt_key key;
196 struct fib_result res;
197
198 key.dst = src;
199 key.src = dst;
200 key.tos = tos;
201 key.oif = 0;
202 key.iif = oif;
203 key.scope = RT_SCOPE_UNIVERSE;
204
205 if (in_dev == NULL)
206 return -EINVAL;
207 if (fib_lookup(&key, &res))
208 goto last_resort;
209 if (res.type != RTN_UNICAST)
210 return -EINVAL;
211 *spec_dst = FIB_RES_PREFSRC(res);
212 if (itag)
213 fib_combine_itag(itag, &res);
214#ifdef CONFIG_IP_ROUTE_MULTIPATH
215 if (FIB_RES_DEV(res) == dev || res.fi->fib_nhs > 1)
216#else
217 if (FIB_RES_DEV(res) == dev)
218#endif
219 return FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
220
221 if (in_dev->ifa_list == NULL)
222 goto last_resort;
223 if (IN_DEV_RPFILTER(in_dev))
224 return -EINVAL;
225 key.oif = dev->ifindex;
226 if (fib_lookup(&key, &res) == 0 && res.type == RTN_UNICAST) {
227 *spec_dst = FIB_RES_PREFSRC(res);
228 return FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
229 }
230 return 0;
231
232last_resort:
233 if (IN_DEV_RPFILTER(in_dev))
234 return -EINVAL;
235 *spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
236 *itag = 0;
237 return 0;
238}
239
240#ifndef CONFIG_IP_NOSIOCRT
241
242
243
244
245
246int ip_rt_ioctl(unsigned int cmd, void *arg)
247{
248 int err;
249 struct kern_rta rta;
250 struct rtentry r;
251 struct {
252 struct nlmsghdr nlh;
253 struct rtmsg rtm;
254 } req;
255
256 switch (cmd) {
257 case SIOCADDRT:
258 case SIOCDELRT:
259 if (!capable(CAP_NET_ADMIN))
260 return -EPERM;
261 if (copy_from_user(&r, arg, sizeof(struct rtentry)))
262 return -EFAULT;
263 rtnl_lock();
264 err = fib_convert_rtentry(cmd, &req.nlh, &req.rtm, &rta, &r);
265 if (err == 0) {
266 if (cmd == SIOCDELRT) {
267 struct fib_table *tb = fib_get_table(req.rtm.rtm_table);
268 err = -ESRCH;
269 if (tb)
270 err = tb->tb_delete(tb, &req.rtm, &rta, &req.nlh, NULL);
271 } else {
272 struct fib_table *tb = fib_new_table(req.rtm.rtm_table);
273 err = -ENOBUFS;
274 if (tb)
275 err = tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL);
276 }
277 if (rta.rta_mx)
278 kfree(rta.rta_mx);
279 }
280 rtnl_unlock();
281 return err;
282 }
283 return -EINVAL;
284}
285
286#else
287
288int ip_rt_ioctl(unsigned int cmd, void *arg)
289{
290 return -EINVAL;
291}
292
293#endif
294
295#ifdef CONFIG_RTNETLINK
296
297static int inet_check_attr(struct rtmsg *r, struct rtattr **rta)
298{
299 int i;
300
301 for (i=1; i<=RTA_MAX; i++) {
302 struct rtattr *attr = rta[i-1];
303 if (attr) {
304 if (RTA_PAYLOAD(attr) < 4)
305 return -EINVAL;
306 if (i != RTA_MULTIPATH && i != RTA_METRICS)
307 rta[i-1] = (struct rtattr*)RTA_DATA(attr);
308 }
309 }
310 return 0;
311}
312
313int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
314{
315 struct fib_table * tb;
316 struct rtattr **rta = arg;
317 struct rtmsg *r = NLMSG_DATA(nlh);
318
319 if (inet_check_attr(r, rta))
320 return -EINVAL;
321
322 tb = fib_get_table(r->rtm_table);
323 if (tb)
324 return tb->tb_delete(tb, r, (struct kern_rta*)rta, nlh, &NETLINK_CB(skb));
325 return -ESRCH;
326}
327
328int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
329{
330 struct fib_table * tb;
331 struct rtattr **rta = arg;
332 struct rtmsg *r = NLMSG_DATA(nlh);
333
334 if (inet_check_attr(r, rta))
335 return -EINVAL;
336
337 tb = fib_new_table(r->rtm_table);
338 if (tb)
339 return tb->tb_insert(tb, r, (struct kern_rta*)rta, nlh, &NETLINK_CB(skb));
340 return -ENOBUFS;
341}
342
343int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
344{
345 int t;
346 int s_t;
347 struct fib_table *tb;
348
349 if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) &&
350 ((struct rtmsg*)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)
351 return ip_rt_dump(skb, cb);
352
353 s_t = cb->args[0];
354 if (s_t == 0)
355 s_t = cb->args[0] = RT_TABLE_MIN;
356
357 for (t=s_t; t<=RT_TABLE_MAX; t++) {
358 if (t < s_t) continue;
359 if (t > s_t)
360 memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0]));
361 if ((tb = fib_get_table(t))==NULL)
362 continue;
363 if (tb->tb_dump(tb, skb, cb) < 0)
364 break;
365 }
366
367 cb->args[0] = t;
368
369 return skb->len;
370}
371
372#endif
373
374
375
376
377
378
379
380
381static void fib_magic(int cmd, int type, u32 dst, int dst_len, struct in_ifaddr *ifa)
382{
383 struct fib_table * tb;
384 struct {
385 struct nlmsghdr nlh;
386 struct rtmsg rtm;
387 } req;
388 struct kern_rta rta;
389
390 memset(&req.rtm, 0, sizeof(req.rtm));
391 memset(&rta, 0, sizeof(rta));
392
393 if (type == RTN_UNICAST)
394 tb = fib_new_table(RT_TABLE_MAIN);
395 else
396 tb = fib_new_table(RT_TABLE_LOCAL);
397
398 if (tb == NULL)
399 return;
400
401 req.nlh.nlmsg_len = sizeof(req);
402 req.nlh.nlmsg_type = cmd;
403 req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_APPEND;
404 req.nlh.nlmsg_pid = 0;
405 req.nlh.nlmsg_seq = 0;
406
407 req.rtm.rtm_dst_len = dst_len;
408 req.rtm.rtm_table = tb->tb_id;
409 req.rtm.rtm_protocol = RTPROT_KERNEL;
410 req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST);
411 req.rtm.rtm_type = type;
412
413 rta.rta_dst = &dst;
414 rta.rta_prefsrc = &ifa->ifa_local;
415 rta.rta_oif = &ifa->ifa_dev->dev->ifindex;
416
417 if (cmd == RTM_NEWROUTE)
418 tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL);
419 else
420 tb->tb_delete(tb, &req.rtm, &rta, &req.nlh, NULL);
421}
422
423static void fib_add_ifaddr(struct in_ifaddr *ifa)
424{
425 struct in_device *in_dev = ifa->ifa_dev;
426 struct device *dev = in_dev->dev;
427 struct in_ifaddr *prim = ifa;
428 u32 mask = ifa->ifa_mask;
429 u32 addr = ifa->ifa_local;
430 u32 prefix = ifa->ifa_address&mask;
431
432 if (ifa->ifa_flags&IFA_F_SECONDARY) {
433 prim = inet_ifa_byprefix(in_dev, prefix, mask);
434 if (prim == NULL) {
435 printk(KERN_DEBUG "fib_add_ifaddr: bug: prim == NULL\n");
436 return;
437 }
438 }
439
440 fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim);
441
442 if (!(dev->flags&IFF_UP))
443 return;
444
445
446 if (ifa->ifa_broadcast && ifa->ifa_broadcast != 0xFFFFFFFF)
447 fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
448
449 if (!ZERONET(prefix) && !(ifa->ifa_flags&IFA_F_SECONDARY) &&
450 (prefix != addr || ifa->ifa_prefixlen < 32)) {
451 fib_magic(RTM_NEWROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL :
452 RTN_UNICAST, prefix, ifa->ifa_prefixlen, prim);
453
454
455 if (ifa->ifa_prefixlen < 31) {
456 fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix, 32, prim);
457 fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix|~mask, 32, prim);
458 }
459 }
460}
461
462static void fib_del_ifaddr(struct in_ifaddr *ifa)
463{
464 struct in_device *in_dev = ifa->ifa_dev;
465 struct device *dev = in_dev->dev;
466 struct in_ifaddr *ifa1;
467 struct in_ifaddr *prim = ifa;
468 u32 brd = ifa->ifa_address|~ifa->ifa_mask;
469 u32 any = ifa->ifa_address&ifa->ifa_mask;
470#define LOCAL_OK 1
471#define BRD_OK 2
472#define BRD0_OK 4
473#define BRD1_OK 8
474 unsigned ok = 0;
475
476 if (!(ifa->ifa_flags&IFA_F_SECONDARY))
477 fib_magic(RTM_DELROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL :
478 RTN_UNICAST, any, ifa->ifa_prefixlen, prim);
479 else {
480 prim = inet_ifa_byprefix(in_dev, any, ifa->ifa_mask);
481 if (prim == NULL) {
482 printk(KERN_DEBUG "fib_del_ifaddr: bug: prim == NULL\n");
483 return;
484 }
485 }
486
487
488
489
490
491
492
493 for (ifa1 = in_dev->ifa_list; ifa1; ifa1 = ifa1->ifa_next) {
494 if (ifa->ifa_local == ifa1->ifa_local)
495 ok |= LOCAL_OK;
496 if (ifa->ifa_broadcast == ifa1->ifa_broadcast)
497 ok |= BRD_OK;
498 if (brd == ifa1->ifa_broadcast)
499 ok |= BRD1_OK;
500 if (any == ifa1->ifa_broadcast)
501 ok |= BRD0_OK;
502 }
503
504 if (!(ok&BRD_OK))
505 fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
506 if (!(ok&BRD1_OK))
507 fib_magic(RTM_DELROUTE, RTN_BROADCAST, brd, 32, prim);
508 if (!(ok&BRD0_OK))
509 fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim);
510 if (!(ok&LOCAL_OK)) {
511 fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim);
512
513
514 if (inet_addr_type(ifa->ifa_local) != RTN_LOCAL) {
515
516
517
518
519
520
521 if (fib_sync_down(ifa->ifa_local, NULL, 0))
522 fib_flush();
523 }
524 }
525#undef LOCAL_OK
526#undef BRD_OK
527#undef BRD0_OK
528#undef BRD1_OK
529}
530
531static void fib_disable_ip(struct device *dev, int force)
532{
533 if (fib_sync_down(0, dev, force))
534 fib_flush();
535 rt_cache_flush(0);
536 arp_ifdown(dev);
537}
538
539static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr)
540{
541 struct in_ifaddr *ifa = (struct in_ifaddr*)ptr;
542
543 switch (event) {
544 case NETDEV_UP:
545 fib_add_ifaddr(ifa);
546 rt_cache_flush(-1);
547 break;
548 case NETDEV_DOWN:
549 if (ifa->ifa_dev && ifa->ifa_dev->ifa_list == NULL) {
550
551
552
553 fib_disable_ip(ifa->ifa_dev->dev, 1);
554 } else {
555 fib_del_ifaddr(ifa);
556 rt_cache_flush(-1);
557 }
558 break;
559 }
560 return NOTIFY_DONE;
561}
562
563static int fib_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
564{
565 struct device *dev = ptr;
566 struct in_device *in_dev = dev->ip_ptr;
567
568 if (!in_dev)
569 return NOTIFY_DONE;
570
571 switch (event) {
572 case NETDEV_UP:
573 for_ifa(in_dev) {
574 fib_add_ifaddr(ifa);
575 } endfor_ifa(in_dev);
576#ifdef CONFIG_IP_ROUTE_MULTIPATH
577 fib_sync_up(dev);
578#endif
579 rt_cache_flush(-1);
580 break;
581 case NETDEV_DOWN:
582 fib_disable_ip(dev, 0);
583 break;
584 case NETDEV_UNREGISTER:
585 fib_disable_ip(dev, 1);
586 break;
587 case NETDEV_CHANGEMTU:
588 case NETDEV_CHANGE:
589 rt_cache_flush(0);
590 break;
591 }
592 return NOTIFY_DONE;
593}
594
595struct notifier_block fib_inetaddr_notifier = {
596 fib_inetaddr_event,
597 NULL,
598 0
599};
600
601struct notifier_block fib_netdev_notifier = {
602 fib_netdev_event,
603 NULL,
604 0
605};
606
607__initfunc(void ip_fib_init(void))
608{
609#ifdef CONFIG_PROC_FS
610 proc_net_register(&(struct proc_dir_entry) {
611 PROC_NET_ROUTE, 5, "route",
612 S_IFREG | S_IRUGO, 1, 0, 0,
613 0, &proc_net_inode_operations,
614 fib_get_procinfo
615 });
616#endif
617
618#ifndef CONFIG_IP_MULTIPLE_TABLES
619 local_table = fib_hash_init(RT_TABLE_LOCAL);
620 main_table = fib_hash_init(RT_TABLE_MAIN);
621#else
622 fib_rules_init();
623#endif
624
625 register_netdevice_notifier(&fib_netdev_notifier);
626 register_inetaddr_notifier(&fib_inetaddr_notifier);
627}
628
629