Main Page | Class List | File List | Class Members | File Members

fib_frontend.c

Go to the documentation of this file.
00001 /* 00002 * INET An implementation of the TCP/IP protocol suite for the LINUX 00003 * operating system. INET is implemented using the BSD Socket 00004 * interface as the means of communication with the user level. 00005 * 00006 * IPv4 Forwarding Information Base: FIB frontend. 00007 * 00008 * Version: $Id: fib_frontend.c,v 1.26 2001/10/31 21:55:54 davem Exp $ 00009 * 00010 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 00011 * 00012 * This program is free software; you can redistribute it and/or 00013 * modify it under the terms of the GNU General Public License 00014 * as published by the Free Software Foundation; either version 00015 * 2 of the License, or (at your option) any later version. 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 /* CONFIG_IP_MULTIPLE_TABLES */ 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 /* CONFIG_IP_MULTIPLE_TABLES */ 00091 flushed += main_table->tb_flush(main_table); 00092 flushed += local_table->tb_flush(local_table); 00093 #endif /* CONFIG_IP_MULTIPLE_TABLES */ 00094 00095 if (flushed) 00096 rt_cache_flush(-1); 00097 } 00098 00099 00100 #ifdef CONFIG_PROC_FS 00101 00102 /* 00103 * Called from the PROCfs module. This outputs /proc/net/route. 00104 * 00105 * It always works in backward compatibility mode. 00106 * The format of the file is not supposed to be changed. 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 /* CONFIG_PROC_FS */ 00140 00141 /* 00142 * Find the first device with a given source address. 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 /* Given (packet source, input interface) and optional (dst, oif, tos): 00199 - (main) check, that source is valid i.e. not broadcast or our local 00200 address. 00201 - figure out what "logical" interface this packet arrived 00202 and calculate "specific destination" address. 00203 - check, that packet arrived from expected physical interface. 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 * Handle IP routing ioctl calls. These are used to manipulate the routing tables 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: /* Add a route */ 00304 case SIOCDELRT: /* Delete a route */ 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 /* Prepare and feed intra-kernel routing request. 00417 Really, it should be netlink message, but :-( netlink 00418 can be not configured, so that we feed it directly 00419 to fib engine. It is legal, because all events occur 00420 only when netlink is already locked. 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 /* Add broadcast address, if it is explicitly assigned. */ 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 /* Add network specific broadcasts, when it takes a sense */ 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 /* Deletion is more complicated than add. 00530 We should take care of not to delete too much :-) 00531 00532 Scan address list to be sure that addresses are really gone. 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 /* Check, that this local address finally disappeared. */ 00556 if (inet_addr_type(ifa->ifa_local) != RTN_LOCAL) { 00557 /* And the last, but not the least thing. 00558 We must flush stray FIB entries. 00559 00560 First of all, we scan fib_info list searching 00561 for stray nexthop entries, then ignite fib_flush. 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 /* Last address was deleted from this interface. 00597 Disable IP. 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 /* CONFIG_PROC_FS */ 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

Generated on Wed Dec 1 21:25:30 2004 for Linux 2.4.23 Networking by doxygen 1.3.8