include upstream ip1000a driver version 2.09f
[linux-2.4.git] / net / ipv4 / fib_frontend.c
1 /*
2  * INET         An implementation of the TCP/IP protocol suite for the LINUX
3  *              operating system.  INET is implemented using the  BSD Socket
4  *              interface as the means of communication with the user level.
5  *
6  *              IPv4 Forwarding Information Base: FIB frontend.
7  *
8  * Version:     $Id: fib_frontend.c,v 1.26 2001/10/31 21:55:54 davem Exp $
9  *
10  * Authors:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
11  *
12  *              This program is free software; you can redistribute it and/or
13  *              modify it under the terms of the GNU General Public License
14  *              as published by the Free Software Foundation; either version
15  *              2 of the License, or (at your option) any later version.
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
54 struct fib_table *local_table;
55 struct fib_table *main_table;
56
57 #else
58
59 #define RT_TABLE_MIN 1
60
61 struct fib_table *fib_tables[RT_TABLE_MAX+1];
62
63 struct 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 /* CONFIG_IP_MULTIPLE_TABLES */
76
77
78 void 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 /* CONFIG_IP_MULTIPLE_TABLES */
91         flushed += main_table->tb_flush(main_table);
92         flushed += local_table->tb_flush(local_table);
93 #endif /* CONFIG_IP_MULTIPLE_TABLES */
94
95         if (flushed)
96                 rt_cache_flush(-1);
97 }
98
99
100 #ifdef CONFIG_PROC_FS
101
102 /* 
103  *      Called from the PROCfs module. This outputs /proc/net/route.
104  *
105  *      It always works in backward compatibility mode.
106  *      The format of the file is not supposed to be changed.
107  */
108  
109 static int
110 fib_get_procinfo(char *buffer, char **start, off_t offset, int length)
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         if (main_table && count > 0) {
127                 int n = main_table->tb_get_info(main_table, ptr, first, count);
128                 count -= n;
129                 ptr += n*128;
130         }
131         len = ptr - *start;
132         if (len >= length)
133                 return length;
134         if (len >= 0)
135                 return len;
136         return 0;
137 }
138
139 #endif /* CONFIG_PROC_FS */
140
141 /*
142  *      Find the first device with a given source address.
143  */
144
145 struct net_device * ip_dev_find(u32 addr)
146 {
147         struct rt_key key;
148         struct fib_result res;
149         struct net_device *dev = NULL;
150
151         memset(&key, 0, sizeof(key));
152         key.dst = addr;
153 #ifdef CONFIG_IP_MULTIPLE_TABLES
154         res.r = NULL;
155 #endif
156
157         if (!local_table || local_table->tb_lookup(local_table, &key, &res)) {
158                 return NULL;
159         }
160         if (res.type != RTN_LOCAL)
161                 goto out;
162         dev = FIB_RES_DEV(res);
163
164         if (dev)
165                 dev_hold(dev);
166 out:
167         fib_res_put(&res);
168         return dev;
169 }
170
171 unsigned inet_addr_type(u32 addr)
172 {
173         struct rt_key           key;
174         struct fib_result       res;
175         unsigned ret = RTN_BROADCAST;
176
177         if (ZERONET(addr) || BADCLASS(addr))
178                 return RTN_BROADCAST;
179         if (MULTICAST(addr))
180                 return RTN_MULTICAST;
181
182         memset(&key, 0, sizeof(key));
183         key.dst = addr;
184 #ifdef CONFIG_IP_MULTIPLE_TABLES
185         res.r = NULL;
186 #endif
187         
188         if (local_table) {
189                 ret = RTN_UNICAST;
190                 if (local_table->tb_lookup(local_table, &key, &res) == 0) {
191                         ret = res.type;
192                         fib_res_put(&res);
193                 }
194         }
195         return ret;
196 }
197
198 /* Given (packet source, input interface) and optional (dst, oif, tos):
199    - (main) check, that source is valid i.e. not broadcast or our local
200      address.
201    - figure out what "logical" interface this packet arrived
202      and calculate "specific destination" address.
203    - check, that packet arrived from expected physical interface.
204  */
205
206 int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
207                         struct net_device *dev, u32 *spec_dst, u32 *itag)
208 {
209         struct in_device *in_dev;
210         struct rt_key key;
211         struct fib_result res;
212         int no_addr, rpf;
213         int ret;
214
215         key.dst = src;
216         key.src = dst;
217         key.tos = tos;
218         key.oif = 0;
219         key.iif = oif;
220         key.scope = RT_SCOPE_UNIVERSE;
221
222         no_addr = rpf = 0;
223         read_lock(&inetdev_lock);
224         in_dev = __in_dev_get(dev);
225         if (in_dev) {
226                 no_addr = in_dev->ifa_list == NULL;
227                 rpf = IN_DEV_RPFILTER(in_dev);
228         }
229         read_unlock(&inetdev_lock);
230
231         if (in_dev == NULL)
232                 goto e_inval;
233
234         if (fib_lookup(&key, &res))
235                 goto last_resort;
236         if (res.type != RTN_UNICAST)
237                 goto e_inval_res;
238         *spec_dst = FIB_RES_PREFSRC(res);
239         fib_combine_itag(itag, &res);
240 #ifdef CONFIG_IP_ROUTE_MULTIPATH
241         if (FIB_RES_DEV(res) == dev || res.fi->fib_nhs > 1)
242 #else
243         if (FIB_RES_DEV(res) == dev)
244 #endif
245         {
246                 ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
247                 fib_res_put(&res);
248                 return ret;
249         }
250         fib_res_put(&res);
251         if (no_addr)
252                 goto last_resort;
253         if (rpf)
254                 goto e_inval;
255         key.oif = dev->ifindex;
256
257         ret = 0;
258         if (fib_lookup(&key, &res) == 0) {
259                 if (res.type == RTN_UNICAST) {
260                         *spec_dst = FIB_RES_PREFSRC(res);
261                         ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
262                 }
263                 fib_res_put(&res);
264         }
265         return ret;
266
267 last_resort:
268         if (rpf)
269                 goto e_inval;
270         *spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
271         *itag = 0;
272         return 0;
273
274 e_inval_res:
275         fib_res_put(&res);
276 e_inval:
277         return -EINVAL;
278 }
279
280 #ifndef CONFIG_IP_NOSIOCRT
281
282 /*
283  *      Handle IP routing ioctl calls. These are used to manipulate the routing tables
284  */
285  
286 int ip_rt_ioctl(unsigned int cmd, void *arg)
287 {
288         int err;
289         struct kern_rta rta;
290         struct rtentry  r;
291         struct {
292                 struct nlmsghdr nlh;
293                 struct rtmsg    rtm;
294         } req;
295
296         switch (cmd) {
297         case SIOCADDRT:         /* Add a route */
298         case SIOCDELRT:         /* Delete a route */
299                 if (!capable(CAP_NET_ADMIN))
300                         return -EPERM;
301                 if (copy_from_user(&r, arg, sizeof(struct rtentry)))
302                         return -EFAULT;
303                 rtnl_lock();
304                 err = fib_convert_rtentry(cmd, &req.nlh, &req.rtm, &rta, &r);
305                 if (err == 0) {
306                         if (cmd == SIOCDELRT) {
307                                 struct fib_table *tb = fib_get_table(req.rtm.rtm_table);
308                                 err = -ESRCH;
309                                 if (tb)
310                                         err = tb->tb_delete(tb, &req.rtm, &rta, &req.nlh, NULL);
311                         } else {
312                                 struct fib_table *tb = fib_new_table(req.rtm.rtm_table);
313                                 err = -ENOBUFS;
314                                 if (tb)
315                                         err = tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL);
316                         }
317                         if (rta.rta_mx)
318                                 kfree(rta.rta_mx);
319                 }
320                 rtnl_unlock();
321                 return err;
322         }
323         return -EINVAL;
324 }
325
326 #else
327
328 int ip_rt_ioctl(unsigned int cmd, void *arg)
329 {
330         return -EINVAL;
331 }
332
333 #endif
334
335 static int inet_check_attr(struct rtmsg *r, struct rtattr **rta)
336 {
337         int i;
338
339         for (i=1; i<=RTA_MAX; i++) {
340                 struct rtattr *attr = rta[i-1];
341                 if (attr) {
342                         if (RTA_PAYLOAD(attr) < 4)
343                                 return -EINVAL;
344                         if (i != RTA_MULTIPATH && i != RTA_METRICS)
345                                 rta[i-1] = (struct rtattr*)RTA_DATA(attr);
346                 }
347         }
348         return 0;
349 }
350
351 int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
352 {
353         struct fib_table * tb;
354         struct rtattr **rta = arg;
355         struct rtmsg *r = NLMSG_DATA(nlh);
356
357         if (inet_check_attr(r, rta))
358                 return -EINVAL;
359
360         tb = fib_get_table(r->rtm_table);
361         if (tb)
362                 return tb->tb_delete(tb, r, (struct kern_rta*)rta, nlh, &NETLINK_CB(skb));
363         return -ESRCH;
364 }
365
366 int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
367 {
368         struct fib_table * tb;
369         struct rtattr **rta = arg;
370         struct rtmsg *r = NLMSG_DATA(nlh);
371
372         if (inet_check_attr(r, rta))
373                 return -EINVAL;
374
375         tb = fib_new_table(r->rtm_table);
376         if (tb)
377                 return tb->tb_insert(tb, r, (struct kern_rta*)rta, nlh, &NETLINK_CB(skb));
378         return -ENOBUFS;
379 }
380
381 int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
382 {
383         int t;
384         int s_t;
385         struct fib_table *tb;
386
387         if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) &&
388             ((struct rtmsg*)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)
389                 return ip_rt_dump(skb, cb);
390
391         s_t = cb->args[0];
392         if (s_t == 0)
393                 s_t = cb->args[0] = RT_TABLE_MIN;
394
395         for (t=s_t; t<=RT_TABLE_MAX; t++) {
396                 if (t < s_t) continue;
397                 if (t > s_t)
398                         memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0]));
399                 if ((tb = fib_get_table(t))==NULL)
400                         continue;
401                 if (tb->tb_dump(tb, skb, cb) < 0) 
402                         break;
403         }
404
405         cb->args[0] = t;
406
407         return skb->len;
408 }
409
410 /* Prepare and feed intra-kernel routing request.
411    Really, it should be netlink message, but :-( netlink
412    can be not configured, so that we feed it directly
413    to fib engine. It is legal, because all events occur
414    only when netlink is already locked.
415  */
416
417 static void fib_magic(int cmd, int type, u32 dst, int dst_len, struct in_ifaddr *ifa)
418 {
419         struct fib_table * tb;
420         struct {
421                 struct nlmsghdr nlh;
422                 struct rtmsg    rtm;
423         } req;
424         struct kern_rta rta;
425
426         memset(&req.rtm, 0, sizeof(req.rtm));
427         memset(&rta, 0, sizeof(rta));
428
429         if (type == RTN_UNICAST)
430                 tb = fib_new_table(RT_TABLE_MAIN);
431         else
432                 tb = fib_new_table(RT_TABLE_LOCAL);
433
434         if (tb == NULL)
435                 return;
436
437         req.nlh.nlmsg_len = sizeof(req);
438         req.nlh.nlmsg_type = cmd;
439         req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_APPEND;
440         req.nlh.nlmsg_pid = 0;
441         req.nlh.nlmsg_seq = 0;
442
443         req.rtm.rtm_dst_len = dst_len;
444         req.rtm.rtm_table = tb->tb_id;
445         req.rtm.rtm_protocol = RTPROT_KERNEL;
446         req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST);
447         req.rtm.rtm_type = type;
448
449         rta.rta_dst = &dst;
450         rta.rta_prefsrc = &ifa->ifa_local;
451         rta.rta_oif = &ifa->ifa_dev->dev->ifindex;
452
453         if (cmd == RTM_NEWROUTE)
454                 tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL);
455         else
456                 tb->tb_delete(tb, &req.rtm, &rta, &req.nlh, NULL);
457 }
458
459 static void fib_add_ifaddr(struct in_ifaddr *ifa)
460 {
461         struct in_device *in_dev = ifa->ifa_dev;
462         struct net_device *dev = in_dev->dev;
463         struct in_ifaddr *prim = ifa;
464         u32 mask = ifa->ifa_mask;
465         u32 addr = ifa->ifa_local;
466         u32 prefix = ifa->ifa_address&mask;
467
468         if (ifa->ifa_flags&IFA_F_SECONDARY) {
469                 prim = inet_ifa_byprefix(in_dev, prefix, mask);
470                 if (prim == NULL) {
471                         printk(KERN_DEBUG "fib_add_ifaddr: bug: prim == NULL\n");
472                         return;
473                 }
474         }
475
476         fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim);
477
478         if (!(dev->flags&IFF_UP))
479                 return;
480
481         /* Add broadcast address, if it is explicitly assigned. */
482         if (ifa->ifa_broadcast && ifa->ifa_broadcast != 0xFFFFFFFF)
483                 fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
484
485         if (!ZERONET(prefix) && !(ifa->ifa_flags&IFA_F_SECONDARY) &&
486             (prefix != addr || ifa->ifa_prefixlen < 32)) {
487                 fib_magic(RTM_NEWROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL :
488                           RTN_UNICAST, prefix, ifa->ifa_prefixlen, prim);
489
490                 /* Add network specific broadcasts, when it takes a sense */
491                 if (ifa->ifa_prefixlen < 31) {
492                         fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix, 32, prim);
493                         fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix|~mask, 32, prim);
494                 }
495         }
496 }
497
498 static void fib_del_ifaddr(struct in_ifaddr *ifa)
499 {
500         struct in_device *in_dev = ifa->ifa_dev;
501         struct net_device *dev = in_dev->dev;
502         struct in_ifaddr *ifa1;
503         struct in_ifaddr *prim = ifa;
504         u32 brd = ifa->ifa_address|~ifa->ifa_mask;
505         u32 any = ifa->ifa_address&ifa->ifa_mask;
506 #define LOCAL_OK        1
507 #define BRD_OK          2
508 #define BRD0_OK         4
509 #define BRD1_OK         8
510         unsigned ok = 0;
511
512         if (!(ifa->ifa_flags&IFA_F_SECONDARY))
513                 fib_magic(RTM_DELROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL :
514                           RTN_UNICAST, any, ifa->ifa_prefixlen, prim);
515         else {
516                 prim = inet_ifa_byprefix(in_dev, any, ifa->ifa_mask);
517                 if (prim == NULL) {
518                         printk(KERN_DEBUG "fib_del_ifaddr: bug: prim == NULL\n");
519                         return;
520                 }
521         }
522
523         /* Deletion is more complicated than add.
524            We should take care of not to delete too much :-)
525
526            Scan address list to be sure that addresses are really gone.
527          */
528
529         for (ifa1 = in_dev->ifa_list; ifa1; ifa1 = ifa1->ifa_next) {
530                 if (ifa->ifa_local == ifa1->ifa_local)
531                         ok |= LOCAL_OK;
532                 if (ifa->ifa_broadcast == ifa1->ifa_broadcast)
533                         ok |= BRD_OK;
534                 if (brd == ifa1->ifa_broadcast)
535                         ok |= BRD1_OK;
536                 if (any == ifa1->ifa_broadcast)
537                         ok |= BRD0_OK;
538         }
539
540         if (!(ok&BRD_OK))
541                 fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
542         if (!(ok&BRD1_OK))
543                 fib_magic(RTM_DELROUTE, RTN_BROADCAST, brd, 32, prim);
544         if (!(ok&BRD0_OK))
545                 fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim);
546         if (!(ok&LOCAL_OK)) {
547                 fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim);
548
549                 /* Check, that this local address finally disappeared. */
550                 if (inet_addr_type(ifa->ifa_local) != RTN_LOCAL) {
551                         /* And the last, but not the least thing.
552                            We must flush stray FIB entries.
553
554                            First of all, we scan fib_info list searching
555                            for stray nexthop entries, then ignite fib_flush.
556                         */
557                         if (fib_sync_down(ifa->ifa_local, NULL, 0))
558                                 fib_flush();
559                 }
560         }
561 #undef LOCAL_OK
562 #undef BRD_OK
563 #undef BRD0_OK
564 #undef BRD1_OK
565 }
566
567 static void fib_disable_ip(struct net_device *dev, int force)
568 {
569         if (fib_sync_down(0, dev, force))
570                 fib_flush();
571         rt_cache_flush(0);
572         arp_ifdown(dev);
573 }
574
575 static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr)
576 {
577         struct in_ifaddr *ifa = (struct in_ifaddr*)ptr;
578
579         switch (event) {
580         case NETDEV_UP:
581                 fib_add_ifaddr(ifa);
582 #ifdef CONFIG_IP_ROUTE_MULTIPATH
583                 fib_sync_up(ifa->ifa_dev->dev);
584 #endif
585                 rt_cache_flush(-1);
586                 break;
587         case NETDEV_DOWN:
588                 fib_del_ifaddr(ifa);
589                 if (ifa->ifa_dev && ifa->ifa_dev->ifa_list == NULL) {
590                         /* Last address was deleted from this interface.
591                            Disable IP.
592                          */
593                         fib_disable_ip(ifa->ifa_dev->dev, 1);
594                 } else {
595                         rt_cache_flush(-1);
596                 }
597                 break;
598         }
599         return NOTIFY_DONE;
600 }
601
602 static int fib_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
603 {
604         struct net_device *dev = ptr;
605         struct in_device *in_dev = __in_dev_get(dev);
606
607         if (event == NETDEV_UNREGISTER) {
608                 fib_disable_ip(dev, 2);
609                 return NOTIFY_DONE;
610         }
611
612         if (!in_dev)
613                 return NOTIFY_DONE;
614
615         switch (event) {
616         case NETDEV_UP:
617                 for_ifa(in_dev) {
618                         fib_add_ifaddr(ifa);
619                 } endfor_ifa(in_dev);
620 #ifdef CONFIG_IP_ROUTE_MULTIPATH
621                 fib_sync_up(dev);
622 #endif
623                 rt_cache_flush(-1);
624                 break;
625         case NETDEV_DOWN:
626                 fib_disable_ip(dev, 0);
627                 break;
628         case NETDEV_CHANGEMTU:
629         case NETDEV_CHANGE:
630                 rt_cache_flush(0);
631                 break;
632         }
633         return NOTIFY_DONE;
634 }
635
636 struct notifier_block fib_inetaddr_notifier = {
637         notifier_call:  fib_inetaddr_event,
638 };
639
640 struct notifier_block fib_netdev_notifier = {
641         notifier_call:  fib_netdev_event,
642 };
643
644 void __init ip_fib_init(void)
645 {
646 #ifdef CONFIG_PROC_FS
647         proc_net_create("route",0,fib_get_procinfo);
648 #endif          /* CONFIG_PROC_FS */
649
650 #ifndef CONFIG_IP_MULTIPLE_TABLES
651         local_table = fib_hash_init(RT_TABLE_LOCAL);
652         main_table = fib_hash_init(RT_TABLE_MAIN);
653 #else
654         fib_rules_init();
655 #endif
656
657         register_netdevice_notifier(&fib_netdev_notifier);
658         register_inetaddr_notifier(&fib_inetaddr_notifier);
659 }
660