Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dn_fib.c
Go to the documentation of this file.
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 <[email protected]>
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 
59 static DEFINE_SPINLOCK(dn_fib_multipath_lock);
60 static struct dn_fib_info *dn_fib_info_list;
61 static DEFINE_SPINLOCK(dn_fib_info_lock);
62 
63 static struct
64 {
65  int error;
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 
82 static int dn_fib_sync_down(__le16 local, struct net_device *dev, int force);
83 static int dn_fib_sync_up(struct net_device *dev);
84 
85 void 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 
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 
116 static 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 
132 static 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 
148 __le16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type)
149 {
150  while(RTA_OK(attr,attrlen)) {
151  if (attr->rta_type == type)
152  return *(__le16*)RTA_DATA(attr);
153  attr = RTA_NEXT(attr, attrlen);
154  }
155 
156  return 0;
157 }
158 
159 static int dn_fib_count_nhs(struct rtattr *rta)
160 {
161  int nhs = 0;
162  struct rtnexthop *nhp = RTA_DATA(rta);
163  int nhlen = RTA_PAYLOAD(rta);
164 
165  while(nhlen >= (int)sizeof(struct rtnexthop)) {
166  if ((nhlen -= nhp->rtnh_len) < 0)
167  return 0;
168  nhs++;
169  nhp = RTNH_NEXT(nhp);
170  }
171 
172  return nhs;
173 }
174 
175 static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct rtattr *rta, const struct rtmsg *r)
176 {
177  struct rtnexthop *nhp = RTA_DATA(rta);
178  int nhlen = RTA_PAYLOAD(rta);
179 
180  change_nexthops(fi) {
181  int attrlen = nhlen - sizeof(struct rtnexthop);
182  if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0)
183  return -EINVAL;
184 
185  nh->nh_flags = (r->rtm_flags&~0xFF) | nhp->rtnh_flags;
186  nh->nh_oif = nhp->rtnh_ifindex;
187  nh->nh_weight = nhp->rtnh_hops + 1;
188 
189  if (attrlen) {
190  nh->nh_gw = dn_fib_get_attr16(RTNH_DATA(nhp), attrlen, RTA_GATEWAY);
191  }
192  nhp = RTNH_NEXT(nhp);
193  } endfor_nexthops(fi);
194 
195  return 0;
196 }
197 
198 
199 static int dn_fib_check_nh(const struct rtmsg *r, struct dn_fib_info *fi, struct dn_fib_nh *nh)
200 {
201  int err;
202 
203  if (nh->nh_gw) {
204  struct flowidn fld;
205  struct dn_fib_res res;
206 
207  if (nh->nh_flags&RTNH_F_ONLINK) {
208  struct net_device *dev;
209 
210  if (r->rtm_scope >= RT_SCOPE_LINK)
211  return -EINVAL;
212  if (dnet_addr_type(nh->nh_gw) != RTN_UNICAST)
213  return -EINVAL;
214  if ((dev = __dev_get_by_index(&init_net, nh->nh_oif)) == NULL)
215  return -ENODEV;
216  if (!(dev->flags&IFF_UP))
217  return -ENETDOWN;
218  nh->nh_dev = dev;
219  dev_hold(dev);
220  nh->nh_scope = RT_SCOPE_LINK;
221  return 0;
222  }
223 
224  memset(&fld, 0, sizeof(fld));
225  fld.daddr = nh->nh_gw;
226  fld.flowidn_oif = nh->nh_oif;
227  fld.flowidn_scope = r->rtm_scope + 1;
228 
229  if (fld.flowidn_scope < RT_SCOPE_LINK)
230  fld.flowidn_scope = RT_SCOPE_LINK;
231 
232  if ((err = dn_fib_lookup(&fld, &res)) != 0)
233  return err;
234 
235  err = -EINVAL;
236  if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
237  goto out;
238  nh->nh_scope = res.scope;
239  nh->nh_oif = DN_FIB_RES_OIF(res);
240  nh->nh_dev = DN_FIB_RES_DEV(res);
241  if (nh->nh_dev == NULL)
242  goto out;
243  dev_hold(nh->nh_dev);
244  err = -ENETDOWN;
245  if (!(nh->nh_dev->flags & IFF_UP))
246  goto out;
247  err = 0;
248 out:
250  return err;
251  } else {
252  struct net_device *dev;
253 
255  return -EINVAL;
256 
257  dev = __dev_get_by_index(&init_net, nh->nh_oif);
258  if (dev == NULL || dev->dn_ptr == NULL)
259  return -ENODEV;
260  if (!(dev->flags&IFF_UP))
261  return -ENETDOWN;
262  nh->nh_dev = dev;
263  dev_hold(nh->nh_dev);
264  nh->nh_scope = RT_SCOPE_HOST;
265  }
266 
267  return 0;
268 }
269 
270 
271 struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta *rta, const struct nlmsghdr *nlh, int *errp)
272 {
273  int err;
274  struct dn_fib_info *fi = NULL;
275  struct dn_fib_info *ofi;
276  int nhs = 1;
277 
278  if (r->rtm_type > RTN_MAX)
279  goto err_inval;
280 
281  if (dn_fib_props[r->rtm_type].scope > r->rtm_scope)
282  goto err_inval;
283 
284  if (rta->rta_mp) {
285  nhs = dn_fib_count_nhs(rta->rta_mp);
286  if (nhs == 0)
287  goto err_inval;
288  }
289 
290  fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct dn_fib_nh), GFP_KERNEL);
291  err = -ENOBUFS;
292  if (fi == NULL)
293  goto failure;
294 
295  fi->fib_protocol = r->rtm_protocol;
296  fi->fib_nhs = nhs;
297  fi->fib_flags = r->rtm_flags;
298  if (rta->rta_priority)
299  fi->fib_priority = *rta->rta_priority;
300  if (rta->rta_mx) {
301  int attrlen = RTA_PAYLOAD(rta->rta_mx);
302  struct rtattr *attr = RTA_DATA(rta->rta_mx);
303 
304  while(RTA_OK(attr, attrlen)) {
305  unsigned int flavour = attr->rta_type;
306 
307  if (flavour) {
308  if (flavour > RTAX_MAX)
309  goto err_inval;
310  fi->fib_metrics[flavour-1] = *(unsigned int *)RTA_DATA(attr);
311  }
312  attr = RTA_NEXT(attr, attrlen);
313  }
314  }
315  if (rta->rta_prefsrc)
316  memcpy(&fi->fib_prefsrc, rta->rta_prefsrc, 2);
317 
318  if (rta->rta_mp) {
319  if ((err = dn_fib_get_nhs(fi, rta->rta_mp, r)) != 0)
320  goto failure;
321  if (rta->rta_oif && fi->fib_nh->nh_oif != *rta->rta_oif)
322  goto err_inval;
323  if (rta->rta_gw && memcmp(&fi->fib_nh->nh_gw, rta->rta_gw, 2))
324  goto err_inval;
325  } else {
326  struct dn_fib_nh *nh = fi->fib_nh;
327  if (rta->rta_oif)
328  nh->nh_oif = *rta->rta_oif;
329  if (rta->rta_gw)
330  memcpy(&nh->nh_gw, rta->rta_gw, 2);
331  nh->nh_flags = r->rtm_flags;
332  nh->nh_weight = 1;
333  }
334 
335  if (r->rtm_type == RTN_NAT) {
336  if (rta->rta_gw == NULL || nhs != 1 || rta->rta_oif)
337  goto err_inval;
338  memcpy(&fi->fib_nh->nh_gw, rta->rta_gw, 2);
339  goto link_it;
340  }
341 
342  if (dn_fib_props[r->rtm_type].error) {
343  if (rta->rta_gw || rta->rta_oif || rta->rta_mp)
344  goto err_inval;
345  goto link_it;
346  }
347 
348  if (r->rtm_scope > RT_SCOPE_HOST)
349  goto err_inval;
350 
351  if (r->rtm_scope == RT_SCOPE_HOST) {
352  struct dn_fib_nh *nh = fi->fib_nh;
353 
354  /* Local address is added */
355  if (nhs != 1 || nh->nh_gw)
356  goto err_inval;
358  nh->nh_dev = dev_get_by_index(&init_net, fi->fib_nh->nh_oif);
359  err = -ENODEV;
360  if (nh->nh_dev == NULL)
361  goto failure;
362  } else {
363  change_nexthops(fi) {
364  if ((err = dn_fib_check_nh(r, fi, nh)) != 0)
365  goto failure;
366  } endfor_nexthops(fi)
367  }
368 
369  if (fi->fib_prefsrc) {
370  if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL ||
371  memcmp(&fi->fib_prefsrc, rta->rta_dst, 2))
373  goto err_inval;
374  }
375 
376 link_it:
377  if ((ofi = dn_fib_find_info(fi)) != NULL) {
378  fi->fib_dead = 1;
379  dn_fib_free_info(fi);
380  ofi->fib_treeref++;
381  return ofi;
382  }
383 
384  fi->fib_treeref++;
385  atomic_inc(&fi->fib_clntref);
386  spin_lock(&dn_fib_info_lock);
387  fi->fib_next = dn_fib_info_list;
388  fi->fib_prev = NULL;
389  if (dn_fib_info_list)
390  dn_fib_info_list->fib_prev = fi;
391  dn_fib_info_list = fi;
392  spin_unlock(&dn_fib_info_lock);
393  return fi;
394 
395 err_inval:
396  err = -EINVAL;
397 
398 failure:
399  *errp = err;
400  if (fi) {
401  fi->fib_dead = 1;
402  dn_fib_free_info(fi);
403  }
404 
405  return NULL;
406 }
407 
408 int dn_fib_semantic_match(int type, struct dn_fib_info *fi, const struct flowidn *fld, struct dn_fib_res *res)
409 {
410  int err = dn_fib_props[type].error;
411 
412  if (err == 0) {
413  if (fi->fib_flags & RTNH_F_DEAD)
414  return 1;
415 
416  res->fi = fi;
417 
418  switch (type) {
419  case RTN_NAT:
420  DN_FIB_RES_RESET(*res);
421  atomic_inc(&fi->fib_clntref);
422  return 0;
423  case RTN_UNICAST:
424  case RTN_LOCAL:
425  for_nexthops(fi) {
426  if (nh->nh_flags & RTNH_F_DEAD)
427  continue;
428  if (!fld->flowidn_oif ||
429  fld->flowidn_oif == nh->nh_oif)
430  break;
431  }
432  if (nhsel < fi->fib_nhs) {
433  res->nh_sel = nhsel;
434  atomic_inc(&fi->fib_clntref);
435  return 0;
436  }
437  endfor_nexthops(fi);
438  res->fi = NULL;
439  return 1;
440  default:
441  net_err_ratelimited("DECnet: impossible routing event : dn_fib_semantic_match type=%d\n",
442  type);
443  res->fi = NULL;
444  return -EINVAL;
445  }
446  }
447  return err;
448 }
449 
450 void dn_fib_select_multipath(const struct flowidn *fld, struct dn_fib_res *res)
451 {
452  struct dn_fib_info *fi = res->fi;
453  int w;
454 
455  spin_lock_bh(&dn_fib_multipath_lock);
456  if (fi->fib_power <= 0) {
457  int power = 0;
458  change_nexthops(fi) {
459  if (!(nh->nh_flags&RTNH_F_DEAD)) {
460  power += nh->nh_weight;
461  nh->nh_power = nh->nh_weight;
462  }
463  } endfor_nexthops(fi);
464  fi->fib_power = power;
465  if (power < 0) {
466  spin_unlock_bh(&dn_fib_multipath_lock);
467  res->nh_sel = 0;
468  return;
469  }
470  }
471 
472  w = jiffies % fi->fib_power;
473 
474  change_nexthops(fi) {
475  if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) {
476  if ((w -= nh->nh_power) <= 0) {
477  nh->nh_power--;
478  fi->fib_power--;
479  res->nh_sel = nhsel;
480  spin_unlock_bh(&dn_fib_multipath_lock);
481  return;
482  }
483  }
484  } endfor_nexthops(fi);
485  res->nh_sel = 0;
486  spin_unlock_bh(&dn_fib_multipath_lock);
487 }
488 
489 
490 static int dn_fib_check_attr(struct rtmsg *r, struct rtattr **rta)
491 {
492  int i;
493 
494  for(i = 1; i <= RTA_MAX; i++) {
495  struct rtattr *attr = rta[i-1];
496  if (attr) {
497  if (RTA_PAYLOAD(attr) < 4 && RTA_PAYLOAD(attr) != 2)
498  return -EINVAL;
499  if (i != RTA_MULTIPATH && i != RTA_METRICS &&
500  i != RTA_TABLE)
501  rta[i-1] = (struct rtattr *)RTA_DATA(attr);
502  }
503  }
504 
505  return 0;
506 }
507 
508 static inline u32 rtm_get_table(struct rtattr **rta, u8 table)
509 {
510  if (rta[RTA_TABLE - 1])
511  table = nla_get_u32((struct nlattr *) rta[RTA_TABLE - 1]);
512 
513  return table;
514 }
515 
516 static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
517 {
518  struct net *net = sock_net(skb->sk);
519  struct dn_fib_table *tb;
520  struct rtattr **rta = arg;
521  struct rtmsg *r = NLMSG_DATA(nlh);
522 
523  if (!net_eq(net, &init_net))
524  return -EINVAL;
525 
526  if (dn_fib_check_attr(r, rta))
527  return -EINVAL;
528 
529  tb = dn_fib_get_table(rtm_get_table(rta, r->rtm_table), 0);
530  if (tb)
531  return tb->delete(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb));
532 
533  return -ESRCH;
534 }
535 
536 static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
537 {
538  struct net *net = sock_net(skb->sk);
539  struct dn_fib_table *tb;
540  struct rtattr **rta = arg;
541  struct rtmsg *r = NLMSG_DATA(nlh);
542 
543  if (!net_eq(net, &init_net))
544  return -EINVAL;
545 
546  if (dn_fib_check_attr(r, rta))
547  return -EINVAL;
548 
549  tb = dn_fib_get_table(rtm_get_table(rta, r->rtm_table), 1);
550  if (tb)
551  return tb->insert(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb));
552 
553  return -ENOBUFS;
554 }
555 
556 static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifaddr *ifa)
557 {
558  struct dn_fib_table *tb;
559  struct {
560  struct nlmsghdr nlh;
561  struct rtmsg rtm;
562  } req;
563  struct dn_kern_rta rta;
564 
565  memset(&req.rtm, 0, sizeof(req.rtm));
566  memset(&rta, 0, sizeof(rta));
567 
568  if (type == RTN_UNICAST)
570  else
572 
573  if (tb == NULL)
574  return;
575 
576  req.nlh.nlmsg_len = sizeof(req);
577  req.nlh.nlmsg_type = cmd;
578  req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_APPEND;
579  req.nlh.nlmsg_pid = 0;
580  req.nlh.nlmsg_seq = 0;
581 
582  req.rtm.rtm_dst_len = dst_len;
583  req.rtm.rtm_table = tb->n;
584  req.rtm.rtm_protocol = RTPROT_KERNEL;
585  req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST);
586  req.rtm.rtm_type = type;
587 
588  rta.rta_dst = &dst;
589  rta.rta_prefsrc = &ifa->ifa_local;
590  rta.rta_oif = &ifa->ifa_dev->dev->ifindex;
591 
592  if (cmd == RTM_NEWROUTE)
593  tb->insert(tb, &req.rtm, &rta, &req.nlh, NULL);
594  else
595  tb->delete(tb, &req.rtm, &rta, &req.nlh, NULL);
596 }
597 
598 static void dn_fib_add_ifaddr(struct dn_ifaddr *ifa)
599 {
600 
601  fib_magic(RTM_NEWROUTE, RTN_LOCAL, ifa->ifa_local, 16, ifa);
602 
603 #if 0
604  if (!(dev->flags&IFF_UP))
605  return;
606  /* In the future, we will want to add default routes here */
607 
608 #endif
609 }
610 
611 static void dn_fib_del_ifaddr(struct dn_ifaddr *ifa)
612 {
613  int found_it = 0;
614  struct net_device *dev;
615  struct dn_dev *dn_db;
616  struct dn_ifaddr *ifa2;
617 
618  ASSERT_RTNL();
619 
620  /* Scan device list */
621  rcu_read_lock();
623  dn_db = rcu_dereference(dev->dn_ptr);
624  if (dn_db == NULL)
625  continue;
626  for (ifa2 = rcu_dereference(dn_db->ifa_list);
627  ifa2 != NULL;
628  ifa2 = rcu_dereference(ifa2->ifa_next)) {
629  if (ifa2->ifa_local == ifa->ifa_local) {
630  found_it = 1;
631  break;
632  }
633  }
634  }
635  rcu_read_unlock();
636 
637  if (found_it == 0) {
638  fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 16, ifa);
639 
640  if (dnet_addr_type(ifa->ifa_local) != RTN_LOCAL) {
641  if (dn_fib_sync_down(ifa->ifa_local, NULL, 0))
642  dn_fib_flush();
643  }
644  }
645 }
646 
647 static void dn_fib_disable_addr(struct net_device *dev, int force)
648 {
649  if (dn_fib_sync_down(0, dev, force))
650  dn_fib_flush();
653 }
654 
655 static int dn_fib_dnaddr_event(struct notifier_block *this, unsigned long event, void *ptr)
656 {
657  struct dn_ifaddr *ifa = (struct dn_ifaddr *)ptr;
658 
659  switch (event) {
660  case NETDEV_UP:
661  dn_fib_add_ifaddr(ifa);
662  dn_fib_sync_up(ifa->ifa_dev->dev);
663  dn_rt_cache_flush(-1);
664  break;
665  case NETDEV_DOWN:
666  dn_fib_del_ifaddr(ifa);
667  if (ifa->ifa_dev && ifa->ifa_dev->ifa_list == NULL) {
668  dn_fib_disable_addr(ifa->ifa_dev->dev, 1);
669  } else {
670  dn_rt_cache_flush(-1);
671  }
672  break;
673  }
674  return NOTIFY_DONE;
675 }
676 
677 static int dn_fib_sync_down(__le16 local, struct net_device *dev, int force)
678 {
679  int ret = 0;
680  int scope = RT_SCOPE_NOWHERE;
681 
682  if (force)
683  scope = -1;
684 
685  for_fib_info() {
686  /*
687  * This makes no sense for DECnet.... we will almost
688  * certainly have more than one local address the same
689  * over all our interfaces. It needs thinking about
690  * some more.
691  */
692  if (local && fi->fib_prefsrc == local) {
693  fi->fib_flags |= RTNH_F_DEAD;
694  ret++;
695  } else if (dev && fi->fib_nhs) {
696  int dead = 0;
697 
698  change_nexthops(fi) {
699  if (nh->nh_flags&RTNH_F_DEAD)
700  dead++;
701  else if (nh->nh_dev == dev &&
702  nh->nh_scope != scope) {
703  spin_lock_bh(&dn_fib_multipath_lock);
704  nh->nh_flags |= RTNH_F_DEAD;
705  fi->fib_power -= nh->nh_power;
706  nh->nh_power = 0;
707  spin_unlock_bh(&dn_fib_multipath_lock);
708  dead++;
709  }
710  } endfor_nexthops(fi)
711  if (dead == fi->fib_nhs) {
712  fi->fib_flags |= RTNH_F_DEAD;
713  ret++;
714  }
715  }
716  } endfor_fib_info();
717  return ret;
718 }
719 
720 
721 static int dn_fib_sync_up(struct net_device *dev)
722 {
723  int ret = 0;
724 
725  if (!(dev->flags&IFF_UP))
726  return 0;
727 
728  for_fib_info() {
729  int alive = 0;
730 
731  change_nexthops(fi) {
732  if (!(nh->nh_flags&RTNH_F_DEAD)) {
733  alive++;
734  continue;
735  }
736  if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
737  continue;
738  if (nh->nh_dev != dev || dev->dn_ptr == NULL)
739  continue;
740  alive++;
741  spin_lock_bh(&dn_fib_multipath_lock);
742  nh->nh_power = 0;
743  nh->nh_flags &= ~RTNH_F_DEAD;
744  spin_unlock_bh(&dn_fib_multipath_lock);
745  } endfor_nexthops(fi);
746 
747  if (alive > 0) {
748  fi->fib_flags &= ~RTNH_F_DEAD;
749  ret++;
750  }
751  } endfor_fib_info();
752  return ret;
753 }
754 
755 static struct notifier_block dn_fib_dnaddr_notifier = {
756  .notifier_call = dn_fib_dnaddr_event,
757 };
758 
760 {
763 
764  unregister_dnaddr_notifier(&dn_fib_dnaddr_notifier);
765 }
766 
767 
768 void __init dn_fib_init(void)
769 {
772 
773  register_dnaddr_notifier(&dn_fib_dnaddr_notifier);
774 
775  rtnl_register(PF_DECnet, RTM_NEWROUTE, dn_fib_rtm_newroute, NULL, NULL);
776  rtnl_register(PF_DECnet, RTM_DELROUTE, dn_fib_rtm_delroute, NULL, NULL);
777 }
778 
779