00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
#include <linux/config.h>
00019
#include <asm/uaccess.h>
00020
#include <asm/system.h>
00021
#include <asm/bitops.h>
00022
#include <linux/types.h>
00023
#include <linux/kernel.h>
00024
#include <linux/sched.h>
00025
#include <linux/mm.h>
00026
#include <linux/string.h>
00027
#include <linux/socket.h>
00028
#include <linux/sockios.h>
00029
#include <linux/errno.h>
00030
#include <linux/in.h>
00031
#include <linux/inet.h>
00032
#include <linux/netdevice.h>
00033
#include <linux/if_arp.h>
00034
#include <linux/proc_fs.h>
00035
#include <linux/skbuff.h>
00036
#include <linux/netlink.h>
00037
#include <linux/init.h>
00038
00039
#include <net/ip.h>
00040
#include <net/protocol.h>
00041
#include <net/route.h>
00042
#include <net/tcp.h>
00043
#include <net/sock.h>
00044
#include <net/icmp.h>
00045
#include <net/arp.h>
00046
#include <net/ip_fib.h>
00047
00048 #define FFprint(a...) printk(KERN_DEBUG a)
00049
00050
#ifndef CONFIG_IP_MULTIPLE_TABLES
00051
00052 #define RT_TABLE_MIN RT_TABLE_MAIN
00053
00054 struct fib_table *
local_table;
00055 struct fib_table *
main_table;
00056
00057
#else
00058
00059
#define RT_TABLE_MIN 1
00060
00061
struct fib_table *fib_tables[RT_TABLE_MAX+1];
00062
00063
struct fib_table *__fib_new_table(
int id)
00064 {
00065
struct fib_table *tb;
00066
00067 tb =
fib_hash_init(
id);
00068
if (!tb)
00069
return NULL;
00070 fib_tables[
id] = tb;
00071
return tb;
00072 }
00073
00074
00075
#endif
00076
00077
00078 void fib_flush(
void)
00079 {
00080
int flushed = 0;
00081
#ifdef CONFIG_IP_MULTIPLE_TABLES
00082
struct fib_table *tb;
00083
int id;
00084
00085
for (
id = RT_TABLE_MAX;
id>0;
id--) {
00086
if ((tb =
fib_get_table(
id))==NULL)
00087
continue;
00088 flushed += tb->tb_flush(tb);
00089 }
00090
#else
00091 flushed +=
main_table->
tb_flush(
main_table);
00092 flushed +=
local_table->
tb_flush(
local_table);
00093
#endif
00094
00095
if (flushed)
00096
rt_cache_flush(-1);
00097 }
00098
00099
00100
#ifdef CONFIG_PROC_FS
00101
00102
00103
00104
00105
00106
00107
00108
00109
static int
00110 fib_get_procinfo(
char *buffer,
char **start, off_t offset,
int length)
00111 {
00112
int first = offset/128;
00113
char *ptr = buffer;
00114
int count = (length+127)/128;
00115
int len;
00116
00117 *start = buffer + offset%128;
00118
00119
if (--first < 0) {
00120 sprintf(buffer,
"%-127s\n",
"Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU\tWindow\tIRTT");
00121 --count;
00122 ptr += 128;
00123 first = 0;
00124 }
00125
00126
if (
main_table && count > 0) {
00127
int n =
main_table->
tb_get_info(main_table, ptr, first, count);
00128 count -= n;
00129 ptr += n*128;
00130 }
00131 len = ptr - *start;
00132
if (len >= length)
00133
return length;
00134
if (len >= 0)
00135
return len;
00136
return 0;
00137 }
00138
00139
#endif
00140
00141
00142
00143
00144
00145 struct net_device *
ip_dev_find(u32 addr)
00146 {
00147
struct rt_key key;
00148
struct fib_result res;
00149
struct net_device *dev = NULL;
00150
00151 memset(&key, 0,
sizeof(key));
00152 key.dst = addr;
00153
#ifdef CONFIG_IP_MULTIPLE_TABLES
00154
res.r = NULL;
00155
#endif
00156
00157
if (!
local_table ||
local_table->
tb_lookup(
local_table, &key, &res)) {
00158
return NULL;
00159 }
00160
if (res.
type != RTN_LOCAL)
00161
goto out;
00162 dev =
FIB_RES_DEV(res);
00163
00164
if (dev)
00165
dev_hold(dev);
00166 out:
00167
fib_res_put(&res);
00168
return dev;
00169 }
00170
00171 unsigned inet_addr_type(u32 addr)
00172 {
00173
struct rt_key key;
00174
struct fib_result res;
00175
unsigned ret = RTN_BROADCAST;
00176
00177
if (
ZERONET(addr) ||
BADCLASS(addr))
00178
return RTN_BROADCAST;
00179
if (
MULTICAST(addr))
00180
return RTN_MULTICAST;
00181
00182 memset(&key, 0,
sizeof(key));
00183 key.dst = addr;
00184
#ifdef CONFIG_IP_MULTIPLE_TABLES
00185
res.r = NULL;
00186
#endif
00187
00188
if (
local_table) {
00189 ret = RTN_UNICAST;
00190
if (
local_table->
tb_lookup(
local_table, &key, &res) == 0) {
00191 ret = res.
type;
00192
fib_res_put(&res);
00193 }
00194 }
00195
return ret;
00196 }
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206 int fib_validate_source(u32 src, u32 dst, u8 tos,
int oif,
00207
struct net_device *dev, u32 *spec_dst, u32 *itag)
00208 {
00209
struct in_device *in_dev;
00210
struct rt_key key;
00211
struct fib_result res;
00212
int no_addr, rpf, loop;
00213
int ret;
00214
00215 key.
dst = src;
00216 key.
src = dst;
00217 key.
tos = tos;
00218 key.
oif = 0;
00219 key.
iif = oif;
00220 key.
scope = RT_SCOPE_UNIVERSE;
00221
00222 no_addr = rpf = loop = 0;
00223 read_lock(&
inetdev_lock);
00224 in_dev =
__in_dev_get(dev);
00225
if (in_dev) {
00226 no_addr = in_dev->ifa_list == NULL;
00227 rpf =
IN_DEV_RPFILTER(in_dev);
00228 loop =
IN_DEV_LOOP(in_dev);
00229 }
00230 read_unlock(&
inetdev_lock);
00231
00232
if (in_dev == NULL)
00233
goto e_inval;
00234
00235
if (
fib_lookup(&key, &res))
00236
goto last_resort;
00237
if (loop && res.
type == RTN_LOCAL) {
00238 *spec_dst =
FIB_RES_PREFSRC(res);
00239
fib_res_put(&res);
00240
return 0;
00241 }
00242
if (res.
type != RTN_UNICAST)
00243
goto e_inval_res;
00244 *spec_dst =
FIB_RES_PREFSRC(res);
00245
fib_combine_itag(itag, &res);
00246
#ifdef CONFIG_IP_ROUTE_MULTIPATH
00247
if (
FIB_RES_DEV(res) == dev || res.
fi->
fib_nhs > 1)
00248
#else
00249
if (
FIB_RES_DEV(res) == dev)
00250
#endif
00251
{
00252 ret =
FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
00253
fib_res_put(&res);
00254
return ret;
00255 }
00256
fib_res_put(&res);
00257
if (no_addr)
00258
goto last_resort;
00259
if (rpf)
00260
goto e_inval;
00261 key.
oif = dev->
ifindex;
00262
00263 ret = 0;
00264
if (
fib_lookup(&key, &res) == 0) {
00265
if (res.
type == RTN_UNICAST) {
00266 *spec_dst =
FIB_RES_PREFSRC(res);
00267 ret =
FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
00268 }
00269
fib_res_put(&res);
00270 }
00271
return ret;
00272
00273 last_resort:
00274
if (rpf)
00275
goto e_inval;
00276 *spec_dst =
inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
00277 *itag = 0;
00278
return 0;
00279
00280 e_inval_res:
00281
fib_res_put(&res);
00282 e_inval:
00283
return -EINVAL;
00284 }
00285
00286
#ifndef CONFIG_IP_NOSIOCRT
00287
00288
00289
00290
00291
00292 int ip_rt_ioctl(
unsigned int cmd,
void *arg)
00293 {
00294
int err;
00295
struct kern_rta rta;
00296
struct rtentry r;
00297
struct {
00298
struct nlmsghdr nlh;
00299
struct rtmsg rtm;
00300 } req;
00301
00302
switch (cmd) {
00303
case SIOCADDRT:
00304
case SIOCDELRT:
00305
if (!capable(CAP_NET_ADMIN))
00306
return -EPERM;
00307
if (copy_from_user(&r, arg,
sizeof(
struct rtentry)))
00308
return -EFAULT;
00309
rtnl_lock();
00310 err =
fib_convert_rtentry(cmd, &req.nlh, &req.rtm, &rta, &r);
00311
if (err == 0) {
00312
if (cmd == SIOCDELRT) {
00313
struct fib_table *tb =
fib_get_table(req.rtm.rtm_table);
00314 err = -ESRCH;
00315
if (tb)
00316 err = tb->tb_delete(tb, &req.rtm, &rta, &req.nlh, NULL);
00317 }
else {
00318
struct fib_table *tb =
fib_new_table(req.rtm.rtm_table);
00319 err = -ENOBUFS;
00320
if (tb)
00321 err = tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL);
00322 }
00323
if (rta.
rta_mx)
00324 kfree(rta.
rta_mx);
00325 }
00326
rtnl_unlock();
00327
return err;
00328 }
00329
return -EINVAL;
00330 }
00331
00332
#else
00333
00334
int ip_rt_ioctl(
unsigned int cmd,
void *arg)
00335 {
00336
return -EINVAL;
00337 }
00338
00339
#endif
00340
00341 static int inet_check_attr(
struct rtmsg *r,
struct rtattr **rta)
00342 {
00343
int i;
00344
00345
for (i=1; i<=RTA_MAX; i++) {
00346
struct rtattr *attr = rta[i-1];
00347
if (attr) {
00348
if (RTA_PAYLOAD(attr) < 4)
00349
return -EINVAL;
00350
if (i != RTA_MULTIPATH && i != RTA_METRICS)
00351 rta[i-1] = (
struct rtattr*)RTA_DATA(attr);
00352 }
00353 }
00354
return 0;
00355 }
00356
00357 int inet_rtm_delroute(
struct sk_buff *skb,
struct nlmsghdr* nlh,
void *arg)
00358 {
00359
struct fib_table * tb;
00360
struct rtattr **rta = arg;
00361
struct rtmsg *r =
NLMSG_DATA(nlh);
00362
00363
if (
inet_check_attr(r, rta))
00364
return -EINVAL;
00365
00366 tb =
fib_get_table(r->rtm_table);
00367
if (tb)
00368
return tb->tb_delete(tb, r, (
struct kern_rta*)rta, nlh, &
NETLINK_CB(skb));
00369
return -ESRCH;
00370 }
00371
00372 int inet_rtm_newroute(
struct sk_buff *skb,
struct nlmsghdr* nlh,
void *arg)
00373 {
00374
struct fib_table * tb;
00375
struct rtattr **rta = arg;
00376
struct rtmsg *r =
NLMSG_DATA(nlh);
00377
00378
if (
inet_check_attr(r, rta))
00379
return -EINVAL;
00380
00381 tb =
fib_new_table(r->rtm_table);
00382
if (tb)
00383
return tb->tb_insert(tb, r, (
struct kern_rta*)rta, nlh, &
NETLINK_CB(skb));
00384
return -ENOBUFS;
00385 }
00386
00387 int inet_dump_fib(
struct sk_buff *skb,
struct netlink_callback *cb)
00388 {
00389
int t;
00390
int s_t;
00391
struct fib_table *tb;
00392
00393
if (
NLMSG_PAYLOAD(cb->
nlh, 0) >=
sizeof(
struct rtmsg) &&
00394 ((
struct rtmsg*)
NLMSG_DATA(cb->
nlh))->rtm_flags&RTM_F_CLONED)
00395
return ip_rt_dump(skb, cb);
00396
00397 s_t = cb->
args[0];
00398
if (s_t == 0)
00399 s_t = cb->
args[0] =
RT_TABLE_MIN;
00400
00401
for (t=s_t; t<=RT_TABLE_MAX; t++) {
00402
if (t < s_t)
continue;
00403
if (t > s_t)
00404 memset(&cb->
args[1], 0,
sizeof(cb->
args)-
sizeof(cb->
args[0]));
00405
if ((tb =
fib_get_table(t))==NULL)
00406
continue;
00407
if (tb->tb_dump(tb, skb, cb) < 0)
00408
break;
00409 }
00410
00411 cb->
args[0] = t;
00412
00413
return skb->
len;
00414 }
00415
00416
00417
00418
00419
00420
00421
00422
00423 static void fib_magic(
int cmd,
int type, u32 dst,
int dst_len,
struct in_ifaddr *ifa)
00424 {
00425
struct fib_table * tb;
00426
struct {
00427
struct nlmsghdr nlh;
00428
struct rtmsg rtm;
00429 } req;
00430
struct kern_rta rta;
00431
00432 memset(&req.rtm, 0,
sizeof(req.rtm));
00433 memset(&rta, 0,
sizeof(rta));
00434
00435
if (type == RTN_UNICAST)
00436 tb =
fib_new_table(RT_TABLE_MAIN);
00437
else
00438 tb =
fib_new_table(RT_TABLE_LOCAL);
00439
00440
if (tb == NULL)
00441
return;
00442
00443 req.nlh.nlmsg_len =
sizeof(req);
00444 req.nlh.nlmsg_type = cmd;
00445 req.nlh.nlmsg_flags =
NLM_F_REQUEST|
NLM_F_CREATE|
NLM_F_APPEND;
00446 req.nlh.nlmsg_pid = 0;
00447 req.nlh.nlmsg_seq = 0;
00448
00449 req.rtm.rtm_dst_len = dst_len;
00450 req.rtm.rtm_table = tb->tb_id;
00451 req.rtm.rtm_protocol = RTPROT_KERNEL;
00452 req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST);
00453 req.rtm.rtm_type = type;
00454
00455 rta.rta_dst = &dst;
00456 rta.rta_prefsrc = &ifa->
ifa_local;
00457 rta.rta_oif = &ifa->
ifa_dev->
dev->
ifindex;
00458
00459
if (cmd == RTM_NEWROUTE)
00460 tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL);
00461
else
00462 tb->tb_delete(tb, &req.rtm, &rta, &req.nlh, NULL);
00463 }
00464
00465 static void fib_add_ifaddr(
struct in_ifaddr *ifa)
00466 {
00467
struct in_device *in_dev = ifa->
ifa_dev;
00468
struct net_device *dev = in_dev->
dev;
00469
struct in_ifaddr *prim = ifa;
00470 u32 mask = ifa->
ifa_mask;
00471 u32 addr = ifa->ifa_local;
00472 u32 prefix = ifa->ifa_address&mask;
00473
00474
if (ifa->ifa_flags&IFA_F_SECONDARY) {
00475 prim =
inet_ifa_byprefix(in_dev, prefix, mask);
00476
if (prim == NULL) {
00477 printk(KERN_DEBUG
"fib_add_ifaddr: bug: prim == NULL\n");
00478
return;
00479 }
00480 }
00481
00482
fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim);
00483
00484
if (!(dev->flags&IFF_UP))
00485
return;
00486
00487
00488
if (ifa->ifa_broadcast && ifa->ifa_broadcast != 0xFFFFFFFF)
00489
fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
00490
00491
if (!
ZERONET(prefix) && !(ifa->ifa_flags&IFA_F_SECONDARY) &&
00492 (prefix != addr || ifa->ifa_prefixlen < 32)) {
00493
fib_magic(RTM_NEWROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL :
00494 RTN_UNICAST, prefix, ifa->ifa_prefixlen, prim);
00495
00496
00497
if (ifa->ifa_prefixlen < 31) {
00498
fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix, 32, prim);
00499
fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix|~mask, 32, prim);
00500 }
00501 }
00502 }
00503
00504 static void fib_del_ifaddr(
struct in_ifaddr *ifa)
00505 {
00506
struct in_device *in_dev = ifa->
ifa_dev;
00507
struct net_device *dev = in_dev->
dev;
00508
struct in_ifaddr *ifa1;
00509
struct in_ifaddr *prim = ifa;
00510 u32 brd = ifa->
ifa_address|~ifa->ifa_mask;
00511 u32 any = ifa->ifa_address&ifa->ifa_mask;
00512
#define LOCAL_OK 1
00513
#define BRD_OK 2
00514
#define BRD0_OK 4
00515
#define BRD1_OK 8
00516
unsigned ok = 0;
00517
00518
if (!(ifa->ifa_flags&IFA_F_SECONDARY))
00519
fib_magic(RTM_DELROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL :
00520 RTN_UNICAST, any, ifa->ifa_prefixlen, prim);
00521
else {
00522 prim =
inet_ifa_byprefix(in_dev, any, ifa->ifa_mask);
00523
if (prim == NULL) {
00524 printk(KERN_DEBUG
"fib_del_ifaddr: bug: prim == NULL\n");
00525
return;
00526 }
00527 }
00528
00529
00530
00531
00532
00533
00534
00535
for (ifa1 = in_dev->ifa_list; ifa1; ifa1 = ifa1->ifa_next) {
00536
if (ifa->ifa_local == ifa1->ifa_local)
00537 ok |=
LOCAL_OK;
00538
if (ifa->ifa_broadcast == ifa1->ifa_broadcast)
00539 ok |=
BRD_OK;
00540
if (brd == ifa1->ifa_broadcast)
00541 ok |=
BRD1_OK;
00542
if (any == ifa1->ifa_broadcast)
00543 ok |=
BRD0_OK;
00544 }
00545
00546
if (!(ok&
BRD_OK))
00547
fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
00548
if (!(ok&
BRD1_OK))
00549
fib_magic(RTM_DELROUTE, RTN_BROADCAST, brd, 32, prim);
00550
if (!(ok&
BRD0_OK))
00551
fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim);
00552
if (!(ok&
LOCAL_OK)) {
00553
fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim);
00554
00555
00556
if (
inet_addr_type(ifa->ifa_local) != RTN_LOCAL) {
00557
00558
00559
00560
00561
00562
00563
if (
fib_sync_down(ifa->ifa_local, NULL, 0))
00564
fib_flush();
00565 }
00566 }
00567
#undef LOCAL_OK
00568
#undef BRD_OK
00569
#undef BRD0_OK
00570
#undef BRD1_OK
00571
}
00572
00573 static void fib_disable_ip(
struct net_device *dev,
int force)
00574 {
00575
if (
fib_sync_down(0, dev, force))
00576
fib_flush();
00577
rt_cache_flush(0);
00578
arp_ifdown(dev);
00579 }
00580
00581 static int fib_inetaddr_event(
struct notifier_block *
this,
unsigned long event,
void *ptr)
00582 {
00583
struct in_ifaddr *ifa = (
struct in_ifaddr*)ptr;
00584
00585
switch (event) {
00586
case NETDEV_UP:
00587
fib_add_ifaddr(ifa);
00588
#ifdef CONFIG_IP_ROUTE_MULTIPATH
00589
fib_sync_up(ifa->ifa_dev->dev);
00590
#endif
00591
rt_cache_flush(-1);
00592
break;
00593
case NETDEV_DOWN:
00594
fib_del_ifaddr(ifa);
00595
if (ifa->ifa_dev && ifa->ifa_dev->ifa_list == NULL) {
00596
00597
00598
00599
fib_disable_ip(ifa->ifa_dev->dev, 1);
00600 }
else {
00601
rt_cache_flush(-1);
00602 }
00603
break;
00604 }
00605
return NOTIFY_DONE;
00606 }
00607
00608 static int fib_netdev_event(
struct notifier_block *
this,
unsigned long event,
void *ptr)
00609 {
00610
struct net_device *dev = ptr;
00611
struct in_device *in_dev =
__in_dev_get(dev);
00612
00613
if (event == NETDEV_UNREGISTER) {
00614
fib_disable_ip(dev, 2);
00615
return NOTIFY_DONE;
00616 }
00617
00618
if (!in_dev)
00619
return NOTIFY_DONE;
00620
00621
switch (event) {
00622
case NETDEV_UP:
00623
for_ifa(in_dev) {
00624
fib_add_ifaddr(ifa);
00625 }
endfor_ifa(in_dev);
00626
#ifdef CONFIG_IP_ROUTE_MULTIPATH
00627
fib_sync_up(dev);
00628
#endif
00629
rt_cache_flush(-1);
00630
break;
00631
case NETDEV_DOWN:
00632
fib_disable_ip(dev, 0);
00633
break;
00634
case NETDEV_CHANGEMTU:
00635
case NETDEV_CHANGE:
00636
rt_cache_flush(0);
00637
break;
00638 }
00639
return NOTIFY_DONE;
00640 }
00641
00642 struct notifier_block
fib_inetaddr_notifier = {
00643 notifier_call:
fib_inetaddr_event,
00644 };
00645
00646 struct notifier_block
fib_netdev_notifier = {
00647 notifier_call:
fib_netdev_event,
00648 };
00649
00650 void __init
ip_fib_init(
void)
00651 {
00652
#ifdef CONFIG_PROC_FS
00653
proc_net_create(
"route",0,fib_get_procinfo);
00654
#endif
00655
00656
#ifndef CONFIG_IP_MULTIPLE_TABLES
00657
local_table =
fib_hash_init(RT_TABLE_LOCAL);
00658
main_table =
fib_hash_init(RT_TABLE_MAIN);
00659
#else
00660
fib_rules_init();
00661
#endif
00662
00663
register_netdevice_notifier(&
fib_netdev_notifier);
00664
register_inetaddr_notifier(&
fib_inetaddr_notifier);
00665 }
00666