1/* 2 * DECnet An implementation of the DECnet protocol suite for the LINUX 3 * operating system. DECnet is implemented using the BSD Socket 4 * interface as the means of communication with the user level. 5 * 6 * DECnet Routing Forwarding Information Base (Glue/Info List) 7 * 8 * Author: Steve Whitehouse <SteveW@ACM.org> 9 * 10 * 11 * Changes: 12 * Alexey Kuznetsov : SMP locking changes 13 * Steve Whitehouse : Rewrote it... Well to be more correct, I 14 * copied most of it from the ipv4 fib code. 15 * Steve Whitehouse : Updated it in style and fixed a few bugs 16 * which were fixed in the ipv4 code since 17 * this code was copied from it. 18 * 19 */ 20#include <linux/string.h> 21#include <linux/net.h> 22#include <linux/socket.h> 23#include <linux/slab.h> 24#include <linux/sockios.h> 25#include <linux/init.h> 26#include <linux/skbuff.h> 27#include <linux/netlink.h> 28#include <linux/rtnetlink.h> 29#include <linux/proc_fs.h> 30#include <linux/netdevice.h> 31#include <linux/timer.h> 32#include <linux/spinlock.h> 33#include <linux/atomic.h> 34#include <asm/uaccess.h> 35#include <net/neighbour.h> 36#include <net/dst.h> 37#include <net/flow.h> 38#include <net/fib_rules.h> 39#include <net/dn.h> 40#include <net/dn_route.h> 41#include <net/dn_fib.h> 42#include <net/dn_neigh.h> 43#include <net/dn_dev.h> 44 45#define RT_MIN_TABLE 1 46 47#define for_fib_info() { struct dn_fib_info *fi;\ 48 for(fi = dn_fib_info_list; fi; fi = fi->fib_next) 49#define endfor_fib_info() } 50 51#define for_nexthops(fi) { int nhsel; const struct dn_fib_nh *nh;\ 52 for(nhsel = 0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++) 53 54#define change_nexthops(fi) { int nhsel; struct dn_fib_nh *nh;\ 55 for(nhsel = 0, nh = (struct dn_fib_nh *)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nh++, nhsel++) 56 57#define endfor_nexthops(fi) } 58 59static DEFINE_SPINLOCK(dn_fib_multipath_lock); 60static struct dn_fib_info *dn_fib_info_list; 61static DEFINE_SPINLOCK(dn_fib_info_lock); 62 63static struct 64{ 65 int error; 66 u8 scope; 67} dn_fib_props[RTN_MAX+1] = { 68 [RTN_UNSPEC] = { .error = 0, .scope = RT_SCOPE_NOWHERE }, 69 [RTN_UNICAST] = { .error = 0, .scope = RT_SCOPE_UNIVERSE }, 70 [RTN_LOCAL] = { .error = 0, .scope = RT_SCOPE_HOST }, 71 [RTN_BROADCAST] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }, 72 [RTN_ANYCAST] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }, 73 [RTN_MULTICAST] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }, 74 [RTN_BLACKHOLE] = { .error = -EINVAL, .scope = RT_SCOPE_UNIVERSE }, 75 [RTN_UNREACHABLE] = { .error = -EHOSTUNREACH, .scope = RT_SCOPE_UNIVERSE }, 76 [RTN_PROHIBIT] = { .error = -EACCES, .scope = RT_SCOPE_UNIVERSE }, 77 [RTN_THROW] = { .error = -EAGAIN, .scope = RT_SCOPE_UNIVERSE }, 78 [RTN_NAT] = { .error = 0, .scope = RT_SCOPE_NOWHERE }, 79 [RTN_XRESOLVE] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }, 80}; 81 82static int dn_fib_sync_down(__le16 local, struct net_device *dev, int force); 83static int dn_fib_sync_up(struct net_device *dev); 84 85void dn_fib_free_info(struct dn_fib_info *fi) 86{ 87 if (fi->fib_dead == 0) { 88 printk(KERN_DEBUG "DECnet: BUG! Attempt to free alive dn_fib_info\n"); 89 return; 90 } 91 92 change_nexthops(fi) { 93 if (nh->nh_dev) 94 dev_put(nh->nh_dev); 95 nh->nh_dev = NULL; 96 } endfor_nexthops(fi); 97 kfree(fi); 98} 99 100void dn_fib_release_info(struct dn_fib_info *fi) 101{ 102 spin_lock(&dn_fib_info_lock); 103 if (fi && --fi->fib_treeref == 0) { 104 if (fi->fib_next) 105 fi->fib_next->fib_prev = fi->fib_prev; 106 if (fi->fib_prev) 107 fi->fib_prev->fib_next = fi->fib_next; 108 if (fi == dn_fib_info_list) 109 dn_fib_info_list = fi->fib_next; 110 fi->fib_dead = 1; 111 dn_fib_info_put(fi); 112 } 113 spin_unlock(&dn_fib_info_lock); 114} 115 116static inline int dn_fib_nh_comp(const struct dn_fib_info *fi, const struct dn_fib_info *ofi) 117{ 118 const struct dn_fib_nh *onh = ofi->fib_nh; 119 120 for_nexthops(fi) { 121 if (nh->nh_oif != onh->nh_oif || 122 nh->nh_gw != onh->nh_gw || 123 nh->nh_scope != onh->nh_scope || 124 nh->nh_weight != onh->nh_weight || 125 ((nh->nh_flags^onh->nh_flags)&~RTNH_F_DEAD)) 126 return -1; 127 onh++; 128 } endfor_nexthops(fi); 129 return 0; 130} 131 132static inline struct dn_fib_info *dn_fib_find_info(const struct dn_fib_info *nfi) 133{ 134 for_fib_info() { 135 if (fi->fib_nhs != nfi->fib_nhs) 136 continue; 137 if (nfi->fib_protocol == fi->fib_protocol && 138 nfi->fib_prefsrc == fi->fib_prefsrc && 139 nfi->fib_priority == fi->fib_priority && 140 memcmp(nfi->fib_metrics, fi->fib_metrics, sizeof(fi->fib_metrics)) == 0 && 141 ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 && 142 (nfi->fib_nhs == 0 || dn_fib_nh_comp(fi, nfi) == 0)) 143 return fi; 144 } endfor_fib_info(); 145 return NULL; 146} 147 148static int dn_fib_count_nhs(const struct nlattr *attr) 149{ 150 struct rtnexthop *nhp = nla_data(attr); 151 int nhs = 0, nhlen = nla_len(attr); 152 153 while(nhlen >= (int)sizeof(struct rtnexthop)) { 154 if ((nhlen -= nhp->rtnh_len) < 0) 155 return 0; 156 nhs++; 157 nhp = RTNH_NEXT(nhp); 158 } 159 160 return nhs; 161} 162 163static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct nlattr *attr, 164 const struct rtmsg *r) 165{ 166 struct rtnexthop *nhp = nla_data(attr); 167 int nhlen = nla_len(attr); 168 169 change_nexthops(fi) { 170 int attrlen = nhlen - sizeof(struct rtnexthop); 171 if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0) 172 return -EINVAL; 173 174 nh->nh_flags = (r->rtm_flags&~0xFF) | nhp->rtnh_flags; 175 nh->nh_oif = nhp->rtnh_ifindex; 176 nh->nh_weight = nhp->rtnh_hops + 1; 177 178 if (attrlen) { 179 struct nlattr *gw_attr; 180 181 gw_attr = nla_find((struct nlattr *) (nhp + 1), attrlen, RTA_GATEWAY); 182 nh->nh_gw = gw_attr ? nla_get_le16(gw_attr) : 0; 183 } 184 nhp = RTNH_NEXT(nhp); 185 } endfor_nexthops(fi); 186 187 return 0; 188} 189 190 191static int dn_fib_check_nh(const struct rtmsg *r, struct dn_fib_info *fi, struct dn_fib_nh *nh) 192{ 193 int err; 194 195 if (nh->nh_gw) { 196 struct flowidn fld; 197 struct dn_fib_res res; 198 199 if (nh->nh_flags&RTNH_F_ONLINK) { 200 struct net_device *dev; 201 202 if (r->rtm_scope >= RT_SCOPE_LINK) 203 return -EINVAL; 204 if (dnet_addr_type(nh->nh_gw) != RTN_UNICAST) 205 return -EINVAL; 206 if ((dev = __dev_get_by_index(&init_net, nh->nh_oif)) == NULL) 207 return -ENODEV; 208 if (!(dev->flags&IFF_UP)) 209 return -ENETDOWN; 210 nh->nh_dev = dev; 211 dev_hold(dev); 212 nh->nh_scope = RT_SCOPE_LINK; 213 return 0; 214 } 215 216 memset(&fld, 0, sizeof(fld)); 217 fld.daddr = nh->nh_gw; 218 fld.flowidn_oif = nh->nh_oif; 219 fld.flowidn_scope = r->rtm_scope + 1; 220 221 if (fld.flowidn_scope < RT_SCOPE_LINK) 222 fld.flowidn_scope = RT_SCOPE_LINK; 223 224 if ((err = dn_fib_lookup(&fld, &res)) != 0) 225 return err; 226 227 err = -EINVAL; 228 if (res.type != RTN_UNICAST && res.type != RTN_LOCAL) 229 goto out; 230 nh->nh_scope = res.scope; 231 nh->nh_oif = DN_FIB_RES_OIF(res); 232 nh->nh_dev = DN_FIB_RES_DEV(res); 233 if (nh->nh_dev == NULL) 234 goto out; 235 dev_hold(nh->nh_dev); 236 err = -ENETDOWN; 237 if (!(nh->nh_dev->flags & IFF_UP)) 238 goto out; 239 err = 0; 240out: 241 dn_fib_res_put(&res); 242 return err; 243 } else { 244 struct net_device *dev; 245 246 if (nh->nh_flags&(RTNH_F_PERVASIVE|RTNH_F_ONLINK)) 247 return -EINVAL; 248 249 dev = __dev_get_by_index(&init_net, nh->nh_oif); 250 if (dev == NULL || dev->dn_ptr == NULL) 251 return -ENODEV; 252 if (!(dev->flags&IFF_UP)) 253 return -ENETDOWN; 254 nh->nh_dev = dev; 255 dev_hold(nh->nh_dev); 256 nh->nh_scope = RT_SCOPE_HOST; 257 } 258 259 return 0; 260} 261 262 263struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct nlattr *attrs[], 264 const struct nlmsghdr *nlh, int *errp) 265{ 266 int err; 267 struct dn_fib_info *fi = NULL; 268 struct dn_fib_info *ofi; 269 int nhs = 1; 270 271 if (r->rtm_type > RTN_MAX) 272 goto err_inval; 273 274 if (dn_fib_props[r->rtm_type].scope > r->rtm_scope) 275 goto err_inval; 276 277 if (attrs[RTA_MULTIPATH] && 278 (nhs = dn_fib_count_nhs(attrs[RTA_MULTIPATH])) == 0) 279 goto err_inval; 280 281 fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct dn_fib_nh), GFP_KERNEL); 282 err = -ENOBUFS; 283 if (fi == NULL) 284 goto failure; 285 286 fi->fib_protocol = r->rtm_protocol; 287 fi->fib_nhs = nhs; 288 fi->fib_flags = r->rtm_flags; 289 290 if (attrs[RTA_PRIORITY]) 291 fi->fib_priority = nla_get_u32(attrs[RTA_PRIORITY]); 292 293 if (attrs[RTA_METRICS]) { 294 struct nlattr *attr; 295 int rem; 296 297 nla_for_each_nested(attr, attrs[RTA_METRICS], rem) { 298 int type = nla_type(attr); 299 300 if (type) { 301 if (type > RTAX_MAX || nla_len(attr) < 4) 302 goto err_inval; 303 304 fi->fib_metrics[type-1] = nla_get_u32(attr); 305 } 306 } 307 } 308 309 if (attrs[RTA_PREFSRC]) 310 fi->fib_prefsrc = nla_get_le16(attrs[RTA_PREFSRC]); 311 312 if (attrs[RTA_MULTIPATH]) { 313 if ((err = dn_fib_get_nhs(fi, attrs[RTA_MULTIPATH], r)) != 0) 314 goto failure; 315 316 if (attrs[RTA_OIF] && 317 fi->fib_nh->nh_oif != nla_get_u32(attrs[RTA_OIF])) 318 goto err_inval; 319 320 if (attrs[RTA_GATEWAY] && 321 fi->fib_nh->nh_gw != nla_get_le16(attrs[RTA_GATEWAY])) 322 goto err_inval; 323 } else { 324 struct dn_fib_nh *nh = fi->fib_nh; 325 326 if (attrs[RTA_OIF]) 327 nh->nh_oif = nla_get_u32(attrs[RTA_OIF]); 328 329 if (attrs[RTA_GATEWAY]) 330 nh->nh_gw = nla_get_le16(attrs[RTA_GATEWAY]); 331 332 nh->nh_flags = r->rtm_flags; 333 nh->nh_weight = 1; 334 } 335 336 if (r->rtm_type == RTN_NAT) { 337 if (!attrs[RTA_GATEWAY] || nhs != 1 || attrs[RTA_OIF]) 338 goto err_inval; 339 340 fi->fib_nh->nh_gw = nla_get_le16(attrs[RTA_GATEWAY]); 341 goto link_it; 342 } 343 344 if (dn_fib_props[r->rtm_type].error) { 345 if (attrs[RTA_GATEWAY] || attrs[RTA_OIF] || attrs[RTA_MULTIPATH]) 346 goto err_inval; 347 348 goto link_it; 349 } 350 351 if (r->rtm_scope > RT_SCOPE_HOST) 352 goto err_inval; 353 354 if (r->rtm_scope == RT_SCOPE_HOST) { 355 struct dn_fib_nh *nh = fi->fib_nh; 356 357 /* Local address is added */ 358 if (nhs != 1 || nh->nh_gw) 359 goto err_inval; 360 nh->nh_scope = RT_SCOPE_NOWHERE; 361 nh->nh_dev = dev_get_by_index(&init_net, fi->fib_nh->nh_oif); 362 err = -ENODEV; 363 if (nh->nh_dev == NULL) 364 goto failure; 365 } else { 366 change_nexthops(fi) { 367 if ((err = dn_fib_check_nh(r, fi, nh)) != 0) 368 goto failure; 369 } endfor_nexthops(fi) 370 } 371 372 if (fi->fib_prefsrc) { 373 if (r->rtm_type != RTN_LOCAL || !attrs[RTA_DST] || 374 fi->fib_prefsrc != nla_get_le16(attrs[RTA_DST])) 375 if (dnet_addr_type(fi->fib_prefsrc) != RTN_LOCAL) 376 goto err_inval; 377 } 378 379link_it: 380 if ((ofi = dn_fib_find_info(fi)) != NULL) { 381 fi->fib_dead = 1; 382 dn_fib_free_info(fi); 383 ofi->fib_treeref++; 384 return ofi; 385 } 386 387 fi->fib_treeref++; 388 atomic_inc(&fi->fib_clntref); 389 spin_lock(&dn_fib_info_lock); 390 fi->fib_next = dn_fib_info_list; 391 fi->fib_prev = NULL; 392 if (dn_fib_info_list) 393 dn_fib_info_list->fib_prev = fi; 394 dn_fib_info_list = fi; 395 spin_unlock(&dn_fib_info_lock); 396 return fi; 397 398err_inval: 399 err = -EINVAL; 400 401failure: 402 *errp = err; 403 if (fi) { 404 fi->fib_dead = 1; 405 dn_fib_free_info(fi); 406 } 407 408 return NULL; 409} 410 411int dn_fib_semantic_match(int type, struct dn_fib_info *fi, const struct flowidn *fld, struct dn_fib_res *res) 412{ 413 int err = dn_fib_props[type].error; 414 415 if (err == 0) { 416 if (fi->fib_flags & RTNH_F_DEAD) 417 return 1; 418 419 res->fi = fi; 420 421 switch (type) { 422 case RTN_NAT: 423 DN_FIB_RES_RESET(*res); 424 atomic_inc(&fi->fib_clntref); 425 return 0; 426 case RTN_UNICAST: 427 case RTN_LOCAL: 428 for_nexthops(fi) { 429 if (nh->nh_flags & RTNH_F_DEAD) 430 continue; 431 if (!fld->flowidn_oif || 432 fld->flowidn_oif == nh->nh_oif) 433 break; 434 } 435 if (nhsel < fi->fib_nhs) { 436 res->nh_sel = nhsel; 437 atomic_inc(&fi->fib_clntref); 438 return 0; 439 } 440 endfor_nexthops(fi); 441 res->fi = NULL; 442 return 1; 443 default: 444 net_err_ratelimited("DECnet: impossible routing event : dn_fib_semantic_match type=%d\n", 445 type); 446 res->fi = NULL; 447 return -EINVAL; 448 } 449 } 450 return err; 451} 452 453void dn_fib_select_multipath(const struct flowidn *fld, struct dn_fib_res *res) 454{ 455 struct dn_fib_info *fi = res->fi; 456 int w; 457 458 spin_lock_bh(&dn_fib_multipath_lock); 459 if (fi->fib_power <= 0) { 460 int power = 0; 461 change_nexthops(fi) { 462 if (!(nh->nh_flags&RTNH_F_DEAD)) { 463 power += nh->nh_weight; 464 nh->nh_power = nh->nh_weight; 465 } 466 } endfor_nexthops(fi); 467 fi->fib_power = power; 468 if (power < 0) { 469 spin_unlock_bh(&dn_fib_multipath_lock); 470 res->nh_sel = 0; 471 return; 472 } 473 } 474 475 w = jiffies % fi->fib_power; 476 477 change_nexthops(fi) { 478 if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) { 479 if ((w -= nh->nh_power) <= 0) { 480 nh->nh_power--; 481 fi->fib_power--; 482 res->nh_sel = nhsel; 483 spin_unlock_bh(&dn_fib_multipath_lock); 484 return; 485 } 486 } 487 } endfor_nexthops(fi); 488 res->nh_sel = 0; 489 spin_unlock_bh(&dn_fib_multipath_lock); 490} 491 492static inline u32 rtm_get_table(struct nlattr *attrs[], u8 table) 493{ 494 if (attrs[RTA_TABLE]) 495 table = nla_get_u32(attrs[RTA_TABLE]); 496 497 return table; 498} 499 500static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh) 501{ 502 struct net *net = sock_net(skb->sk); 503 struct dn_fib_table *tb; 504 struct rtmsg *r = nlmsg_data(nlh); 505 struct nlattr *attrs[RTA_MAX+1]; 506 int err; 507 508 if (!capable(CAP_NET_ADMIN)) 509 return -EPERM; 510 511 if (!net_eq(net, &init_net)) 512 return -EINVAL; 513 514 err = nlmsg_parse(nlh, sizeof(*r), attrs, RTA_MAX, rtm_dn_policy); 515 if (err < 0) 516 return err; 517 518 tb = dn_fib_get_table(rtm_get_table(attrs, r->rtm_table), 0); 519 if (!tb) 520 return -ESRCH; 521 522 return tb->delete(tb, r, attrs, nlh, &NETLINK_CB(skb)); 523} 524 525static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh) 526{ 527 struct net *net = sock_net(skb->sk); 528 struct dn_fib_table *tb; 529 struct rtmsg *r = nlmsg_data(nlh); 530 struct nlattr *attrs[RTA_MAX+1]; 531 int err; 532 533 if (!capable(CAP_NET_ADMIN)) 534 return -EPERM; 535 536 if (!net_eq(net, &init_net)) 537 return -EINVAL; 538 539 err = nlmsg_parse(nlh, sizeof(*r), attrs, RTA_MAX, rtm_dn_policy); 540 if (err < 0) 541 return err; 542 543 tb = dn_fib_get_table(rtm_get_table(attrs, r->rtm_table), 1); 544 if (!tb) 545 return -ENOBUFS; 546 547 return tb->insert(tb, r, attrs, nlh, &NETLINK_CB(skb)); 548} 549 550static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifaddr *ifa) 551{ 552 struct dn_fib_table *tb; 553 struct { 554 struct nlmsghdr nlh; 555 struct rtmsg rtm; 556 } req; 557 struct { 558 struct nlattr hdr; 559 __le16 dst; 560 } dst_attr = { 561 .dst = dst, 562 }; 563 struct { 564 struct nlattr hdr; 565 __le16 prefsrc; 566 } prefsrc_attr = { 567 .prefsrc = ifa->ifa_local, 568 }; 569 struct { 570 struct nlattr hdr; 571 u32 oif; 572 } oif_attr = { 573 .oif = ifa->ifa_dev->dev->ifindex, 574 }; 575 struct nlattr *attrs[RTA_MAX+1] = { 576 [RTA_DST] = (struct nlattr *) &dst_attr, 577 [RTA_PREFSRC] = (struct nlattr * ) &prefsrc_attr, 578 [RTA_OIF] = (struct nlattr *) &oif_attr, 579 }; 580 581 memset(&req.rtm, 0, sizeof(req.rtm)); 582 583 if (type == RTN_UNICAST) 584 tb = dn_fib_get_table(RT_MIN_TABLE, 1); 585 else 586 tb = dn_fib_get_table(RT_TABLE_LOCAL, 1); 587 588 if (tb == NULL) 589 return; 590 591 req.nlh.nlmsg_len = sizeof(req); 592 req.nlh.nlmsg_type = cmd; 593 req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_APPEND; 594 req.nlh.nlmsg_pid = 0; 595 req.nlh.nlmsg_seq = 0; 596 597 req.rtm.rtm_dst_len = dst_len; 598 req.rtm.rtm_table = tb->n; 599 req.rtm.rtm_protocol = RTPROT_KERNEL; 600 req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST); 601 req.rtm.rtm_type = type; 602 603 if (cmd == RTM_NEWROUTE) 604 tb->insert(tb, &req.rtm, attrs, &req.nlh, NULL); 605 else 606 tb->delete(tb, &req.rtm, attrs, &req.nlh, NULL); 607} 608 609static void dn_fib_add_ifaddr(struct dn_ifaddr *ifa) 610{ 611 612 fib_magic(RTM_NEWROUTE, RTN_LOCAL, ifa->ifa_local, 16, ifa); 613 614#if 0 615 if (!(dev->flags&IFF_UP)) 616 return; 617 /* In the future, we will want to add default routes here */ 618 619#endif 620} 621 622static void dn_fib_del_ifaddr(struct dn_ifaddr *ifa) 623{ 624 int found_it = 0; 625 struct net_device *dev; 626 struct dn_dev *dn_db; 627 struct dn_ifaddr *ifa2; 628 629 ASSERT_RTNL(); 630 631 /* Scan device list */ 632 rcu_read_lock(); 633 for_each_netdev_rcu(&init_net, dev) { 634 dn_db = rcu_dereference(dev->dn_ptr); 635 if (dn_db == NULL) 636 continue; 637 for (ifa2 = rcu_dereference(dn_db->ifa_list); 638 ifa2 != NULL; 639 ifa2 = rcu_dereference(ifa2->ifa_next)) { 640 if (ifa2->ifa_local == ifa->ifa_local) { 641 found_it = 1; 642 break; 643 } 644 } 645 } 646 rcu_read_unlock(); 647 648 if (found_it == 0) { 649 fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 16, ifa); 650 651 if (dnet_addr_type(ifa->ifa_local) != RTN_LOCAL) { 652 if (dn_fib_sync_down(ifa->ifa_local, NULL, 0)) 653 dn_fib_flush(); 654 } 655 } 656} 657 658static void dn_fib_disable_addr(struct net_device *dev, int force) 659{ 660 if (dn_fib_sync_down(0, dev, force)) 661 dn_fib_flush(); 662 dn_rt_cache_flush(0); 663 neigh_ifdown(&dn_neigh_table, dev); 664} 665 666static int dn_fib_dnaddr_event(struct notifier_block *this, unsigned long event, void *ptr) 667{ 668 struct dn_ifaddr *ifa = (struct dn_ifaddr *)ptr; 669 670 switch (event) { 671 case NETDEV_UP: 672 dn_fib_add_ifaddr(ifa); 673 dn_fib_sync_up(ifa->ifa_dev->dev); 674 dn_rt_cache_flush(-1); 675 break; 676 case NETDEV_DOWN: 677 dn_fib_del_ifaddr(ifa); 678 if (ifa->ifa_dev && ifa->ifa_dev->ifa_list == NULL) { 679 dn_fib_disable_addr(ifa->ifa_dev->dev, 1); 680 } else { 681 dn_rt_cache_flush(-1); 682 } 683 break; 684 } 685 return NOTIFY_DONE; 686} 687 688static int dn_fib_sync_down(__le16 local, struct net_device *dev, int force) 689{ 690 int ret = 0; 691 int scope = RT_SCOPE_NOWHERE; 692 693 if (force) 694 scope = -1; 695 696 for_fib_info() { 697 /* 698 * This makes no sense for DECnet.... we will almost 699 * certainly have more than one local address the same 700 * over all our interfaces. It needs thinking about 701 * some more. 702 */ 703 if (local && fi->fib_prefsrc == local) { 704 fi->fib_flags |= RTNH_F_DEAD; 705 ret++; 706 } else if (dev && fi->fib_nhs) { 707 int dead = 0; 708 709 change_nexthops(fi) { 710 if (nh->nh_flags&RTNH_F_DEAD) 711 dead++; 712 else if (nh->nh_dev == dev && 713 nh->nh_scope != scope) { 714 spin_lock_bh(&dn_fib_multipath_lock); 715 nh->nh_flags |= RTNH_F_DEAD; 716 fi->fib_power -= nh->nh_power; 717 nh->nh_power = 0; 718 spin_unlock_bh(&dn_fib_multipath_lock); 719 dead++; 720 } 721 } endfor_nexthops(fi) 722 if (dead == fi->fib_nhs) { 723 fi->fib_flags |= RTNH_F_DEAD; 724 ret++; 725 } 726 } 727 } endfor_fib_info(); 728 return ret; 729} 730 731 732static int dn_fib_sync_up(struct net_device *dev) 733{ 734 int ret = 0; 735 736 if (!(dev->flags&IFF_UP)) 737 return 0; 738 739 for_fib_info() { 740 int alive = 0; 741 742 change_nexthops(fi) { 743 if (!(nh->nh_flags&RTNH_F_DEAD)) { 744 alive++; 745 continue; 746 } 747 if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP)) 748 continue; 749 if (nh->nh_dev != dev || dev->dn_ptr == NULL) 750 continue; 751 alive++; 752 spin_lock_bh(&dn_fib_multipath_lock); 753 nh->nh_power = 0; 754 nh->nh_flags &= ~RTNH_F_DEAD; 755 spin_unlock_bh(&dn_fib_multipath_lock); 756 } endfor_nexthops(fi); 757 758 if (alive > 0) { 759 fi->fib_flags &= ~RTNH_F_DEAD; 760 ret++; 761 } 762 } endfor_fib_info(); 763 return ret; 764} 765 766static struct notifier_block dn_fib_dnaddr_notifier = { 767 .notifier_call = dn_fib_dnaddr_event, 768}; 769 770void __exit dn_fib_cleanup(void) 771{ 772 dn_fib_table_cleanup(); 773 dn_fib_rules_cleanup(); 774 775 unregister_dnaddr_notifier(&dn_fib_dnaddr_notifier); 776} 777 778 779void __init dn_fib_init(void) 780{ 781 dn_fib_table_init(); 782 dn_fib_rules_init(); 783 784 register_dnaddr_notifier(&dn_fib_dnaddr_notifier); 785 786 rtnl_register(PF_DECnet, RTM_NEWROUTE, dn_fib_rtm_newroute, NULL, NULL); 787 rtnl_register(PF_DECnet, RTM_DELROUTE, dn_fib_rtm_delroute, NULL, NULL); 788} 789 790 791