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